ManimCE Multi-Animation Synchronization Guide: 3 Parallel Animation Techniques and Rate Function Control

This article focuses on ManimCE’s multi-animation synchronization model. It explains how to coordinate movement, color changes, rotation, and other actions on the same timeline, helping you solve common problems such as unsynchronized animations, hard-to-control pacing, and disorganized animation logic. Keywords: ManimCE, multi-animation synchronization, rate_func.

Technical Snapshot

Parameter Description
Core topic Running multiple animations simultaneously in ManimCE
Primary language Python
Animation interfaces Scene.play(), animate syntax
Core classes AnimationGroup, LaggedStart, Succession, ApplyMethod
Coordination mechanisms run_time, lag_ratio, rate_func
Common use cases Math visualization, teaching animations, demo videos
Star count Not provided in the source content
Core dependency manim

ManimCE provides several ways to run animations in parallel

In mathematical animation, the most common requirement is not simply to make objects move, but to make multiple objects move together with a consistent rhythm. For example, axes and labels may need to appear at the same time, or a shape may need to change color while it moves.

The main entry point for parallel animation in ManimCE is still self.play(). As long as you pass multiple animation objects as separate arguments, the renderer places them on the same timeline. This is the foundation for understanding all advanced synchronization patterns that follow.

Passing multiple animations into a single play() call is the most direct approach

from manim import *

class SimpleMultiAnimation(Scene):
    def construct(self):
        # Create two basic shapes
        circle = Circle(color=BLUE).shift(LEFT * 2)
        square = Square(color=RED).shift(RIGHT * 2)

        # Add the objects to the scene first so later animations are visible
        self.add(circle, square)
        self.wait(0.5)

        # Pass two animations into the same play call to run them simultaneously
        self.play(
            circle.animate.shift(UP * 2),   # Move the circle upward
            square.animate.shift(DOWN * 2)  # Move the square downward
        )
        self.wait()

This code makes two shapes start and finish opposite-direction translation animations at the same time.

AI Visual Insight: The image shows two basic geometric shapes positioned on the left and right, moving in opposite directions on the same timeline. The blue circle rises upward while the red square moves downward, demonstrating that play() can directly schedule multiple animate-based animations while keeping their start and end times synchronized.

AnimationGroup is better for organizing related animations

As the number of animations grows, placing every action directly inside play() reduces readability. In that case, a better pattern is to package animations into a logical group and then play that group as a single unit.

The value of AnimationGroup is not just that it can also play animations simultaneously. More importantly, it turns a set of animations into a reusable, nestable, and composable scheduling unit. That matters when you need to break a complex scene into manageable parts.

Using AnimationGroup improves the structure of animation orchestration

from manim import *

class AnimationGroupExample(Scene):
    def construct(self):
        # Create three dots and arrange them horizontally
        dots = VGroup(*[Dot(radius=0.1) for _ in range(3)])
        dots.arrange(RIGHT, buff=1)

        # Define a different action for each dot
        animations = [
            dots[0].animate.shift(UP * 2).set_color(YELLOW),   # Move up and turn yellow
            dots[1].animate.shift(DOWN * 2).set_color(GREEN),  # Move down and turn green
            dots[2].animate.shift(LEFT * 2).set_color(RED)     # Move left and turn red
        ]

        # Play multiple animations simultaneously as a single unit
        self.play(AnimationGroup(*animations))
        self.wait()

This code organizes three animations with different directions and color transitions into one unified structure, making them easier to manage consistently.

AI Visual Insight: The scene shows three dots performing distinct transformations from the same frame-aligned starting point: one moves upward, one downward, and one leftward, each with a corresponding color change. This demonstrates that AnimationGroup is well suited for batch animation tasks that share the same start time but perform different actions.

LaggedStart enables staggered starts while preserving overall continuity

Parallel animation does not always mean everything must start at exactly the same instant. Many polished animations use staggered starts with partial overlap to create a stronger sense of rhythm. LaggedStart is designed for exactly this need.

It uses lag_ratio to control the startup offset between adjacent animations. Each object begins before the previous one fully finishes, so the sequence advances through overlapping motion rather than strict turn-taking. The result feels smoother and more continuous.

Using LaggedStart creates a balance between synchronization and visual layering

