
Animation Composer
- 7 installs
- 292 repo stars
- Updated January 29, 2026
- rohitg00/manim-video-generator
Helps with ai & agent building tasks during AI-assisted development.
About
animation-composer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- animation-composer
- AI & Agent Building
- AI-coding skill
Animation Composer by the numbers
- 7 all-time installs (skills.sh)
- Ranked #12,545 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/rohitg00/manim-video-generator --skill animation-composerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7 |
|---|---|
| repo stars | ★ 292 |
| Last updated | January 29, 2026 |
| Repository | rohitg00/manim-video-generator ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Animation Composer Skill
The Animation Composer orchestrates complex multi-part animations by breaking them into logical acts, coordinating timing, and managing transitions between scenes.
Core Concepts
Scene Graph Architecture
SceneGraph
├── GlobalStyle (colors, fonts, camera)
├── Acts[]
│ ├── Mobjects[] (visual elements)
│ ├── Animations[] (transformations)
│ └── Transitions (fade, slide, zoom)
└── Timeline (duration, pacing)Act Structure
Each animation is composed of one or more Acts:
- Introduction Act: Set the stage, introduce key elements
- Development Acts: Build complexity, show transformations
- Conclusion Act: Summarize, highlight key takeaways
Rules
rules/scene-structure.md
Guidelines for structuring scenes with clear beginnings, middles, and ends.
rules/timing-coordination.md
Best practices for coordinating multiple animations and avoiding visual clutter.
rules/transitions.md
Smooth transitions between acts using fades, slides, and morphs.
rules/camera-control.md
Camera movements, zooms, and focus to guide viewer attention.
Templates
Basic Multi-Act Scene
from manim import *
class ComposedScene(Scene):
def construct(self):
# Act 1: Introduction
title = Text("Introduction").scale(1.5)
self.play(Write(title))
self.wait(1)
self.play(FadeOut(title))
# Act 2: Main Content
content = self.create_main_content()
self.play(Create(content))
self.animate_content(content)
# Act 3: Conclusion
self.play(FadeOut(content))
conclusion = Text("Key Takeaway").scale(1.2)
self.play(FadeIn(conclusion))Camera-Controlled Scene
from manim import *
class CameraComposedScene(MovingCameraScene):
def construct(self):
# Create elements at different positions
left_group = self.create_left_section().shift(LEFT * 4)
right_group = self.create_right_section().shift(RIGHT * 4)
# Act 1: Overview
self.camera.frame.scale(2)
self.add(left_group, right_group)
self.wait()
# Act 2: Focus on left
self.play(self.camera.frame.animate.scale(0.5).move_to(left_group))
self.animate_left(left_group)
# Act 3: Focus on right
self.play(self.camera.frame.animate.move_to(right_group))
self.animate_right(right_group)
# Act 4: Zoom out for conclusion
self.play(self.camera.frame.animate.scale(2).move_to(ORIGIN))Composition Patterns
Sequential Composition
Elements appear one after another in a logical sequence.
self.play(Create(element1))
self.play(Create(element2))
self.play(Create(element3))Parallel Composition
Multiple elements animate simultaneously for visual impact.
self.play(
Create(element1),
Create(element2),
Create(element3)
)Staggered Composition
Elements appear with slight delays for a cascading effect.
self.play(LaggedStart(
*[Create(e) for e in elements],
lag_ratio=0.2
))Hierarchical Composition
Parent-child relationships for grouped animations.
group = VGroup(child1, child2, child3)
self.play(Create(group)) # All children animate togetherBest Practices
1. Start simple, build complexity - Introduce elements gradually 2. Use visual hierarchy - Important elements should be larger/brighter 3. Maintain rhythm - Consistent timing creates professional feel 4. Guide the eye - Use camera and highlights to direct attention 5. End with impact - Conclusions should be memorable
Anti-Patterns to Avoid
- Overwhelming the viewer with too many simultaneous elements
- Inconsistent timing that feels jarring
- Missing transitions between conceptually different sections
- Ignoring visual hierarchy (everything same size/color)
Camera Control Rules
Camera Scene Types
MovingCameraScene
For 2D panning and zooming:
class MyScene(MovingCameraScene):
def construct(self):
# Access camera frame
self.camera.frameThreeDScene
For 3D rotation and perspective:
class MyScene(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=75*DEGREES, theta=-45*DEGREES)2D Camera Operations
Panning (Moving the View)
# Pan to follow an object
self.play(self.camera.frame.animate.move_to(target_object))
# Pan to specific coordinates
self.play(self.camera.frame.animate.move_to(RIGHT * 3 + UP * 2))
# Smooth follow
self.camera.frame.add_updater(lambda m: m.move_to(moving_object))Zooming
# Zoom in (scale down the frame = objects appear larger)
self.play(self.camera.frame.animate.scale(0.5))
# Zoom out (scale up the frame = see more)
self.play(self.camera.frame.animate.scale(2))
# Zoom to fit specific object
self.play(self.camera.frame.animate.set_width(target.width * 1.5))Combined Pan and Zoom
# Focus on detail area
self.play(
self.camera.frame.animate.scale(0.3).move_to(detail_area),
run_time=2
)3D Camera Operations
Setting Initial View
# Standard viewing angles
self.set_camera_orientation(
phi=75 * DEGREES, # Elevation angle (tilt)
theta=-45 * DEGREES, # Azimuth angle (rotation)
gamma=0 # Roll angle
)Common Camera Angles
| View | phi | theta |
|---|---|---|
| Front | 90° | 0° |
| Top-down | 0° | 0° |
| Isometric | 60° | -45° |
| 3/4 View | 75° | -45° |
| Side | 90° | -90° |
Animated Camera Movement
# Rotate around the scene
self.move_camera(phi=60*DEGREES, theta=45*DEGREES, run_time=2)
# Continuous rotation
self.begin_ambient_camera_rotation(rate=0.2) # radians per second
self.wait(5)
self.stop_ambient_camera_rotation()Zoom in 3D
# Move camera closer
self.set_camera_orientation(zoom=2)
# Animated zoom
self.play(self.camera.animate.set_zoom(1.5), run_time=1)Focus Techniques
Highlight with Camera
# Zoom into important element
self.play(
self.camera.frame.animate.scale(0.4).move_to(important_element),
important_element.animate.set_color(YELLOW),
run_time=1.5
)Depth of Field Effect (Simulated)
# Blur background by reducing opacity
background_elements = VGroup(elem1, elem2, elem3)
self.play(
self.camera.frame.animate.move_to(focus_object),
background_elements.animate.set_opacity(0.2)
)Split Focus
# Show two areas by zooming out enough to see both
both = VGroup(area1, area2)
self.play(
self.camera.frame.animate.set_width(both.width * 1.5).move_to(both)
)Camera Movement Timing
Smooth Camera Motion
self.play(
self.camera.frame.animate.move_to(target),
rate_func=smooth,
run_time=1.5
)Quick Cuts (Instant Change)
# No animation, immediate change
self.camera.frame.move_to(new_position)
self.camera.frame.scale(0.5)Dramatic Zoom
# Slow zoom for emphasis
self.play(
self.camera.frame.animate.scale(0.3),
rate_func=ease_in_out_cubic,
run_time=3
)Best Practices
1. Establish Context First
# Start zoomed out to show everything
self.camera.frame.scale(2)
self.wait(1) # Let viewer see the whole scene
# Then zoom to detail
self.play(self.camera.frame.animate.scale(0.5).move_to(detail))2. Don't Move Camera and Content Simultaneously
# BAD - disorienting
self.play(
self.camera.frame.animate.move_to(RIGHT * 3),
object.animate.move_to(LEFT * 3)
)
# GOOD - one thing at a time
self.play(self.camera.frame.animate.move_to(RIGHT * 3))
self.play(object.animate.move_to(LEFT * 3))3. Return to Overview
# After zooming in, zoom back out
self.play(self.camera.frame.animate.scale(2).move_to(ORIGIN))4. Match Camera Speed to Content
- Fast cuts for dynamic content
- Slow pans for detailed examination
- Medium speed for transitions
Anti-Patterns
DON'T: Constant camera movement
# BAD - makes viewers dizzy
self.begin_ambient_camera_rotation(rate=1) # Too fast, too long
self.wait(30)DON'T: Zoom too close
# BAD - pixelation, lost context
self.play(self.camera.frame.animate.scale(0.01))DO: Purposeful camera movement
# GOOD - camera moves to reveal or emphasize
self.play(self.camera.frame.animate.move_to(reveal_area))
self.play(FadeIn(newly_visible_content))Community Edition Implementation Patterns
Best practices for implementing animations with the Manim Community Edition renderer.
Import Patterns
# Standard import (recommended)
from manim import *
# Selective imports for clarity
from manim import Scene, Circle, Square, Write, FadeIn, MathTexScene Types
Standard Scene
class MyAnimation(Scene):
def construct(self):
circle = Circle()
self.play(Create(circle))
self.wait()3D Scene
class My3DAnimation(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
sphere = Sphere()
self.play(Create(sphere))Moving Camera Scene
class CameraAnimation(MovingCameraScene):
def construct(self):
circle = Circle()
self.play(Create(circle))
self.play(self.camera.frame.animate.scale(0.5).move_to(circle))Core Animations
Creation Animations
| Animation | Use Case |
|---|---|
Create(mobject) | Draw shapes stroke-first |
Write(text) | Write text/equations |
FadeIn(mobject) | Gentle appearance |
GrowFromCenter(mobject) | Expand from center |
DrawBorderThenFill(mobject) | Outline then fill |
Transformation Animations
| Animation | Use Case |
|---|---|
Transform(a, b) | Morph a into b |
ReplacementTransform(a, b) | Replace a with b |
TransformMatchingTex(a, b) | Match LaTeX parts |
TransformMatchingShapes(a, b) | Match shape components |
Exit Animations
| Animation | Use Case |
|---|---|
FadeOut(mobject) | Gentle disappearance |
Uncreate(mobject) | Reverse of Create |
ShrinkToCenter(mobject) | Collapse to center |
LaTeX Rendering
Basic Math
# Simple equation
eq = MathTex("E = mc^2")
# With color isolation
eq = MathTex("E", "=", "m", "c^2")
eq[0].set_color(YELLOW) # E
eq[3].set_color(BLUE) # c^2Using substrings_to_isolate
eq = MathTex(
"x^2 + 2x + 1 = 0",
substrings_to_isolate=["x", "1", "0"]
)
eq.set_color_by_tex("x", BLUE)
eq.set_color_by_tex("1", GREEN)Text with Math
text = Tex("The area is ", "$A = \\pi r^2$")CLI Usage
# Preview with low quality (fast)
manim -pql script.py SceneName
# Preview with medium quality
manim -pqm script.py SceneName
# High quality render
manim -pqh script.py SceneName
# 4K render
manim -pqk script.py SceneName
# Save last frame as image
manim -pql -s script.py SceneName
# Transparent background
manim -pql -t script.py SceneNameQuality Presets
| Flag | Resolution | FPS | Use Case |
|---|---|---|---|
-ql | 480p | 15 | Quick preview |
-qm | 720p | 30 | Development |
-qh | 1080p | 60 | Production |
-qk | 4K | 60 | High-end production |
Debugging Techniques
Visual Debugging
# Add without animation (instant)
self.add(circle)
# Show bounding box
circle.add(SurroundingRectangle(circle))
# Add coordinate labels
self.add(NumberPlane())Print Debugging
def construct(self):
circle = Circle()
print(f"Circle center: {circle.get_center()}")
print(f"Circle radius: {circle.radius}")
print(f"Circle color: {circle.get_color()}")Interactive Mode
# Pause and inspect
self.wait()
self.interactive_embed() # Opens interactive shellAnimation Timing
Run Time Control
self.play(Create(circle), run_time=2) # 2 seconds
self.play(FadeIn(square), run_time=0.5) # FastSimultaneous Animations
# All at once
self.play(Create(circle), Write(text), FadeIn(square))
# With AnimationGroup
self.play(AnimationGroup(
Create(circle),
Write(text),
lag_ratio=0.5 # Stagger start times
))Sequential with Succession
self.play(Succession(
Create(circle),
circle.animate.shift(RIGHT),
FadeOut(circle)
))Common Patterns
Animate Method
# Fluent animation syntax
self.play(circle.animate.shift(RIGHT).scale(2).set_color(RED))Value Tracking
tracker = ValueTracker(0)
number = always_redraw(lambda: DecimalNumber(tracker.get_value()))
self.play(tracker.animate.set_value(100), run_time=3)Updaters
dot = Dot()
label = always_redraw(lambda: Text(f"({dot.get_x():.1f}, {dot.get_y():.1f})").next_to(dot, UP))
self.add(dot, label)
self.play(dot.animate.shift(RIGHT * 3))Anti-Patterns
Avoid
# Don't modify mobjects during play
self.play(Create(circle))
circle.shift(RIGHT) # Wrong - not animated
# Don't forget to add mobjects
text = Text("Hello")
self.play(text.animate.shift(UP)) # Error - text not addedPrefer
# Animate changes
self.play(Create(circle))
self.play(circle.animate.shift(RIGHT)) # Correct
# Add before animating
text = Text("Hello")
self.add(text)
self.play(text.animate.shift(UP)) # Or use FadeInAnimation Composer Rules
Scene Structure
Act-Based Organization
- Divide animations into logical acts (Introduction, Development, Conclusion)
- Each act should have a clear purpose
- Use transitions between acts for visual continuity
Timing Guidelines
- Introduction: 2-5 seconds (set context)
- Main content: Variable (depends on complexity)
- Conclusion: 2-3 seconds (reinforce key points)
Spatial Composition
Screen Regions
┌─────────────────────────────────┐
│ Title Area (UP, buff=0.5) │
├─────────────────────────────────┤
│ │
│ Main Stage (CENTER) │
│ │
├─────────────────────────────────┤
│ Caption Area (DOWN, buff=0.5) │
└─────────────────────────────────┘Positioning Best Practices
- Use
to_edge()for consistent margins - Use
arrange()for grouped elements - Maintain visual hierarchy with size and color
Animation Sequencing
Parallel vs Sequential
# Parallel - elements appear together
self.play(Create(obj1), Create(obj2))
# Sequential - one after another
self.play(Create(obj1))
self.play(Create(obj2))
# Staggered - with delay
self.play(LaggedStart(
Create(obj1), Create(obj2), Create(obj3),
lag_ratio=0.3
))Transition Types
FadeIn/FadeOut- Subtle, professionalGrowFromCenter- Emphasis, importanceTransform- Metamorphosis, changeReplacementTransform- Direct substitution
Common Patterns
Title Sequence
title = Text("My Animation").scale(1.5)
subtitle = Text("A Visual Journey").scale(0.7)
VGroup(title, subtitle).arrange(DOWN)
self.play(Write(title))
self.play(FadeIn(subtitle))Scene Clear
self.play(*[FadeOut(mob) for mob in self.mobjects])Avoid
- Overcrowding the screen
- Inconsistent animation speeds
- Abrupt transitions without purpose
- Too many simultaneous movements
Layout Validation System
Ensures visual elements are properly positioned without overlaps or boundary violations.
Screen Dimensions
Default Frame Size
The standard Manim frame has the following dimensions:
Width: 14.22 units (-7.11 to +7.11)
Height: 8.0 units (-4.0 to +4.0)Safe Zones
┌─────────────────────────────────────────────────────┐
│ DANGER ZONE (edges may be cut off) │
│ ┌─────────────────────────────────────────────┐ │
│ │ SAFE ZONE (guaranteed visible) │ │
│ │ │ │
│ │ Title Area (y > 2.5) │ │
│ │ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │
│ │ │ │
│ │ Main Content Area (-2.5 < y < 2.5) │ │
│ │ │ │
│ │ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │
│ │ Caption Area (y < -2.5) │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
Safe Zone Bounds:
x: -6.0 to +6.0
y: -3.5 to +3.5Position Specification Format
scene_with_position.md Template
# [Scene Name] - Position Specification
## Screen Layout
### Frame Bounds
- Width: 14.22 units
- Height: 8.0 units
### Zone Allocation
- Title Zone: y ∈ [2.5, 3.5]
- Main Zone: y ∈ [-2.0, 2.0]
- Caption Zone: y ∈ [-3.5, -2.5]
---
## Object Positions
### Object: title
- Type: Text
- Position: (0, 3.0)
- Size: width ≈ 8.0, height ≈ 0.6
- Bounds: x ∈ [-4.0, 4.0], y ∈ [2.7, 3.3]
### Object: main_equation
- Type: MathTex
- Position: (0, 1.0)
- Size: width ≈ 5.0, height ≈ 1.0
- Bounds: x ∈ [-2.5, 2.5], y ∈ [0.5, 1.5]
### Object: diagram
- Type: VGroup
- Position: (0, -1.5)
- Size: width ≈ 4.0, height ≈ 3.0
- Bounds: x ∈ [-2.0, 2.0], y ∈ [-3.0, 0]
---
## Overlap Check
| Object A | Object B | Overlap? | Resolution |
|----------|----------|----------|------------|
| title | main_equation | No | - |
| main_equation | diagram | No | - |
| title | diagram | No | - |
---
## Boundary Check
| Object | Within Safe Zone? | Issues |
|--------|-------------------|--------|
| title | Yes | - |
| main_equation | Yes | - |
| diagram | Yes | - |
Overlap Detection
Algorithm
def check_overlap(obj_a_bounds, obj_b_bounds):
"""
Check if two rectangular bounds overlap.
Bounds format: (x_min, x_max, y_min, y_max)
"""
a_x_min, a_x_max, a_y_min, a_y_max = obj_a_bounds
b_x_min, b_x_max, b_y_min, b_y_max = obj_b_bounds
# No overlap if:
# - A is entirely to the left of B
# - A is entirely to the right of B
# - A is entirely above B
# - A is entirely below B
if (a_x_max < b_x_min or # A left of B
a_x_min > b_x_max or # A right of B
a_y_max < b_y_min or # A below B
a_y_min > b_y_max): # A above B
return False
return TrueManim Implementation
def get_bounds(mobject):
"""Get bounding box of a mobject."""
return (
mobject.get_left()[0], # x_min
mobject.get_right()[0], # x_max
mobject.get_bottom()[1], # y_min
mobject.get_top()[1] # y_max
)
def validate_no_overlap(obj_a, obj_b, buffer=0.2):
"""Check that two objects don't overlap (with buffer)."""
a_bounds = get_bounds(obj_a)
b_bounds = get_bounds(obj_b)
# Add buffer
a_bounds = (
a_bounds[0] - buffer,
a_bounds[1] + buffer,
a_bounds[2] - buffer,
a_bounds[3] + buffer
)
return not check_overlap(a_bounds, b_bounds)Boundary Validation
Safe Zone Checker
SAFE_ZONE = {
"x_min": -6.0,
"x_max": 6.0,
"y_min": -3.5,
"y_max": 3.5
}
def is_within_safe_zone(mobject):
"""Check if mobject is entirely within safe zone."""
left = mobject.get_left()[0]
right = mobject.get_right()[0]
bottom = mobject.get_bottom()[1]
top = mobject.get_top()[1]
return (
left >= SAFE_ZONE["x_min"] and
right <= SAFE_ZONE["x_max"] and
bottom >= SAFE_ZONE["y_min"] and
top <= SAFE_ZONE["y_max"]
)Boundary Violation Report
def report_boundary_issues(mobject, name="object"):
"""Report any boundary violations."""
issues = []
left = mobject.get_left()[0]
right = mobject.get_right()[0]
bottom = mobject.get_bottom()[1]
top = mobject.get_top()[1]
if left < SAFE_ZONE["x_min"]:
issues.append(f"{name} extends {SAFE_ZONE['x_min'] - left:.2f} past left edge")
if right > SAFE_ZONE["x_max"]:
issues.append(f"{name} extends {right - SAFE_ZONE['x_max']:.2f} past right edge")
if bottom < SAFE_ZONE["y_min"]:
issues.append(f"{name} extends {SAFE_ZONE['y_min'] - bottom:.2f} past bottom edge")
if top > SAFE_ZONE["y_max"]:
issues.append(f"{name} extends {top - SAFE_ZONE['y_max']:.2f} past top edge")
return issuesCommon Layout Patterns
Centered Single Element
element.move_to(ORIGIN)
# Position: (0, 0)Title + Content
title.to_edge(UP, buff=0.5) # Position: (0, ~3.5)
content.move_to(ORIGIN) # Position: (0, 0)Side by Side
left_item.shift(LEFT * 3) # Position: (-3, 0)
right_item.shift(RIGHT * 3) # Position: (3, 0)Grid Layout
items = VGroup(*items)
items.arrange_in_grid(rows=2, cols=3, buff=0.5)
items.move_to(ORIGIN)Vertical Stack
items = VGroup(*items)
items.arrange(DOWN, buff=0.5)
items.move_to(ORIGIN)Position Constants
Standard Positions
# Edges
UP = (0, 1, 0) # Top center
DOWN = (0, -1, 0) # Bottom center
LEFT = (-1, 0, 0) # Left center
RIGHT = (1, 0, 0) # Right center
# Corners
UL = UP + LEFT # Upper left
UR = UP + RIGHT # Upper right
DL = DOWN + LEFT # Lower left
DR = DOWN + RIGHT # Lower right
# Center
ORIGIN = (0, 0, 0)Recommended Buffers
# Distance from edge
EDGE_BUFF = 0.5 # Standard edge buffer
SMALL_BUFF = 0.2 # Tight spacing
MED_BUFF = 0.5 # Medium spacing
LARGE_BUFF = 1.0 # Wide spacingValidation Workflow
Before Coding
1. List all objects with estimated sizes 2. Assign positions to each object 3. Check for overlaps in specification 4. Verify boundary compliance 5. Document in scene_with_position.md
During Coding
class ValidatedScene(Scene):
def construct(self):
# Create objects
title = Text("Title")
content = MathTex("E = mc^2")
# Position objects
title.to_edge(UP)
content.move_to(ORIGIN)
# Validate before adding
self._validate_layout([
("title", title),
("content", content)
])
# Proceed with animation
self.play(Write(title), Write(content))
def _validate_layout(self, named_objects):
"""Validate all objects before rendering."""
# Check boundaries
for name, obj in named_objects:
issues = report_boundary_issues(obj, name)
if issues:
print(f"WARNING: {issues}")
# Check overlaps
for i, (name_a, obj_a) in enumerate(named_objects):
for name_b, obj_b in named_objects[i+1:]:
if not validate_no_overlap(obj_a, obj_b):
print(f"WARNING: {name_a} overlaps with {name_b}")Anti-Patterns
Avoid
- Positioning without checking bounds
- Overlapping text and diagrams
- Elements cut off at edges
- Crowded layouts with no breathing room
Prefer
- Explicit position specifications
- Adequate spacing between elements
- Safe zone compliance
- Visual hierarchy through positioning
OpenGL Renderer Implementation Patterns
Best practices for implementing animations with the OpenGL-based renderer (alternative to Cairo).
Key Differences from Community Edition
| Feature | Community Edition | OpenGL Renderer |
|---|---|---|
| Creation animation | Create() | ShowCreation() |
| Color in LaTeX | set_color_by_tex() | t2c parameter |
| Camera control | self.camera.frame | self.frame |
| 3D Scene class | ThreeDScene | Standard Scene |
| Interactive mode | Limited | Full with -se flag |
Import Patterns
# Standard import for OpenGL renderer
from manimlib import *
# Note: Different package nameInteractive Development
Starting Interactive Mode
# Run with interactive embed
manimgl script.py SceneName -se
# The -se flag enables:
# - Pausing at self.embed() calls
# - Live code execution
# - Real-time mobject inspectionUsing embed()
class InteractiveScene(Scene):
def construct(self):
circle = Circle()
self.play(ShowCreation(circle))
# Pause here for interactive exploration
self.embed()
# Continue after exiting embed
self.play(circle.animate.shift(RIGHT))Checkpoint Workflow
def construct(self):
# Create initial state
circle = Circle()
self.play(ShowCreation(circle))
# Save checkpoint
self.checkpoint_paste() # Copy current state
# Experiment from here
self.play(circle.animate.scale(2))LaTeX with Color Coding
Using t2c Parameter
# t2c = "tex to color" dictionary
equation = Tex(
"E = mc^2",
t2c={
"E": YELLOW,
"m": GREEN,
"c": BLUE
}
)Complex Color Mapping
# Multiple characters with same color
formula = Tex(
"\\frac{d}{dx}[x^n] = nx^{n-1}",
t2c={
"x": BLUE,
"n": RED,
"d": GREEN,
"dx": GREEN
}
)Isolating Substrings
# For transformation matching
eq1 = Tex("x^2", " + ", "2x", " + ", "1")
eq2 = Tex("(x + 1)^2")
# Color individual parts
eq1[0].set_color(BLUE) # x^2
eq1[2].set_color(GREEN) # 2xCamera Control
Frame-Based Control
class CameraScene(Scene):
def construct(self):
circle = Circle()
self.play(ShowCreation(circle))
# Access frame directly (not self.camera.frame)
self.play(self.frame.animate.scale(0.5))
self.play(self.frame.animate.move_to(circle))3D Camera Orientation
class My3DScene(Scene):
def construct(self):
# No special 3D scene class needed
surface = Surface(lambda u, v: [u, v, u*v])
self.play(ShowCreation(surface))
# Reorient camera
self.play(self.frame.animate.reorient(45, 60))
# Camera parameters: theta (rotation), phi (elevation)Camera Movements
# Pan
self.play(self.frame.animate.shift(RIGHT * 2))
# Zoom
self.play(self.frame.animate.scale(0.5)) # Zoom in
self.play(self.frame.animate.scale(2)) # Zoom out
# Combined
self.play(
self.frame.animate
.move_to(target)
.scale(0.3)
.reorient(30, 45)
)Animation Syntax
ShowCreation (not Create)
# Correct for OpenGL renderer
self.play(ShowCreation(circle))
# NOT Create(circle) - that's Community EditionOther Animation Differences
# These work the same
self.play(Write(text))
self.play(FadeIn(mobject))
self.play(Transform(a, b))
# Animate method works the same
self.play(circle.animate.shift(RIGHT).scale(2))3D Without Special Classes
class Simple3D(Scene):
def construct(self):
# 3D objects work in regular Scene
axes = ThreeDAxes()
sphere = Sphere(radius=1)
self.play(ShowCreation(axes))
self.play(ShowCreation(sphere))
# Camera reorientation
self.play(self.frame.animate.reorient(60, 70))
# Continuous rotation
self.frame.add_updater(lambda m, dt: m.increment_theta(0.1 * dt))
self.wait(5)Debugging in Interactive Mode
Inspecting Mobjects
def construct(self):
circle = Circle()
self.add(circle)
self.embed()
# In interactive mode, you can:
# >>> circle.get_center()
# >>> circle.set_color(RED)
# >>> self.play(circle.animate.scale(2))Real-Time Modifications
# While in embed(), you can:
# - Create new mobjects
# - Run animations
# - Test transformations
# - Adjust colors and positionsPerformance Optimizations
GPU Acceleration
# OpenGL renderer leverages GPU for:
# - Shader-based rendering
# - Real-time preview
# - Smooth 3D rotationsEfficient Updates
# Use always_redraw for dynamic content
graph = always_redraw(lambda: FunctionGraph(
lambda x: np.sin(x + tracker.get_value()),
x_range=[-PI, PI]
))Common Patterns
Interactive Workflow
# 1. Start with interactive flag
manimgl script.py MyScene -se
# 2. Scene runs until embed()
# 3. Test changes in Python shell
# 4. Type 'exit()' to continue
# 5. Iterate on codeRapid Prototyping
class Prototype(Scene):
def construct(self):
# Quick setup
self.play(ShowCreation(Circle()))
# Pause to experiment
self.embed()
# Continue with refined versionAnti-Patterns
Avoid
# Don't use Create() - use ShowCreation()
self.play(Create(circle)) # Wrong for OpenGL
# Don't use self.camera.frame
self.play(self.camera.frame.animate.scale(0.5)) # WrongPrefer
# Use ShowCreation()
self.play(ShowCreation(circle)) # Correct
# Use self.frame directly
self.play(self.frame.animate.scale(0.5)) # CorrectScene Planning Methodology
A structured approach to planning animations before writing code. Planning first prevents wasted effort and ensures cohesive final products.
The Planning-First Principle
Never write animation code without a scene specification document.
Code written without planning leads to:
- Inconsistent timing
- Overlapping elements
- Missing transitions
- Scope creep
- Rework
Planning Workflow
Phase 0: Requirements → Understand the goal
↓
Phase 1: Scene Spec → Create scenes.md
↓
Phase 1.5: Layout Spec → Create scene_with_position.md
↓
Phase 2: Review → Validate and lock plan
↓
Phase 3: Implementation → Write codePhase 0: Requirements Gathering
Key Questions
| Question | Why It Matters |
|---|---|
| Who is the audience? | Determines complexity level |
| What's the core message? | Guides content focus |
| How long should it be? | Sets scope boundaries |
| What style is desired? | Informs visual choices |
| What are the constraints? | Identifies limitations |
Requirements Template
## Animation Requirements
**Title:** [Animation name]
**Purpose:** [What it should accomplish]
**Audience:** [Who will watch this]
**Duration:** [Target length in seconds/minutes]
### Content Scope
- Include: [Topics to cover]
- Exclude: [Topics to avoid]
- Emphasis: [Key points to highlight]
### Style Guidelines
- Visual style: [Modern, classic, playful, etc.]
- Color scheme: [Palette or theme]
- Pacing: [Fast, moderate, slow]
### Constraints
- Technical: [Resolution, format, etc.]
- Time: [Deadline if any]
- Resources: [Available assets]Phase 1: Scene Specification Document
scenes.md Format
# [Animation Title] - Scene Specification
## Overview
- **Total Duration:** [X minutes Y seconds]
- **Scene Count:** [N]
- **Act Structure:** [3-act / linear / modular]
---
## Scene 1: [Scene Name]
**Duration:** [Xs]
**Purpose:** [What this scene accomplishes]
### Objects
- object_1: [Description]
- object_2: [Description]
### Animations
1. [Animation description] (Xs)
2. [Animation description] (Xs)
3. [Animation description] (Xs)
### Transitions
- Entry: [How scene begins]
- Exit: [How scene ends]
### Notes
- [Any special considerations]
---
## Scene 2: [Scene Name]
...Scene Specification Example
# Pythagorean Theorem - Scene Specification
## Overview
- **Total Duration:** 2 minutes 30 seconds
- **Scene Count:** 4
- **Act Structure:** 3-act (Intro, Demo, Conclusion)
---
## Scene 1: Introduction
**Duration:** 20s
**Purpose:** Present the theorem statement
### Objects
- title: "The Pythagorean Theorem" (Text)
- equation: "a² + b² = c²" (MathTex)
- right_triangle: Right triangle with labeled sides
### Animations
1. Write title (1s)
2. Wait (1s)
3. FadeIn equation below title (0.5s)
4. Create right_triangle to the right (1s)
5. Indicate the three sides with colors (2s)
### Transitions
- Entry: Fade from black
- Exit: Shift all left, make room for proof
---
## Scene 2: Visual Proof
**Duration:** 90s
**Purpose:** Demonstrate the proof visually
### Objects
- triangle: Same triangle from Scene 1
- square_a: Square on side a (area a²)
- square_b: Square on side b (area b²)
- square_c: Square on side c (area c²)
### Animations
1. Grow square_a from side a (1.5s)
2. Label with "a²" (0.5s)
3. Grow square_b from side b (1.5s)
4. Label with "b²" (0.5s)
5. Grow square_c from side c (1.5s)
6. Label with "c²" (0.5s)
7. Rearrange to show a² + b² = c² (3s)
...Phase 1.5: Layout Specification
See layout-validation.md for detailed position specifications.
Phase 2: Review and Approval
Review Checklist
- [ ] All scenes serve the stated purpose
- [ ] Timing adds up correctly
- [ ] No gaps between scenes
- [ ] Transitions are logical
- [ ] Objects are clearly defined
- [ ] Animations are achievable
- [ ] Scope matches requirements
Approval Gate
Before proceeding to implementation: 1. Self-review the specification 2. Check for missing pieces 3. Validate against requirements 4. Lock the specification
Phase 3: Implementation
Implementation Guidelines
"""
Scene 1: Introduction
Duration: 20s
"""
class Scene1Introduction(Scene):
def construct(self):
# Objects (as specified)
title = Text("The Pythagorean Theorem", font_size=48)
equation = MathTex("a^2 + b^2 = c^2")
# ... etc
# Animations (as specified)
self.play(Write(title), run_time=1)
self.wait(1)
self.play(FadeIn(equation), run_time=0.5)
# ... etcTracking Progress
Mark scenes as implemented:
## Implementation Status
- [x] Scene 1: Introduction
- [x] Scene 2: Visual Proof
- [ ] Scene 3: Examples
- [ ] Scene 4: ConclusionScene Planning Templates
Simple Animation (< 1 minute)
## [Title]
Duration: Xs
### Setup
- [Objects to create]
### Main Animation
1. [Step 1]
2. [Step 2]
3. [Step 3]
### Cleanup
- [Exit animations]Multi-Act Animation (> 2 minutes)
## [Title]
### Act 1: Setup (X%)
- Scene 1.1: [Purpose]
- Scene 1.2: [Purpose]
### Act 2: Development (Y%)
- Scene 2.1: [Purpose]
- Scene 2.2: [Purpose]
- Scene 2.3: [Purpose]
### Act 3: Conclusion (Z%)
- Scene 3.1: [Purpose]
- Scene 3.2: [Purpose]Common Pitfalls
Avoid
- Starting to code before completing scenes.md
- Vague descriptions ("make it look good")
- Missing timing estimates
- Undefined transitions
- Scope creep during implementation
Prefer
- Complete specification before coding
- Specific, measurable descriptions
- Time allocations for each step
- Explicit transition definitions
- Scope changes require spec update
Integration with Codebase
File Organization
project/
├── specs/
│ ├── scenes.md # Scene specification
│ └── scene_with_position.md # Layout specification
├── src/
│ ├── scene_1.py # Implementation
│ ├── scene_2.py
│ └── ...
└── output/
└── final.mp4Spec-to-Code Mapping
Each scene in the specification maps to:
- One Python file or class
- One rendered segment
- One section in final video
Scene Structure Rules
The Three-Act Framework
Every well-composed animation follows a three-act structure:
Act 1: Introduction (10-20% of duration)
Purpose: Set context and introduce key elements
def act_introduction(self):
# Title/header
title = Text("Understanding Recursion")
self.play(Write(title))
self.wait(1)
# Move to make room for content
self.play(title.animate.to_edge(UP).scale(0.7))
# Introduce the core concept
concept = Text("A function that calls itself", font_size=28)
self.play(FadeIn(concept))Act 2: Development (60-80% of duration)
Purpose: Build complexity, demonstrate, explain
def act_development(self):
# Multiple sub-sections
for section in self.sections:
self.present_section(section)
self.transition_to_next()Act 3: Conclusion (10-20% of duration)
Purpose: Summarize, reinforce key points
def act_conclusion(self):
# Clear previous content
self.clear_with_transition()
# Summary
key_points = BulletedList(
"Point 1: ...",
"Point 2: ...",
"Point 3: ..."
)
self.play(Write(key_points))
# Final emphasis
self.play(Indicate(key_points[0]))Screen Layout Zones
┌──────────────────────────────────────────┐
│ TITLE ZONE │ buff=0.5 from top
│ (headers, labels) │
├──────────────────────────────────────────┤
│ │
│ │
│ PRIMARY ZONE │ Main content area
│ (main content) │
│ │
│ │
├──────────────────────────────────────────┤
│ CAPTION ZONE │ buff=0.5 from bottom
│ (explanations, formulas) │
└──────────────────────────────────────────┘Zone Positioning
# Title zone
title.to_edge(UP, buff=0.5)
# Primary zone
content.move_to(ORIGIN)
# Caption zone
caption.to_edge(DOWN, buff=0.5)Scene Transitions
Fade Transition (Default)
def clear_with_fade(self):
self.play(*[FadeOut(m) for m in self.mobjects])Slide Transition
def slide_out_left(self):
self.play(*[m.animate.shift(LEFT * 15) for m in self.mobjects])Zoom Transition
def zoom_out_transition(self):
all_objects = VGroup(*self.mobjects)
self.play(all_objects.animate.scale(0).set_opacity(0))Grouping Guidelines
Logical Groups
# Group related elements
equation_group = VGroup(equation, label, box)
graph_group = VGroup(axes, function, dots)
# Animate groups together
self.play(
equation_group.animate.shift(LEFT * 3),
graph_group.animate.shift(RIGHT * 3)
)Spatial Groups
# Elements that move together
header = VGroup(title, subtitle, underline)
header.arrange(DOWN, buff=0.2)Anti-Patterns
DON'T: Start with complex scene
# BAD
self.add(element1, element2, element3, element4, element5)
# All appear at once - overwhelmingDO: Build up gradually
# GOOD
for element in [element1, element2, element3, element4, element5]:
self.play(FadeIn(element))
self.wait(0.3)DON'T: Abrupt endings
# BAD
self.wait(1)
# Scene just stopsDO: Proper conclusion
# GOOD
self.play(FadeOut(*self.mobjects))
self.wait(0.5)Timing Coordination Rules
Animation Duration Standards
Quick Actions (0.2-0.5s)
- Simple property changes
- Small movements
- Opacity changes
self.play(obj.animate.set_opacity(0.5), run_time=0.3)Standard Actions (0.5-1s)
- Object creation
- Basic transforms
- Position changes
self.play(Create(circle), run_time=0.7)Deliberate Actions (1-2s)
- Complex transforms
- Educational reveals
- Important transitions
self.play(TransformMatchingTex(eq1, eq2), run_time=1.5)Slow Actions (2-4s)
- Building complex diagrams
- Tracing curves
- Multi-step processes
self.play(Create(complex_graph), run_time=3)Coordination Patterns
Sequential (One After Another)
self.play(Create(obj1))
self.play(Create(obj2))
self.play(Create(obj3))
# Total: 3 animations, clear orderParallel (Simultaneous)
self.play(
Create(obj1),
Create(obj2),
Create(obj3)
)
# Total: 1 animation, happening togetherStaggered (Cascade Effect)
self.play(LaggedStart(
Create(obj1),
Create(obj2),
Create(obj3),
lag_ratio=0.3
))
# Total: 1 animation, cascading startPhased (Grouped Sequences)
# Phase 1: Setup
self.play(Create(axes), Create(labels))
# Phase 2: Content
self.play(Create(graph))
# Phase 3: Annotations
self.play(Write(annotation1), Write(annotation2))Wait Times
Purpose-Based Waits
| After... | Wait Time | Purpose |
|---|---|---|
| Title appears | 1-2s | Read title |
| Equation shown | 1-3s | Process math |
| Complex diagram | 2-4s | Understand structure |
| Transformation | 0.5-1s | Observe change |
| Step completion | 1s | Mental checkpoint |
| Final reveal | 2-3s | Absorb conclusion |
Dynamic Waits (Advanced)
# Scale wait time by content complexity
word_count = len(text.text.split())
wait_time = max(1, word_count * 0.3) # ~0.3s per word
self.wait(wait_time)Avoiding Visual Clutter
Rule: Maximum 3 Simultaneous Movements
# GOOD: Focused attention
self.play(obj1.animate.shift(UP), obj2.animate.shift(DOWN))
# BAD: Too much happening
self.play(
obj1.animate.shift(UP),
obj2.animate.shift(DOWN),
obj3.animate.rotate(PI),
obj4.animate.scale(2),
obj5.animate.set_color(RED)
) # Viewer can't track all changesRule: Related Objects Move Together
# GOOD: Logically grouped
graph_elements = VGroup(axes, curve, label)
self.play(graph_elements.animate.shift(LEFT * 2))
# BAD: Unrelated simultaneous movement
self.play(
axes.animate.shift(LEFT),
title.animate.shift(RIGHT), # Unrelated to axes
caption.animate.shift(UP) # Also unrelated
)Rhythm and Pacing
Consistent Rhythm Pattern
# Establish a rhythm
for step in steps:
self.play(FadeIn(step), run_time=0.5) # Consistent timing
self.wait(1) # Consistent pauseRhythm Variation for Emphasis
# Normal pace
self.play(Create(normal_element), run_time=0.5)
self.wait(0.5)
# Slow down for important moment
self.play(Create(important_element), run_time=2)
self.wait(2)
# Return to normal
self.play(Create(next_element), run_time=0.5)Synchronization Techniques
Animation Groups
# Ensure multiple animations have same duration
self.play(
Create(obj1),
Create(obj2),
run_time=1 # Both take exactly 1 second
)Value Trackers for Sync
# Synchronized movement
t = ValueTracker(0)
obj1.add_updater(lambda m: m.set_x(t.get_value()))
obj2.add_updater(lambda m: m.set_y(t.get_value()))
self.play(t.animate.set_value(3))Timing Guidelines for Animation Composition
Default Durations
| Animation Type | Duration | Use Case |
|---|---|---|
Write | 1-2s | Text, equations |
Create | 0.5-1s | Shapes, lines |
FadeIn/Out | 0.5s | Transitions |
Transform | 1s | Shape morphing |
MoveToTarget | 0.5-1s | Repositioning |
Wait Times
# After title
self.wait(1)
# After important information
self.wait(2)
# After complex animation
self.wait(1.5)
# Brief pause for rhythm
self.wait(0.5)Pacing Strategies
Educational Content
- Slower pace (1.5x default durations)
- Longer wait times
- Step-by-step reveals
Entertainment/Dynamic
- Faster pace (0.7x default durations)
- Shorter waits
- Parallel animations
Professional/Corporate
- Medium pace (default durations)
- Consistent timing
- Smooth transitions
Animation Speed Modifiers
# Slow motion effect
self.play(Create(obj), run_time=3)
# Quick action
self.play(FadeIn(obj), run_time=0.3)
# Rate functions for easing
self.play(obj.animate.shift(RIGHT), rate_func=smooth)
self.play(obj.animate.shift(RIGHT), rate_func=rush_into)
self.play(obj.animate.shift(RIGHT), rate_func=there_and_back)Total Duration Guidelines
| Content Type | Recommended Length |
|---|---|
| Quick concept | 10-30 seconds |
| Single topic explanation | 30-60 seconds |
| Multi-step tutorial | 1-3 minutes |
| Comprehensive overview | 3-5 minutes |
Transition Rules
Transition Types
1. Fade Transitions
Best for: Topic changes, scene endings, gentle transitions
# Fade out everything
self.play(*[FadeOut(m) for m in self.mobjects])
# Fade out old, fade in new
self.play(FadeOut(old_content), FadeIn(new_content))
# Cross-fade (simultaneous)
self.play(
FadeOut(old_content),
FadeIn(new_content),
run_time=1
)2. Slide Transitions
Best for: Sequential content, timeline progressions, revealing more
# Slide out left, new content from right
self.play(
old_content.animate.shift(LEFT * 15),
new_content.animate.shift(LEFT * 15), # Starts off-screen right
run_time=0.8
)
# Vertical slide (like scrolling)
self.play(
old_content.animate.shift(UP * 8),
new_content.animate.shift(UP * 8), # Starts below
)3. Scale/Zoom Transitions
Best for: Focus changes, detail views, conclusions
# Zoom into detail
self.play(
camera.frame.animate.scale(0.5).move_to(detail_area),
run_time=1.5
)
# Zoom out for overview
self.play(
camera.frame.animate.scale(2).move_to(ORIGIN),
run_time=1.5
)4. Transform Transitions
Best for: Showing evolution, concept connections
# Morph one concept into another
self.play(Transform(concept_a, concept_b), run_time=2)
# Replacement (cleaner for text)
self.play(ReplacementTransform(old_text, new_text))5. Wipe Transitions
Best for: Clean breaks, professional feel
# Create a wipe rectangle
wipe = Rectangle(width=16, height=10, fill_opacity=1, color=BLACK)
wipe.to_edge(LEFT, buff=0).shift(LEFT * 16)
# Wipe across screen
self.play(wipe.animate.shift(RIGHT * 32), run_time=0.8)
self.remove(*self.mobjects)
self.remove(wipe)Transition Selection Guide
| Situation | Recommended Transition |
|---|---|
| End of major section | Fade out all |
| Moving to related topic | Cross-fade |
| Showing progression/steps | Slide |
| Diving into detail | Zoom in |
| Returning to big picture | Zoom out |
| Complete topic change | Wipe or full fade |
| Showing before/after | Split or slide |
Transition Timing
Standard Durations
- Quick transition: 0.3-0.5s
- Standard transition: 0.7-1s
- Dramatic transition: 1.5-2s
Pacing Rule
# Don't linger after transition starts
self.play(FadeOut(old), run_time=0.5)
# Immediately bring in new content
self.play(FadeIn(new), run_time=0.5)
# THEN wait for viewer
self.wait(1)Easing for Transitions
Smooth (Default)
self.play(obj.animate.shift(RIGHT), rate_func=smooth)Ease Out (Decelerate)
# Feels like sliding into place
self.play(obj.animate.shift(RIGHT), rate_func=ease_out_cubic)Ease In (Accelerate)
# Feels like launching away
self.play(obj.animate.shift(LEFT * 15), rate_func=ease_in_cubic)Linear (Constant Speed)
# Mechanical, robotic feel - rarely used
self.play(obj.animate.shift(RIGHT), rate_func=linear)Common Transition Patterns
The "Gather and Leave" Pattern
# All elements gather to center
all_elements = VGroup(*self.mobjects)
self.play(all_elements.animate.move_to(ORIGIN).scale(0.5))
# Then exit together
self.play(FadeOut(all_elements, scale=0))The "Push Out" Pattern
# New content pushes old off-screen
new_content.next_to(old_content, RIGHT, buff=8) # Off-screen
self.play(
old_content.animate.shift(LEFT * 16),
new_content.animate.move_to(ORIGIN)
)
self.remove(old_content)The "Dissolve to Background" Pattern
# Elements fade into background before new content
for mob in self.mobjects:
mob.save_state()
self.play(*[m.animate.set_opacity(0.1) for m in self.mobjects])
# Add new content on top
self.play(FadeIn(new_content))
# Optionally restore later
self.play(*[m.animate.restore() for m in old_mobjects])Anti-Patterns
DON'T: Multiple transition types at once
# BAD - confusing
self.play(
obj1.animate.shift(LEFT * 10), # Sliding
obj2.animate.scale(0), # Scaling
FadeOut(obj3) # Fading
)DON'T: Transition without purpose
# BAD - transition adds nothing
self.play(FadeOut(text))
self.play(FadeIn(same_text)) # Why?DO: Match transition to content relationship
# GOOD - transform shows relationship
self.play(TransformMatchingTex(equation_v1, equation_v2))"""
Template: Multi-Act Scene Composition
Use for structured animations with clear sections
"""
from manim import *
class MultiActScene(Scene):
def construct(self):
# Act 1: Introduction
self.act_introduction()
# Transition
self.clear_scene()
# Act 2: Main Content
self.act_main_content()
# Transition
self.clear_scene()
# Act 3: Conclusion
self.act_conclusion()
def act_introduction(self):
"""Set up context and introduce the topic"""
title = Text("Your Title Here", font_size=48)
subtitle = Text("Subtitle or context", font_size=24, color=GRAY)
header = VGroup(title, subtitle).arrange(DOWN, buff=0.3)
self.play(Write(title))
self.play(FadeIn(subtitle))
self.wait(2)
def act_main_content(self):
"""Present the core content"""
# Example: Show a sequence of concepts
concepts = [
Text("Concept 1"),
Text("Concept 2"),
Text("Concept 3"),
]
for i, concept in enumerate(concepts):
concept.move_to(ORIGIN)
self.play(FadeIn(concept))
self.wait(1)
if i < len(concepts) - 1:
self.play(FadeOut(concept))
def act_conclusion(self):
"""Summarize and conclude"""
summary = Text("Key Takeaway", font_size=36)
self.play(GrowFromCenter(summary))
self.wait(2)
def clear_scene(self):
"""Smooth transition between acts"""
self.play(*[FadeOut(mob) for mob in self.mobjects])
self.wait(0.5)
[Animation Title] - Scene Specification
Overview
Project: [Project name] Author: [Your name] Date: [Creation date] Version: [1.0]
Summary
| Attribute | Value |
|---|---|
| Total Duration | [X minutes Y seconds] |
| Scene Count | [N] |
| Act Structure | [3-act / linear / modular] |
| Target Audience | [Description] |
| Visual Style | [Modern / Classic / Playful / etc.] |
---
Act 1: Introduction
Purpose: Set up the context and introduce the main topic Duration: ~20% of total
Scene 1.1: [Opening Title]
Duration: [Xs] Purpose: [What this scene accomplishes]
Objects
| Name | Type | Description |
|---|---|---|
| title | Text | Main title text |
| subtitle | Text | Supporting text |
Positions
| Object | Position | Size (approx) |
|---|---|---|
| title | (0, 2.5) | 8.0 × 0.8 |
| subtitle | (0, 1.5) | 6.0 × 0.5 |
Animation Sequence
| # | Animation | Duration | Notes |
|---|---|---|---|
| 1 | Write(title) | 1.0s | - |
| 2 | Wait | 0.5s | Let title settle |
| 3 | FadeIn(subtitle) | 0.5s | Shift up slightly |
Transitions
- Entry: Fade from black
- Exit: FadeOut all, or shift left
---
Scene 1.2: [Problem Statement]
Duration: [Xs] Purpose: [What this scene accomplishes]
Objects
| Name | Type | Description |
|---|---|---|
| question | Text | The main question |
| visual | Mobject | Supporting visual |
Positions
| Object | Position | Size (approx) |
|---|---|---|
| question | (0, 2.0) | 10.0 × 0.6 |
| visual | (0, -0.5) | 5.0 × 4.0 |
Animation Sequence
| # | Animation | Duration | Notes |
|---|---|---|---|
| 1 | Write(question) | 1.5s | - |
| 2 | Create(visual) | 2.0s | Build the visual |
| 3 | Indicate(visual) | 1.0s | Draw attention |
Transitions
- Entry: Continue from previous
- Exit: Keep visual, fade question
---
Act 2: Development
Purpose: Explain the main content in detail Duration: ~60% of total
Scene 2.1: [First Key Point]
Duration: [Xs] Purpose: [What this scene accomplishes]
Objects
| Name | Type | Description |
|---|---|---|
| heading | Text | Section heading |
| equation | MathTex | Key equation |
| diagram | VGroup | Supporting diagram |
Positions
| Object | Position | Size (approx) |
|---|---|---|
| heading | (0, 3.0) | 6.0 × 0.5 |
| equation | (-3, 0) | 4.0 × 1.0 |
| diagram | (3, 0) | 4.0 × 3.0 |
Animation Sequence
| # | Animation | Duration | Notes |
|---|---|---|---|
| 1 | Write(heading) | 0.8s | - |
| 2 | Write(equation) | 1.5s | - |
| 3 | Create(diagram) | 2.0s | - |
| 4 | Transform connection | 1.5s | Show relationship |
Transitions
- Entry: Quick fade from previous
- Exit: Equation transforms to next
---
Scene 2.2: [Second Key Point]
Duration: [Xs] Purpose: [What this scene accomplishes]
[Follow same structure as Scene 2.1]
---
Scene 2.3: [Third Key Point]
Duration: [Xs] Purpose: [What this scene accomplishes]
[Follow same structure as Scene 2.1]
---
Act 3: Conclusion
Purpose: Summarize and reinforce key takeaways Duration: ~20% of total
Scene 3.1: [Summary]
Duration: [Xs] Purpose: Recap the main points
Objects
| Name | Type | Description |
|---|---|---|
| summary_title | Text | "Key Takeaways" |
| points | BulletedList | Main points |
| final_equation | MathTex | Final form |
Positions
| Object | Position | Size (approx) |
|---|---|---|
| summary_title | (0, 3.0) | 5.0 × 0.5 |
| points | (-3, 0) | 5.0 × 3.0 |
| final_equation | (3, 0) | 4.0 × 1.5 |
Animation Sequence
| # | Animation | Duration | Notes |
|---|---|---|---|
| 1 | Write(summary_title) | 0.5s | - |
| 2 | FadeIn(points[0]) | 0.5s | First point |
| 3 | FadeIn(points[1]) | 0.5s | Second point |
| 4 | FadeIn(points[2]) | 0.5s | Third point |
| 5 | Write(final_equation) | 1.0s | - |
| 6 | Circumscribe(final_equation) | 1.0s | Emphasize |
Transitions
- Entry: Clean transition from development
- Exit: Fade to black
---
Scene 3.2: [Closing]
Duration: [Xs] Purpose: End card / call to action
Objects
| Name | Type | Description |
|---|---|---|
| thanks | Text | Thank you message |
| cta | Text | Call to action |
Animation Sequence
| # | Animation | Duration | Notes |
|---|---|---|---|
| 1 | FadeIn(thanks) | 0.5s | - |
| 2 | Wait | 1.0s | - |
| 3 | FadeIn(cta) | 0.5s | - |
| 4 | Wait | 2.0s | Hold for viewers |
| 5 | FadeOut(all) | 0.5s | End |
---
Appendix
Color Palette
| Use | Color | Hex |
|---|---|---|
| Primary | BLUE | #58C4DD |
| Secondary | GREEN | #83C167 |
| Accent | YELLOW | #FFFF00 |
| Text | WHITE | #FFFFFF |
| Background | BLACK | #000000 |
Typography
| Element | Font Size | Style |
|---|---|---|
| Title | 48 | Bold |
| Heading | 36 | Regular |
| Body | 32 | Regular |
| Caption | 24 | Light |
| Math | 40 | Default |
Timing Summary
| Scene | Duration | Cumulative |
|---|---|---|
| 1.1 | Xs | Xs |
| 1.2 | Xs | Xs |
| 2.1 | Xs | Xs |
| 2.2 | Xs | Xs |
| 2.3 | Xs | Xs |
| 3.1 | Xs | Xs |
| 3.2 | Xs | Xs |
| Total | Xs | - |
Implementation Checklist
- [ ] Scene 1.1: Opening Title
- [ ] Scene 1.2: Problem Statement
- [ ] Scene 2.1: First Key Point
- [ ] Scene 2.2: Second Key Point
- [ ] Scene 2.3: Third Key Point
- [ ] Scene 3.1: Summary
- [ ] Scene 3.2: Closing
- [ ] Final review
- [ ] Export
---
Revision History
| Version | Date | Changes |
|---|---|---|
| 1.0 | [Date] | Initial specification |
"""
Template: Side-by-Side Comparison
Use for comparing two concepts, before/after, or alternatives
"""
from manim import *
class SideBySideComparison(Scene):
def construct(self):
# Title
title = Text("Comparison", font_size=40).to_edge(UP)
self.play(Write(title))
# Divider line
divider = Line(UP * 2, DOWN * 2, color=GRAY)
self.play(Create(divider))
# Left side
left_title = Text("Option A", font_size=28, color=BLUE)
left_title.move_to(LEFT * 3.5 + UP * 1.5)
left_content = VGroup(
Text("• Feature 1", font_size=20),
Text("• Feature 2", font_size=20),
Text("• Feature 3", font_size=20),
).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
left_content.next_to(left_title, DOWN, buff=0.5)
# Right side
right_title = Text("Option B", font_size=28, color=GREEN)
right_title.move_to(RIGHT * 3.5 + UP * 1.5)
right_content = VGroup(
Text("• Feature 1", font_size=20),
Text("• Feature 2", font_size=20),
Text("• Feature 3", font_size=20),
).arrange(DOWN, aligned_edge=LEFT, buff=0.3)
right_content.next_to(right_title, DOWN, buff=0.5)
# Animate
self.play(
Write(left_title),
Write(right_title)
)
self.play(
LaggedStart(*[FadeIn(item) for item in left_content], lag_ratio=0.2),
LaggedStart(*[FadeIn(item) for item in right_content], lag_ratio=0.2),
)
self.wait(2)
# Highlight winner (optional)
winner_box = SurroundingRectangle(
VGroup(right_title, right_content),
color=YELLOW,
buff=0.2
)
self.play(Create(winner_box))
self.wait(2)