How to Use Transform and TransformMatchingParts Animations in Manim
Use Transform to interpolate every sub‑mobject of a source Mobject into a target Mobject by aligning their hierarchical data and applying a path function, while TransformMatchingParts automatically groups individual transforms for matching shapes and fades unmatched parts.
The 3b1b/manim library provides a robust animation framework built around the abstract Animation base class. Mastering the Transform and TransformMatchingParts animations in Manim allows you to create seamless morphs between geometric shapes, text, and complex mathematical expressions. This guide examines the source‑level implementation in manimlib/animation/transform.py and manimlib/animation/transform_matching_parts.py, and provides runnable examples for common use cases.
How Transform Works Under the Hood
The Transform class handles the fundamental mechanics of morphing one Mobject into another. Its implementation in manimlib/animation/transform.py follows a strict pipeline:
- Target creation – The constructor accepts a
target_mobjectargument. If none is provided, the subclass methodcreate_targetgenerates the destination object. - Data alignment – The
beginmethod callsself.mobject.align_data_and_family(self.target_copy). This ensures both source and target possess identical family trees, establishing a one‑to‑one mapping between sub‑mobjects. - Path function initialization –
init_path_funcselects the interpolation trajectory:path_arc == 0→straight_path(linear motion).- Non‑zero
path_arc→path_along_arc(imported frommanimlib/utils/paths), generating a circular arc through 3D space.
- Per‑submobject interpolation – During each frame,
interpolate_submobjectcallssubmob.interpolate(start, target_copy, alpha, self.path_func), moving points along the chosen path. - Scene cleanup – When
replace_mobject_with_target_in_sceneisTrue(as inReplacementTransform), the scene swaps the source for the target upon completion.
How TransformMatchingParts Works Under the Hood
TransformMatchingParts (defined in manimlib/animation/transform_matching_parts.py) automates the creation of multiple synchronized transforms for complex objects such as Tex strings. It operates by decomposing source and target into their atomic vector components:
- Piece collection – The constructor gathers all sub‑mobjects containing points via
source.family_members_with_points()andtarget.family_members_with_points(). - Explicit pairing – User‑provided tuples of
(source_piece, target_piece)are processed throughadd_transform, creating individualTransforminstances (or any specified animation class). - Shape‑based auto‑matching –
find_pairs_with_matching_shapesiterates through remaining pieces, identifying pairs wherehas_same_shape_asreturnsTrue. Each match is converted into amatch_animation(defaultTransform). - Mismatch handling – Unmatched source pieces execute
FadeOutToPointtoward the target’s center, while unmatched target pieces executeFadeInFromPointfrom the source’s center. - Group execution – All generated animations are bundled into an
AnimationGroup(defined inmanimlib/animation/composition.py) with a configurablelag_ratio, allowing concurrent playback with optional staggered timing.
Specialized subclasses TransformMatchingStrings and TransformMatchingTex extend this logic by employing SequenceMatcher to identify longest matching substrings before applying the part‑matching algorithm.
Practical Code Examples
Simple Transform Morphing
Use Transform to morph a circle into a square with an arced trajectory. The path_arc parameter leverages path_along_arc from manimlib/utils/paths.
from manim import *
class TransformDemo(Scene):
def construct(self):
circle = Circle(radius=1, color=BLUE).shift(LEFT)
square = Square(side_length=2, color=RED).shift(RIGHT)
# Morph with a quarter-circle arc path
self.play(Transform(circle, square, path_arc=PI/4))
self.wait()
ReplacementTransform for Scene Updates
ReplacementTransform (a subclass where replace_mobject_with_target_in_scene=True) removes the source Tex object and leaves the target in the scene.
class ReplacementDemo(Scene):
def construct(self):
tex_a = Tex(r"\int_a^b f(x)\,dx")
tex_b = Tex(r"F(b)-F(a)").next_to(tex_a, DOWN)
# Original is removed; new Tex remains
self.play(ReplacementTransform(tex_a, tex_b))
self.wait()
TransformMatchingParts for Equations
Automatically match identical characters between two Tex objects while fading non-matching parts. This uses the find_pairs_with_matching_shapes logic internally.
class MatchingPartsDemo(Scene):
def construct(self):
src = Tex(r"E = mc^2")
tgt = Tex(r"F = ma").shift(RIGHT)
# Auto-match '=' and 'm', fade 'E', 'c^2' / 'F', 'a'
self.play(TransformMatchingParts(src, tgt, run_time=3))
self.wait()
Custom Match and Mismatch Animations
Override match_animation and mismatch_animation to use different animation classes (e.g., rotating transforms or scaling fades).
class CustomMatchDemo(Scene):
def construct(self):
src = Tex(r"\alpha + \beta")
tgt = Tex(r"\gamma + \delta").shift(UP)
# Use rotating transform for matches, custom fade for mismatches
self.play(
TransformMatchingParts(
src, tgt,
match_animation=Transform,
mismatch_animation=FadeInFromPoint,
path_arc=PI/2,
run_time=2,
lag_ratio=0.2,
)
)
self.wait()
Key Implementation Files
Understanding the source architecture helps when debugging or extending these animations.
| File | Purpose |
|---|---|
manimlib/animation/animation.py |
Base Animation class defining the lifecycle (begin, interpolate, finish). |
manimlib/animation/transform.py |
Core Transform and ReplacementTransform implementations, including align_data_and_family and path logic. |
manimlib/animation/transform_matching_parts.py |
TransformMatchingParts, TransformMatchingStrings, and TransformMatchingTex with shape matching and AnimationGroup orchestration. |
manimlib/animation/composition.py |
AnimationGroup used by TransformMatchingParts to play concurrent animations. |
manimlib/mobject/mobject.py |
Mobject methods align_data_and_family, get_family, and has_same_shape_as used for data alignment and shape comparison. |
manimlib/utils/paths.py |
Path functions straight_path and path_along_arc used by Transform. |
Summary
Transforminterpolates every sub‑mobject of a source into a target by first aligning their family trees viaalign_data_and_family, then applying a path function (straight line or arc) duringinterpolate_submobject.ReplacementTransformis a subclass that setsreplace_mobject_with_target_in_scene=True, swapping the source for the target in the scene graph after playback.TransformMatchingPartsautomates the creation of multipleTransforminstances by matching sub‑mobjects with identical shapes usingfind_pairs_with_matching_shapes, fading unmatched parts viaFadeOutToPointandFadeInFromPoint, and grouping everything into anAnimationGroup.- Customization options include
path_arcfor curved trajectories, andmatch_animation/mismatch_animationparameters to substitute different animation classes for the default behaviors.
Frequently Asked Questions
What is the difference between Transform and ReplacementTransform?
Transform morphs the source Mobject into the target but leaves the original object in the scene’s memory unless manually removed. ReplacementTransform (defined in manimlib/animation/transform.py) sets the flag replace_mobject_with_target_in_scene=True, which tells the scene to remove the source and insert the target upon completion, effectively swapping them.
How does TransformMatchingParts decide which parts to match?
The class uses find_pairs_with_matching_shapes in manimlib/animation/transform_matching_parts.py to compare every sub‑mobject from the source and target via the has_same_shape_as method. Pairs with identical point arrays are linked and animated with the match_animation class (default Transform). Unmatched pieces are faded out or in using FadeOutToPoint and FadeInFromPoint.
Can I use custom animations for matching or mismatching parts?
Yes. TransformMatchingParts accepts match_animation and mismatch_animation parameters in its constructor. You can pass any Animation subclass—such as Rotate, ScaleInPlace, or a custom Transform variant—to override the default behaviors for matched and unmatched sub‑mobjects respectively.
Why do my objects flicker or misalign during a Transform?
Flickering usually occurs when the source and target Mobjects have different family tree structures. The begin method of Transform calls align_data_and_family (from manimlib/mobject/mobject.py) to synchronize sub‑mobject lists. If you manually construct Mobjects with mismatched hierarchies, override create_target or ensure both objects have identical sub‑mobject counts to prevent alignment artifacts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →