A cat dances a waltz
Cream cat, rose tutu, plum curtains. An original 24 bar waltz in D major with a B minor middle and a final ritardando, on piano, pizzicato strings, flute and glockenspiel. The choreography is driven by musical time.
Open source, MIT, by Calvin at ArchAstro
Write videos in React. Render them to MP4. Review them like a studio would. Every frame is a pure function of the frame number, the music is code, and the reviewer is an agent with a contact sheet.
npx skills add ArchAstro/clapper --skill clapper --global
The one idea
There is no clock. A scene reads useFrame() and draws itself. That is why the renderer can visit frame 212 without playing frames 0 to 211, why a preview can scrub in any direction, and why two renders of the same source are identical to the byte. Drag the slider. The picture below is computed from the number, nothing else.
Try dragging backwards. A timeline built on wall clock time cannot do that; a pure function of the frame can.
// a scene, as Clapper would write it
function Hop() {
const f = useFrame(); // local frame
const x = interpolate(f, [0, 149], [130, 470]);
const hop = Math.abs(Math.sin(f / 9)) * 120;
const squash = f % 28 < 3 ? 0.82 : 1;
return (
<Box x={x} y={280 - hop} scaleY={squash} />
);
}
// time belongs to the plan, not the scene
const SCENES = defineScenes({
hook: { seconds: 2.5 },
proof: { seconds: 4, transition: { type: "fade" } },
});
How a render works
The CLI builds the project with Vite, opens it in headless Chromium, sets the frame, takes a JPEG, and streams the frames into ffmpeg. Sounds are React elements too; they register cues that an offline synth turns into a stereo mix, which is muxed in at the end.
The studio: live thumbnails, viewport overlays, a timeline with lanes per audio kind, an inspector with cue preview, and a scratch panel that compiles TSX in the browser.
First, middle and last frame of a scene, or every tenth frame, into a folder. The fastest way to see whether a beat lands before spending a render.
A contact sheet, nine tile motion strips around every cut, a spectrogram, a waveform, a lint report and a brief with a reviewer prompt. Hand the folder to a person or a subagent.
Music as code
A score has a tempo map, a meter, tracks and clips. Each track names a sampled instrument from a catalog of CC0 presets, rendered with a native sampler, mixed to stems and mastered to a broadcast loudness target. The studio shows the piano roll beside the film; click a note and the video seeks there.
// videos/cat-ballet/src/score.ts, abridged
export default defineScore({
title: "A small waltz",
tempo: [{ at: 0, bpm: 108 }, { at: 12, bpm: 96 }],
meter: [3, 4], seed: 17, tail: 3,
tracks: [
track("piano", {
instrument: "vsupright1", gain: 0.6, reverb: 0.4,
clips: [{ notes: phrase("D5 F#5 A5 F#5 E5 D5", { duration: 0.5 }),
length: 3, repeat: 4 }],
humanize: { timing: 0.006, velocity: 3 },
}),
track("strings", {
instrument: "violin-ens-pizz", pan: 0.25, gain: 0.3,
clips: [{ at: 3, notes: chord(["D4", "F#4", "A4"]), length: 3, repeat: 3 }],
}),
],
});
Made with it so far
Every one of these was rendered from the source in the repo, music and all. Some exist to sell something. One exists because a cat in a tutu deserved a waltz. Press play; they have sound.
Cream cat, rose tutu, plum curtains. An original 24 bar waltz in D major with a B minor middle and a final ritardando, on piano, pizzicato strings, flute and glockenspiel. The choreography is driven by musical time.
An E minor jam at 112 bpm: count in, riff, solo, breakdown, return, one unified hit. Picking, fretting and drum gestures come from actual note onsets. No backing recording, no invisible overdub.
A mischievous clapperboard slams, bows, and walks a reader from a React expression to a groove to a scrubbed preview. Two rounds with an independent visual reviewer before the README got it.
Four people ask for four sites and each request materializes as a durable company URL, scored with bowed strings and tuned wooden mallets. Brand tokens and copy are lifted straight from the live landing page.
Boiling ink on a sketched laptop, a camera pull back into the story, and a score whose risers land exactly on the cut. One of five ArchDev cuts built on a monoline character rig.
An agency spot for a product that does not exist, built to find out what the review loop catches. Three rounds: a blank tail, cuts landing on empty frames, a number roll clipping the type.
Playful spring motion and spatial staging. The reviewer caught a block sliding through another with no elevation, and a banner held under 1.2 seconds.
Camera push, tiled grain and live log panels. This is the spot that proved PNG capture, not the page, was the render bottleneck.
Reviewed like a studio
A finished render is not a finished film. Each spot went to an independent reviewer briefed as a creative director, sometimes with an audio director and a feed strategist alongside, who read the contact sheet, rendered their own stills, and returned a verdict with frame referenced fixes. These are the real rounds from the showcase notes.
| Spot | Round 1 | Round 2 | Round 3 | What the reviewers caught |
|---|---|---|---|---|
| Ledger | REVISE 6 | REVISE 6 | SHIP 9 | A blank tail because transition overlaps were never subtracted, hard cuts landing on empty frames, empty quadrants, a number roll clipping the type |
| Orbit | REVISE 7 | SHIP 8 | A block sliding through another with no elevation, a banner held under 1.2 seconds, a mechanical waveform | |
| Nimbus | REVISE 6 | REVISE 6 | SHIP 9 | A graph edge crossing the headline, a camera push cropping the log panel, a hot pad under quiet holds |
| ArchDev | REVISE 6 | SHIP 8 | SHIP 9 | A hands to head beat hidden behind windows, generic swivel arms, no hit on a cut, the character missing from the end card |
| ArchDev v3 | CD 7 · X 7 · audio 7 | SHIP 8 · 9 · 8 | Three reviewers in parallel named the same three defects; the audio director found a duck swallowing a paper flip by measuring peaks around every cut |
Four rules
useFrame(). No wall clock, no timers, no Math.random. Use the seeded helpers.From the friction log
Try it
Install the skill for your coding agent. It installs Clapper, prepares a managed runtime with Node, Chromium and ffmpeg, creates a project, and walks the visual and audio review with you. No separate setup.
npx skills add ArchAstro/clapper --skill clapper --global
Then, in a new session: "Use the Clapper skill to make a video with original music. Set up everything needed."