Objects That Know Their Shape: The Mobject Model

In 3b1b ManimGL, the thing that changes is not a finished picture but a structured mathematical object. This chapter asks what that object contains, how groups and subobjects preserve visual relationships, and why curves and notation must remain manipulable if a transformation is meant to explain something. The practical payoff is a better test for animation design: before asking how to move an object, ask whether its representation preserves the relationship the viewer needs to follow.

State, not screenshot

A Mobject—short for mathematical object—is the basic unit of visible state in ManimGL. It can represent a point, a curve, a text fragment, a graph, a surface, or a group of other objects. The useful distinction is that it carries the ingredients from which a frame can be drawn, rather than storing only the already-drawn frame.

At the center is point data: the positions that define an object's geometry. Around that are uniforms, values shared or interpreted by the renderer, such as color, opacity, shading, depth behavior, and other drawing controls. An object may also hold textures, a drawing class, and a shader choice. These terms belong to different boundaries, but the author usually experiences their combined effect as one thing: a circle has a location, a shape, a fill, a stroke, and a relationship to the camera.

The separation is still important when an object changes. Moving a point changes geometry; changing opacity changes a drawing value; replacing a texture changes an external resource. They may appear together in one animation, but they do not have the same interpolation rules or the same cost at the rendering boundary. A well-formed mobject keeps these kinds of state available without pretending they are interchangeable. That is what allows a color change to leave the path untouched, or a geometric transform to move the path while preserving its style.

The distinction also gives identity a concrete meaning. A mobject can be copied, and the copy can be changed without mutating the original. It can become another mobject by matching family members and their data. These operations are not just conveniences for Python code: animation uses copies to remember starting and target states. If the system could only hold one undifferentiated image, it could not compare those states field by field or decide which parts need new data during a frame.

That combined state is mutable. Operations such as shifting, scaling, rotating, or applying a function change the stored points and then refresh the bounding information used to position and test the object. A bounding box is not the shape itself; it is a compact description of the object's extent. It lets ManimGL answer practical questions such as where an object is, whether it is near another object, or which edge should align with a label. The distinction matters because a transformation can alter geometry while higher-level layout still depends on a refreshed summary of that geometry.

A mobject is also a hierarchy. It may contain submobjects, and each child keeps track of its parents. The repository caches a “family” traversal so that an operation can address an object and the visual parts below it. A group holding an equation, for example, can be moved as one object while its individual symbols remain available for coloring or later transformation. A graph can be treated as a whole while its points, labels, and guide lines retain their own identities.

The Scene owns top-level mobjects and walks their families when it draws or animates. Adding an object places it in the scene's ordered collection; removing a child from a group can restructure the remaining family rather than simply erasing a rectangle from a canvas. Display order is also meaningful. Objects added later generally appear in front, while explicit depth or z-order settings can change how the renderer resolves the final arrangement. A visual hierarchy is therefore both a convenience for the author and part of the system's state.

That hierarchy supports two kinds of control at once. A scene can move an entire group because the parent supplies a meaningful unit of composition, while an animation can still reach a child because the family remains addressable. The same design is useful for a sentence, an equation, or a diagram: the author can lay out the whole object, then isolate one symbol or curve when the explanation turns to a local relationship. The cost is that restructuring is real state. Adding, removing, copying, or replacing a child can change the family traversal that later animation and rendering depend on.

This is also why the object model cannot be reduced to a tree of names. The implementation keeps parent links and may cache family lists for speed, then marks those caches stale when the hierarchy changes. Bounding boxes and updater status similarly propagate through ancestors. A local edit can therefore have a system-level consequence: changing one submobject may change its parent's extent, the scene's draw order, the set of objects an animation sees, and the renderer's decision about what can be grouped.

This explains why a mobject is more than a bitmap with a convenient name. A bitmap can be moved, but it does not inherently expose the points, subpaths, symbols, or parent-child relationships that make a mathematical change readable. ManimGL's object model gives later operations something to act on. A transformation can address a family, a label can follow a related object, and a renderer can decide how the object's geometry and style become draw calls.

The model does not promise that every attribute of a Python object participates in this process. The implementation separates pointlike data, structural data, and uniform values. Fields that describe how points are grouped may need special interpolation; fields that locate points can follow a chosen path; ordinary values can be blended more directly. An arbitrary attribute added by a user is not automatically a meaningful part of the animated visual state. That boundary is easy to miss when the public syntax feels fluid, but it is what keeps the renderer's data contract intelligible.

The relationship can be summarized without treating the repository as a class catalogue:

classDiagram class Scene class Mobject { point_data uniforms textures submobjects } class Group class VMobject { anchors_and_handles subpaths fill_and_stroke } class Text_TeX { selectable_parts rendered_paths } class Animation Scene o-- Mobject : displays Mobject *-- Mobject : contains family Mobject <|-- Group Mobject <|-- VMobject VMobject <|-- Text_TeX Animation ..> Mobject : changes over time

The diagram shows ownership and use, not a claim that every concrete class follows exactly this simplified inheritance path. A Scene holds top-level visual state; a Mobject can contain more mobjects; vectorized objects add path-specific data; text becomes a specialized set of paths; and animation consumes the resulting state. The hierarchy is what allows a high-level mathematical object to remain addressable at several scales.

Curves, notation, and the limits of correspondence

Vectorized mobjects make this state especially useful for geometry. A VMobject stores point records that describe paths, together with stroke information and subpath boundaries. Curves are built from anchors and handles; a new subpath, a quadratic or cubic curve, a closing segment, and a smoothed path are distinguishable operations. This is not an implementation detail detached from the image. It determines whether a line can be drawn progressively, whether a path can be reshaped, and whether a group of curves can be styled without flattening it into pixels.

