Chapter 2 · Manim

Every example below shows the exact code on the left and the real video it rendered on the right — click any video to play it, click again to replay. Eleven topics from first circle to 3D camera work — about 6 hours total; each topic stands alone, so stop whenever you like.

Topics 1 Scenes & Mobjects2 Animations 3 Positioning4 Color & styling 5 Updaters6 Graphs & MathTex 7 MathTex mastery8 Timing 9 Camera10 3D 11 Production ✅ Self-exam
🧠 Before you start (30 seconds)Try to answer these from intuition — being wrong is fine, guessing first is proven to make the real answers stick better:
Guess: in an animation library, what might a 'Scene' be?
Your canvas + timeline. You subclass it and describe what happens in construct() — Topic 1.
How do you think you'd make two animations happen at once?
Pass both to one play() call. Sequential = separate calls — Topic 2.
What could make a label FOLLOW a moving dot?
A function that runs every frame — an updater. That's Topic 5, the superpower one.

1Scenes & Mobjects — the two words that explain everything

A Scene is your canvas + timeline. A Mobject ("mathematical object") is anything drawable: circles, text, formulas, graphs. You subclass Scene, override construct(), and inside it you create mobjects and play() animations on them. That's the whole framework.

EASYThe smallest possible animation
from manim import *

class FirstCircle(Scene):
    def construct(self):
        circle = Circle(radius=1.5, color=BLUE)
        self.play(Create(circle))
        self.wait(0.5)

▶ click the video to play — click again to replay

Render it: manim render -ql -p first.py FirstCircle

EASYTwo mobjects, two animations
class SquareAndLabel(Scene):
    def construct(self):
        square = Square(side_length=2, color=GREEN)
        label = Text("A square", font_size=36).next_to(square, DOWN)
        self.play(Create(square))
        self.play(Write(label))
        self.wait(0.5)

▶ click the video to play — click again to replay

Each self.play(...) is one beat of the timeline — they run in order.

LEVEL UPVGroup: treat many mobjects as one
class ShapeFamily(Scene):
    def construct(self):
        shapes = VGroup(
            Circle(color=BLUE), Square(color=GREEN),
            Triangle(color=YELLOW), Star(color=RED),
        ).arrange(RIGHT, buff=0.8).scale(0.7)
        self.play(LaggedStart(*[Create(s) for s in shapes],
                              lag_ratio=0.3))

▶ click the video to play — click again to replay

arrange lays members out; LaggedStart staggers their animations.

LEVEL UPTransform: one mobject, many forms
class MorphingShapes(Scene):
    def construct(self):
        shape = Circle(radius=1.5, color=BLUE)
        self.play(Create(shape))
        for target in [Square(side_length=2.5, color=GREEN),
                       Triangle(color=YELLOW).scale(1.5),
                       RegularPolygon(6, color=PURPLE).scale(1.5)]:
            self.play(Transform(shape, target))

▶ click the video to play — click again to replay

Transform(a, b) smoothly morphs a into b's shape.

🎯 Your turn to write — your very first scene:
Write a scene class called MyFirst that creates a blue Circle and plays Create on it.

2The animation vocabulary

Manim ships dozens of animation classes, but you'll use about eight constantly: Create, Write, FadeIn/FadeOut, Transform, GrowFromCenter, LaggedStart, and the special .animate syntax. Multiple animations passed to one play() run simultaneously.

EASYWrite — the classic for text
class HelloWrite(Scene):
    def construct(self):
        text = Text("Hello, Manim!", font_size=60,
                    gradient=(BLUE, TEAL))
        self.play(Write(text))

▶ click the video to play — click again to replay

EASYParallel animations & directional fades
class FadeAndGrow(Scene):
    def construct(self):
        circle = Circle(color=BLUE, fill_opacity=0.5).shift(LEFT * 2.5)
        square = Square(color=GREEN, fill_opacity=0.5).shift(RIGHT * 2.5)
        self.play(FadeIn(circle), GrowFromCenter(square))  # together!
        self.wait(0.3)
        self.play(FadeOut(circle, shift=UP),
                  FadeOut(square, shift=DOWN))

