All skills
adithya-s-k avatar

/manimgl-best-practices

@2375ac0
by Adithya S Kadithya-s-k/manim_skill1.1k stars
94

Trigger when: (1) User mentions "manimgl" or "ManimGL" or "3b1b manim", (2) Code contains `from manimlib import *`, (3) User runs `manimgl` CLI commands, (4) Working with InteractiveScene, self.frame, self.embed(), ShowCreation(), or ManimGL-specific patterns. Best practices for ManimGL (Grant Sanderson's 3Blue1Brown version) - OpenGL-based animation engine with interactive development. Covers InteractiveScene, Tex with t2c, camera frame control, interactive mode (-se flag), 3D rendering, and checkpoint_paste() workflow. NOT for Manim Community Edition (which uses `manim` imports and `manim` CLI).

Use this Skill: https://skilld.dev/gh/adithya-s-k/manim_skill/manimgl-best-practices

This session only. Nothing lands on disk.

rulesembedding.md

≈2.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Interactive Embedding in ManimGL

ManimGL's self.embed() feature drops you into an interactive IPython shell during scene execution, making debugging and experimentation incredibly powerful.

Basic Usage

Adding embed() to Your Scene

from manimlib import *

class MyScene(Scene):
    def construct(self):
        circle = Circle()
        self.play(ShowCreation(circle))

        # Drop into interactive shell here
        self.embed()

        # Code continues after you exit the shell
        self.play(circle.animate.shift(RIGHT))
        self.wait()

Running with Embed

# Run scene - will pause at embed() point
manimgl scene.py MyScene

Interactive Commands

Available in Shell

When self.embed() opens the IPython shell, you have access to:

# Scene methods (abbreviated - no 'self.' needed)
play(animation)              # Play animation
add(mobject)                 # Add mobject to scene
remove(mobject)              # Remove mobject
wait(duration)               # Wait for duration
clear()                      # Clear scene

# Camera/frame control
frame                        # Access camera frame
play(frame.animate.shift(RIGHT))

# All local variables from construct()
circle, square, text, etc.   # Your mobjects

# Interactive camera
touch()                      # Enter touch mode (press 'q' to exit)
                            # Press 'd' + mouse to rotate
                            # Press 'z' + scroll to zoom
                            # Press 'r' to reset

# Exit shell and continue
exit()                       # Continue scene execution

Practical Examples

Debugging Animation

class DebugScene(Scene):
    def construct(self):
        circle = Circle()
        square = Square()
        self.add(circle, square)

        # Problem with this animation?
        self.play(circle.animate.move_to(square))

        # Debug it interactively
        self.embed()

        # In the shell:
        # >>> play(circle.animate.set_color(RED))
        # >>> circle.get_center()
        # >>> square.get_center()

Experimenting with Positioning

class PositioningExperiment(Scene):
    def construct(self):
        shapes = VGroup(*[
            Circle(radius=0.5) for _ in range(5)
        ])

        # Try different arrangements interactively
        self.add(shapes)
        self.embed()

        # In the shell, try:
        # >>> play(shapes.animate.arrange(RIGHT, buff=1))
        # >>> play(shapes.animate.arrange(DOWN, buff=0.5))
        # >>> play(shapes.animate.arrange_in_grid(rows=2))

Color and Style Exploration

class StyleExploration(Scene):
    def construct(self):
        text = Text("Experiment", font_size=72)
        self.add(text)
        self.embed()

        # In the shell:
        # >>> play(text.animate.set_color(BLUE))
        # >>> text.set_backstroke(BLACK, width=10)
        # >>> play(text.animate.scale(2))

Advanced embed() Usage

Multiple Embed Points

class MultipleEmbeds(Scene):
    def construct(self):
        # First checkpoint
        circle = Circle()
        self.play(ShowCreation(circle))
        self.embed()  # First pause

        # Second checkpoint
        square = Square()
        self.play(ShowCreation(square))
        self.embed()  # Second pause

        # Third checkpoint
        self.play(FadeOut(VGroup(circle, square)))
        self.embed()  # Third pause

Conditional Embedding

class ConditionalEmbed(Scene):
    def construct(self):
        DEBUG = True

        circle = Circle()
        self.play(ShowCreation(circle))

        if DEBUG:
            self.embed()  # Only embed in debug mode

        self.play(circle.animate.shift(RIGHT))

Using with -se Flag

Skip and Embed

The -se flag skips to a specific line and embeds:

class LargeScene(Scene):
    def construct(self):
        # Line 5
        circle = Circle()
        self.play(ShowCreation(circle))

        # Line 10
        square = Square()
        self.play(ShowCreation(square))

        # Line 15
        text = Text("Hello")
        self.play(Write(text))

        # Line 20
        self.play(FadeOut(VGroup(circle, square, text)))
# Skip directly to line 15 and embed
manimgl scene.py LargeScene -se 15

checkpoint_paste()

Interactive Code Execution

checkpoint_paste() runs code from your clipboard:

class CheckpointScene(Scene):
    def construct(self):
        circle = Circle()
        self.add(circle)
        self.embed()
# Run the scene
manimgl scene.py CheckpointScene

In the shell:

# Copy this code to clipboard first:
"""
square = Square()
play(ShowCreation(square))
play(square.animate.next_to(circle, RIGHT))
"""

# Then in the shell:
>>> checkpoint_paste()              # Runs with animations
>>> checkpoint_paste(skip=True)     # Runs instantly
>>> checkpoint_paste(record=True)   # Records while running

Saving and Restoring State

save_state() and restore()

class StateManagement(Scene):
    def construct(self):
        circle = Circle()
        square = Square()
        self.add(circle, square)

        # Save current state
        self.save_state()

        # Make changes
        self.play(circle.animate.shift(RIGHT * 3))
        self.play(square.animate.shift(LEFT * 3))

        self.embed()

        # In the shell:
        # >>> restore()  # Revert to saved state

Interactive 3D Exploration

touch() Mode

class Interactive3D(Scene):
    def construct(self):
        frame = self.camera.frame
        frame.reorient(20, 70)

        # Create 3D object
        sphere = Sphere(radius=2, color=BLUE)
        self.add(sphere)

        self.embed()

        # In the shell:
        # >>> touch()
        # Now you can:
        # - Press 'd' and move mouse to rotate
        # - Press 'z' and scroll to zoom
        # - Press 'r' to reset camera
        # - Press 'q' to exit touch mode

Debugging Patterns

Inspect Mobject Properties

class InspectProperties(Scene):
    def construct(self):
        circle = Circle(radius=2, color=BLUE)
        circle.shift(RIGHT * 3)
        self.add(circle)
        self.embed()

        # In the shell:
        # >>> circle.get_center()
        # >>> circle.get_color()
        # >>> circle.get_width()
        # >>> circle.get_height()
        # >>> circle.get_all_points()

Test Animation Timing

class TimingTest(Scene):
    def construct(self):
        circle = Circle()
        self.add(circle)
        self.embed()

        # In the shell, test different timings:
        # >>> play(circle.animate.shift(RIGHT), run_time=0.5)
        # >>> play(circle.animate.shift(LEFT), run_time=2)
        # >>> play(circle.animate.shift(UP), run_time=1, rate_func=smooth)

Build Complex Scenes Iteratively

class IterativeBuilding(Scene):
    def construct(self):
        self.embed()

        # Build entire scene in the shell:
        # >>> title = Text("My Animation")
        # >>> title.to_edge(UP)
        # >>> add(title)
        #
        # >>> circles = VGroup(*[Circle(radius=0.5) for _ in range(5)])
        # >>> circles.arrange(RIGHT, buff=0.5)
        # >>> play(LaggedStart(*[ShowCreation(c) for c in circles], lag_ratio=0.2))
        #
        # >>> formula = Tex(R"E = mc^2")
        # >>> formula.next_to(circles, DOWN, buff=1)
        # >>> play(Write(formula))

Best Practices

  1. Use for debugging: Add self.embed() when animations don't work as expected
  2. Experiment freely: Try different approaches in the shell before adding to code
  3. save_state() before experimenting: Easy to revert if something goes wrong
  4. Use -se for large scenes: Jump to problem area instead of watching entire animation
  5. checkpoint_paste() for iteration: Quickly test code snippets
  6. touch() for 3D: Essential for finding the right camera angle
  7. Remove embed() for final render: Don't forget to remove debugging embeds

Common Patterns

Quick experiment pattern

# Add at problem point
self.embed()

# In shell, test fix
play(mobject.animate.scale(2))  # Test different values

# If it works, add to code
# exit()

Interactive development pattern

# Start with minimal setup
class Scene(Scene):
    def construct(self):
        self.embed()

# Build everything in the shell
# Copy successful commands back to code

3D camera setup pattern

# Get to 3D scene
frame.reorient(20, 70)
add(sphere)
self.embed()

# Find perfect angle
touch()  # Rotate with mouse
# Press 'q' when done
# Check frame.get_theta(), frame.get_phi()
# Add those values to code

Troubleshooting

embed() Not Working

  • Ensure you're running with manimgl command
  • Check that IPython is installed
  • Verify no syntax errors before embed() point

Can't Access Variables

  • Variables must be defined before self.embed()
  • Use locals() or globals() to inspect available variables

Shell Exits Immediately

  • Don't call exit() unless you want to continue
  • Press Ctrl+D to exit and continue
  • Use quit() or exit() to close shell

Example: Full Interactive Development

class InteractiveDevelopment(Scene):
    def construct(self):
        # Start with embed
        self.embed()

        # In the shell, build everything:
        """
        # Create title
        title = Text("Interactive Development", font_size=60)
        title.to_edge(UP)
        play(Write(title))

        # Create content
        circle = Circle(radius=1.5, color=BLUE)
        circle.set_fill(BLUE, opacity=0.5)
        circle.set_stroke(WHITE, width=3)
        play(ShowCreation(circle))

        # Add label
        label = Text("Circle", font_size=36)
        label.next_to(circle, DOWN)
        play(FadeIn(label, shift=UP))

        # Animate
        play(
            circle.animate.shift(RIGHT * 2),
            label.animate.shift(RIGHT * 2)
        )

        wait(2)

        # When happy, copy all this code to your construct method
        exit()
        """

This makes ManimGL incredibly powerful for rapid prototyping and debugging!

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill is an educational resource for the ManimGL mathematical animation library, providing best practices and functional examples. All code patterns, including CLI boilerplate and external asset references, are standard and safe for the intended use cases.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    1/107 files flagged

  • ZeroLeaks5mo

    1 finding · Score: 86/100

Signed by skilld at 2375ac0. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Dormantupdated 8 months ago

README badge

README badge for adithya-s-k/manim_skill/manimgl-best-practices