04 · Figures & Animations
← Docs home · Task: replace a static figure with a Manim-drawn static graphic or a silent looping animation.
Source of truth:
figure-animator,figure-batch-render,manim-textbook,manim-render-checkpoint. CLI:scripts/workflows/figure_animate/. Scenes:manim-videos/figure-*/.
Decide first: static or animation?
Use the figure-animator decision tree (SKILL.md):
- Animation — when motion is the lesson: a secant slope sliding to a tangent, a transformation sweeping a parameter, a sampling distribution building up. Section-thesis figures.
- Static (theme-aware PNG pair) — when the figure is a fixed diagram, or when it’s an exercise/answer figure (animation would give the answer away).
Memory rule: exercise-prompt figures are always static; an animation in a problem reveals the answer.
Either way you get a dual-theme output (light + dark) so the figure matches the reader’s mode.
Procedure A — author one figure (static or animated)
- Discover candidates
python -m figure_animate discover --project "Calculus Volume 1" --section 3.1 - Author the scene — write
manim-videos/figure-<n>.<m>-<slug>/script.py.- Parameterize the theme (
FIGURE_THEME=light|dark). - For an animation: drive motion with a
ValueTracker+always_redrawfor a smooth monotonic sweep. - Keep the slug ≤ 4 hyphen-tokens — longer slugs truncate the render path.
- Shield labels from lint auto-drift by wrapping figure + labels in a
Group()(see memory: figure visual-verify).
- Parameterize the theme (
- Smoke-check before a full render — the
manim-render-checkpointprocedure: render at low quality (-ql), extract a midframe PNG, compare to the storyboard. Only then commit to a full-qhrender. - Render light + dark.
- Animation → MP4 pair, then apply an FFmpeg
reverse + concatto make a ping-pong loop (~8 s, ~1 MB/theme). - Static → PNG pair.
- Animation → MP4 pair, then apply an FFmpeg
- Visual-verify — lint exit 0 ≠ correct figure. Read the rendered PNGs and confirm labels, axes, and sweep direction (AnnularSector pies sweep CCW).
- Register in the manifest — add an entry to
projects/<Book>/figure_animations.yamlwithmode: animation|static,caption:, and acache_buster:token. - Publish with the swap applied
python scripts/workflows/publish.py --project "Calculus Volume 1" --section 3.1 --auto-renderpublish.py’s figure-animator survival guard rewrites the<img>to a<figure-anim-wrap>(or<figure-static-wrap>) in the published HTML. The source HTML keeps its plain<img>.
Outputs
- Static:
docs/images/figure_X.Y_{light,dark}.png - Animation:
docs/images/figure_X.Y_{light,dark}.mp4 - HTML wrap: applied in
docs/<book>/<chapter>/<section>.htmlat publish time.
Cache busting: when you re-render a figure, bump its
cache_buster:infigure_animations.yamland the?v=token in the HTML together — see thebump-cache-versionskill and 08.
Procedure B — batch render a whole section’s figures
Use the figure-batch-render skill when a section has many candidates:
- Triage the manifest — classify each entry static vs animation.
- Validate slugs (≤4 hyphen-tokens) before authoring — path truncation is the #1 batch failure.
- Bulk-author all
script.pyfiles. - Batch render (expect 15–30 % first-pass failures):
python -m figure_animate render --project "<Book>" --execute --parallel 4 - Triage failures (slug too long / scene error / timeout / missing import),
then targeted re-render:
figure_animate render --only <slug> --execute. - Sweep orphan PNGs after renders settle, then full publish:
python scripts/workflows/publish.py --project "<Book>" --sweep-only python scripts/workflows/publish.py --project "<Book>" --section X.Y --auto-render
Gotchas
- Docker required. Renders run in Docker; if absent,
publish.py --auto-renderlogs a warning and skips (it won’t fail the publish). - Lint is not verification. Always Read the output image. A green lint with a label collision or a backwards sweep is still wrong.
- Group() your labels. Without it, lint auto-drift can nudge labels off their anchors on re-render.
- Exercise figures need tags in the Solutions.md (
) so the publish swap can find and wrap them.
For narrated, multi-scene videos (not silent figure loops), see 05 · Section Videos.