Skip to content

xraymanim v0.1, the visual grammar and the first two animations - #66

Merged
tamnd merged 3 commits into
mainfrom
xraymanim
Aug 29, 2026
Merged

xraymanim v0.1, the visual grammar and the first two animations#66
tamnd merged 3 commits into
mainfrom
xraymanim

Conversation

@tamnd

@tamnd tamnd commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Closes #15.

Some things about CPython are hard to teach in a still picture, because the whole point of them is that something changes. A refcount going up and down, an instruction pointer walking along a strip of bytecode, a value moving on and off the stack. This adds the library those get made with, and the first two animations built from it.

The fifteen shapes

Nine primitives (box, arrow, slots, column, stream, tree, graph, counter, highlight) and six named objects (PyObjectBox, RefArrow, Frame, CodeStrip, DictTable, ArenaMap). The primitives are shapes. The named ones are nouns: a PyObjectBox is not a box with a label on it, it is the two fields every object in CPython actually starts with, drawn the same way every time so that a reader stops decoding the picture and starts looking at what changed in it.

The issue asked for a documented rule that a new shape needs an amendment to the visual system document before it is drawn. Written as prose that would be a rule somebody has to remember, so it is code instead. grammar.SHAPES is the list, a storyboard naming a shape outside it fails its own check, and a shape that is drawable but not described in xraymanim/VISUAL-SYSTEM.md fails too. The three cannot drift apart.

Colours come from pyxray.theme, the same six tones the diagrams and the charts already use, so an animation and the diagram next to it in a lesson are recognisably from one project. There is a test that a tone renamed in pyxray shows up here rather than being copied and frozen.

Importing it does not import manim

manim is about thirty packages and a Cairo build. Every CI job would otherwise pay for that, so the package is split down the middle. The grammar, the storyboards, the catalogue and the checks are all manim free and run everywhere. The drawing half is behind [project.optional-dependencies] render, reached through the root anim extra, and only the new animations job installs it.

Storyboards, because a render costs a minute

Every animation is planned as data before it is drawn. A Storyboard holds the slug, the lesson it belongs to, the shapes it will use and the caption track as a list of beats with durations, and it checks itself in milliseconds: under the ninety second cap, no caption that wraps onto the picture, no line break inside a caption, at least three beats because two is a slide and a slide should be a still image.

The scene then has to play the beats it planned. Explainer.tear_down counts them and fails the render if the tally is wrong, so a scene cannot quietly diverge from its plan. That is worth having precisely because inspecting an animation is expensive: a render is a minute, so a mistake in the plan costs several before you see it.

xraymanim check also confirms the scene file exists and defines the class the slug implies, the GIF is committed and under 6 MB, and every animation is listed in anim/README.md. It is in just check and every CI job runs it.

The two animations

a01, one line of Python, seven stages. answer = 6 * 7 walked through the eight artifacts of the pipeline, ending with the multiplication disappearing between codegen and the optimizer. Every artifact on screen came from a real run of pyxray.compiler.stages on 3.15.0rc1: the tokens are what tokenize returns, and both instruction listings are what CPython emits. A reader watching an animation cannot pause and check the bytecode, so nothing in it is typed from memory.

a02, a name is a label, not a box. a = [], b = a, del a, with the refcount on the object going one, two, one, zero and the memory going back at the end. The count is drawn inside the object rather than beside it, because it is a field of the object, and drawing it outside is how a reader ends up believing the interpreter keeps counts in a table somewhere.

Why the GIFs are committed

A reader on GitHub or in Colab is looking at a page and cannot run a build first. They go through ffmpeg with a generated palette rather than straight out of manim, which is several times smaller for the same picture and is the difference between this repository staying clonable and not. 2.3 MB and 856 KB.

They are deliberately not compared byte for byte, unlike the notebooks and the diagrams. Video encoders are not reproducible across versions or platforms, so a checksum here would fail for reasons nobody can fix. CI re-renders instead, which catches the failure that actually happens: a scene that raises because the library moved underneath it.

Also in here

just animations and just build-animations, with the first one added to just check. A new animations CI job that installs the extra, runs the tests and re-renders both. A xraymanim row in the README table and a section on the animations. 45 new tests, and the suite goes from 915 to 960.

One thing worth flagging: manim's text rendering leaks an unclosed xml.etree.iterparse iterator, so the ResourceWarning arrives from a destructor at an arbitrary later moment. With filterwarnings = ["error"] that does not fail the test that caused it, it fails whichever test happened to be running when the collector got round to it. There is a targeted ignore for it with the reason written down. The tests also point manim's media cache at a temporary directory, so a test run leaves nothing in the working tree.

Checked

just check is green: ruff, 960 passed and 1 skipped, 352 citations, 2 blueprints, 96 diagrams, 12 notebooks executed end to end, and 2 animations. Both animations were re-rendered from a clean checkout of this branch.

Fifteen shapes, nine primitives and six named objects, and a rule that a
sixteenth needs an amendment to VISUAL-SYSTEM.md before it is drawn. The rule
is enforced rather than remembered: the shape list is code, a storyboard that
names something outside it fails, and a shape that is drawable but undescribed
fails too.

Importing xraymanim deliberately does not import manim. The grammar, the
storyboards, the catalogue and the checks are all manim free, so every CI job
runs them, and the drawing half sits behind the anim extra where only the one
job that renders pays for thirty packages and a Cairo build.

Each animation is planned as a storyboard first, which is data and checks in
milliseconds: the ninety second cap, the caption track, the shapes it draws.
A scene then has to play the beats it planned, checked by a tally in tear_down,
so a scene cannot quietly drift from its plan. That matters because a render
takes a minute and a mistake in the plan costs several.

a01 walks answer = 6 * 7 through the eight artifacts of the pipeline, with the
tokens, the tree, the symbol table and both instruction listings taken from a
real 3.15.0rc1 run rather than typed from memory. a02 is a list with two names
pointing at it and a refcount going one, two, one, zero.

The GIFs are committed because a reader on GitHub or in Colab cannot run a
build first, and they go through ffmpeg with a generated palette, which is
several times smaller than what manim writes. CI re-renders instead of
comparing bytes, because video encoders are not reproducible across platforms
and a checksum would fail for reasons nobody can fix.

Closes #15
@tamnd tamnd added kind/animation A manim scene or the mobject library area/pedagogy Sequencing, the beginner ramp and assessment labels Aug 29, 2026
tamnd added 2 commits August 29, 2026 07:03
There are no manimpango or pycairo wheels for 3.15 yet, so both build from
source on the runner and need the headers. Locally they are already there,
courtesy of Homebrew, which is why this only turned up in CI.
ubuntu-latest does not have ffmpeg any more, and the step meant to catch that
was written as `ffmpeg -version | head -n 1`. Under set -e a pipeline's exit
status is the last command's, so head succeeded and the missing ffmpeg went
unnoticed until the render failed two minutes later.
@tamnd
tamnd merged commit 31b6159 into main Aug 29, 2026
8 checks passed
@tamnd
tamnd deleted the xraymanim branch August 29, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/pedagogy Sequencing, the beginner ramp and assessment kind/animation A manim scene or the mobject library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

xraymanim v0.1: the nine primitives and the six mobjects

1 participant