Animation engine for explanatory math videos with programmatic mathematical visualization capabilities
—
ManimGL provides sophisticated animation capabilities beyond basic transformations, including specialized animation techniques, transform matching systems, and advanced composition patterns for complex mathematical demonstrations and educational content.
Advanced object morphing that intelligently matches corresponding parts between objects for smooth, meaningful transformations.
class TransformMatchingParts(AnimationGroup):
def __init__(
self,
mobject: Mobject,
target_mobject: Mobject,
transform_mismatches: bool = False,
fade_transform_mismatches: bool = False,
key_map: dict | None = None,
**kwargs
):
"""
Transform objects by matching corresponding parts.
Parameters:
- mobject: Source object to transform
- target_mobject: Target object to transform into
- transform_mismatches: Transform unmatched parts
- fade_transform_mismatches: Fade unmatched parts during transform
- key_map: Manual mapping of parts between objects
"""
class TransformMatchingTex(TransformMatchingParts):
def __init__(
self,
mobject: Mobject,
target_mobject: Mobject,
key_map: dict | None = None,
**kwargs
):
"""
Specialized transform for LaTeX expressions with intelligent symbol matching.
Parameters:
- mobject: Source LaTeX expression
- target_mobject: Target LaTeX expression
- key_map: Manual mapping of LaTeX symbols
"""
class TransformMatchingShapes(TransformMatchingParts):
def __init__(
self,
mobject: Mobject,
target_mobject: Mobject,
transform_mismatches: bool = True,
**kwargs
):
"""
Transform shapes by matching geometric components.
Parameters:
- mobject: Source shape
- target_mobject: Target shape
- transform_mismatches: Handle unmatched components
"""Advanced animation effects for specific use cases and visual impact in mathematical demonstrations.
class Homotopy(Animation):
def __init__(
self,
homotopy_function: Callable,
mobject: Mobject,
**kwargs
):
"""
Apply continuous deformation via homotopy function.
Parameters:
- homotopy_function: Function (x, y, z, t) -> (x', y', z')
- mobject: Object to deform
"""
class PhaseFlow(Animation):
def __init__(
self,
function: Callable,
mobject: Mobject,
**kwargs
):
"""
Move object along vector field flow.
Parameters:
- function: Vector field function
- mobject: Object to move along flow
"""
class ComplexHomotopy(Homotopy):
def __init__(
self,
complex_homotopy: Callable,
mobject: Mobject,
**kwargs
):
"""
Apply complex function transformations over time.
Parameters:
- complex_homotopy: Complex function (z, t) -> z'
- mobject: Object to transform
"""Advanced patterns for combining and sequencing animations with sophisticated timing and coordination.
class AnimationGroup(Animation):
def __init__(
self,
*animations: Animation,
lag_ratio: float = 0,
run_time: float | None = None,
**kwargs
):
"""
Group animations with staggered timing.
Parameters:
- animations: List of animations to group
- lag_ratio: Delay between animation starts (0-1)
- run_time: Total duration (max of animations if None)
"""
class Succession(AnimationGroup):
def __init__(self, *animations: Animation, **kwargs):
"""
Play animations in sequence (lag_ratio=1).
Parameters:
- animations: Animations to play sequentially
"""
class LaggedStart(AnimationGroup):
def __init__(
self,
*animations: Animation,
lag_ratio: float = DEFAULT_LAGGED_START_LAG_RATIO,
**kwargs
):
"""
Start animations with uniform lag.
Parameters:
- animations: Animations to stagger
- lag_ratio: Delay ratio between starts
"""
class LaggedStartMap(LaggedStart):
def __init__(
self,
AnimationClass: type,
mobject: Mobject,
arg_creator: Callable | None = None,
**kwargs
):
"""
Apply animation class to submobjects with lag.
Parameters:
- AnimationClass: Animation class to apply
- mobject: Object with submobjects
- arg_creator: Function to create arguments for each submobject
"""Dynamic animations that continuously update based on functions or external state.
class UpdateFromFunc(Animation):
def __init__(
self,
mobject: Mobject,
update_function: Callable,
**kwargs
):
"""
Continuously update mobject via function.
Parameters:
- mobject: Object to update
- update_function: Function taking (mobject, dt) or (mobject, alpha)
"""
class UpdateFromAlphaFunc(UpdateFromFunc):
def __init__(
self,
mobject: Mobject,
update_function: Callable,
**kwargs
):
"""
Update mobject based on animation progress (alpha 0-1).
Parameters:
- mobject: Object to update
- update_function: Function taking (mobject, alpha)
"""
class MaintainPositionRelativeTo(Animation):
def __init__(
self,
mobject: Mobject,
tracked_mobject: Mobject,
**kwargs
):
"""
Keep mobject positioned relative to another mobject.
Parameters:
- mobject: Object to maintain position
- tracked_mobject: Object to track
"""Domain-specific animations for mathematical concepts and demonstrations.
class CyclicReplace(Transform):
def __init__(self, *mobjects: Mobject, **kwargs):
"""
Cyclically replace mobjects in sequence.
Parameters:
- mobjects: Objects to cycle through
"""
class Swap(CyclicReplace):
def __init__(self, mobject1: Mobject, mobject2: Mobject, **kwargs):
"""
Swap positions of two mobjects.
Parameters:
- mobject1: First object
- mobject2: Second object
"""
class TransformFromCopy(Transform):
def __init__(
self,
mobject: Mobject,
target_mobject: Mobject,
**kwargs
):
"""
Transform copy of mobject, leaving original unchanged.
Parameters:
- mobject: Source object (remains unchanged)
- target_mobject: Target for transformation
"""from manimlib import *
class ExpressionTransform(Scene):
def construct(self):
# Start with a complex expression
expr1 = Tex(r"(x + y)^2")
expr2 = Tex(r"x^2 + 2xy + y^2")
expr1.scale(1.5)
expr2.scale(1.5)
self.play(Write(expr1))
self.wait()
# Use intelligent symbol matching
self.play(
TransformMatchingTex(expr1, expr2),
run_time=3
)
self.wait()
# Transform to factored form
expr3 = Tex(r"(x + y)(x + y)")
expr3.scale(1.5)
self.play(
TransformMatchingTex(expr2, expr3),
run_time=2
)
self.wait()class ComplexTransformation(Scene):
def construct(self):
# Create a grid in the complex plane
grid = NumberPlane(
x_range=[-3, 3], y_range=[-3, 3],
background_line_style={"stroke_width": 1, "stroke_opacity": 0.5}
)
# Define complex transformation z -> z^2
def complex_func(z, t):
# Gradually apply z^2 transformation
return z * (1 + t * (z - 1))
self.add(grid)
# Apply complex homotopy
self.play(
ComplexHomotopy(complex_func, grid),
run_time=4
)
self.wait()class GeometricHomotopy(Scene):
def construct(self):
# Create a circle
circle = Circle(radius=2, color=BLUE, fill_opacity=0.3)
self.add(circle)
# Define homotopy: circle -> square
def circle_to_square(x, y, z, t):
# Interpolate between circular and square coordinates
r = np.sqrt(x*x + y*y)
if r == 0:
return np.array([x, y, z])
# Square coordinates
max_coord = max(abs(x), abs(y))
square_x = x * (max_coord / r) if r > 0 else x
square_y = y * (max_coord / r) if r > 0 else y
# Interpolate
new_x = x + t * (square_x - x)
new_y = y + t * (square_y - y)
return np.array([new_x, new_y, z])
self.play(
Homotopy(circle_to_square, circle),
run_time=3
)
self.wait()class CoordinatedAnimations(Scene):
def construct(self):
# Create a group of objects
dots = VGroup(*[
Dot(radius=0.1).move_to([i*0.5, 0, 0])
for i in range(-5, 6)
])
colors = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE] * 2
self.add(dots)
# Animate with staggered timing
self.play(
LaggedStartMap(
lambda dot, color: dot.animate.set_color(color).scale(2),
dots,
lambda dot: {"color": colors[dots.submobjects.index(dot)]},
lag_ratio=0.1
),
run_time=3
)
# Coordinated movement
self.play(
LaggedStart(
*[dot.animate.shift(UP * 2) for dot in dots],
lag_ratio=0.05
),
run_time=2
)
# Return with different pattern
self.play(
AnimationGroup(
*[dot.animate.shift(DOWN * 2).scale(0.5) for dot in dots],
lag_ratio=0.8 # More staggered
),
run_time=3
)class DynamicTracking(Scene):
def construct(self):
# Create axes and function
axes = Axes(x_range=[-3, 3], y_range=[-2, 2])
# Time-varying function
t_tracker = ValueTracker(0)
def get_func():
t = t_tracker.get_value()
return axes.plot(
lambda x: np.sin(x + t),
color=YELLOW
)
graph = get_func()
graph.add_updater(lambda g: g.become(get_func()))
# Dot that follows the function maximum
dot = Dot(color=RED)
def update_dot(d):
t = t_tracker.get_value()
max_x = -t % (2 * PI) - PI # Position of maximum
max_y = 1 # Maximum value of sine
d.move_to(axes.c2p(max_x, max_y))
dot.add_updater(update_dot)
self.add(axes, graph, dot)
# Animate time parameter
self.play(
t_tracker.animate.set_value(4 * PI),
run_time=8,
rate_func=linear
)class CustomTransformMatching(Scene):
def construct(self):
# Create source and target expressions
source = VGroup(
Circle(radius=0.3, color=BLUE).shift(LEFT * 2),
Square(side_length=0.6, color=RED),
Triangle().scale(0.4).shift(RIGHT * 2).set_color(GREEN)
)
target = VGroup(
Square(side_length=0.6, color=BLUE).shift(LEFT * 2),
Triangle().scale(0.4).set_color(RED),
Circle(radius=0.3, color=GREEN).shift(RIGHT * 2)
)
self.add(source)
self.wait()
# Custom key mapping for transform
key_map = {
source[0]: target[2], # Circle -> Circle (different position)
source[1]: target[0], # Square -> Square (different position)
source[2]: target[1] # Triangle -> Triangle (different position)
}
self.play(
TransformMatchingParts(
source,
target,
key_map=key_map,
transform_mismatches=True
),
run_time=3
)
self.wait()class AdvancedUpdates(Scene):
def construct(self):
# Create objects with complex interdependencies
center_dot = Dot(color=YELLOW)
# Orbiting dots
orbit_dots = VGroup(*[
Dot(radius=0.05, color=BLUE).shift(RIGHT * (1 + 0.3 * i))
for i in range(5)
])
# Time tracker
time_tracker = ValueTracker(0)
# Update function for orbital motion
def update_orbits(group):
t = time_tracker.get_value()
center = center_dot.get_center()
for i, dot in enumerate(group):
radius = 1 + 0.3 * i
angle = t + i * PI / 3
pos = center + radius * np.array([
np.cos(angle), np.sin(angle), 0
])
dot.move_to(pos)
orbit_dots.add_updater(update_orbits)
# Trailing effect
trails = VGroup()
def add_trail_points(mob):
t = time_tracker.get_value()
if int(t * 10) % 3 == 0: # Add point every 0.3 seconds
for dot in orbit_dots:
trail_point = Dot(
radius=0.02,
color=dot.get_color(),
fill_opacity=0.5
).move_to(dot.get_center())
trails.add(trail_point)
trails.add_updater(add_trail_points)
self.add(center_dot, orbit_dots, trails)
# Animate the system
self.play(
time_tracker.animate.set_value(8),
run_time=8,
rate_func=linear
)
# Move center and watch system adapt
self.play(
center_dot.animate.shift(RIGHT * 2),
run_time=2
)
self.play(
time_tracker.animate.set_value(12),
run_time=4,
rate_func=linear
)class CustomWaveAnimation(Animation):
def __init__(self, mobject, amplitude=1, frequency=1, **kwargs):
self.amplitude = amplitude
self.frequency = frequency
super().__init__(mobject, **kwargs)
def interpolate_mobject(self, alpha):
# Custom interpolation logic
wave_offset = self.amplitude * np.sin(2 * PI * self.frequency * alpha)
# Apply wave transformation
pass# Efficient group animations
def optimize_group_animation(group, animation_func):
# Batch similar animations for better performance
return AnimationGroup(*[
animation_func(mob) for mob in group
], lag_ratio=0.02)
# Conditional animation execution
def conditional_animate(condition, true_anim, false_anim):
return true_anim if condition else false_animThe advanced animations module in ManimGL provides sophisticated tools for creating complex, coordinated animations with intelligent object matching, continuous deformations, and advanced timing patterns essential for mathematical demonstrations and educational content.
Install with Tessl CLI
npx tessl i tessl/pypi-manimgldocs