▶ click the video to play — click again to replay

Two animations in one play() = simultaneous.

LEVEL UPTransformMatchingShapes — smart morphing
class WordMorph(Scene):
    def construct(self):
        a = Text("mathematics", font_size=56)
        b = Text("animations", font_size=56, color=TEAL)
        self.play(Write(a))
        self.play(TransformMatchingShapes(a, b))

▶ click the video to play — click again to replay

Letters that exist in both words fly to their new positions.

LEVEL UPLaggedStart + rate functions
class RainDots(Scene):
    def construct(self):
        dots = VGroup(*[Dot(color=random_bright_color())
                        .move_to([x, 3.5, 0])
                        for x in np.linspace(-6, 6, 25)])
        self.play(LaggedStart(
            *[d.animate.shift(DOWN * 7) for d in dots],
            lag_ratio=0.05, run_time=2.5,
            rate_func=rate_functions.ease_in_quad))

▶ click the video to play — click again to replay

rate_func shapes the speed curve — ease_in_quad = accelerating, like gravity.

🎯 Your turn to write — three beats of animation:
A Square appears with Create, transforms into a Circle, then fades out. Three plays.

3Positioning: shift, next_to, arrange, paths

The screen is a coordinate grid: origin at center, ~7 units left-right, ~4 up-down. Constants UP, DOWN, LEFT, RIGHT are unit vectors you can scale and add: UP * 2 + RIGHT * 3 is just a point.

EASYshift() — move by an offset
class ShiftAround(Scene):
    def construct(self):
        dot = Dot(color=YELLOW).scale(2)
        self.play(FadeIn(dot))
        for direction in [UP * 2, RIGHT * 3, DOWN * 4,
                          LEFT * 6, UP * 2 + RIGHT * 3]:
            self.play(dot.animate.shift(direction), run_time=0.5)

▶ click the video to play — click again to replay

.animate.shift() animates the move; plain .shift() teleports before rendering.

EASYnext_to() — position relative to another mobject
class NeighborLayout(Scene):
    def construct(self):
        center = Square(color=BLUE)
        up = Text("above", font_size=30).next_to(center, UP)
        down = Text("below", font_size=30).next_to(center, DOWN)
        left = Text("left", font_size=30).next_to(center, LEFT)
        right = Text("right", font_size=30).next_to(center, RIGHT)
        self.play(Create(center))
        self.play(FadeIn(up), FadeIn(down),
                  FadeIn(left), FadeIn(right))

▶ click the video to play — click again to replay

Relative positioning survives refactors — move the square, labels follow (at creation time).

LEVEL UParrange_in_grid & re-arranging live
class GridOfShapes(Scene):
    def construct(self):
        grid = VGroup(*[
            Circle(radius=0.3, color=c, fill_opacity=0.8)
            for c in [RED, ORANGE, YELLOW, GREEN, TEAL,
                      BLUE, PURPLE, PINK, WHITE]
        ]).arrange_in_grid(rows=3, cols=3, buff=0.6)
        self.play(LaggedStart(*[GrowFromCenter(s) for s in grid],
                              lag_ratio=0.1))
        self.play(grid.animate.arrange(RIGHT, buff=0.25).scale(0.8))

▶ click the video to play — click again to replay

A VGroup can be re-arranged as an animation — the layout itself animates.

LEVEL UPMoveAlongPath — any mobject, any curve
class OrbitingMoon(Scene):
    def construct(self):
        planet = Circle(radius=0.6, color=BLUE, fill_opacity=1)
        orbit = Circle(radius=2.2, color=GREY).set_stroke(width=2)
        moon = Dot(color=WHITE).scale(1.5)
        moon.move_to(orbit.point_from_proportion(0))
        self.play(FadeIn(planet), Create(orbit), FadeIn(moon))
        self.play(MoveAlongPath(moon, orbit),
                  run_time=3, rate_func=linear)

