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 MySceneInteractive 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 executionPractical 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 pauseConditional 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 15checkpoint_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 CheckpointSceneIn 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 runningSaving 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 stateInteractive 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 modeDebugging 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
- Use for debugging: Add
self.embed()when animations don't work as expected - Experiment freely: Try different approaches in the shell before adding to code
- save_state() before experimenting: Easy to revert if something goes wrong
- Use -se for large scenes: Jump to problem area instead of watching entire animation
- checkpoint_paste() for iteration: Quickly test code snippets
- touch() for 3D: Essential for finding the right camera angle
- 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 code3D 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 codeTroubleshooting
embed() Not Working
- Ensure you're running with
manimglcommand - 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()orglobals()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()orexit()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!