manim_skill Documentation

repository·main·Indexed 21 days ago

https://github.com/adithya-s-k/manim_skill

A repository of best practices, patterns, and tested code examples for Manim Community Edition and ManimGL. It provides installation guides, troubleshooting for system dependencies like FFmpeg and LaTeX, and narrative patterns for mathematical animations. The documentation includes specific implementation guides for visualizing Dot Products, Fourier Series, and Matrix Linear Transformations, as well as pacing and emotional arc guidelines for educational math videos.

Tokens
79.1K
Snippets
329
Records
381
Agent score
76%

What's inside manim_skill

  1. ManimCE Best Practices Reference Guide

    main

    The manimce-best-practices skill contains detailed rules and examples for various ManimCE domains. Refer to the following categories for specific implementation guidance:

    • Core Concepts: Scene structure, Mobjects, and Animation classes.
    • Creation & Transformation: Using Create, Write, Transform, and ReplacementTransform.
    • Text & Math: Styling Text and using MathTex for LaTeX rendering.
    • Styling: Managing colors, gradients, fill, and stroke.
    • Positioning: Using move_to, next_to, align_to, and VGroup for layout.
    • Coordinate Systems: Working with Axes, NumberPlane, and ThreeDScene.
    • Animation Control: Using Rate functions, Updaters, and ValueTracker for dynamic movement.
    • Configuration: Managing manim.cfg and CLI options.
  2. Control the camera using CameraFrame in ManimGL

    main

    In ManimGL, camera control is managed via self.camera.frame, which is a CameraFrame object (a type of Mobject). If you are using an InteractiveScene, you can use self.frame as a convenient shortcut. You can manipulate the camera's orientation using Euler angles (theta, phi, gamma) to position the view in 3D space.

    frame = self.camera.frame
    
    # Set euler angles for 3D orientation
    frame.set_euler_angles(
        theta=-30 * DEGREES,
        phi=70 * DEGREES,
    )
  3. Pattern: TracedPath for real-time graphs

    main

    To visualize a real-time graph of a moving object's position (e.g., $x(t)$), use a TracedPath attached to a dummy Point.

    1. Create a Point object.
    2. Add an updater to the Point that moves it to the coordinate corresponding to the current time and position (using axes.c2p).
    3. Create a TracedPath that follows the center of that Point.
    tracking_point = Point()
    tracking_point.add_updater(lambda p: p.move_to(
        axes.c2p(time_tracker.get_value(), spring.get_x())
    ))
    position_graph = TracedPath(tracking_point.get_center, stroke_color=BLUE)
  4. Apply core principles for math animation

    main

    To create effective mathematical visualizations, follow these four core principles:

    1. Progressive Disclosure: Build complexity gradually. Instead of showing a full equation immediately, build it term by term (e.g., start with $f(x) = x^2$, then add $ax^2$, then the full quadratic).
    2. Transform, Don't Replace: Use morphing animations to maintain visual continuity. Instead of using FadeOut and FadeIn for different equations, use TransformMatchingTex to show the relationship between forms.
    3. Color as Meaning: Use a consistent color encoding system. For example:
      • BLUE: Input/given values
      • GREEN: Output/results
      • YELLOW: Key terms being discussed
      • RED: Errors/negatives
      • WHITE/GREY: Neutral/supporting elements
    4. Spatial Relationships: Use positioning to encode logic:
      • Left-to-right: Transformation, time, or causation.
      • Top-to-bottom: Hierarchy or derivation.
      • Center: Primary focus.
      • Periphery: Context or reference.
  5. Implement Transit and Periodic Motion

    main

    Transit animations involve objects moving along paths, often leaving traces or showing periodic behavior. This is useful for astronomical transits, loading indicators, or physics demonstrations.

    Common implementation strategies include:

    • Snapshots: Creating static copies of a moving object at specific intervals to create a 'trail' or 'trace' effect.
    • Orbital Motion with Depth: Simulating 3D depth in a 2D plane by varying the object's scale (width/height) based on its position in the orbit (e.g., using a sine wave to scale the object as it moves).
    • Phase-Shifted Oscillation: Creating synchronized but offset animations (like loading dots) by applying a phase shift to the trigonometric function used in the updater.
    # Example: Phase-Shifted Oscillation (Loading Dots)
    for i, dot in enumerate(dots):
        phase = i * TAU / n_dots
        dot.add_updater(lambda m, p=phase: m.set_y(
            original_y + 0.3 * np.sin(3 * time.get_value() + p)
        ))
  6. Choosing between VGroup and Group

    main

    Manim provides two primary ways to group mobjects, depending on the types of objects you are combining:

    1. VGroup (Vectorized Group): Use this for grouping VMobjects (Vectorized Mobjects). This is the most common type of group and offers better performance and compatibility for vector-based shapes.
    2. Group: Use this when you need to mix different mobject types that are not all VMobjects, such as combining a Circle (VMobject) with an ImageMobject or Text.

    When you apply transformations (like .shift(), .scale(), or .set_color()) to a group, the operation is applied to all members of that group.

    from manim import *
    
    # Use VGroup for VMobjects
    vgroup = VGroup(Circle(), Square(), Triangle())
    vgroup.set_color(RED)
    
    # Use Group for mixed types
    group = Group(Circle(), Text("Hello"))
  7. Understand the Manim Mobject hierarchy

    main

    A Mobject (Mathematical Object) is the base class for all displayable objects in Manim. The hierarchy determines how objects are rendered and animated:

    • Mobject: The base class.
    • VMobject (Vectorized Mobject): The most common type, defined by Bézier curves. Includes shapes like Circle, Square, Line, Text, Axes, and the container VGroup.
    • ImageMobject: Used for displaying images.
    • PMobject: Used for point clouds.
    • Group: A collection for non-VMobject items.
  8. Understand the difference between Manim Community and ManimGL

    main

    The repository supports two distinct, incompatible versions of Manim. Choosing the right one depends on your project needs:

    Manim Community Edition (manim)

    • Best For: Production use, educational content, and collaborative projects.
    • Focus: Stable, well-documented, and community-maintained.
    • CLI Command: manim
    • Import Pattern: from manim import *

    ManimGL (manimgl)

    • Best For: Interactive development, 3D scenes, and rapid prototyping.
    • Focus: Grant Sanderson's (3Blue1Brown) original version with OpenGL rendering.
    • CLI Command: manimgl
    • Import Pattern: from manimlib import *

    Warning: Code written for one version will not work with the other without modifications.

  9. Choose the correct ManimGL Scene type

    main

    ManimGL provides three primary scene classes depending on your animation requirements:

    • InteractiveScene (Recommended): The standard choice for development. It supports interactive mode via the -se flag, allowing you to manipulate the scene in real-time.
    • Scene: The base class for basic animations that do not require interactive features.
    • ThreeDScene: Used for 3D animations. It provides the necessary camera setup for 3D space.

    Always import from manimlib to access these classes.

    from manimlib import *
    
    # For interactive development
    class MyScene(InteractiveScene):
        def construct(self):
            pass
    
    # For 3D animations
    class My3DScene(ThreeDScene):
        def construct(self):
            axes = ThreeDAxes()
            self.add(axes)
            self.camera.frame.reorient(-45*DEGREES, 75*DEGREES)
    
    # For basic non-interactive animations
    class BasicScene(Scene):
        def construct(self):
            pass
  10. Pattern: Use closures for updaters in loops

    main

    When creating multiple Mobjects in a loop and assigning each a unique updater, you must use a closure. This ensures that each updater captures the specific state/instance of the Mobject it is intended for, rather than all updaters referencing the last object created in the loop. Inside the updater, always use the mob argument provided by the updater signature rather than the loop variable.

    for i in range(n):
        dot = Dot(...)
        def make_updater():  # Closure captures current state
            def update(mob, dt):
                # use mob, not dot
                ...
            return update
        dot.add_updater(make_updater())