Worked examples for Codimate: explainer videos
made from Python. One folder per example, one main.py inside it, and a README saying
what that example teaches. The library, its guide and its reference are in the
main repository, and
the site.
Small examples are a single main.py. Bigger ones split. See
When to split below for the rule, which is not the one you might
expect.
git clone https://github.com/darhnoel/codimate-examples && cd codimate-examples
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt # builds Codimate's Rust engine: needs Rust
brew install ffmpeg typst # ffmpeg encodes; typst typesets formulas
.venv/bin/python bubble_sort/main.py # writes results/bubble_sort.mp4Run any example from the repository root. Each writes its video into results/, which
is not committed. Resolution is a render argument (scale=1.5), not something the views
know about. requirements.txt installs Codimate from its main branch until the next
release; some examples use the science kit and the Previewer, which the last PyPI
release (0.1.5) does not have.
Several examples have a Khmer narration. That needs a Kiri TTS
key in .env (KIRI_API_KEY=..., never committed) and spends credits; without the audio
they render silent, and --silent forces that.
.venv/bin/python tests/run.py # builds every film, typesets every formula: no video
.venv/bin/python tests/run.py --render # also renders every example (needs ffmpeg)
.venv/bin/python tests/run.py --render year maxwell # or only thoseExamples are found, not listed: a new folder with a main.py is covered the day it is
added. ruff check must pass too, including no function with more than five arguments.
bubble_sort/ — things that move.
Bars slide when they swap. Names follow the thing, so cm.items() gives each
value an identity of its own and the Engine can tell that bar 3 travelled
rather than that two bars changed height. Read this one first; everything else
assumes it.
galton_board/ — both kinds of name, side by side.
Pegs and bins never move, so their names follow the place:
("peg", row, i), no cm.items() anywhere. Balls do move, so each is named
after itself and travels because the trace says where it is at each moment —
the view never mentions movement. A dozen are in flight at once, each on its
own path, falling under a real ballistic simulation sampled at a fixed time
step, which is what lets balls at different depths move at different speeds.
Everything else is a consequence of choosing between those two.
dharma_wheel/ — a turning wheel, with no rotation in the
API.
The trace says where the spokes are every 15 degrees and the Engine fills in the rest, exactly as it does for a sliding bar. Rotation is just position over time. The README works through why 15 degrees and not 45.
pendulum/ — gravity supplies the acceleration; Codimate
connects the moments.
The simulation advances angle and angular velocity at a fixed time step. The
view turns each sampled angle into a string and bob, and linear interpolation
keeps that already-continuous motion from stopping at every event.
helical_solar_system/ — the Sun moves, so every
orbit is a helix.
The popular "solar system is a vortex" video has the orbital plane square to the direction of travel and the planets trailing behind like a comet's tail. Neither is true. This one inclines the plane 60° and lets half of each orbit run ahead of the Sun, which is what actually happens.
bernoulli_lift/ — and the story that goes with it.
The air over a wing really is faster and really is at lower pressure. The "equal transit time" reason for it is not true, and this measures the two parcels to show it: the upper one arrives 1.35x sooner. The flow is the exact Joukowski solution, so the speeds and the times are consequences rather than choices.
rubiks_cube/ — a cube solving itself, beside a drawing
that turned out to be the same cube.
Nine overlapping circles, twelve places on each, every place on exactly two. That is not decoration, it is the cube's nine layers, and the example searches for the pairing that proves it rather than assuming one. Turn a layer and its twelve dots slide three places along their circle.
It is also where the drawing order had to be got right four separate times, and each of those is written down where it happened.
spacetime/ — a lattice of space deformed by a mass inside
it, in wireframe 3D.
Codimate has no camera, no depth buffer and no 3D of any kind, so this one writes its own projection and pays for it. It is here for what that cost: the lattice flickered for four attempts, and the cause turned out to be that draw order is resolved once per segment rather than per frame — so any layer that changes is a hard cut at a scene boundary, sixteen times a second. The fix is to freeze the order, which is free when nothing is filled.
orbits/ — the Sun, the Earth and the Moon, and a camera pulling
back from one to all three.
Built from codimate.science alone:
a camera, spheres, orbits, labels that stay clear of each other. It is here for what the kit made
easy and for what it did not: one moment per frame or the draw order tears, names
that follow bodies collide unless something moves them, and a pull-back is dolly,
not moved.
maxwell/ — how did Maxwell find his equations? Nine scenes in Khmer,
from a compass and a wire to the number that matched light.
Every equation is LaTeX, written on the moment its discovery happens, and Maxwell's own term is a separate formula so it can arrive alone. It is here for the narration: each word is lined up with the voice by transcribing the recording, and for how a long film splits into one module per scene.
cavendish/ — how do you weigh the Earth? Two minutes of Khmer
captions, a torsion balance, and a zoom out through four scales to say how small the
twist was.
The long film the science kit was cut out of, drawn by hand and kept as it was. It is here for the captions that pace the scenes, and for zoom levels nested round one point.
year/ — the same three bodies for a real 365 days, 2025.
The motion is taken from the sky and only the sizes are made up: true eccentricity
and closest approach, the equinoxes and solstices on their dates, a Moon whose
orbit turns and whose phases come from the light. sky.py is the astronomy and
knows nothing about drawing; its test checks it against the almanac.
archimedes/ — one box that becomes water, ice, steel and
then a ship.
It is one name the whole way through, so the Engine tweens between the four rather than cutting. Nothing about the picture is placed by eye: the hull's wall thickness is solved so that the ship holds exactly the steel the block was made from, and the 821 kg/m³ that floats it is a consequence of the drawing rather than a figure picked to make the point come out.
It is also the example that renders in two languages — main.py km gives the
Khmer one — and the README says what that took, which was less than you would
think everywhere except the title card that types itself on.
otsu/ — a threshold chosen by looking at the histogram.
The example where Codimate cannot help: an image is pixels, and scene.image
places a file without being able to compute one, so a sliding threshold is a
sequence of PNGs written before the render. The README is mostly about the
three places where a jump in the threshold drew a chord instead of a path.
manim/ — five of Manim's tutorial scenes, translated.
Not a fight Codimate wins: for two shapes and three verbs, a library built
around shapes-and-verbs is shorter, and the README says so. It is here because
two of them say the quiet part out loud. DifferentRotations — where
.animate and Rotate do different things from calls that look alike — is
the clearest statement of the rule this library runs on: what you put in the
payload decides what the motion is. And TwoTransforms asks for a distinction
that does not exist here, because the name is the identity.
Split where the knowledge splits, not by the four pieces.
The temptation is state.py / algorithm.py / view.py / motion.py /
timing.py, mirroring the Rust examples. Don't. Those four pieces are short —
in bubble_sort they are 8, 20, 1 and 1 lines — and they are already named
where they are used:
cm.explain(trace=..., view=..., motion=..., timing=...)That call shows how the pieces connect, which a directory listing cannot. Splitting there gives you five files of a dozen lines each and five import blocks, which is the ceremony the Python surface exists to remove (ADR 0008).
A seam is worth having when the file on one side of it does not need Codimate. That is the test, and it is easy to apply:
rubiks_cube/
main.py the four pieces, together, plus the view
cube.py the cube as a permutation of 54 stickers — no drawing at all
geometry.py where a sticker is in space, and what a turn does to it
graph.py the traced drawing: places, lines, circles, colours
places.py which place holds which sticker — searched for, then checked
Only main.py imports codimate. The other four are plain Python that can be
run, checked and argued with on their own — and they are: cube.py verifies
that (R U R' U') has order 6, places.py verifies that a quarter turn slides
a circle's twelve places exactly three along it. Neither needs a video to say
whether it is right.
galton_board splits on the same test for one file: physics.py is the
ballistic simulation and imports nothing of ours.
Rough threshold: one main.py until it passes ~150 lines or grows a part
that could be checked without rendering anything. bubble_sort (57 lines) and
galton_board's view (72) are single files and should stay that way.
your_example/
main.py the whole explanation
README.md what it teaches, and what to try changing
Start with one file. Split a part out only when you could test it on its own.
See Writing Your First Animation for the walkthrough and How Codimate Thinks for why it is shaped this way.