Feed it an outline.json: the skeleton is pre-filled deterministically, the drama is written as alternating action and dialogue beats, 10 code-enforced quality gates check every rule, and you get script.json, a Markdown dialogue book, and a single-page HTML review report.
BEFORE · GUT FEEL
Two minutes per episode, timed entirely by feel. Finish a draft, guess, set it aside, and only when the voiceover comes back discover it runs 90 seconds or drags to 150. The quickest fix is padding with small talk: the drama doesn't improve, but the runtime gets filled.
AFTER · COMPUTED ON THE SPOT
Dialogue seconds = non-whitespace characters ÷ 4.5; action seconds = action beats × 2.5. Each episode's estimate is computed immediately, and anything outside ±15% of target raises an error, naming the exact gap in seconds.

BEFORE · NOBODY CHECKS
The outline defines the opening hook and the script includes it, but which beat it lands on, nobody checks. The first two beats typically go to atmosphere and introductions, so the hook surfaces at beat five or six. The cold open stays a nice idea, not a rule.
AFTER · ON THE RECORD
The hook is the first beat of the beat flow, not a sticker applied afterwards. hookBeat claims a concrete position, and a gate verifies it falls within the episode's first three beats. No claim, no pass.

BEFORE · SURFACES TOO LATE
The outline carries a character roster; the art bible carries scenes, lighting states and props. Writing along, the script casually drops in “lamplight in the night”, a lighting state art never registered. The problem surfaces at image generation, when the artwork changes, not the script.
AFTER · BOOKS CLOSED ON DELIVERY
--outline reconciles characters and payoffs; --art reconciles scenes, lighting states and props. All four reference types are checked item by item; anything written but never registered is flagged on the spot. Missing files are reported as “skipped”, never a silent pass.

You provide outline.json; pass in art.json and cast.json as well if they exist, for reconciliation and name display. Missing upstream files are fine.
Target seconds, hook, suspense, payoff claims, candidate scenes and characters, all pre-filled deterministically from the outline. The model's only job is to write the drama, not to decide what it should be.
An action beat is one visual, in narrative prose; a dialogue beat carries a speaker and a delivery. One beat, one thing, never action and quoted dialogue mixed. Dialogue feeds TTS as-is.
All 10 gates are code-enforced: runtime ±15%, hookBeat within the first 3 beats, character/scene/lighting/prop reconciliation, narrative action, line length… none left to the model to “feel”.
script.json for downstream storyboard and TTS; a Markdown dialogue book for humans; a single-page HTML review report for briefings and retros.
All numbers and screenshots below come from one actual production run of the public-domain novel “Du Shiniang Sinks the Jewel Box in Anger”, end to end. This is not a demo.





Figure: four intercept types from the first round (deliberate fault reproductions, not real product defects; each image is labeled with how the fault was injected). 1: C01 removed from the S03 roster with the line kept, the gate names “C01 in episode 2 S03 is not in the scene's character list”. 2: episode 1 cut to 5 action beats, the gate reports “short by 89.5 seconds (estimated 12.5s / target 120s)”. 3: “he said, don't touch this chest” appended to an action, blocked. 4: one line inflated to 51 characters, the gate reports the count and the line.

Dialogue at 4.5 chars/second, action at 2.5 seconds/beat; every episode within ±15% of target. Not “about two minutes”, an auditable number that names the gap to the second.
hookBeat claims a concrete position and a gate forces it into the first three beats. The cold open goes from discipline to rule; lose the hook in a revision and the gate stops you.
Every line carries a speaker and a delivery; the book is grouped by character and copyable as a whole. With cast.json, each group header carries a voice-prompt button, lines and voice on one page.
Characters reconcile against outline.json; scenes, lighting states and props against art.json. Write an unregistered lighting state and validation flags it, resolved at the script layer, not at image generation.
All 10 gates are code-enforced. Facts fixed by the outline are pre-filled by seed, never re-imagined; the model only writes the drama. Missing files are reported as skips, never silent passes.
The review report is fully inline CSS and SVG: no external links, no CDN, no build step. It opens offline with a double-click, ready for briefings, review and retros.
Public-domain or original novels → core extraction → episode outline → verifiable script. One fixed pipeline; runtime, hook and paypoints all on the record, so the adaptation never drifts off course.
Several titles in parallel, episodes in batches. What slows production down is rediscovering the same error in every episode and every revision, the gates take that over.
Writers, art and voice share one set of structured facts: characters against outline.json, scenes/lighting/props against art.json, dialogue grouped by character straight into TTS, every decision traceable to its beat.
Type $novel-script in a Codex or Claude Code session (or explicitly ask to “use the novel-script skill”), attach your story materials, episode count and target duration. Missing upstream files are fine, the gates will honestly say “skipped”.
Deliverables: script.json (storyboard / TTS) · Markdown dialogue book (human reading) · HTML review report (briefings & retros)