An updater function in Manim redraws a mobject on the screen for every new frame being played. You can use it to continually update things like the size, position, or value of an object during an animation.
How to use the always_redraw updater function in Manim
The most convenient way to add an updater in Manim is to use the always_redraw() function.
You can surround any mobject that you want to update with it like so:
always_redraw(lambda: everything_you_want_to_be_updated)
Example:
from manim import *
class updaters(Scene):
def construct(self):
s = Square(color = RED)
d1 = always_redraw(lambda: Dot().next_to(s, RIGHT))
d2 = always_redraw(lambda: Dot().next_to(s, UP))
d3 = always_redraw(lambda: Dot().next_to(s, LEFT))
d4 = always_redraw(lambda: Dot().next_to(s, DOWN))
dot_group = VGroup(d1, d2, d3, d4)
self.play(Write(s), Write(dot_group))
self.play(s.animate.shift(UP))
self.play(s.animate.scale(0.5))
self.play(Rotate(s, PI/2))
self.wait()
Output:
Code explanation:
Line 1: I imported the Manim library into VS Code so that it understands the code syntax.
Lines 3 and 4: I created a new Manim scene and called it “updaters”.
Line 5: I created a red square and assigned it to a new variable s.
Line 6: I created a dot and positioned it next to the square on the right side with the next_to() parameter. Then I surrounded everything with an updater function always_redraw(lambda:) so that no matter what happens the dot will always be redrawn next to the square and on the right side of it. I then assigned this dot to a new variable that I named d1. To learn more about positioning in Manim I recommend checking out this guide: Manim: How To Align Objects.
Lines 7, 8, and 9: I created 3 more dots and positioned them at the top, bottom, and left side of the rectangle. I also added an always_redraw() updater function to each of the dots so that they always get redrawn to be on the side of the rectangle no matter if it moves, gets resized, or if anything else happens to it.
Line 11: I grouped all of the dots with the VGroup() command. This step wasn’t necessary here but it made it easier for me to animate the whole group on the screen instead of having to Write() each dot on the screen on its own.
Line 13: I used the self.play() command and the Write() animation type to show the square as well as all the dots on the screen.
Line 15: I moved the square up with the .shift() command.
Line 16: I scaled the square to 50% of its original size.
Line 17: I rotated the square by 90 degrees or pi/2 radians.
Line 18: I paused the animation on the screen for 1 second.
Since I surrounded all of the dots with an updater function, for every new frame in the animation, they were always redrawn to be next to the square.
That meant that no matter what happened to the square each dot always tried to be on the side of it.
How to attach one object to another in Manim using an updater
The first way you can animate two objects together in Manim is by grouping them using a VGruop() and then animating that group which will move or resize all of the objects inside that group.
However, using a VGroup() to animate two mobjects together might not work in certain scenarios.
In those cases, you can use an updater function.
Example:
from manim import *
class updaters2(Scene):
def construct(self):
tri = Triangle()
s = always_redraw(lambda: SurroundingRectangle(tri, corner_radius = 0.15, buff = 0.3))
text = always_redraw(lambda: Text("Yoink").next_to(s, UP))
self.play(Write(tri), Write(s), Write(text))
self.play(tri.animate.scale(0.5))
self.play(tri.animate.shift(LEFT))
self.play(Rotate(tri))
g = VGroup(tri, s, text)
self.play(Unwrite(g))
Output:
Code explanation:
Line 1: I imported the Manim library into Python.
Lines 3 and 4: I created a new scene and named it “updaters2”.
Line 5: I created a triangle and assigned it to a new variable that I named tri.
Line 6: I created a SurroundingRectangle() and told it to surround the triangle. I also defined a custom corner_radius() to round off the corners of the surrounding rectangle as well as a custom buff value that defines the space between the edge of the surrounding rectangle and the edge of the triangle. I then surrounded everything with the always_redraw(lambda: ) updater function. So now, no matter what happens, the SurroundingRectangle() will always be redrawn to surround the triangle and to always have a corner radius of 0.15 and a buff value of 0.3.
Line 7: I created a text that says “Yoink” and positioned it at the top of the SurroundingRectangle() with the next_to() command. You can think of it like this: next_to(what, where). I added an updater function to this text as well, so that no matter what happens to the SurroundingRectangle() this text will always try to stick to the top of it.
Line 9: I used the self.play() command and the Write() to animation type to show the triangle, the surrounding rectangle, and the text on the screen.
Line 11: I used the .scale() command to scale the triangle to 50% of its original size.
Line 12: I used the .shift() command to move the triangle left.
Line 13: I used the Rotate() command to rotate the triangle by a default amount (which is 180 degrees or PI radians).
Line 14: I grouped all objects with the VGgroup() command. This allows to animate the whole group instead of each individual mobject.
Line 15: I used the Unwrite() animation type to remove the group of objects from the screen.
In this example, I used the always_redraw(lambda:) updater functions to make sure that the SurroudningRectangle() was always redrawn to surround the Triangle() and the Text() was always redrawn to be on top of the SurroudningRectangle().
Let me help you learn Manim
If you want to skip the headache of trying to learn Manim from a bunch of scattered information, I put together a comprehensive 3-hour Manim course for complete beginners.
It will give you all the foundational skills you need to start creating stunning animations with code.
Enroll In Manim Course For Beginners