▶ click the video to play — click again to replay

Any VMobject can be a path — circles, arcs, even hand-drawn Bezier curves.

🎯 Your turn to write — place things precisely:
Make a Circle, put a Text label below it with next_to, then group both in a VGroup and shift the group 2 units LEFT.

4Color & styling

Every mobject has a stroke (outline) and a fill. color= sets both; fill_opacity= reveals the fill (default 0!). Gradients work on both text and shapes.

EASYStroke, fill, and both
class FillAndStroke(Scene):
    def construct(self):
        s1 = Square(color=BLUE).shift(LEFT * 3)   # stroke only
        s2 = Square(color=BLUE, fill_opacity=1)   # filled
        s3 = Square(fill_color=YELLOW, fill_opacity=1,
                    stroke_color=RED, stroke_width=8).shift(RIGHT * 3)
        self.play(Create(s1), Create(s2), Create(s3))

▶ click the video to play — click again to replay

The #1 beginner surprise: shapes are hollow until you set fill_opacity.

EASYGradients
class GradientTitle(Scene):
    def construct(self):
        title = Text("Gradients!", font_size=72,
                     gradient=(RED, YELLOW, GREEN))
        underline = Line(LEFT * 3, RIGHT * 3).next_to(title, DOWN)
        underline.set_color_by_gradient(RED, YELLOW, GREEN)
        self.play(Write(title), Create(underline))

▶ click the video to play — click again to replay

LEVEL UPDashed lines & opacity for de-emphasis
class DashAndOpacity(Scene):
    def construct(self):
        solid = Circle(radius=1.2, color=TEAL).shift(LEFT * 3)
        dashed = DashedVMobject(Circle(radius=1.2, color=TEAL))
        ghost = Circle(radius=1.2, color=TEAL, fill_opacity=0.25,
                       stroke_opacity=0.4).shift(RIGHT * 3)
        self.play(Create(solid), Create(dashed), FadeIn(ghost))

▶ click the video to play — click again to replay

Low opacity = 'this is context, not the point' — a key visual-communication trick.

LEVEL UPGradient across a whole group + there_and_back
class StyleWave(Scene):
    def construct(self):
        squares = VGroup(*[Square(side_length=0.7, fill_opacity=0.9)
                           for _ in range(10)]).arrange(RIGHT, buff=0.15)
        squares.set_color_by_gradient(PURPLE, TEAL, YELLOW)
        self.play(LaggedStart(*[GrowFromCenter(s) for s in squares],
                              lag_ratio=0.08))
        self.play(LaggedStart(
            *[s.animate.shift(UP * 0.8).set_fill(WHITE)
              for s in squares],
            lag_ratio=0.1, rate_func=there_and_back, run_time=2))

▶ click the video to play — click again to replay

there_and_back plays the animation forward then in reverse — great for waves and pulses.

🎯 Your turn to write — style it like you mean it:
Create a Square with 50% fill opacity, then animate it turning RED using the .animate syntax.

5Updaters & ValueTracker — animations that react

So far every animation was pre-scripted. Updaters are little functions that run every frame: "keep this line attached to that dot", "keep this number equal to that value". ValueTracker holds a number you can animate; always_redraw rebuilds a mobject each frame. This combination is Manim's superpower.

EASYA number that counts to 100
class LiveCounter(Scene):
    def construct(self):
        value = ValueTracker(0)
        number = DecimalNumber(0, num_decimal_places=1,
                               font_size=96)
        number.add_updater(
            lambda m: m.set_value(value.get_value()))
        self.add(number)
        self.play(value.animate.set_value(100),
                  run_time=3, rate_func=linear)

▶ click the video to play — click again to replay

You animate the tracker; the updater drags the number along every frame.

