Manim Community Edition

repository·main·Indexed 12 days ago

https://github.com/manimcommunity/manim

A programmatic animation engine for creating high-quality, precise mathematical explanatory videos using Python. Version 0.21.0 allows developers to define scenes, Mobjects, and complex animations using a Python API, featuring tools for plotting functions on Axes, performing Boolean operations on shapes, and creating dynamic updates with ValueTrackers.

Tokens
36.5K
Snippets
123
Records
179
Agent score
98%

What's inside Manim

  1. Explore Manim Mobjects

    main

    Mobjects (Mathematical Objects) are the fundamental building blocks of Manim animations. They represent the visual elements that appear on screen, such as shapes, text, mathematical formulas, and graphs. The manim module provides a wide variety of specialized Mobjects categorized by their function:

    • Basic & Geometric: Standard shapes and geometric primitives (mobject.geometry, mobject.types).
    • Text & Math: Textual elements, mathematical notation, and matrices (mobject.text, mobject.matrix).
    • Data & Graphs: Visual representations of data, including graphs, graphing functions, and vector fields (mobject.graph, mobject.graphing, mobject.vector_field).
    • Tables & Structures: Organized data structures like tables (mobject.table).
    • 3D Objects: Mobjects designed for three-dimensional scenes (mobject.three_d).
    • Specialized: SVG imports (mobject.svg), logos (mobject.logo), and frames (mobject.frame).
    • Dynamic Control: Tools for managing animation state, such as ValueTracker (mobject.value_tracker).
  2. Use ValueTrackers to drive animations

    main

    A ValueTracker is a specialized Mobject used to track a numerical value that can be animated. By using add_updater on other Mobjects, you can make them react to the changes in a ValueTracker's value, allowing for complex, coordinated animations.

    Key concepts:

    • tracker.get_value(): Retrieves the current value.
    • tracker.animate.set_value(new_value): Animates the tracker to a new value.
    • tracker.animate.increment_value(amount): Animates an incremental change.
    • add_updater(func): Attaches a function to a Mobject that runs every frame, typically using the tracker's value to update the Mobject's properties.

    Example: Animating an angle and its label using a ValueTracker:

    theta_tracker = ValueTracker(110)
    # ... inside construct ...
    line_moving.add_updater(
        lambda x: x.become(line_ref.copy()).rotate(
            theta_tracker.get_value() * DEGREES, about_point=rotation_center
        )
    )
    self.play(theta_tracker.animate.set_value(40))
    class MovingAngle(Scene):
        def construct(self):
            rotation_center = LEFT
    
            theta_tracker = ValueTracker(110)
            line1 = Line(LEFT, RIGHT)
            line_moving = Line(LEFT, RIGHT)
            line_ref = line_moving.copy()
            line_moving.rotate(
                theta_tracker.get_value() * DEGREES, about_point=rotation_center
            )
            a = Angle(line1, line_moving, radius=0.5, other_angle=False)
            tex = MathTex(r"\theta").move_to(
                Angle(
                    line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False
                ).point_from_proportion(0.5)
            )
    
            self.add(line1, line_moving, a, tex)
            self.wait()
    
            line_moving.add_updater(
                lambda x: x.become(line_ref.copy()).rotate(
                    theta_tracker.get_value() * DEGREES, about_point=rotation_center
                )
            )
    
            a.add_updater(
                lambda x: x.become(Angle(line1, line_moving, radius=0.5, other_angle=False))
            )
            tex.add_updater(
                lambda x: x.move_to(
                    Angle(
                        line1, line_moving, radius=0.5 + 3 * SMALL_BUFF, other_angle=False
                    ).point_from_proportion(0.5)
                )
            )
    
            self.play(theta_tracker.animate.set_value(40))
            self.play(theta_tracker.animate.increment_value(140))
            self.play(tex.animate.set_color(RED), run_time=0.5)
            self.play(theta_tracker.animate.set_value(350))
  3. Control Mobject Z-order (on-screen layering)

    main

    The order in which mobjects are passed to self.add() determines their stacking order (Z-order) on the screen. The first argument is placed at the bottom (the back), and subsequent arguments are layered on top of it.

    class MobjectZOrder(Scene):
        def construct(self):
            circle = Circle()
            square = Square()
            triangle = Triangle()
    
            # triangle will be in the back, circle will be in the front
            self.add(triangle, square, circle)
            self.wait(1)
  4. The Scene class lifecycle and core methods

    main

    The Scene class is the fundamental container for all Manim content.

    Key Requirements:

    • Subclassing: All video content must be written inside the construct() method of a class that inherits from Scene.
    • Displaying Mobjects: Use self.add(mobject) to place a Mobject on screen immediately, or self.play(Animation(mobject)) to animate its appearance.
    • Removing Mobjects: Use self.remove(mobject) to take a Mobject off the screen.
    • Timing: Use self.wait(seconds) to create pauses in the animation sequence.
    • Multiple Scenes: A single Python file can contain multiple Scene subclasses, allowing you to render several different scenes in one execution.
  5. Understand the Manim configuration precedence

    main

    Manim uses a cascading configuration system where settings are applied in a specific order. If multiple sources define the same setting, the source with the highest precedence wins.

    When using the CLI, the order of precedence from lowest to highest is:

    1. Library-wide config file: The default settings bundled with Manim.
    2. User-wide config file: A configuration file specific to your user account (if it exists).
    3. Folder-wide config file OR Custom config file: A file in your current working directory (if it exists) OR a specific file provided via the --config_file flag.
    4. CLI flags: Arguments passed directly to the manim command.
    5. Programmatic changes: Any modifications made to the config object within your Python code after the configuration system has been initialized.
  6. How Scene instantiation and rendering works

    main

    Regardless of whether you use the CLI (manim -qm file.py SceneName) or Jupyter notebooks (%%manim), the underlying process is the same:

    1. Instantiation: A Scene object is created. During __init__, the scene inspects config.renderer to instantiate either a CairoRenderer or an OpenGLRenderer.
    2. Renderer Initialization: The scene calls self.renderer.init_scene(self), which triggers the creation of a SceneFileWriter (the interface to FFMPEG) to handle the output file.
    3. Rendering: The render() method is called, which triggers the lifecycle hooks (setup, construct, tear_down).
    4. Completion: Once finished, the renderer calls scene_finished, which instructs the SceneFileWriter to finalize the video file (encoding partial segments into the final movie).
  7. Use updaters and always_redraw for dynamic animations

    main

    Manim provides two primary ways to handle objects that change over time based on other objects' movements:

    1. add_updater(func): Attaches a function to a Mobject that is called every frame. The function receives the Mobject (mob) and the time delta (dt) as arguments. This is useful for continuous movement, such as a dot orbiting a circle.
    2. always_redraw(func): A helper function that creates a new Mobject every frame by calling func. This is ideal for lines or shapes that must constantly re-calculate their geometry based on the current position of other moving objects (e.g., a line connecting a moving dot to a fixed point).

    To stop an updater, use remove_updater(func).

    # Using an updater for continuous movement
    def go_around_circle(mob, dt):
        self.t_offset += (dt * rate)
        mob.move_to(orbit.point_from_proportion(self.t_offset % 1))
    
    dot.add_updater(go_around_circle)
    
    # Using always_redraw for a line that follows a moving object
    def get_line_to_circle():
        return Line(origin_point, dot.get_center(), color=BLUE)
    
    origin_to_circle_line = always_redraw(get_line_to_circle)
    self.add(origin_to_circle_line)
    
    # Removing the updater
    dot.remove_updater(go_around_circle)
  8. Understand the Mobject hierarchy

    main

    In Manim, Mobject (Mathematical Object) is the base class for all visual elements. However, a pure Mobject cannot be rendered by the camera. To display something on screen, you must use one of the following specialized types:

    • ImageMobject: Used for displaying images.
    • PMobject: Used for representing point clouds.
    • VMobject (Vectorized Mobject): The most common type. These consist of points connected via cubic Bézier curves. The renderer processes VMobject points in sets of four: the first and last points are 'anchors', and the middle two are 'handles' (control points).
    from manim import VMobject
    
    # Example of a VMobject with 8 points (forming 2 cubic Bézier curves)
    my_vmobject = VMobject(color=GREEN).set_points([
        [-2, -1, 0],  # start of first curve
        [-3, 1, 0],   # handle 1
        [0, 3, 0],    # handle 2
        [1, 3, 0],    # end of first curve
        [1, 3, 0],    # start of second curve
        [0, 1, 0],   # handle 3
        [4, 3, 0],    # handle 4
        [4, -2, 0],   # end of second curve
    ])
  9. How Scene.add() manages mobjects

    main

    When you call Scene.add(mobject), Manim adds the object to the Scene.mobjects list. To prevent the same object from being rendered multiple times (e.g., if it's already part of a Group in the scene), Manim uses Scene.restructure_mobjects().

    If you add a Group that contains an object already present in the scene, Manim will deconstruct the parent group and move the existing object's siblings up to the root level to ensure a clean, non-redundant hierarchy.

    from manim import Scene, Square, Circle, Group
    
    test_scene = Scene()
    mob1 = Square()
    mob2 = Circle()
    mob_group = Group(mob1, mob2)
    
    test_scene.add(mob_group)
    # test_scene.mobjects is [Group]
    
    test_scene.restructure_mobjects(to_remove=[mob1])
    # test_scene.mobjects is now [Circle] because the group was disbanded
  10. Understand the Manim render process overview

    main

    Manim's rendering process follows a structured lifecycle to transform scene code into video. The process can be broken down into three main stages:

    1. Preliminaries: Preparing the scene for rendering, which includes setting up the environment before the user-defined construct method is executed. This can be triggered via the Manim CLI, within Jupyter notebooks, or by manually calling the Scene.render method in a Python script.
    2. Mobject Initialization: Creating and managing Mobject instances (the basic visual elements). This involves handling different Mobject types (primarily vectorized Mobjects) and using Scene.add to manage which objects are tracked for rendering.
    3. Animations and the Render Loop: Executing Animation objects (blueprints for Mobject changes) via Scene.play. The Scene.play call processes animations, runs a render loop that steps through a timeline to produce frames, and handles the encoding of 'partial movie files' which are eventually combined into the final video.
  11. Choose a text rendering method in Manim

    main

    Manim provides three distinct ways to render text and formulas, depending on your needs:

    1. Pango-based (Text, MarkupText, Paragraph): The simplest method for plain text or markup. It supports non-English alphabets (e.g., Chinese, Japanese, Arabic) and does not require a TeX distribution.
    2. LaTeX-based (Tex, MathTex): Best for high-quality mathematical typesetting using a TeX distribution.
    3. Typst-based (Typst, MathTypst): A modern alternative that compiles Typst markup directly to SVG. It offers both general markup and math support without requiring TeX. Requires the typst dependency (pip install manim[typst]).
  12. Important runtime notes for Manim Docker images

    main

    When using the Manim Docker image, be aware of the following environmental constraints:

    • Build Structure: The image uses a multi-stage Dockerfile; build dependencies are excluded from the final runtime stage to keep the image lean.
    • FFmpeg: The ffmpeg CLI binary is not included in the image.
    • TeX Installation: The default TeX installation is minimal and does not include ctex.
    • OpenGL Rendering: Headless OpenGL rendering depends on the EGL/GL runtime libraries provided within the image.