From Mobjects to Frames: The GPU Rendering Contract
In 3b1b ManimGL, the renderer is the boundary where structured mathematical visuals become pixels, but it is not the owner of all the meaning that reaches the screen. This chapter traces what crosses that boundary: mobject records and uniforms become Drawing state, shared Materials, buffer writes, shader passes, and a camera output texture. It also explains why vector fill order, transparency, grouping, and render-bundle invalidation are correctness contracts as much as performance choices.
What crosses the GPU boundary
A scene author works with mobjects. The renderer does not receive an abstract “circle” or “equation” in that form; it resolves the families of mobjects into drawable members and asks each member how it should be drawn. In the current implementation, a Renderer walks the mobject families, skips members with nothing to draw, and creates or reuses a Drawing for each drawable member. The Drawing is the per-object bridge between mobject state and GPU resources.
A Drawing keeps references to the mobject's data and uniforms. Data contains the records that describe points, paths, colors, widths, or other per-record values; uniforms carry values that apply to the object or to the shader's interpretation of it. The Drawing also tracks where the object's data was written in shared buffers, which version was last sent, what textures and samplers it uses, and whether a previous render decision has become stale. It is not a second mathematical object. It is the renderer's current arrangement of one mobject's state for a frame.
Materials hold a different kind of ownership. Mobjects can share a Material when they agree on the drawing class, shader, data layout, uniform layout, texture kinds, and related compilation inputs. The Material owns reusable GPU decisions such as shader modules, buffers, bind groups, and pipelines. A mobject can change its position or opacity while another mobject continues to use the same material, provided both still fit the material's key. This is why per-object state and shared GPU state must remain separate.
The distinction is easiest to see as a flow. The mobject remains the source of current data. The Drawing claims a stretch of a shared buffer and writes changed records or uniforms into it. The Material supplies the shader and pipeline that know how to interpret those records. The Renderer resolves the order and compatibility of Drawings, then opens a render pass and issues the draws. The Camera owns the target texture into which those passes write. Each boundary has a different trigger: data versions change when mobject data changes, grouping changes when compatible runs change, and pipeline decisions change when the material key or render state changes.
For a page of text, this separation is especially concrete. Each glyph can retain its own records and style while several compatible glyph Drawings share a material and may be gathered into runs. Changing one glyph's opacity or position should update the relevant data without forcing every other glyph to acquire a new shader pipeline. The renderer still has to preserve the order and fill assumptions that make the grouping safe, but it need not treat the page as either one indivisible bitmap or hundreds of fully independent GPU programs.
Uniforms and records also change at different conceptual scales. A record can hold a point or a per-point stroke value; a uniform can describe a whole object's fill, gradient, texture binding, or depth state. A Drawing writes them into the buffers that their shaders read, and the renderer can compare the versions it wrote previously.