EASYA rope that never lets go
class DotChaser(Scene):
    def construct(self):
        anchor = Dot(LEFT * 4, color=BLUE).scale(1.5)
        runner = Dot(RIGHT * 4 + UP * 2, color=YELLOW).scale(1.5)
        rope = always_redraw(lambda: Line(
            anchor.get_center(), runner.get_center(), color=GREY))
        self.add(anchor, runner, rope)
        self.play(runner.animate.move_to(RIGHT * 4 + DOWN * 2))
        self.play(runner.animate.move_to(UP * 2.5))

▶ click the video to play — click again to replay

always_redraw rebuilds the line every frame from live positions.

LEVEL UPdt-updaters: perpetual motion
class TickingClock(Scene):
    def construct(self):
        face = Circle(radius=2, color=WHITE)
        hand = Line(ORIGIN, UP * 1.6, color=YELLOW,
                    stroke_width=6)
        hand.add_updater(lambda m, dt:
            m.rotate(-dt * PI / 2, about_point=ORIGIN))
        self.play(Create(face))
        self.add(hand)
        self.wait(4)   # the hand keeps turning by itself!

▶ click the video to play — click again to replay

An updater taking (mobject, dt) runs on wall-clock time — even during wait().

LEVEL UPA live progress bar (three updaters cooperating)
class GrowingBar(Scene):
    def construct(self):
        progress = ValueTracker(0)
        track = Rectangle(width=8, height=0.6, color=GREY)
        bar = always_redraw(lambda: Rectangle(
            width=max(progress.get_value() * 8, 0.001), height=0.6,
            fill_color=TEAL, fill_opacity=1, stroke_width=0,
        ).align_to(track, LEFT))
        pct = always_redraw(lambda: Integer(
            int(progress.get_value() * 100), unit=r"\%",
            font_size=40).next_to(track, UP))
        self.add(track, bar, pct)
        self.play(progress.animate.set_value(1), run_time=3,
                  rate_func=rate_functions.ease_in_out_sine)

▶ click the video to play — click again to replay

One tracker drives both the bar's width and the percentage — single source of truth.

🎯 Your turn to write — a number that counts:
Make a ValueTracker starting at 0, a DecimalNumber that follows it with an updater, and animate the tracker to 100.

6Graphs & MathTex — where LaTeX pays off

Axes gives you a coordinate system; .plot() draws functions on it; MathTex renders any LaTeX from Chapter 1 as an animatable mobject. This is the toolkit of every math explainer video you've ever watched.

EASYPlot a sine wave
class SinePlot(Scene):
    def construct(self):
        axes = Axes(x_range=[-4, 4], y_range=[-2, 2],
                    x_length=10, y_length=5)
        curve = axes.plot(lambda x: np.sin(x), color=YELLOW)
        self.play(Create(axes))
        self.play(Create(curve), run_time=2)

▶ click the video to play — click again to replay

plot() takes any Python function of x.

EASYYour LaTeX, animated
class EulerFormula(Scene):
    def construct(self):
        formula = MathTex(r"e^{i\pi} + 1 = 0", font_size=96)
        name = Text("Euler's identity", font_size=32,
                    color=GREY).next_to(formula, DOWN)
        self.play(Write(formula))
        self.play(FadeIn(name))

▶ click the video to play — click again to replay

Everything from Chapter 1 works inside MathTex — always with the r prefix.

LEVEL UPRiemann rectangles refining themselves
class RiemannIntro(Scene):
    def construct(self):
        axes = Axes(x_range=[0, 4], y_range=[0, 9],
                    x_length=9, y_length=5)
        curve = axes.plot(lambda x: x**2 * 0.55 + 0.5, color=TEAL)
        rects = axes.get_riemann_rectangles(
            curve, x_range=[0, 4], dx=0.5, fill_opacity=0.7)
        fine = axes.get_riemann_rectangles(
            curve, x_range=[0, 4], dx=0.125, fill_opacity=0.7)
        self.play(Create(axes), Create(curve))
        self.play(FadeIn(rects))
        self.play(Transform(rects, fine))