An anchor says where a path is meant to pass; a handle influences how it bends between anchors. The representation also marks where one subpath ends and another begins. Those distinctions let a creation animation reveal a curve in order, let a shape close its boundary without inventing a visible segment, and let later interpolation preserve the difference between a continuous path and separate pieces. The extra structure is useful precisely because the viewer may attach meaning to continuity, corners, and boundaries.

It also explains why a vector object can carry both shape and presentation without being a finished render. Stroke width can vary along point records, while fill colors and gradients can be held in uniforms and positioned against the object's bounds. A change in the camera should not require rewriting the mathematical path; a change in the path should not require baking a new bitmap. The renderer can make those choices later because the mobject has retained enough information to support them.

The renderer can use the same representation for fills and strokes. A fill needs to know the region enclosed by a path, while a stroke follows the path itself. Style can be held uniformly or along the records, and gradients can be defined across an object's spatial extent. Because the geometry and style remain in the mobject, an animation can change position, color, opacity, or shape through one coordinated state model. The visual result still depends on the renderer's later ordering rules, but the object has not lost the information needed to make those rules meaningful.

Text demonstrates the same principle in a less obvious form. The repository distinguishes ordinary text from LaTeX-backed mathematical text, but both ultimately enter the mobject world as rendered paths. ManimPango helps convert markup into SVG content; cached conversion and scale calibration make the result usable as scene geometry. The important consequence is that a letter or selected substring can be treated as a part of a larger visual family. It can be colored, arranged, indexed, or matched against another expression instead of being painted as one uninspectable label.

The conversion step creates both power and a boundary. Text is convenient to author as characters and markup, but the renderer ultimately works with the resulting geometric parts. Font choice, markup validity, platform text libraries, caching, and scale calibration all belong to the conversion path before animation begins. Once the paths exist, ManimGL can operate on them as objects; it cannot make a missing font or a different glyph outline mean the same thing by mathematical fiat. Text therefore belongs to the same visual model as a curve while retaining an external production dependency.

The distinction between content and geometry is especially useful in an explanation. A word can be selected by its textual identity when the author wants to emphasize a term, yet the motion that viewers see is a motion of path data. If the source-to-target selection is stable, that crossing from textual meaning to geometric movement is powerful. If it is not, a symbol may be colored or moved unexpectedly even though the source string looks correct. Explicit isolation is a way of making the intended boundary visible to the object model.

The examples use this capability for equation transformations. A source expression can be reorganized into a target expression while selected parts are matched, so the viewer sees terms move into new positions rather than watching one equation disappear and another appear. That motion is persuasive only when the selected parts represent the relationship the author wants to emphasize. It is not enough that two strings share characters. Mathematical notation may be rendered in an order that differs from the order in which it is written, and the examples note that explicit isolation can be needed when a later selection must reliably identify a symbol.

This is where representation meets a deeper limit: geometry does not automatically understand mathematical meaning. A Transform prepares source and target families so they have compatible structures. If their subobject counts differ, the implementation can add repeated or invisible pieces; if point counts differ, it can resize data so corresponding records can be blended. It then interpolates the starting and target data, including a selected path for point movement when the animation calls for one. A replacement transform can remove the source and insert the target when the two should not remain as separate scene objects.

Alignment is therefore a preparation step, not a theorem about identity. The source and target may have different family shapes because one is a single path and the other is a group, or because one contains more points than the other. Making their arrays compatible prevents the interpolation loop from having to invent a rule for every mismatch, but it also means that some correspondences are technical rather than semantic. An invisible repeated part lets the data line up; it does not tell a viewer why that part should exist.

The choice of path matters for the same reason. A straight path is often appropriate when a point or symbol should move directly to a new position. An arc can suggest rotation or avoid an awkward collision. A custom path can make a transformation follow a mathematical construction. But no path function can repair a misleading source-target pairing. Motion has explanatory force only when the geometry, the correspondence, and the timing point in the same direction.

That preparation makes a wide range of visual changes possible, but it does not decide whether the correspondence is truthful. Repeated points can make two shapes technically compatible without explaining why one part should become another. A smooth arc can make a transition attractive while obscuring a discontinuity that matters. Conversely, a carefully matched equation can use the same machinery to make an algebraic rearrangement visible. The engine supplies a representation and a blending mechanism; the author supplies the semantic judgment.

This is why the choice between a transform and a replacement is not merely stylistic. If the source and target share an explanatory identity, interpolation can preserve that identity across time. If they are conceptually different objects, a fade, a new construction, or a staged rearrangement may be clearer. The object model supports all of these because it can preserve identity, add a target, or remove a source, but it cannot infer the intended argument from shape alone.

The same boundary appears in groups. A group is not just a bag of children; its arrangement, family membership, and style relationships affect what later operations mean. Copying a mobject creates a new family, which matters when the copy overlaps the original: the renderer must not assume that their filled regions are safely disjoint merely because the original object once made such a promise. A mathematical diagram can therefore carry hidden relationships that are helpful when preserved and misleading when duplicated without thought.

The practical rule is to preserve structure only when it serves the explanation. Keep a graph's axes, curve, point, and label separate when the viewer needs to understand how they relate. Keep an equation's meaningful parts selectable when movement should reveal an algebraic relationship. Use a flatter or more disposable representation when no such correspondence exists. Structured state is a means of making change legible, not a requirement to expose every internal part of every object.

A mobject, then, is best understood as a stateful visual argument: geometry says where the parts are, hierarchy says how they belong together, style says how they should be read, and identity determines what can plausibly change into what. The next step is to examine the mechanism that moves this state through time. Once source and target objects have been prepared, how does ManimGL turn their compatibility into paced motion rather than a mere jump from one frame to another?

References