| name | manim-animations |
| description | Use when composing Manim animations: choosing between Create/Write/FadeIn/Transform, sequencing animations with AnimationGroup/LaggedStart/Succession, controlling timing with run_time and rate_func, pacing (how long things stay on screen), ValueTracker-driven continuous animation, semantic color discipline, and animating between TeX expressions with TransformMatchingTex. |
Manim animations
Once you have Mobjects ([[manim-scenes]]), animations make them change over time. Each call to self.play(...) consumes time equal to its longest animation.
Reveal / appearance
Create(mobject)
Write(text_or_tex)
DrawBorderThenFill(shape)
FadeIn(mobject, shift=UP)
GrowFromCenter(mobject)
GrowFromPoint(mobject, point)
SpinInFromNothing(mobject)
Reverse counterparts: Uncreate, Unwrite, FadeOut, ShrinkToCenter.
Rule of thumb:
Create for shapes.
Write for text/math.
FadeIn for grouped or complex objects where the "drawing" effect looks busy.
Transformations
Transform(a, b)
ReplacementTransform(a, b)
TransformFromCopy(a, b)
The difference between Transform and ReplacementTransform matters: after Transform(a, b), the Mobject a is on screen but looks like b. After ReplacementTransform(a, b), b is on screen. ReplacementTransform is what people usually want; the bare Transform causes subtle bugs where references go stale.
Morph, don't blink. When an object conceptually persists across a change (an equation being rearranged, a shape becoming its area), use the Transform family (ReplacementTransform, TransformMatchingTex) rather than FadeOut + FadeIn of a replacement. The eye following one thing as it becomes another is most of what makes 3b1b-style videos legible. Reserve fades for objects genuinely entering or leaving the story.
TeX-specific transforms
eq1 = MathTex(r"a + b = c")
eq2 = MathTex(r"a + b - c = 0")
self.play(TransformMatchingTex(eq1, eq2))
self.play(TransformMatchingShapes(eq1, eq2))
TransformMatchingTex is magic when it works (matching glyphs animate, new ones fade in). When it doesn't, fall back to TransformMatchingShapes or to grouped MathTex parts with explicit ReplacementTransform.
Movement and properties
mobject.animate.shift(2*UP)
mobject.animate.move_to(target_point)
mobject.animate.scale(1.5)
mobject.animate.rotate(PI/4)
mobject.animate.set_color(RED)
mobject.animate.set_opacity(0.5)
You can chain: square.animate.shift(RIGHT).rotate(PI/4).set_color(BLUE). The whole chain becomes one animation.
Composing animations in time
Parallel. Multiple animations in one play run simultaneously:
self.play(
FadeIn(title),
Create(circle),
Write(label),
)
Sequential. Multiple play calls run one after another. Or use Succession:
self.play(Succession(
Create(a),
Create(b),
Create(c),
))
Staggered. LaggedStart for "domino" effects:
self.play(LaggedStart(
*[Create(d) for d in dots],
lag_ratio=0.1,
))
lag_ratio=0 → all parallel. lag_ratio=1 → fully sequential.
AnimationGroup is the explicit version of "play these together," with lag_ratio control. LaggedStart is a shorthand with lag_ratio=0.05 by default. The default (0.05) is tighter than the 0.1-0.3 you usually want, so set it explicitly.
Timing controls
self.play(Create(c), run_time=2)
self.play(Create(c), rate_func=smooth)
self.play(Create(c), rate_func=linear)
self.play(Create(c), rate_func=there_and_back)
self.play(Create(c), rate_func=rush_into)
self.play(Create(c), rate_func=double_smooth)
run_time defaults to 1 second per play. total_frames = run_time x fps; each frame advances the animation by 1/fps of real time.
Pacing: the numbers that matter
run_time window: 0.5–3s. Below 0.5s reads as a glitch; above 3s drags. 1s is right for small moves; 1.5–2.5s for math reveals.
self.wait(1) after every beat. Viewers need ~2s to read one line of text, so wait longer after text-heavy reveals. A scene with no waits is unwatchable at any run_time.
- Groups:
LaggedStart(..., lag_ratio=0.1–0.3), never simultaneous pops. The eye tracks a cascade; it cannot track twelve things appearing at once.
Updaters (continuous animation)
For things that should track a value, not be played:
dot = Dot()
label = always_redraw(lambda: Tex(f"({dot.get_center()[0]:.2f}, ...)").next_to(dot, UP))
self.add(dot, label)
self.play(dot.animate.shift(2*RIGHT))
always_redraw re-creates the label every frame using current state. Or use add_updater:
def follow(mob):
mob.next_to(dot, UP)
label.add_updater(follow)
self.add(label)
self.play(dot.animate.shift(2*RIGHT))
label.remove_updater(follow)
Updaters are CPU-hungry; remove them when no longer needed.
ValueTracker: continuous relationships
When one number drives several mobjects, animate the number:
x = ValueTracker(-2)
curve = axes.plot(lambda t: t**2, color=BLUE)
dot = always_redraw(lambda: Dot(axes.c2p(x.get_value(), x.get_value() ** 2), color=YELLOW))
readout = always_redraw(lambda: DecimalNumber(x.get_value()).next_to(dot, UR))
self.add(curve, dot, readout)
self.play(x.animate.set_value(2), run_time=4)
Rule of thumb: discrete events → one self.play(...) per beat. Continuous relationships (a point tracing a curve, a sweeping angle, a live readout) → ValueTracker + updaters.
Semantic color discipline
Declare a palette at the top of the file; one concept = one color for the entire video:
FUNC_COLOR = BLUE
DERIV_COLOR = YELLOW
AREA_COLOR = TEAL
Manim's named constants (BLUE, TEAL, YELLOW, MAROON) are tuned for the dark background and read better than hand-picked hex. Re-coloring a concept mid-video silently breaks the viewer's mental mapping.
Gotchas
Transform references. After Transform(a, b), don't refer to b later; it isn't on scene as a separate Mobject. Use ReplacementTransform instead.
FadeOut on a non-added Mobject. Silently does nothing. Make sure it was added or appeared via prior animation.
rate_func=linear for motion. Looks robotic. Smooth is the right default.
- Updaters left attached. Keep slowing the scene as more accumulate. Always
remove_updater when done.
- Animating
Text color via set_color. Works, but for partial color changes use t.set_color_by_gradient(...) or t[0:5].set_color(RED) (slice by glyph).
Related: [[manim-scenes]], [[manim-3d]].