▶ click the video to play — click again to replay

Transforming coarse rectangles into fine ones IS the idea of integration, visually.

LEVEL UPA tangent line sliding along a curve
class TangentSlide(Scene):
    def construct(self):
        axes = Axes(x_range=[-3, 3], y_range=[-1, 8],
                    x_length=10, y_length=5.5)
        curve = axes.plot(lambda x: 0.6 * x**2 + 0.4, color=YELLOW)
        x = ValueTracker(-2.2)
        tangent = always_redraw(lambda: TangentLine(
            curve, alpha=(x.get_value() + 3) / 6,
            length=4, color=RED))
        dot = always_redraw(lambda: Dot(color=RED).move_to(
            axes.c2p(x.get_value(),
                     0.6 * x.get_value()**2 + 0.4)))
        self.play(Create(axes), Create(curve))
        self.add(tangent, dot)
        self.play(x.animate.set_value(2.2), run_time=3,
                  rate_func=linear)

▶ click the video to play — click again to replay

Updaters (topic 5) + graphs (topic 6) = the derivative, animated. This exact scene becomes a slide deck in Chapter 3.

🎯 Your turn to write — a real plot:
Create Axes, plot sin(x) on them with a lambda, and play Create on both.

7MathTex mastery: transforms, braces & spotlights

The killer feature for math talks: split a formula into parts, then morph one equation into another while matching terms fly to their new places. This is why you learned LaTeX first.

class TexTransform(Scene):
    def construct(self):
        eq1 = MathTex("a^2", "+", "b^2", "=", "c^2",
                      font_size=72)
        eq2 = MathTex("c^2", "=", "a^2", "+", "b^2",
                      font_size=72)
        self.play(Write(eq1))
        self.wait(0.6)
        self.play(TransformMatchingTex(eq1, eq2),
                  run_time=1.5)
        self.wait(0.6)

▶ click the video to play — click again to replay

Each string argument becomes a separately-animatable part. TransformMatchingTex moves identical parts to their new positions.

class BraceAnnotate(Scene):
    def construct(self):
        eq = MathTex("(", "x+1", ")", "^2", "=",
                     "x^2+2x+1", font_size=60)
        self.play(Write(eq))
        brace = Brace(eq[1], DOWN, color=YELLOW)
        note = brace.get_text("this part gets squared")
        note.set_color(YELLOW)
        box = SurroundingRectangle(eq[5], color=TEAL,
                                   buff=0.15)
        self.play(GrowFromCenter(brace), FadeIn(note))
        self.play(Create(box), Indicate(eq[5]))

▶ click the video to play — click again to replay

eq[1] indexes the parts you split. Brace points at anything; SurroundingRectangle + Indicate = instant spotlight.

You wrote MathTex(r'a^2 + b^2 = c^2') as ONE string. Why can't you animate just the 'b^2'?
🎯 Your turn to write — equation morphing:
Write MathTex for a²+b²=c² split into separate substrings (so terms can move), then morph it into another MathTex with TransformMatchingTex.

8Timing & choreography: LaggedStart, rate functions

Amateur animations play everything at once at constant speed. Professional ones stagger entrances and ease movements. Two tools give you 90% of that polish.

class LaggedShapes(Scene):
    def construct(self):
        dots = VGroup(*[Dot(radius=0.14, color=TEAL)
                        for _ in range(12)])
        dots.arrange(RIGHT, buff=0.35)
        self.play(LaggedStart(
            *[GrowFromCenter(d) for d in dots],
            lag_ratio=0.15))
        self.play(dots.animate.set_color(YELLOW),
                  run_time=1.5)

▶ click the video to play — click again to replay

lag_ratio=0.15: each dot starts when the previous one is 15% done — a wave instead of a blob.

