Ir al contenido

Animaciones de Manim

Manim cuenta con una gran colección de animaciones ya definida para que no tengamos que estar constantemente cambiando los valores de las propiedades a mano. Todas ellas heredan de la clase Animation y se distinguen una de otra por la forma en la que implementan el método interpolate_mobject.

Las hay cuyo uso es muy habitual en Manim y en otro software como FadeIn o FadeOut que cambian la opacidad y las hay muy características y llamativas como Write o Transform. Vamos a ver algunos ejemplos:

Cambian la opacidad de un objeto:

fade_in_example.py
from manim import *
class FadeInExample(Scene):
def construct(self):
dot = Dot(UP * 2 + LEFT)
self.add(dot)
text = Paragraph(
"FadeIn with ", "shift ", "or target_position", "and scale"
).scale(1)
animations = [
FadeIn(text[0]),
FadeIn(text[1], shift=DOWN),
FadeIn(text[2], target_position=dot),
FadeIn(text[3], scale=1.5),
]
self.play(*animations, run_time=4)

En lugar de cambiar la opacidad de un Mobject aprovechan la naturaleza vectorial de los VMobjects y generan Mobjects intermedios con distinto número de puntos de forma que parece que se está construyendo el objeto.

write_example.py
from manim import *
class WriteExample(Scene):
def construct(self):
logo_write = SVGMobject("logo.svg")
logo_create = SVGMobject("logo.svg")
VGroup(logo_write, logo_create).arrange(buff=2.5)
write_text = Text("Write and Unwrite").scale(0.5).next_to(logo_write, DOWN)
create_text = Text("Create and Uncreate").scale(0.5).next_to(logo_create, DOWN)
self.play(
Write(logo_write),
Create(logo_create),
Write(write_text),
Create(create_text),
run_time=3
)
self.wait()
self.play(
Unwrite(logo_write),
Uncreate(logo_create),
Unwrite(write_text),
Uncreate(create_text),
run_time=3
)
self.wait()

Transform, ReplacementTransform y TransformMatchingShapes

Sección titulada «Transform, ReplacementTransform y TransformMatchingShapes»

La familia Transform es otra familia de animaciones que aprovecha la naturaleza vectorial de los VMobjects y nos permite interpolar sus puntos de forma que nos queda una transformación chulísima. Ahora: ¿Qué diferencia hay entre Transform y ReplacementTransform?

Cuando usamos Transform, la variable que apunta a nuestro Mobject inicial ahora apunta al Mobject en el que se ha transformado. Es como si manim hiciera esto internamente:

mob_a = Square()
mob_b = Circle()
mob_a.become(mob_b)
mob_a = mob_b

A la hora de usar Transform debemos tener esto en cuenta o se nos generará una copia de mob_b en el renderizado.

Aquí un ejemplo para que quede todo más claro.

transform_example.py
from manim import *
class TransformExample(Scene):
def construct(self):
sq = Square()
text_a = Text("Hello World!")
text_b = Text("Hello PyConEs")
text_c = Text("Hello PyConEs 2026")
self.add(sq)
self.wait()
self.play(Transform(sq, text_a), run_time=2)
self.play(ReplacementTransform(sq, text_b), run_time=2)
self.play(TransformMatchingShapes(text_b, text_c), run_time=2)
self.wait()

Por su parte, TransformMatchingShapes intenta conservar lo máximo de los Mobjects originales y solo modifica lo nuevo.

Con Rotate y Rotating podemos rotar un Mobject. Pueden parecer muy similares por el nombre, pero hay una sutil diferencia. Rotate aplica una rotación sobre el Mobject y luego interpola el Mobject original hacia esa versión rotada. Rotating aplica una rotación durante un periodo de tiempo determinado que podemos definir dentro de la misma clase con run_time.

rotate_example.py
from manim import *
class RotateExample(Scene):
def construct(self):
sq_1 = Square(fill_opacity=1)
sq_2 = Square(fill_opacity=1)
VGroup(sq_1, sq_2).arrange(buff=3)
self.add(sq_1, sq_2)
self.wait()
self.play(
Rotate(sq_1, PI/4),
Rotating(sq_2, PI/4, run_time=3),
run_time=2
)
self.wait()
self.play(
Rotate(sq_1, PI/4, axis=UP),
Rotating(sq_2, PI/4, axis=UP, run_time=3),
run_time=2
)
self.wait()
self.play(
Rotate(sq_1, PI/4, axis=RIGHT),
Rotating(sq_2, PI/4, axis=RIGHT, run_time=3),
run_time=2
)

Hay animaciones que nos ayudan a resaltar una parte de la escena. Algunos ejemplos son Indicate, Circumscribe y Flash

indicate_examples.py
from manim import *
class IndicateExamples(Scene):
def construct(self):
circle = Circle(fill_opacity=1)
indicate = Text("Indicate").next_to(circle, DOWN)
circumscribe = Text("Circumscribe").next_to(circle, DOWN)
flash = Text("Flash").next_to(circle, DOWN)
self.add(circle)
self.wait()
self.play(Write(indicate))
self.play(Indicate(circle))
self.play(Unwrite(indicate))
self.wait()
self.play(Write(circumscribe))
self.play(Circumscribe(circle))
self.play(Unwrite(circumscribe))
self.wait()
self.play(Write(flash))
self.play(Flash(circle, flash_radius=circle.radius))
self.play(Unwrite(flash))
self.wait()

Para acabar con este bloque, veremos algunas animaciones de texto que están graciosas.

text_animation_examples.py
from manim import *
class TextAnimationExamples(Scene):
def construct(self):
lbl = Text("Text added letter by letter")
wbw = Text("Text added word by word")
twc = Text("Text typed with cursor")
VGroup(lbl, wbw, twc).arrange(DOWN)
cursor = Rectangle(
color = GREY_A,
fill_color = GREY_A,
fill_opacity = 1.0,
height = 1.1,
width = 0.5,
).move_to(twc[0]) # Position the cursor
self.wait()
self.play(
AddTextLetterByLetter(lbl),
AddTextWordByWord(wbw),
TypeWithCursor(twc, cursor=cursor),
run_time=3
)
self.wait()

Escribe un texto y aplícale alguna de las animaciones que hemos visto más alguna extra que haya en la documentación y que no hayamos tocado.

Solución al ejercicio 1
animation_ex_1.py
from manim import *
class AnimationExerciseOne(Scene):
def construct(self):
text = Text("Welcome to PyConEs 2026!")
self.play(Write(text), run_time=2)
self.wait()
self.play(Wiggle(text))
self.wait()