from manim import *

class LaggedStartExample(Scene):
    def construct(self):
        # Create four squares and arrange them horizontally
        squares = VGroup(*[Square(side_length=1) for _ in range(4)])
        squares.arrange(RIGHT, buff=0.5)

        # Start the rotation animations in sequence with temporal overlap
        self.play(
            LaggedStart(
                *[
                    s.animate.rotate(PI).set_color(random_bright_color())
                    for s in squares
                ],
                lag_ratio=0.3  # Control the startup delay ratio between adjacent animations
            ),
            run_time=3,
        )
        self.wait()

This code makes multiple squares rotate and change color in sequence, producing a continuous forward-moving visual rhythm.

AI Visual Insight: The squares do not rotate in perfect lockstep. Instead, they start one after another with a fixed temporal offset while their colors also change, creating a wave-like propagation effect. This pattern is often used to emphasize order, propagation, or rhythmic progression.

Different animations can share one duration while using different rate functions

In real projects, you often do not want multiple simultaneously running animations to feel identical. Some elements work best with linear motion, some should start fast and slow down, and others should start slowly and speed up.

In these cases, you can use ApplyMethod or other animation objects to assign a separate rate_func to each animation. Even when all animations share the same run_time, their motion curves can still be completely different.

Using rate_func is the key to fine-grained control over animation pacing

from manim import *

class RateFunctionsExample(Scene):
    def construct(self):
        # Create three small balls with different colors
        dot1 = Dot(color=RED, radius=0.2).shift(LEFT * 3 + UP * 2)
        dot2 = Dot(color=GREEN, radius=0.2).shift(LEFT * 3)
        dot3 = Dot(color=BLUE, radius=0.2).shift(LEFT * 3 + DOWN * 2)
        self.add(dot1, dot2, dot3)

        # Assign a different speed curve to each animation
        anim1 = ApplyMethod(dot1.shift, RIGHT * 6, rate_func=linear)  # Move at a constant speed
        anim2 = ApplyMethod(
            dot2.shift, RIGHT * 6,
            rate_func=rate_functions.ease_out_quad  # Start fast, then slow down
        )
        anim3 = ApplyMethod(
            dot3.shift, RIGHT * 6,
            rate_func=rate_functions.ease_in_quad   # Start slow, then speed up
        )

        # Run all three animations at the same time with different pacing
        self.play(anim1, anim2, anim3, run_time=3)
        self.wait()

This code shows how different objects can produce different perceived motion speeds while sharing a single total duration.

AI Visual Insight: The three dots move horizontally along the same path, but their speed curves clearly differ: the top dot moves linearly, the middle dot starts fast and slows down, and the bottom dot starts slowly and speeds up. This makes it easy to see that rate_func controls the time mapping of an animation rather than the path itself.

Choosing the right parallel animation strategy directly affects maintainability

If you only need two objects to move at the same time, passing multiple animations directly into play() is the simplest option. If those animations belong to the same business meaning, such as an entire title section entering the scene, prefer AnimationGroup. If you want a layered, progressive rhythm, use LaggedStart.

When the requirement evolves into shared start times but different motion feels, shift your focus from animation objects to rate functions. run_time determines the total duration, while rate_func determines how time is distributed. Together, they define the texture of the animation.

FAQ

Q1: Why are multiple animations not running at the same time?

A: The most common reason is that you did not pass multiple animations into the same self.play() call, or you accidentally split the logic across multiple play() calls. Parallel animations must share the same invocation context.

Q2: How do I make multiple animations end at exactly the same moment?

A: Set the same run_time for all of them and avoid introducing extra delay controls inside the group. If you use LaggedStart, also evaluate how lag_ratio affects the final end time.

Q3: When should I use AnimationGroup, and when should I use LaggedStart?

A: AnimationGroup is better for logical grouping and unified scheduling, emphasizing management as one whole. LaggedStart is better for staggered starts with overlap, emphasizing layered temporal progression.

AI Readability Summary

This article systematically explains how to run multiple animations simultaneously in ManimCE. It covers direct parallel animation with play(), structured grouping with AnimationGroup, progressive staggered starts with LaggedStart, and pacing control through rate_func, helping developers quickly master synchronized animation orchestration for mathematical visualization.