class RateFuncs(Scene):
    def construct(self):
        labels = ["linear", "smooth",
                  "there_and_back", "rush_into"]
        funcs = [linear, smooth,
                 there_and_back, rush_into]
        rows = VGroup(*[
            VGroup(Text(n, font_size=24), Dot(color=ORANGE))
            .arrange(RIGHT, buff=0.5)
            for n in labels])
        rows.arrange(DOWN, aligned_edge=LEFT,
                     buff=0.5).to_edge(LEFT)
        self.add(rows)
        self.play(*[row[1].animate(rate_func=fn,
                                   run_time=2.5)
                    .shift(RIGHT * 8)
                    for row, fn in zip(rows, funcs)])

▶ click the video to play — click again to replay

Same shift, four personalities. smooth is the default; there_and_back returns home — great for 'pulse' effects.

You want 20 stars to appear one after another, overlapping slightly. Best tool?
🎯 Your turn to write — choreography:
Animate three squares appearing with LaggedStart, a lag_ratio of 0.3, a total run_time of 2, and a rate_func of your choice.

9Camera work: zoom, pan, follow

Switch SceneMovingCameraScene and the viewport itself becomes an animatable object. Zooming into detail and following motion are the two moves you'll actually use.

class CameraZoom(MovingCameraScene):
    def construct(self):
        dots = VGroup(*[Dot(color=BLUE)
                        for _ in range(9)])
        dots.arrange_in_grid(3, 3, buff=1.2)
        target = dots[4].set_color(YELLOW)
        self.play(Create(dots))
        self.camera.frame.save_state()
        self.play(self.camera.frame.animate
                  .scale(0.35).move_to(target))
        self.wait(0.4)
        self.play(Restore(self.camera.frame))

▶ click the video to play — click again to replay

self.camera.frame is a rectangle mobject: scale it (zoom), move_to it (pan), Restore brings it back.

class CameraFollow(MovingCameraScene):
    def construct(self):
        path = Line(LEFT * 5, RIGHT * 5).shift(DOWN)
        car = Triangle(color=RED, fill_opacity=1)
        car.scale(0.3).rotate(-PI / 2)
        car.move_to(path.get_start())
        self.add(path, car)
        self.camera.frame.scale(0.6).move_to(car)
        self.camera.frame.add_updater(
            lambda f: f.move_to(car.get_center()))
        self.play(car.animate.move_to(path.get_end()),
                  run_time=3, rate_func=linear)

▶ click the video to play — click again to replay

An updater on the camera frame = a follow-cam. Same updater idea from Topic 5, applied to the camera.

Zoom into the top-right corner of a diagram. Which line?
🎯 Your turn to write — move the camera:
In a MovingCameraScene, animate self.camera.frame to scale to half size and move to a dot.

103D scenes: axes, spheres, surfaces

ThreeDScene unlocks the third axis. You position the camera with two angles — phi (tilt down from vertical) and theta (spin around) — and can set it slowly orbiting while you present.

class First3D(ThreeDScene):
    def construct(self):
        axes = ThreeDAxes(x_range=[-4, 4],
                          y_range=[-4, 4],
                          z_range=[-3, 3])
        sphere = Sphere(radius=1,
                        resolution=(18, 18))
        sphere.set_color(BLUE)
        self.set_camera_orientation(
            phi=70 * DEGREES, theta=-45 * DEGREES)
        self.play(Create(axes))
        self.play(Create(sphere))
        self.begin_ambient_camera_rotation(rate=0.4)
        self.wait(2.5)

▶ click the video to play — click again to replay

phi=70° tilts you above the plane; ambient rotation keeps the scene alive while you talk over it.

