Template - Animation#
This page is the author reference for narrative animations — short, scripted
clips rendered at make split time by Manim Community Edition
(the maintained fork of 3Blue1Brown’s animation engine) and served as plain
looping video files. It is the book’s second rendering engine, deliberately separate
from the interactive-widget pipeline, because it does a different job:
Interactive widget |
Narrative animation |
|
|---|---|---|
Template |
this page |
|
Engine |
plotly + ipywidgets ( |
manim + |
The reader can |
drag sliders, edit the code, re-run live |
watch — it plays like a figure |
What ships in the page |
a live plotly figure (the in-browser kernel starts on page load) |
bare |
The code on the page |
visible or collapsible, always runnable |
never shown, never runnable |
Best for |
exploring a parameter |
telling one story well — morphing shapes, math that moves, choreography |
Why a second engine: a widget is live — it needs the in-browser kernel and its libraries, and everything it renders has to coexist with the theme and the live-code layer. An animation bakes to inert media — no script, no styles, no kernel, nothing to fight. The cost is symmetry: a clip cannot be edited or re-run in the browser, so it narrates; it never explores.
This page in the sidebar is the generated index.ipynb. Edit main.md or a
companion notebook, then run make template-animation to regenerate it.
Status: adopted
The {animation} machinery is in chapter use — 5.5’s Fourier winding and 7.2’s
wagon wheel are one directive each. manim stays off the approved-library list
in Template - Interactive §4 on purpose: it runs at split time on the author’s
machine, never in the browser kernel and never in CI.
1. How an animation section works#
An animation section is two pieces, exactly like an interactive one:
The section Markdown in
icm-text/{n}-{slug}/index.md, with a directive where the clip belongs:The claim is easier to watch than to read: :::{animation}[notebooks/phasor-unrolled.ipynb] :::A companion notebook in that chapter’s
notebooks/folder, holding the manim scene (next section).
make split expands the directive and renders it: the prose becomes
Markdown cells, the companion runs once under manim, and each anim.show(...)
call lands in the generated notebook as a Markdown cell of bare <video>
elements — a light and a dark render side by side, the page displaying the one
that matches the reader’s theme toggle — autoplaying muted and looping: the
embedded-figure feel of the chapter 4 GIF, at a fraction of a GIF’s weight.
The tags point at small H.264 files committed under the chapter’s anim/
folder; the companion’s code never reaches the page, and nothing renders at
book build time — CI just serves the files. Filenames carry a content hash,
so a re-split re-renders only scenes whose companion changed and reuses every
other clip byte-for-byte.
2. The companion notebook#
Two cells, both pure Python. The widget guideline is binding for animation cells
too — never write HTML or JavaScript in a cell; icm_anim.show() is the one
place the video element is made.
The first cell is the imports:
import numpy as np
from manim import *
import icm_anim as anim
The second defines one scene and ends by showing it:
class MyScene(Scene):
def construct(self):
dot = Dot(color=anim.RED)
self.play(FadeIn(dot))
...
anim.show(MyScene)
The rules of the shape:
anim.show(SceneCls)is a top-level statement: the class a bare name, any keywords literal (theme="dark", nevertheme=mode). The splitter reads the call without running the cell to name the clip files; a call it cannot read stopsmake split. In VS Code the same call is the cell’s last expression, returning the inline preview.Palette:
anim.RED,anim.BLUE,anim.GOLD,anim.IRON,anim.TEAL,anim.STEEL, plusanim.INKfor one-off label greys — never manim’s bare names.from manim import *rebindsRED/BLUE/GOLD/TEALto manim’s neon palette, so a bareREDsilently draws the wrong red. Theanim.*names are the book’s palette (single-sourced inicm_widgets, the same namesicm_plotlyre-exports) — shared with every figure and widget in the book.Clips follow the reader’s theme by default (
theme="auto"): the scene is rendered twice — house palette on the light page, and on the theme’s dark background — and the page displays whichever matches the light/dark toggle.anim.show(MyScene, theme="dark")instead pins the borrowed 3Blue1Brown look in both modes (theme="light"pins the light render). Text ink and background are themed per render and reset afterward — nothing leaks between cells; geometry takes explicitanim.*colors.Three quality words:
quality="low"(480p15) to iterate in VS Code — several times faster —"medium"(720p30, the default) to publish, and"high"(1080p60) only with a reason.show()carries a weight budget (max_mb=8, both renders of an auto clip included). In VS Code that’s the inline preview payload; at split time it’s enforced on the committed files — either way it raises rather than quietly shipping a heavy page.No visibility markers: animation cells are always hidden, and
# hide/# collapse/# no-outputmarkers are ignored.
3. Demo: the phasor, unrolled#
The claim chapter 5 spends its first pages on — a sinusoid is a rotating phasor
read off one axis — as ten seconds of film. Everything here is an
always_redraw updater hanging off one ValueTracker, manim’s version of the
update-function idea from the interactive template; the geometry, the trace, and
the dashed thread stay synchronized because they are all functions of the same
clock.
4. Demo: math that morphs#
The other thing film does that a widget cannot: the formula is a character.
Here the partial Fourier sums of a square wave sharpen step by step, and the
MathTex label morphs in lockstep with the curve — Transform interpolates
both. Try writing that with a matplotlib artist.
5. Demo: the borrowed look#
Section 5.5’s margin cites the 3Blue1Brown video this whole aesthetic comes
from, and its winding machine is one argument away: anim.show(WindingMachine, theme="dark") pins the borrowed look — dark in both reader modes. The signal
\(g(t) = 1 + \cos(2\pi \cdot 3t)\) is wound around the origin while the winding
frequency sweeps up to 3 cycles per second — watch the curve snap into alignment
when the winding rate matches the signal’s own frequency. This clip narrates
the idea; the interactive widget in 5.5 is where the reader gets to drive it.
6. Cost and budget#
Measured on this page’s three clips (Apple silicon, "medium" = 720p30, split
re-encodes at crf 28 veryslow; an auto clip’s weight covers both of its
renders):
clip |
film |
committed video |
|---|---|---|
|
9.6 s |
0.34 MB |
|
9.4 s |
0.49 MB |
|
9.8 s |
0.59 MB |
Rendering costs a handful of seconds per clip and is paid once, at make split — the book build never renders, and an unchanged companion is a cache
hit (the hash in the filename is the key). The page’s HTML carries no embedded
video at all; the mp4s stream as ordinary cacheable files. For scale, the two
interactive pages in chapter 5 weigh 16–19 MB each — a narrative page is
still the light kind of animated page. Note how the codec charges for
change, not seconds: the quiet phasor pair costs about half the single
busy winding clip at the same length. House budget: keep a clip under ~20
seconds, a page under ~4 MB of committed video — a video earns its
seconds or it should be a figure.
7. When something looks wrong#
symptom |
cause and fix |
|---|---|
|
|
|
a companion changed (or a new hash appeared) on a machine without the authoring stack — |
|
the companion broke the show() contract — keep each call a top-level |
colors look neon, the red is wrong |
the scene used manim’s bare |
nothing visible on the white frame |
geometry with no explicit color defaults to manim’s white-on-dark; pass |
the clip does not respond to ▶ Run |
correct — animations are watch-only video files; there is no cell to run. |
|
shorten the clip or calm the motion — codecs charge for change, not seconds (the dark winding clip costs twice the quiet phasor at equal length) — and remember an auto clip ships both renders. |
|
pass the class itself — |
the clip ignores the theme toggle |
it was pinned with |
the render is slow while authoring |
|
the book build fails with “show() executed during a book build” |
a page went stale: a committed section notebook still carries executable animation cells — re-run |
Before publishing
Remove this Template - Animation page from _toc.yml — it is an author
reference, not course content.