# TOO FAST - viewer can't process
self.play(Write(formula), run_time=0.3)
# NO BREATHING ROOM
self.play(anim1)
self.play(anim2)
self.play(anim3)
# GOOD - appropriate pacing
self.play(Write(formula), run_time=2)
self.wait(4) # Time to understand
self.play(next_animation)
# BAD - Multiple concepts
class OverloadedScene(Scene):
def construct(self):
# Concept 1: Definition
# Concept 2: Properties
# Concept 3: Examples
# Concept 4: Proofs
# GOOD - Focused scenes
class DefinitionScene(Scene): ...
class PropertiesScene(Scene): ...
class ExampleScene(Scene): ...
class ProofScene(Scene): ...
Section Organization
class WellOrganizedScene(Scene):
def construct(self):
self.next_section("Introduction")
self.show_title()
self.next_section("Main Concept")
self.show_visualization()
self.next_section("Key Insight")
self.show_insight()
self.next_section("Conclusion")
self.show_summary()
def show_title(self):
"""Isolated logic for title"""
pass
def show_visualization(self):
"""Isolated logic for main content"""
pass
Object Tracking
Track Everything
class ProductionScene(Scene):
def setup(self):
self.tracked = []
def track(self, *mobjects):
"""Add mobjects to tracking and scene"""
for m in mobjects:
self.tracked.append(m)
self.add(m)
return mobjects[0] if len(mobjects) == 1 else mobjects
def cleanup(self, keep=None):
"""Fade out tracked objects except those in keep"""
keep = keep or []
to_remove = [m for m in self.tracked if m not in keep]
if to_remove:
self.play(*[FadeOut(m) for m in to_remove])
self.tracked = list(keep)
Avoid Nuclear Cleanup
# BAD - Destroys everything blindly
self.play(FadeOut(*self.mobjects))
# GOOD - Explicit control
self.cleanup(keep=[title, axes])
Typography Standards
Font Size Scale
FONTS = {
"TITLE": 52, # Scene titles
"SECTION": 42, # Section headers
"BODY": 28, # Body text
"SMALL": 24, # Annotations
"FORMULA": 38, # Standalone formulas
}
# Dim old content when showing new
old_content.animate.set_opacity(0.3)
# Highlight current focus
current.animate.set_color(COLORS["EMPHASIS"])
# Use movement to guide eye
new_element.animate.shift(target_position)
Quality Checklist
Before rendering, verify:
Colors
Maximum 5 semantic colors
Each color has consistent meaning
All colors visible on black background
Timing
No animations under 0.5s
Wait after complex content
Pacing matches content complexity
Positioning
No magic numbers
All positions relative
Consistent spacing/buffers
Organization
One concept per scene
Sections marked with next_section()
Objects tracked for cleanup
Typography
Consistent font sizes
Minimal on-screen text
Formulas properly formatted
Production Workflow
1. Planning
Define ONE concept for scene
Plan timeline with durations
Identify color assignments
2. Implementation
Use config constants
Track all objects
Use helper methods
3. Review
Run quality checklist
Preview at low quality
Check timing feels natural
4. Polish
Fine-tune timing
Adjust colors for clarity
Ensure smooth transitions
5. Export
Render at target quality
Verify output plays correctly
Check file size is reasonable
Example: Production-Quality Scene
from manim import *
COLORS = {
"PRIMARY": BLUE,
"SECONDARY": ORANGE,
"POSITIVE": GREEN,
"EMPHASIS": PURPLE,
"MUTED": GRAY,
}
TIMING = {
"NORMAL": 1.0,
"SLOW": 2.0,
"COMPLEX": 4.0,
}
FONTS = {
"TITLE": 52,
"BODY": 28,
}
class ProductionExample(Scene):
def setup(self):
self.tracked = []
def track(self, *mobjects):
for m in mobjects:
self.tracked.append(m)
self.add(m)
return mobjects[0] if len(mobjects) == 1 else mobjects
def cleanup(self, keep=None):
keep = keep or []
to_remove = [m for m in self.tracked if m not in keep]
if to_remove:
self.play(*[FadeOut(m) for m in to_remove])
self.tracked = list(keep)
def construct(self):
# Section 1: Title
self.next_section("Title")
title = Text("Pythagorean Theorem", font_size=FONTS["TITLE"])
self.play(GrowFromCenter(title), run_time=TIMING["NORMAL"])
self.wait(TIMING["NORMAL"])
self.play(title.animate.to_edge(UP, buff=0.5))
# Section 2: Visualization
self.next_section("Visualization")
# Create triangle (no magic numbers)
triangle = Polygon(
ORIGIN,
RIGHT * 3,
RIGHT * 3 + UP * 4,
color=COLORS["PRIMARY"]
).move_to(ORIGIN)
self.play(Create(triangle), run_time=TIMING["SLOW"])
self.wait(TIMING["NORMAL"])
# Section 3: Formula
self.next_section("Formula")
formula = MathTex(
r"a^2 + b^2 = c^2",
tex_to_color_map={
r"a": COLORS["PRIMARY"],
r"b": COLORS["SECONDARY"],
r"c": COLORS["EMPHASIS"],
}
)
formula.next_to(triangle, RIGHT, buff=1.0)
self.play(Write(formula), run_time=TIMING["SLOW"])
self.wait(TIMING["COMPLEX"]) # Key concept needs time
# Section 4: Emphasis
self.next_section("Emphasis")
self.play(Circumscribe(formula, color=COLORS["EMPHASIS"]))
self.wait(TIMING["NORMAL"])