Skip to content

About

Worked examples for Codimate: explainer videos made from Python

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Codimate examples

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.

Set up

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.mp4

Run 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.

Checks

.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 those

Examples 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.

Start here

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.

The one decision Codimate cannot make for you

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.

Motion you might think needs a new feature

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.

Continuous motion from sampled physics

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.

Getting it right when the famous version does not

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.

When the drawing already knows something

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.

Drawing something with no library help at all

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.

Explaining a physical thing, with a kit

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.

When the numbers have to be real

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.

If you are coming from Manim

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.

When to split

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.

Adding one

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.

About

Worked examples for Codimate: explainer videos made from Python

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages