You cannot hear the film, and a still is not the film. Every step here exists to replace a sense you lack: speech-to-text is your ears, stills and contact sheets are your eyes, and word timestamps are your sense of timing. Ask of every beat: which word does this land on, and have I checked it landed?
Two rules carry the rest:
- Audio first, then pictures. Lock the voice timeline before animating.
Every visual beat is anchored to a word (
word("c02", "bail")), never to a typed number, so re-voicing a line moves the gag with it. - One pure
renderAt(t). The page draws any moment fromtalone. Live playback passesaudio.currentTime; export stepst = frame / fps. Nothing reads the wall clock, so what you review is what renders.
Pipeline
All steps run through scripts/film.py (EXECUTE; uv run scripts/film.py <cmd> <project-dir>; needs ffmpeg, audio steps need ELEVENLABS_API_KEY).
The project's film.json holds voices, lines, SFX, music and the mix cue
sheet; src/scenes.js holds the pictures.
- Brief and script. Budget about 1.8 spoken words per second of runtime: a 60s gag-driven film held 111 words once visual beats had room. v3 voices read slowly and comic pauses cost time; the first draft of that film ran 96s. Write lines as the real people would say them; quote the source (chat, notes) where you can.
- Scaffold:
film.py init <dir> --style collagecopiesassets/engine.html,assets/style-collage.js,assets/scenes.example.jsandassets/film.example.jsoninto the project. Thenfilm.py fontswith the families the style file names. - Voices: cast per line in
film.json, thenfilm.py tts <dir>. It prints each line's transcript: read every one against the script. - Timeline:
film.py timeline <dir>. Trims dead air, shortens named pauses (cuts), applies tempo, overlaps crosstalk (negativegap), and writesbuild/timeline.json(word times + per-speaker mouth envelopes). Iterate lines, cuts and gaps untilENDfits the brief. - Pictures: characters and props per
references/characters.md; scenes in
src/scenes.jsper references/engine.md and the style reference. - Music and SFX:
film.py music <dir>,film.py sfx <dir>, thenfilm.py mix <dir>. - Review:
film.py build,film.py snap <dir> <t...>at every beat, fix, repeat. Thenfilm.py render,film.py sheeton the MP4, andfilm.py stton the share file with--findfor the key words.
Details of each step, with the failures that shaped them:
| When the task involves… | Read |
|---|---|
| Script length, casting, v3 tags, pauses, crosstalk, bleeps, music cues, SFX, mix levels, verifying audio | references/audio.md |
| Turning photos into consistent characters, expressions, lip-sync images, props and backgrounds | references/characters.md |
| Writing scenes: scene contract, anchoring, transitions, freeze frames, canvas traps, performance | references/engine.md |
| Stills, contact sheets, the render, share encode, final checks | references/review.md |
| The collage look: prompts, lettering, stamps, marker write-ons, paper, comic devices | references/style-collage.md |
Adding a style
A style is a pair: assets/style-<name>.js (drawing helpers, STYLE font
defaults, optional drawCaption) and references/style-<name>.md (image
prompts, palette, devices, pacing). Write both from a film that shipped, not
from imagination, and add the row to the table above.
Neighbours
HyperFrames and Remotion skills build video from HTML/React compositions with
their own runtimes; this skill hand-rolls canvas for full control of an
illustrated look. browser-video records real pages. Image generation is
whatever the environment offers (a gpt-image-2 route worked); the ElevenLabs
skills cover their APIs in depth.