class Surface3D(ThreeDScene):
    def construct(self):
        axes = ThreeDAxes(x_range=[-3, 3],
                          y_range=[-3, 3],
                          z_range=[-2, 2])
        surface = Surface(
            lambda u, v: axes.c2p(
                u, v, np.sin(u) * np.cos(v)),
            u_range=[-3, 3], v_range=[-3, 3],
            resolution=(24, 24), fill_opacity=0.8)
        surface.set_fill_by_value(axes=axes,
            colorscale=[(BLUE, -1), (GREEN, 0),
                        (YELLOW, 1)])
        self.set_camera_orientation(
            phi=65 * DEGREES, theta=-50 * DEGREES)
        self.play(Create(axes), Create(surface),
                  run_time=2)
        self.begin_ambient_camera_rotation(rate=0.3)
        self.wait(2)

▶ click the video to play — click again to replay

Surface takes a function (u,v) → 3D point; set_fill_by_value colors by height like a heat map.

Your 3D text looks skewed because the camera tilts. The fix Manim provides?
🎯 Your turn to write — enter the third dimension:
A ThreeDScene that sets a camera orientation (phi and theta), creates ThreeDAxes and a Sphere.

11Production settings: quality, format, partial renders

The last mile: rendering the same scene for a quick check, a slide deck, or a final video are just different flags. These are the ones that matter in real work.

# fast draft while iterating (480p @ 15fps)
manim render -ql --fps 15 scene.py MyScene

# full quality for the final export (1080p60)
manim render -qh scene.py MyScene

# render a transparent-background overlay (for OBS / video editors)
manim render -qh -t --format=mov scene.py MyScene

# just the LAST play() call — lifesaver when polishing an ending
manim render -ql -n -1 scene.py MyScene

# save the final frame as PNG (thumbnails!)
manim render -qh -s scene.py MyScene
# per-project defaults: put a manim.cfg next to your scene file
[CLI]
quality = medium_quality
preview = True
background_color = #101418
Your 3-minute scene's ending is wrong. Fastest way to iterate on just the ending?
🎯 Your turn to write — the render command:
Write the terminal command that renders MyScene from talk.py at high quality and opens the result when done.

Self-examination

Why does a Circle appear as just an outline by default?
What's the difference between circle.shift(UP) and circle.animate.shift(UP) inside play()?
You want a label to follow a moving dot for the whole scene. Best tool?
Write a scene where a red square grows from the center, slides right 3 units, then fades out upward. (Three plays, or fewer!)
show solution
class Ex1(Scene):
    def construct(self):
        sq = Square(color=RED, fill_opacity=0.8)
        self.play(GrowFromCenter(sq))
        self.play(sq.animate.shift(RIGHT * 3))
        self.play(FadeOut(sq, shift=UP))
Make a DecimalNumber that counts DOWN from 10 to 0 in 5 seconds while turning from white to red. (Hint: two updaters or one updater + .animate.set_color.)
show solution
class Countdown(Scene):
    def construct(self):
        t = ValueTracker(10)
        num = DecimalNumber(10, num_decimal_places=1, font_size=96)
        num.add_updater(lambda m: m.set_value(t.get_value()))
        self.add(num)
        self.play(t.animate.set_value(0),
                  num.animate.set_color(RED),
                  run_time=5, rate_func=linear)
Plot y = x³ − 3x on axes from −3 to 3 and animate a dot moving along the curve from left to right. (Hint: ValueTracker + always_redraw + axes.c2p.)
show solution
class CubicDot(Scene):
    def construct(self):
        axes = Axes(x_range=[-3, 3], y_range=[-4, 4],
                    x_length=10, y_length=5.5)
        f = lambda x: x**3 - 3 * x
        curve = axes.plot(f, color=TEAL)
        x = ValueTracker(-2.2)
        dot = always_redraw(lambda: Dot(color=YELLOW).move_to(
            axes.c2p(x.get_value(), f(x.get_value()))))
        self.play(Create(axes), Create(curve))
        self.add(dot)
        self.play(x.animate.set_value(2.2), run_time=4)
← Previous1 · LaTeX Next chapter →3 · manim-slides