When the Picture Must Keep Its Promise: Updaters and Trackers

In 3b1b ManimGL, some relationships cannot be described honestly as one transition from a known start to a known target. A label may need to follow a brace while the brace follows a changing shape; a point may need to remain on a graph while its parameter moves; a number may need to keep reflecting a geometric measurement. This chapter explains how updaters and ValueTrackers express those continuing relationships, how they fit into the frame lifecycle, and why the convenience of per-frame code also creates new responsibilities.

From a finite transition to a continuing relationship

A finite animation answers a bounded question: how should this object change during this interval? An updater answers a different question: what must remain true whenever a new frame is evaluated? The distinction is easy to state but important in practice. If a title should move from the top of the screen to the side, a transform is enough. If the title should always stay next to a shape whose position and width can continue to change, a one-time transform will eventually become stale.

An updater is a function attached to a mobject and called as part of the scene's frame update. It can inspect the current object, read another object's current state, and modify the dependent object. The function may accept only the mobject or may also accept dt, the elapsed time since the previous update. The first form expresses a geometric relationship; the second can express a continuing motion whose behavior depends on time.

The placement of this work in the lifecycle determines what the viewer sees. During a play call, ManimGL first interpolates the animations that are active for the current frame. It then updates mobjects, including their updaters, and only after that does the camera capture the scene. A dependent label can therefore respond to the newly interpolated position of its source before the frame is drawn. An updater is not an event that runs once when an animation starts; it is part of the state calculation for each frame.

This ordering also explains why an updater can be more faithful than a sequence of manual adjustments. Suppose a point is being moved along a curve. A line drawn from the point to an axis, a label showing its coordinate, and a brace indicating a width can all read the point's current state in the same frame. They do not need to predict the path separately or receive a list of callbacks from the original animation. Their relationship is expressed where it is evaluated.

ManimGL provides concise builders for common forms of this idea. The always style calls a mobject method with fixed arguments on each update. The functional form evaluates arguments afresh, which is useful when the source of an argument changes. An always-redraw pattern can reconstruct dependent geometry from a function. These conveniences do not create a declarative dependency graph behind the scenes; they package ordinary updater functions so that the author can state the relationship directly.

That difference between fixed and changing arguments is easy to overlook. A label can be told to remain next to one particular brace, but if the brace itself moves, the label's placement method must receive the brace's current geometry rather than a position captured once at construction. The functional form expresses that distinction. It does not infer which values should be live; the author still decides which source is authoritative and which object is merely following it.

Updaters can also coexist with ordinary animation. A square may be scaled by a finite transition while a brace and label recompute their positions on top of each interpolated state. The animation owns the square's planned change, and the updaters own the continuing relationships.