Skip to content
DavidSling
All work

Equanim

A JSON animation spec where every visual property is a maths expression, designed for AI to write and anything to render.

Role
Designed and built it
When
4 days, March 2026
Stack
TypeScript, mathjs, Canvas
Tests
279 assertions

The idea

Most animation formats describe keyframes. Equanim describes functions. Every number in every frame is a maths expression evaluated at time t. A circle that grows is r = 50 * t. A wave that decays is amplitude * exp(-decay * t) * sin(k * s - omega * t). The whole animation is a function.

A spec is pure JSON: no code, nothing to execute, no renderer assumptions. Hand it to any renderer and it plays. And it is written for language models, which are good at equations and bad at nudging keyframes around a timeline.

Every number is an equation

The double pendulum is the example that convinced me the format works. Its motion is chaotic, so it can't be faked with keyframes. The spec declares the physics once as an ode_system, integrated with RK4, and every object reads the solved angles as functions like phys_th1(t).

"variables": {  "L1": { "default": 2.5, "min": 0.5, "max": 5.0 },  "L2": { "default": 1.8, "min": 0.3, "max": 4.0 },  "m1": { "default": 2.0, "min": 0.5, "max": 5.0 },  "m2": { "default": 1.0, "min": 0.5, "max": 5.0 },  "g": { "default": 9.8, "min": 1.0, "max": 30.0 },},{ "id": "phys", "type": "ode_system",  "solver": "rk4", "step": 0.005,  "derivatives": { "th1": "w1", "th2": "w2", … } },

Running live, RK4

Variables

Hover or tap a block to see what it draws, and drag a variable to change the system live. The spec is trimmed from Equanim's double-pendulum example; the render is a small canvas port of the same equations.

The decisions that mattered

  • Data, not code

    Expressions are strings evaluated by mathjs, never JavaScript. A renderer can validate a spec's shape without running any of it, and a generated spec can't do anything but draw.

  • t-first

    The default clock is local: t runs 0 to 1 over an object's own window. Moving an object's window changes when and how fast it plays, not whether it is visible. Real seconds are one multiply away.

  • Physics as data

    An ode_system holds state and derivatives and names a solver. Its solved state becomes functions sibling objects can call, so arms, bobs and the trace all read one simulation.

  • Built for a model to write

    The schema is flat and regular on purpose. The test for the format is whether a model, given only spec.md, can write a valid and interesting spec without help.

How I built it

About four days in March 2026. The first commit is a CLAUDE.md, and the agent worked from that and from spec.md, which is the source of truth: when the renderer and the spec disagree, the spec wins.

Every core module has its own test file, 279 assertions with no test framework. That is what let an agent change the evaluator or the solver without me re-checking every example by eye.