Programmatic Short Film (short-film)
Turn a topic into a short film: approximately 30 seconds (configurable 15–90 seconds), portrait 1080×1920, 24 fps; alternating hand-drawn ink-style paper plate shots and deep-blue blueprint plate shots; every event lands on the beat grid (bpm → beat → frame); every pixel and every audio sample is computed with pure browser JavaScript. Deliverables are dist/<slug>.html (self-contained player), exports/<slug>.mp4 (with phone and preview transcodes), and a publish pack: a TikTok cover image (HTML screenshot), recommended title, and description.
This skill encapsulates a proven pipeline. It comes with three things:
foundation/— The engine and tools, copied into each new project:src/core.js,src/lib.js,src/player.js,src/music.js(engine + a sample soundtrack), andtools/(build, check, snapshot, render, stub generation, audio analysis, publish pack, test fixtures). Everything is driven bysrc/timeline.js, so each film requires no changes to the tooling code.templates/— Four planning documents to bootstrap each film.reference/— Read when needed: shot types, scene anatomy, music, platform presets; start with the three reference images.
Start in reference/: contact-sheet.jpg is a full contact sheet of the example film (examples/llm-evolution, a custom "ATLAS" style) — that level of detail and polish is the bar; paper-frame.jpg and blueprint-frame.jpg are full frames of each plate from the default style (rendered by tools/fixtures), serving as the visual target for films using the default style.
See the full example at examples/llm-evolution/: a 24-shot film from neurons to large language models, with planning docs, source code, dist/, and publish pack. Note it is a custom-style production (deviating from the default paper × blueprint style via reference analysis), showcasing the skill's full capabilities. When a template leaves you unsure what a filled-in document looks like, read its counterpart there.
The Gate
node tools/check.cjs is the gate: six checks (media scan, determinism, source scan, timeline, draw, frame time), exit code 0 means pass. From the stub pass onward, no step is complete if the gate is red. On a real film it takes under a minute — let it run.
Pipeline
0. Brief
Ask only one round of questions: what is the topic, what must the film include about it, duration (default 30 sec), and which platform to publish to (determines aspect ratio and safe zones, see reference/platform-presets.md). Invent everything else and explain what you invented.
Completion criteria: The topic is phrased as a sentence the user has seen, and duration and platform are decided.
1. Setup
Create the project folder named after the film slug, copy foundation/ into it. Run npm install in tools/ (Playwright; if browser missing, add npx playwright install chromium), confirm ffmpeg is on PATH or set FFMPEG to the binary path. Copy templates into docs/, write the topic into the Goal of docs/CONTRACT.md.
Completion criteria: node tools/smoke.cjs passes, node tools/check.cjs --fixtures is green, and node tools/render.cjs --fixtures --scale 0.5 produces a exports/fixtures.mp4 with sound. This fixtures mini-film proves the toolchain works before any effort goes into planning.
2. Research
List the stages of the topic story, run a web search for each open question, capture 2–4 authoritative full-text sources into .tmp/research/. Research ultimately lands in only two downstream places: the art bible's topic references and each shot's Subject section.
Completion criteria: Every story stage traces to a captured source.
3. Art Bible
Fill in docs/art-bible.md per template. Sections 1–9 are the established style — fixed; section 2.2 (topic palette, each color a named hex and mirrored to src/lib.js annotation block), 2.3's identity tones, and section 10 (topic references) are rewritten per film. Section 10 ends with "mistakes to avoid", each with a correct drawing.
If the user wants a different look than the established style, first do a reference analysis following templates/reference-analysis.md, then update sections 1–9 accordingly.
Completion criteria: Every element to be drawn in the storyboard has draw rules and palette names; src/lib.js agrees with 2.2; the mistake list exists; and node tools/snap.cjs --fixtures --shot palette --samples 5 --sheet has been viewed.
4. Storyboard
Read reference/shot-types.md, fill in docs/storyboard.md per template: logline; numbers (choose bpm first, beat = 60/bpm seconds, duration lands on integer measures); summary table; acts mapped to measures; a shared geometry table for each shape that survives across match cuts; then one entry per shot — 1 to 3 seconds, boundaries on beat grid, alternating plates — with all eight subsections, Sound cues timestamped to the grid.
Completion criteria: Shots exactly tile [0, duration] without gaps; every shot has all eight subsections; every match-cut shape has shared geometry; the document passes a critic's self-review (body numbers match tables, required content inside safe zones — including arithmetic content). Storyboard errors compound into every scene; this is the cheapest moment to catch them.
5. Timeline
Write src/timeline.js per storyboard (shape in storyboard template): title, bpm, duration, shots array (id, file, start, end, mode, title, transitionIn, brief), and flat cues collected from each Sound subsection. The stub pass tests this step — timeline format errors fail loudly.
6. Stub Pass
node tools/stubgen.cjs generates placeholder scenes for each shot, run the gate, then node tools/render.cjs --scale 0.5 --out exports/draft-stubs.mp4 and watch the whole draft from start to end. This is the tracer bullet: before any real scene is drawn, prove that timeline, scenes, gate, render, and audio all work together.
Completion criteria: Gate is green and draft MP4 shows every shot in order, every transition on grid.
7. Scenes
One agent per scene file — file ownership is law (docs/CONTRACT.md). Each scene agent reads reference/scene-anatomy.md, its storyboard entry, the art bible and shared geometry, then writes src/scenes/NN-<id>.js, takes a contact sheet (node tools/snap.cjs --shot <id> --samples 6 --sheet), views each frame, iterates to match the brief. snap --only can render a single shot while sibling files are half-written, so scene agents can freely parallelize.
Shots may also share a draw module (centralized layout, see "Two layouts for scene code" in docs/CONTRACT.md) — then each src/scenes/NN-*.js is just a few lines of registration wrapper, with drawing centralized in FILM.art. The example examples/llm-evolution uses this; it is more efficient when shots share the same geometry and differ only in parameters.
Completion criteria: Each shot's contact sheet has been visually inspected and judged to match the brief, and the gate is green.
8. Music
Write src/music.js per reference/music.md: keep the engine, replace the CH chord table, MIX.ride automation, and the entire score() function, implement every cue at the exact time from FILM.TIMELINE.cues, making accents land on transitions.
Completion criteria: After node tools/audio/render-audio.cjs, node tools/audio/analyze.cjs .tmp/audio/score.wav --cues shows start and cue within 10ms, node tools/audio/peaks.cjs .tmp/audio/score.wav shows headroom below the limiter ceiling, and the gate is green.
9. Critic Waves
First put the whole film on one sheet: node tools/snap.cjs --samples 24 --sheet --scale 0.25. Shots that are unreadable at this size are P1 — fix composition, not detail.
Then review each shot based on rendered frames: re-take contact sheets, use a critic sub-agent to score composition, faithfulness to storyboard, motion, and density. Critics must measure pixel-level critical geometry proportions (band scores, rule of thirds, safe zone arithmetic, shared geometry positions), not just eyeball; and screenshot both sides of each match cut for comparison.
Fix in waves — P1 first, each citing evidence frames, maintaining file ownership (restore the agent that owns the file), re-snapshot after each fix. The director spot-checks each P1 fix on new frames. Check determinism by snapshotting the same frames in two different orders and comparing file hashes.
Completion criteria: Every P1 and P2 fix verified on new frames, and the gate is green.
10. Deliver
node tools/render.cjs writes the master (crf 16). Then transcode:
ffmpeg -i exports/<slug>.mp4 -vf scale=720:1280 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k exports/<slug>-phone.mp4
ffmpeg -i exports/<slug>.mp4 -c:v libx264 -crf 23 -preset medium -c:a copy exports/<slug>-preview.mp4
node tools/build.cjs writes dist/<slug>.html. Then watch the master with sound from start to end, and open the HTML player once (click or space to play, arrow keys to step frame by frame, ?shot=<id> for single-shot loop).
Write exports/<slug>-shots.md: one line per shot explaining what it shows.
Completion criteria: Master, phone transcode, HTML file, and exports/<slug>-shots.md exist; gate is green; final viewing finds nothing to fix.
11. Publish Pack
Use tools/publish.cjs to generate publish-ready cover art and copy scaffolding:
node tools/publish.cjs # defaults to hook frame of shot 1 as cover
node tools/publish.cjs --at 2.5 --title "From One Neuron to a Language Machine" --platform tiktok
It does two things:
- Cover image (HTML screenshot, default 1080×1920): renders the film's frame at
--atas the main visual, overlays title/subtitle/badge, outputsexports/<slug>-cover.png. The cover page may use system fonts and images because it doesn't enter the delivered HTML, bypassing the "no media" rule. - Copy scaffolding
exports/<slug>-publish.md: title candidates, description, tags, shot list, duration/aspect/platform, etc. Titles and descriptions are starting points; you polish them into final recommendations perreference/publish.mdrules.
Completion criteria: exports/<slug>-cover.png generated and visually inspected (title inside safe zone, legible, has hook); titles and descriptions in exports/<slug>-publish.md have been polished to final recommendations by you; platform and aspect match the brief from step 0.