novel-script
Write scripts for AI short dramas. A core premise carved into the foundation: the script handles the drama, storyboarding handles the filming — "whether it's satisfying" and "how to shoot it" follow two different iteration rhythms. Dialogue needs to be rewritten over and over, and if tied to shot breakdowns, every single line change would require reworking all shots. Therefore, this layer only includes episodes, scenes, and beat flows — no shot numbers; shots, first-frame prompts, and generation batches are all the job of the next-level storyboarding skill.
But there's one bottom line: dialogue must be structured data, not prose. Each line of dialogue is an independent entry (speaker + dialogue + delivery), and each action is an independent beat — this is the foundation of all deterministic checks:
| Deliverables | What It Solves |
|---|
| Per-episode duration budget | A three-minute episode is exactly three minutes: dialogue is calculated by speech rate, actions are timed by beats. Over or under runs are caught immediately, not discovered only after reaching the generation stage |
| Beat flow (action ⇄ dialogue) | Dialogue directly feeds into TTS for line-by-line generation; action beats are what happens on screen. Mixed into prose, neither can be fed into the pipeline |
| At least one action beat per scene | Scenes with pure dialogue are radio dramas — there's no visual content for AI to generate |
| Opening hook + closing cliffhanger | The lifeline of short dramas, both must be put on paper for every episode; the hook is not a label, it's the first beat — claims the specific position, and must fall within the first 3 beats of the episode (cold open) |
| Payoff claim | If the outline says this episode has a big highlight, the script must have a scene that claims it — to prevent losing the highlight during revisions |
| Upstream reconciliation | Reconcile scenes/lighting/props against art.json, and characters against outline.json. If a lighting state not registered in art is written, it will be flagged immediately |
= the directory where this file is located. The script
{baseDir}/scripts/novel-script.mjs
has zero dependencies and runs directly with
.
Boundaries (what it doesn't do): No shot breakdowns, no shot numbers, no image generation prompts, no image output, no soundtrack — it does not touch any work belonging to the storyboarding layer. It does not modify the outline structure (cutting plot lines or merging characters is the job of
); it does not create character or scene settings (that's the job of
/
).
Step 0 — Define Inputs and Scope
outline.json is the direct upstream of the script (it contains episode synopses, payoff positions, and per-episode duration). The standard workflow starts with it. If it's not available, first ask the user whether to run
; if the user insists on writing directly, clarify the number of episodes and minutes per episode, build the skeleton manually, and the reconciliation gate will explicitly state that it's skipped.
How many episodes to write at once: Default batch size ≤ 3 episodes. The script is the layer with the most revisions in the entire pipeline, so produce in small batches, get quick approval, then continue writing. Even if the user explicitly requests the entire series, produce in batches, with validation for each batch.
Optional add-ons (all optional, only used for reconciliation/displaying names if provided):
- : Character reference reconciliation + payoff claim check + display C01 as character names in the report
- : Scene/lighting state/prop reconciliation + display S01 as scene names in the report
Step 1 — seed Skeleton
bash
node {baseDir}/scripts/novel-script.mjs seed <outline.json> --eps 1-3 > <workdir>/script.json
Deterministic porting: target seconds (minutes per episode × 60), hook, cliffhanger, payoff claim for the episode, candidate scenes and characters (added to
).
Don't make the model rethink these facts. Leave scenes empty — that's the actual scriptwriting work.
Step 2 — Write Drama Episode by Episode
One task per episode, run concurrently if possible. Each task gets:
{baseDir}/references/script-pass.md
and {baseDir}/references/schema.md
(read them and follow the instructions)
- The seed skeleton of the episode + the synopsis/payoff/target audience plan for this episode from the outline
- Scene cards used in the episode (anchors, lighting states from art.json) and character information (personality, speech style — even better if cast.json is available)
- The closing cliffhanger of the previous episode (the opening of this episode must connect to it)
The core requirements are all in script-pass.md, with the four most important ones being:
Only write common actions for action beats (actions AI has seen millions of times, like carrying a pole onto a boat or helping unload a burden; delicate actions like blocking with a pole or fluttering eyelashes will definitely fail in generation);
Duration budget comes before everything (a three-minute episode has about 50 beats, run validate yourself after writing to check the duration); Dialogue should be colloquial, each line said in one breath,
each character's lines sound like them (use the character's personality and speech style from cast.json if available);
The first beat of each episode is the cold open delivering the concrete hook (claimed by
, the gate checks its position), and the final beat must be a cliffhanger.
Step 3 — Validation ⛔ Cannot Be Skipped
bash
node {baseDir}/scripts/novel-script.mjs validate <script.json> \
--outline <outline.json> --art <art.json>
All 10 quality gates are code-enforced: episode duration within ±15% of target (dialogue calculated at 4.5 characters/second, actions at 2.5 seconds/beat, adjustable via
), single dialogue line ≤35 characters, speaker is in the scene's character list or marked
, hook and cliffhanger documented for each episode,
hook concretization delivered within the first 3 beats of the episode (claimed by
,
adjustable), at least one action beat per scene, action narration not mixed with quoted dialogue, payoff claim, character reconciliation, scene/lighting/prop reconciliation.
Fix violations one by one, rerun after changes, until all pass. If over duration, cut action beats first then trim dialogue; if under duration, add meaningful scenes instead of filler — add conflict, not small talk. If you need a lighting state not registered in art assets, add the state to art.json first then come back — do not bypass the gates.
Step 4 — Output and Reporting
bash
cd <输出目录>
node {baseDir}/scripts/novel-script.mjs render <剧名>-script.json --md \
--outline <outline.json> --art <art.json> > <剧名>-script.md
node {baseDir}/scripts/novel-script.mjs render <剧名>-script.json --html \
--outline <outline.json> --art <art.json> --cast <cast.json> > script-report.html
# 英文界面:加 --lang en(默认中文,也可跟 script.json 顶层的 lang 字段)
The report includes: KPI bar (including dialogue ratio), duration dashboard (each episode's bar is plotted on the target interval band, with over/under runs marked in red), episode scripts (two episodes per row, scene info fades and truncates after 300px, click to expand), scene summary table,
dialogue script (two per row, aggregated by character, scrollable list with 6-line height, copyable as a whole; if
is provided, each character group header has a
voice prompt button — dialogue and voice are configured on one page for direct TTS running), quality gate panel, and JSON export (the downloaded file is exactly the original script.json).
Summarize the report in one sentence: number of episodes, scenes, and dialogue lines, estimated total duration vs target, which episodes are close to the tolerance edge, report path; explicitly state any gates that didn't pass.
Final output structure:
<输出目录>/
├── <剧名>-script.json
├── <剧名>-script.md
└── script-report.html ← 双击就能开
The Four-Skill Relay
novel-outline → outline.json (什么:结构与分集)
novel-characters → cast.json (谁:角色资产)
novel-art → art.json (哪里 + 手里拿的:美术资产)
novel-script → script.json (戏:场次、节拍、台词)
seed consumes outline.json; the
and
flags for validate/render are responsible for reconciliation and name display. Each of the four JSON files has an export button in its respective report, and after modifications, they can be fed back into their respective render/validate processes. The next layer down is storyboarding: shot numbers, per-shot duration, first-frame prompts, and generation batch sheets are all there.
Boundaries
- The report interface has built-in Chinese and English support (, default Chinese, or follows the field in script.json); dialogue language follows the drama
- Duration is an estimate, not a stopwatch — the ±15% tolerance is reserved for this; can be adjusted based on dubbing speed
- is the unified notation for voiceover; a character's inner thoughts are written in ; VO is grouped separately in the dialogue script
- No upper limit on scenes per episode — AI scene changes are free, scene change count is only included in KPI statistics and has no gate
Self-Test
bash
node {baseDir}/scripts/selftest.mjs
154 assertions, no model calls, no quota consumption. Each of the 10 quality gates has failure test cases. Run this first after modifying the script.
Built-in Example
{baseDir}/examples/渡口-script.json
: The
complete 6-episode script of Ferry Crossing (9 scenes, 123 dialogue lines, each episode delivers the hook in a cold open and falls within 120 seconds ±15%). All quality gates pass when checked against the novel-outline and novel-art examples. It serves as the quality benchmark and also as a self-test fixture.