Sci-Fi Sitcom Toon — our demo

One example among many. Don't reuse its story, arc, shots, props or timings.

Demo: Coffee Run (57.5 s) · scifi-toon.mp4 · source in demo/

A 30–60 second film in this style: premise, jokes, cast, shots, timing, music and sound are the director's choice.

Story & structure

The lab is out of coffee. A jaded genius in a bathrobe crosses universes for a refill with his nervous sidekick, Gary; every universe has a worse coffee; the one they bring back is decaf. Tiny, mundane goal + absurdly large sci-fi means.

Ways to turn other topics into an errand (for reference only): - Product launch → the genius crosses dimensions looking for a working version of the product; every universe has a worse one; the one they bring back has a twist. - A lesson / explainer → the sidekick asks a simple question; each universe is a wrong answer taken literally; the last one is right but has a cost. - A holiday / event → "we're out of X for the party" → universes of increasingly wrong X.

Beat sheet of the demo (57.5 s): 1. Cold open (8–12 s): the mundane problem, shown not told (an empty pot, one last drip). The sidekick over-explains, the genius cuts him off with one word. No music, no title yet. 2. Portal + title slam (2–3 s) on a musical downbeat. 3. Jump 1 (6–8 s), jelly world: slow: arrive, try, reveal the wrongness in an insert close-up, cut the music, reaction shot, one-word rejection. 4. Jump 2 (6–8 s), mug world: faster and worse; the sidekick loses it; same rejection word. 5. Montage (3 × 1 s): teeth, pigeon and clone worlds; one second per universe, same word each time, cuts on the beat. 6. The break (4–5 s): a universe that is suspiciously normal. The pattern breaks; the calm is the joke. 7. Home (12–16 s): relief → the reversal (it's decaf) → 2+ seconds of dead silence → the genius reveals his value system in one line → button. 8. Button: callback to the opening line so the story loops. 9. End card (4–5 s).

Shots

Beat Camera
Cold open Static insert close-up of the empty coffee pot, a slow push
Dialogue Medium two-shot; hard cut to a close-up on an interruption
Reveal of the absurd Insert extreme close-up, then cut to a reaction close-up
Panic Tight close-up with a short camera shake on the key word
Jumps "Rush" zoom into the portal → full-screen swirl wipe → next world opens from a swirl
Montage Same framing in every world (duo left, creature right) so only the world changes
Cold silence Two-shot of the standoff, very slow push-in, nothing moves but the boil
Button / ending Wide shot so the portal and both characters are in frame; the end card follows

Score structure

Palette & props

Titles & end card

Build notes

styles/scifi-toon/demo/
  toon.js     vector engine: matrix stack, screen-space boil, constant line width, flat shading
  chars.js    the cast (parametric eyes, mouths, hands, noodle limbs) + props
  worlds.js   one function per universe + creatures + the portal
  story.js    single source of truth: VO start times, shots, wipes, tags, key beats, music cues
  main.js     acting per shot, cameras, wipes, tags, subtitles, title, end card, window.EV
  lines.json  script (tts text, subtitle text, speaker, voice, pitch, cut)
  voice.py    per-character processing + lip-sync envelopes   asr.py   padded whisper check
  music/score.py  synthesized score from the cue list        mix.py   foley + voices + ducking + ambience
  srt.mjs  build.sh  sheet.sh (contact sheets)  strip.sh (consecutive-frame strips)  levels.py (stem meters)
  1. Write the treatment. Cast voices by generating test lines and measuring median f0 / pitch variance.
  2. core/tts/tts.py lines.json out/raw → voice.py → asr.py until every line passes.
  3. Put VO times, shots and cues in story.js; block shots in main.js; review with sheet.sh (1 frame/s) and strip.sh (consecutive frames), at least two rounds.
  4. core/render/events.mjs → music/score.py → mix.py (check levels.py and a spectrogram).
  5. sh demo/build.sh reproduces everything: TTS → voices → events → score → mix → SRT → render (1380 frames ≈ 15 s with 4 workers) → mux at −14 LUFS. Full rebuild ≈ 1 minute on an M-series Mac.

Pitfalls tied to this demo: - Kokoro + whisper: the name "Pim" in a deep voice is heard as "Pam"; "Gary" passes. "b-broken" is heard as "be broken"; write "buh, buh-broken", "Wh, wh, why". "decaf" comes out "D-cuff"; write "dee-caf". - A springy portal (lib spring) overshoots to ~135 % and swallows the actors. - Creatures placed behind the shop counter vanish: place them so face and upper body show.