Animation engine for explanatory math videos
This report presents the forensic synthetic code analysis of 3b1b/manim, a Python project with 88,507 GitHub stars. SynthScan v2.0 examined 25,622 lines of code across 111 source files, recording 393 pattern matches distributed across 12 syntactic categories. The overall adjusted score of 15.2 places this repository in the Moderate AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 393 distinct pattern matches across 12 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | example_scenes.py | 1 | CODE | |
| LOW | manimlib/config.py | 1 | CODE | |
| LOW | manimlib/window.py | 1 | CODE | |
| LOW | manimlib/constants.py | 1 | CODE | |
| LOW | manimlib/__init__.py | 17 | CODE | |
| LOW | manimlib/__init__.py | 19 | CODE | |
| LOW | manimlib/__init__.py | 21 | CODE | |
| LOW | manimlib/__init__.py | 22 | CODE | |
| LOW | manimlib/__init__.py | 23 | CODE | |
| LOW | manimlib/__init__.py | 24 | CODE | |
| LOW | manimlib/__init__.py | 25 | CODE | |
| LOW | manimlib/__init__.py | 26 | CODE | |
| LOW | manimlib/__init__.py | 27 | CODE | |
| LOW | manimlib/__init__.py | 28 | CODE | |
| LOW | manimlib/__init__.py | 29 | CODE | |
| LOW | manimlib/__init__.py | 30 | CODE | |
| LOW | manimlib/__init__.py | 31 | CODE | |
| LOW | manimlib/__init__.py | 32 | CODE | |
| LOW | manimlib/__init__.py | 33 | CODE | |
| LOW | manimlib/__init__.py | 35 | CODE | |
| LOW | manimlib/__init__.py | 37 | CODE | |
| LOW | manimlib/__init__.py | 38 | CODE | |
| LOW | manimlib/__init__.py | 39 | CODE | |
| LOW | manimlib/__init__.py | 40 | CODE | |
| LOW | manimlib/__init__.py | 41 | CODE | |
| LOW | manimlib/__init__.py | 42 | CODE | |
| LOW | manimlib/__init__.py | 43 | CODE | |
| LOW | manimlib/__init__.py | 44 | CODE | |
| LOW | manimlib/__init__.py | 45 | CODE | |
| LOW | manimlib/__init__.py | 46 | CODE | |
| LOW | manimlib/__init__.py | 47 | CODE | |
| LOW | manimlib/__init__.py | 48 | CODE | |
| LOW | manimlib/__init__.py | 49 | CODE | |
| LOW | manimlib/__init__.py | 50 | CODE | |
| LOW | manimlib/__init__.py | 51 | CODE | |
| LOW | manimlib/__init__.py | 52 | CODE | |
| LOW | manimlib/__init__.py | 53 | CODE | |
| LOW | manimlib/__init__.py | 54 | CODE | |
| LOW | manimlib/__init__.py | 55 | CODE | |
| LOW | manimlib/__init__.py | 56 | CODE | |
| LOW | manimlib/__init__.py | 57 | CODE | |
| LOW | manimlib/__init__.py | 58 | CODE | |
| LOW | manimlib/__init__.py | 59 | CODE | |
| LOW | manimlib/__init__.py | 60 | CODE | |
| LOW | manimlib/__init__.py | 61 | CODE | |
| LOW | manimlib/__init__.py | 62 | CODE | |
| LOW | manimlib/__init__.py | 63 | CODE | |
| LOW | manimlib/__init__.py | 64 | CODE | |
| LOW | manimlib/__init__.py | 65 | CODE | |
| LOW | manimlib/__init__.py | 67 | CODE | |
| LOW | manimlib/__init__.py | 68 | CODE | |
| LOW | manimlib/__init__.py | 70 | CODE | |
| LOW | manimlib/__init__.py | 71 | CODE | |
| LOW | manimlib/__init__.py | 72 | CODE | |
| LOW | manimlib/__init__.py | 73 | CODE | |
| LOW | manimlib/__init__.py | 74 | CODE | |
| LOW | manimlib/__init__.py | 75 | CODE | |
| LOW | manimlib/__init__.py | 76 | CODE | |
| LOW | manimlib/__init__.py | 77 | CODE | |
| LOW | manimlib/__init__.py | 78 | CODE | |
| 116 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/config.py | 268 | def update_file_writer_config(config: Dict, args: Namespace): | CODE |
| LOW | manimlib/window.py | 120 | def pixel_coords_to_space_coords( | CODE |
| LOW | manimlib/extract_scene.py | 146 | def insert_embed_line_to_module(module: Module, run_config: Dict) -> None: | CODE |
| LOW | manimlib/module_loader.py | 53 | def _exec_module_and_track_imports(spec, module: Module) -> set[str]: | CODE |
| LOW | manimlib/camera/camera_frame.py | 97 | def get_inverse_camera_rotation_matrix(self): | CODE |
| LOW | manimlib/camera/camera_frame.py | 251 | def get_implied_camera_location(self) -> np.ndarray: | CODE |
| LOW | manimlib/animation/transform_matching_parts.py | 101 | def find_pairs_with_matching_shapes( | CODE |
| LOW | manimlib/animation/animation.py | 113 | def get_all_mobjects_to_update(self) -> list[Mobject]: | CODE |
| LOW | manimlib/animation/transform.py | 83 | def check_target_mobject_validity(self) -> None: | CODE |
| LOW | manimlib/animation/composition.py | 90 | def build_animations_with_timings(self, lag_ratio: float) -> None: | CODE |
| LOW | manimlib/utils/rate_functions.py | 48 | def there_and_back_with_pause(t: float, pause_ratio: float = 1. / 3) -> float: | CODE |
| LOW | manimlib/utils/bezier.py | 75 | def partial_quadratic_bezier_points( | CODE |
| LOW | manimlib/utils/bezier.py | 117 | def set_array_by_interpolation( | CODE |
| LOW | manimlib/utils/bezier.py | 174 | def quadratic_bezier_points_for_arc(angle: float, n_components: int = 8): | CODE |
| LOW | manimlib/utils/bezier.py | 184 | def approx_smooth_quadratic_bezier_handles( | CODE |
| LOW | manimlib/utils/bezier.py | 257 | def get_smooth_cubic_bezier_handle_points( | CODE |
| LOW | manimlib/utils/bezier.py | 343 | def get_quadratic_approximation_of_cubic( | CODE |
| LOW | manimlib/utils/bezier.py | 415 | def get_smooth_quadratic_bezier_path_through( | CODE |
| LOW | manimlib/utils/space_ops.py | 98 | def quaternion_from_angle_axis( | CODE |
| LOW | manimlib/utils/space_ops.py | 105 | def angle_axis_from_quaternion(quat: Vect4) -> Tuple[float, Vect3]: | CODE |
| LOW | manimlib/utils/space_ops.py | 132 | def rotation_matrix_transpose_from_quaternion(quat: Vect4) -> Matrix3x3: | CODE |
| LOW | manimlib/utils/space_ops.py | 136 | def rotation_matrix_from_quaternion(quat: Vect4) -> Matrix3x3: | CODE |
| LOW | manimlib/utils/space_ops.py | 147 | def rotation_matrix_transpose(angle: float, axis: Vect3) -> Matrix3x3: | CODE |
| LOW | manimlib/utils/space_ops.py | 356 | def get_closest_point_on_line(a: VectN, b: VectN, p: VectN) -> VectN: | CODE |
| LOW⚡ | manimlib/utils/images.py | 17 | def get_full_raster_image_path(image_file_name: str) -> str: | CODE |
| LOW⚡ | manimlib/utils/images.py | 25 | def get_full_vector_image_path(image_file_name: str) -> str: | CODE |
| LOW⚡ | manimlib/utils/images.py | 33 | def get_full_three_d_model_path(model_file_name: str) -> str: | CODE |
| LOW | manimlib/utils/family_ops.py | 11 | def extract_mobject_family_members( | CODE |
| LOW | manimlib/utils/iterables.py | 108 | def resize_with_interpolation(nparray: np.ndarray, length: int) -> np.ndarray: | CODE |
| LOW | manimlib/utils/shaders.py | 80 | def get_shader_code_from_file(filename: str) -> str | None: | CODE |
| LOW | manimlib/scene/scene_file_writer.py | 94 | def init_partial_movie_directory(self): | CODE |
| LOW | manimlib/scene/scene_file_writer.py | 121 | def get_next_partial_movie_path(self) -> str: | CODE |
| LOW | manimlib/scene/scene_file_writer.py | 270 | def set_progress_display_description(self, file: str = "", sub_desc: str = "") -> None: | CODE |
| LOW | manimlib/scene/scene.py | 297 | def get_mobject_family_members(self) -> list[Mobject]: | CODE |
| LOW | manimlib/scene/scene.py | 496 | def get_animation_time_progression( | CODE |
| LOW | manimlib/scene/scene.py | 508 | def get_wait_time_progression( | CODE |
| LOW | manimlib/scene/scene.py | 555 | def progress_through_animations(self, animations: Iterable[Animation]) -> None: | CODE |
| LOW | manimlib/scene/scene.py | 640 | def revert_to_original_skipping_status(self): | CODE |
| LOW | manimlib/scene/interactive_scene.py | 145 | def update_selection_rectangle(self, rect: Rectangle): | CODE |
| LOW | manimlib/scene/interactive_scene.py | 161 | def update_selection_highlight(self, highlight: Mobject): | CODE |
| LOW | manimlib/scene/interactive_scene.py | 263 | def regenerate_selection_search_set(self): | CODE |
| LOW | manimlib/scene/interactive_scene.py | 591 | def handle_sweeping_selection(self, point: Vect3): | CODE |
| LOW | manimlib/scene/scene_embed.py | 39 | def get_ipython_shell_for_embedded_scene(self) -> InteractiveShellEmbed: | CODE |
| LOW | manimlib/scene/scene_embed.py | 95 | def ensure_frame_update_post_cell(self): | CODE |
| LOW | manimlib/mobject/matrix.py | 154 | def add_background_to_entries(self) -> Self: | CODE |
| LOW | manimlib/mobject/matrix.py | 167 | def swap_entries_for_ellipses( | CODE |
| LOW | manimlib/mobject/vector_field.py | 34 | def get_vectorized_rgb_gradient_function( | CODE |
| LOW | manimlib/mobject/vector_field.py | 57 | def get_rgb_gradient_function( | CODE |
| LOW | manimlib/mobject/vector_field.py | 89 | def move_submobjects_along_vector_field( | CODE |
| LOW | manimlib/mobject/vector_field.py | 103 | def move_points_along_vector_field( | CODE |
| LOW | manimlib/mobject/vector_field.py | 231 | def init_base_stroke_width_array(self, n_sample_points): | CODE |
| LOW | manimlib/mobject/boolean_ops.py | 12 | def _convert_vmobject_to_skia_path(vmobject: VMobject) -> pathops.Path: | CODE |
| LOW | manimlib/mobject/boolean_ops.py | 26 | def _convert_skia_path_to_vmobject( | CODE |
| LOW⚡ | manimlib/mobject/numbers.py | 80 | def set_submobjects_from_number(self, number: float | complex) -> None: | CODE |
| LOW | manimlib/mobject/numbers.py | 217 | def _handle_scale_side_effects(self, scale_factor: float) -> Self: | CODE |
| LOW | manimlib/mobject/interactive.py | 520 | def move_panel_and_controls_to_panel_opener(self) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 558 | def panel_opener_on_mouse_drag(self, mob, event_data: dict[str, np.ndarray]) -> bool: | CODE |
| LOW | manimlib/mobject/geometry.py | 116 | def reset_endpoints_based_on_tip(self, tip: ArrowTip, at_start: bool) -> Self: | CODE |
| LOW | manimlib/mobject/geometry.py | 798 | def set_perpendicular_to_camera(self, camera_frame): | CODE |
| LOW | manimlib/mobject/geometry.py | 996 | def create_tip_with_stroke_width(self) -> Self: | CODE |
| 73 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/shader_wrapper.py | 233 | CODE | |
| LOW | manimlib/camera/camera.py | 26 | CODE | |
| LOW | manimlib/animation/animation.py | 24 | CODE | |
| LOW | manimlib/animation/specialized.py | 17 | CODE | |
| LOW | manimlib/utils/color.py | 163 | CODE | |
| LOW | manimlib/scene/scene_file_writer.py | 29 | CODE | |
| LOW | manimlib/scene/scene.py | 64 | CODE | |
| LOW | manimlib/mobject/matrix.py | 25 | CODE | |
| LOW | manimlib/mobject/vector_field.py | 52 | CODE | |
| LOW | manimlib/mobject/vector_field.py | 142 | CODE | |
| LOW | manimlib/mobject/vector_field.py | 338 | CODE | |
| LOW | manimlib/mobject/numbers.py | 35 | CODE | |
| LOW | manimlib/mobject/interactive.py | 383 | CODE | |
| LOW | manimlib/mobject/geometry.py | 539 | CODE | |
| LOW | manimlib/mobject/geometry.py | 1077 | CODE | |
| LOW | manimlib/mobject/number_line.py | 28 | CODE | |
| LOW | manimlib/mobject/number_line.py | 245 | CODE | |
| LOW | manimlib/mobject/probability.py | 197 | CODE | |
| LOW | manimlib/mobject/coordinate_systems.py | 363 | CODE | |
| LOW | manimlib/mobject/coordinate_systems.py | 446 | CODE | |
| LOW | manimlib/mobject/mobject.py | 538 | CODE | |
| LOW | manimlib/mobject/svg/drawings.py | 189 | CODE | |
| LOW | manimlib/mobject/svg/drawings.py | 358 | CODE | |
| LOW | manimlib/mobject/svg/drawings.py | 594 | CODE | |
| LOW | manimlib/mobject/svg/drawings.py | 688 | CODE | |
| LOW | manimlib/mobject/svg/svg_mobject.py | 58 | CODE | |
| LOW | manimlib/mobject/svg/string_mobject.py | 46 | CODE | |
| LOW | manimlib/mobject/svg/text_mobject.py | 136 | CODE | |
| LOW | manimlib/mobject/svg/old_tex_mobject.py | 23 | CODE | |
| LOW | manimlib/mobject/svg/tex_mobject.py | 38 | CODE | |
| LOW | manimlib/mobject/types/vectorized_mobject.py | 79 | CODE | |
| LOW | manimlib/mobject/types/vectorized_mobject.py | 215 | CODE | |
| LOW | manimlib/mobject/types/surface.py | 44 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/logger.py | 5 | __all__ = ["log"] | CODE |
| LOW | manimlib/shader_wrapper.py | 144 | def set_ctx_depth_test(self, enable: bool = True) -> None: | CODE |
| LOW | manimlib/shader_wrapper.py | 150 | def set_ctx_clip_plane(self, num_planes: int = 0) -> None: | CODE |
| LOW | manimlib/animation/creation.py | 199 | def update_submobject_list(self, index: int) -> None: | CODE |
| LOW | manimlib/animation/creation.py | 212 | def update_submobject_list(self, index: int) -> None: | CODE |
| LOW | manimlib/animation/animation.py | 105 | def update_mobjects(self, dt: float) -> None: | CODE |
| LOW | manimlib/animation/transform.py | 95 | def update_config(self, **kwargs) -> None: | CODE |
| LOW | manimlib/animation/composition.py | 78 | def update_mobjects(self, dt: float) -> None: | CODE |
| LOW | manimlib/animation/composition.py | 141 | def update_mobjects(self, dt: float) -> None: | CODE |
| LOW | manimlib/scene/scene_file_writer.py | 270 | def set_progress_display_description(self, file: str = "", sub_desc: str = "") -> None: | CODE |
| LOW | manimlib/scene/scene.py | 236 | def update_frame(self, dt: float = 0, force_draw: bool = False) -> None: | CODE |
| LOW | manimlib/scene/scene.py | 264 | def update_mobjects(self, dt: float) -> None: | CODE |
| LOW | manimlib/scene/scene.py | 450 | def update_skipping_status(self) -> None: | CODE |
| LOW | manimlib/scene/scene.py | 876 | def set_background_color(self, background_color, background_opacity=1) -> None: | CODE |
| LOW⚡ | manimlib/mobject/numbers.py | 80 | def set_submobjects_from_number(self, number: float | complex) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 124 | def set_value_anim(self, value: bool) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 176 | def set_value_anim(self, value: bool) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 257 | def set_value_anim(self, value: float) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 419 | def set_value_anim(self, value: str) -> None: | CODE |
| LOW | manimlib/mobject/interactive.py | 422 | def update_text(self, value: str) -> None: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | manimlib/__main__.py | 24 | # Create a new dict to be able to upate without | COMMENT |
| MEDIUM | manimlib/__main__.py | 30 | # Create a reusable window | COMMENT |
| MEDIUM | manimlib/animation/indication.py | 235 | # Create a gaussian such that 3 sigmas out on either side | COMMENT |
| MEDIUM | manimlib/utils/tex_file_writing.py | 98 | temp_dir.mkdir(exist_ok=True) # Create the directory if it does not already exist | CODE |
| MEDIUM⚡ | manimlib/mobject/numbers.py | 81 | # Create the submobject list | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/module_loader.py | 139 | CODE | |
| LOW | manimlib/event_handler/event_dispatcher.py | 37 | CODE | |
| LOW | manimlib/scene/scene_file_writer.py | 349 | CODE | |
| LOW | manimlib/scene/scene.py | 827 | CODE | |
| LOW | manimlib/scene/interactive_scene.py | 413 | CODE | |
| LOW | manimlib/scene/interactive_scene.py | 487 | CODE | |
| LOW | manimlib/scene/interactive_scene.py | 560 | CODE | |
| LOW | manimlib/mobject/boolean_ops.py | 26 | CODE | |
| LOW | manimlib/mobject/interactive.py | 445 | CODE | |
| LOW | manimlib/mobject/coordinate_systems.py | 363 | CODE | |
| LOW | manimlib/mobject/svg/svg_mobject.py | 203 | CODE | |
| LOW | manimlib/mobject/svg/text_mobject.py | 319 | CODE | |
| LOW | manimlib/mobject/svg/old_tex_mobject.py | 153 | CODE | |
| LOW | manimlib/mobject/svg/tex_mobject.py | 92 | CODE | |
| LOW | manimlib/mobject/types/vectorized_mobject.py | 694 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/default_config.yml | 12 | # Set this to true if you want the path to video files | COMMENT |
| LOW | manimlib/utils/file_ops.py | 31 | # Check if this is a file online first, and if so, download | COMMENT |
| LOW | manimlib/utils/file_ops.py | 44 | # Check if what was passed in is already a valid path to a file | COMMENT |
| LOW | manimlib/mobject/mobject.py | 907 | # Check if mark as static or not for camera | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | manimlib/utils/tex_file_writing.py | 58 | Convert LaTeX string to SVG string. Args: latex: LaTeX source code template: Path to a template LaT | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | example_scenes.py | 300 | # If the argument itself might change, you can use f_always, | STRING |
| MEDIUM | manimlib/mobject/svg/old_tex_mobject.py | 111 | # tex == "\\frac", # you can use \\over as a alternative | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/config.py | 260 | except Exception as err: | CODE |
| LOW | manimlib/scene/scene_embed.py | 135 | except Exception as e: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/mobject/mobject.py | 1783 | # If empty, simply add n point mobjects | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | manimlib/default_config.yml | 1 | # This file determines the default configuration for how manim is | COMMENT |