Using Motionstash from a coding agent
The premise of this registry is that a language model should not be writing easing curves. Generated animation code is the part of a video pipeline most likely to be subtly wrong and least likely to be caught by a test: an off-by-four-frames entrance reads as cheap, and it typechecks. So the model’s job here is narrower: pick a component, fill a typed parameter set, order the shots. All 1,105 props across 148 components are declared in Zod schemas, which means every value an agent supplies either validates or fails loudly.
The catalog an agent reads
The whole registry is three static files. None of them require a login, a token or a rate-limit budget, and an agent reads them the way a person browses the gallery.
- /registry.json: every component with its props, budget and source.
- /llms.txt: the catalog as plain text, sized to drop into a context window.
- /llms-full.txt: the same, expanded with every prop of every component.
Getting a component out, for humans
Nothing here is distributed as a package to depend on. You take the component you want plus the four spine files it imports, and the copy is then yours to edit, the same model shadcn/ui popularised, for video.
Copy the component's source from its page. It is one TypeScript file, and it needs the four spine files it imports: types, contract, timing and tokens. Every component page carries a copy button for its source, and registry.json carries the same source for all of them at once, which is the form an agent should read.
The timing grammar
Components in this registry compose in time, not in space, and the grammar is what makes that safe. Everything runs at a canonical 30fps and declares its duration as three numbers: enter, hold, exit, taken from four budgets. Because every component multiplies its own presence by the same stage function, two clips placed back to back cross-dissolve instead of cutting.
| Budget | Enter | Hold | Exit | Total |
|---|---|---|---|---|
| beat | 12f | 36f | 12f | 2.0s |
| statement | 15f | 60f | 15f | 3.0s |
| scene | 18f | 114f | 18f | 5.0s |
| feature | 20f | 200f | 20f | 8.0s |
| Spring | Damping | Stiffness | Mass |
|---|---|---|---|
| settle | 18 | 180 | 0.9 |
| snap | 22 | 300 | 0.7 |
| glide | 26 | 90 | 1.4 |
| pop | 11 | 240 | 0.8 |
Six easing curves exist and no more: enter, exit, travel, accent, snap, crash because a library where every component picks its own bezier is a library that never looks like one system.
What the authoring contract forbids
Every component is checked against these in CI, not by review. They are also the rules to follow if you are generating a new component rather than using one.
- One file per component, self-contained, no shared edits.
- Inline styles only: no CSS, no Tailwind, no className. A copied file must work with nothing but Remotion installed.
- Brand tokens instead of literal colour, so one component serves six palettes.
- Presence animated through the shared stage, never hand-rolled against raw frame numbers.
- Deterministic: no Math.random, no Date.now, no state-driven animation. Every frame is a pure function of the frame number.
- No external assets: every logo, avatar and screenshot is drawn in code, so a render is reproducible on a cold machine.
- Sizes derived from the composition, so the same file renders at 16:9, 9:16, 1:1 and 4:5.
- Every prop carries a description in its schema, because that description is the agent-facing documentation.