Make a script from source
Every later step reads one script.json: scenes → shots → elements in order (dialogue
with character, parenthetical, emotion, V.O. or O.S.; action, with on-screen text as
ON SCREEN: …; reaction beats; sound and music cues), plus the cast and story beats,
all timestamped. It is written alongside a readable script.md and a script.fountain
that opens in screenwriting apps.
First question: what did the person bring? A finished video, a written script, or a deck. If a later job features the same people, carry the earlier script's cast over (labels, looks, voices) instead of starting fresh.
Routes
| Source | Route | Cost and time | Quality | Leaf |
|---|---|---|---|---|
| A finished video (scene, ad, interview, vlog; any length) | Speech-to-text, cuts from ffmpeg, then Gemini watches at 4 fps with sound | A 2:50 video: one call, about 78k prompt tokens, about 2 min. An hour runs as 12 chunks, one after another | Shots match the real cuts; lines verbatim and attributed by mouth | gemini-script-from-video |
| A written script, screenplay or shot list | The agent reads it into the same script.json; code checks every line word for word | One LLM pass, reruns if a line is paraphrased | The script's own shot names kept as labels; timings estimated | llm-convert-written-script |
| A slide deck (PDF) | Ask whether the script already exists (speaker notes, a voiceover draft). If it does, it is a written script. If the deck is all there is, write the narration per slide, then treat it as a written script | Not measured | Only as good as the person's read-through | llm-convert-written-script after the narration exists |
A deck alone means you wrote the words, so the person has to review them. Put every narrated line in front of them on a review page and ask whether they want to read it through and approve it before anything is voiced; tell them clearly that this is the step where wording changes are cheap. When they brought their own script, say so and keep the check to a confirmation. There is no single answer: be explicit about which case this job is.
Choosing and rules (both proven routes)
- Labels carry gender. A name is used only when it is spoken or shown. A named
cue carries the gender as an extension (
NORA (F),RAVI (M)); an unnamed one says it (WOMAN 1,FEMALE EXPERT); unclear presentation getsPERSON 1. Gemini returns bare roles (EXPERT) even when told not to, so enforce the rule in code after it. - A scene is a sequence. It starts at a cut where the story moves on; cutaways, inserts, replays, montage and B-roll that serve it stay in it, and intercutting is one scene. "New location = new scene" gave 16 scenes for a video whose person had cut it into 4; the sequence rule gave 5.
- Shots come from cuts, in code. Cuts at ffmpeg scene score > 0.3, cuts under 0.4 s
apart counted once (
ffmpeg-scene-cuts); each shot's middle frame goes to Gemini labelled with its number. Without the stills its descriptions drifted from shot 16 on (two shots swapped, one off from 18 to 21); with them all 23 matched. - Dialogue goes into shots by transcript time, which is exact; other elements into the shot Gemini names, because its own timestamps drift.
- A line across a cut is split; the part after the cut is continued (CONT'D).
- Every line gets a parenthetical and an emotion, mandatory in the prompt ("even a calm line has a delivery"): optional, only 5 of 27 lines got one.
- Context helps with names and roles the video doesn't state ("a deepfake-awareness training video; the woman in the grey jacket is a security expert").
- Written scripts are timed by word count: dialogue lasts at least its words at 2.8 words/s; sound and music cues play under without taking time. Estimates run long: 267 s estimated came out as a 227 s track on eleven_v4. Speeches may be split sentence by sentence, which is fine for direction.
Process (gate is a review page)
- Make the script by the route above. Long videos are chunked at most 300 s, each chunk ending on a cut, each handed the cast found so far.
- Check it: every line verbatim (the written route reports unmatched lines; rerun those), shots against a first/last-frame contact sheet of the cuts.
- Gate.
review_openwithscript.md(cast table, scenes, the script by scene and shot) and the shot stills. The person corrects names, scene breaks and attributions before any casting or voicing.
Avoid
- Trusting diarization for who spoke: speaker ids cluster voices, not people (a deepfake shares the real man's id). Attribute by mouth and voice.
- Gemini's own timestamps for shots and scenes.
- A paraphrased line in
script.json: everything downstream speaks it.
Related
guide-cast-a-voice,guide-voice-a-script: the next steps.recipe-slide-deck-presenter,recipe-script-to-video: jobs that start here.


