CommunityWriting & Editinggithub.com

novel-script

Write structured scripts for AI short dramas: turn episode synopses from novel-outline into a beat flow (action beats interleaved with dialogue lines), with each line annotated by speaker and delivery.

What is novel-script?

novel-script is a deterministic, zero-dependency skill for generating structured script data (JSON + Markdown + a single-page review report) for AI short dramas. It operates under the strict philosophy that *script handles the drama, storyboard handles the shoot* — meaning it produces scenes, beat flows, and dialogue as structured data without any camera shots, shot numbers, or generation prompts. Each dialogue line is a self-contained entry (speaker + line + delivery), and each action is a separate beat. The skill enforces 10 quality gates via code checks (e.g., per-episode duration within ±15%, single lines ≤35 characters, valid speakers, hook concretization within the first 3 beats, at least one action beat per scene, and upstream reconciliation of characters/scenes/lighting/props from outline.json and art.json). It integrates seamlessly with a four-skill pipeline (novel-outline → novel-characters → novel-art → novel-script) and uses seed skeletons from outline.json via a deterministic CLI (`node scripts/novel-script.mjs seed | validate | render`). The final output includes a reusable script.json, a human-readable Markdown script, and a self-contained HTML report with KPI dashboards, per-episode scripts, a sequence-of-scenes table, and a character-aggregated dialogue book (with exportable JSON). The skill is designed for fast iteration: small batch sizes (≤3 episodes), immediate validation, and no external API calls or API keys—it runs entirely on the current session's compute. Use when asked to write scripts, scenes, dialogue, or screenwriting for an AI short drama.

Works with✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/eternityspring/shuohao-skills/tree/HEAD/skills/novel-script

Installed? Explore more Writing & Editing skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does novel-script do?

Write scripts for AI short dramas. The core premise etched in bone: script handles the drama, storyboard handles the shoot — "does it feel good?" and "how do we shoot it?" follow two different iteration rhythms. Dialogue is rewritten over and over, and if you tie it to shot decomposition, every line change forces a reshuffle of shots. So this layer has only episodes, scenes, and beat flows — no shot numbers. Camera shots, first-frame prompts, and generation batches are all the job of the next storyboarding skill.

But there is one baseline: dialogue must be structured data, not prose. Every line is an independent entry (speaker + line + delivery), and every action is an independent beat — this is the foundation of all deterministic quality gates:

DeliverableWhat It Solves
Per-episode duration budgetA three-minute episode is three minutes: lines are converted by speaking speed, actions estimated by beat count. Overwriting or underwriting is caught here, not at generation time
Beat flow (action ⇄ dialogue)Dialogue feeds directly into TTS generation line by line; action beats define what happens on screen. Mixing them into prose makes both ends unusable in a pipeline
At least one action beat per sceneA scene with only dialogue is a radio play — AI generation has no visuals to write
Opening hook + closing cliffhangerThe lifeline of short dramas; every episode must have them on paper; the hook is not a label — it is the first beat — hookBeat claims its concrete position, must be within the first 3 beats of the whole episode (cold open)
Satisfaction beat claimIf the outline says this episode has a big payoff, the script must have a scene claiming it — prevents losing the payoff during rewrites
Upstream reconciliationScenes/lighting/props reconciled against art.json, characters against outline.json — reports immediately if a lighting state is written but not registered

{baseDir} = The directory containing this file. The script is {baseDir}/scripts/novel-script.mjs, zero dependencies, run directly with node.

Boundaries (things we don't do): No shot breakdowns, no shot numbers, no visual generation prompts, no image generation, no music scoring — nothing in the storyboarding layer. Don't change outline structure (merging/trimming plotlines is novel-outline's job); don't define characters or scenes (those are novel-characters / novel-art's jobs).


Step 0 — Define Input & Scope

outline.json is the direct upstream of the script (episode synopses, satisfaction beat placements, per-episode duration — all there). The standard workflow starts from it. If there is no outline, first ask the user if they want to run novel-outline; if the user insists on writing directly, create a skeleton by asking for the number of episodes and minutes per episode. The reconciliation gates will explicitly state they are skipped.

How many episodes at once? Default batch ≤ 3 episodes. Script is the layer most heavily reworked in the entire pipeline — output in small batches, get quick sign-off, then move on. Even if the user wants the full series, produce it in batches, each passing validation.

Optionally include (these reconcile/show names if provided):

  • --outline: Character reference reconciliation + satisfaction beat claim check + reports show C01 as character name
  • --art: Scene/lighting state/prop reconciliation + reports show S01 as scene name

Step 1 — Seed the Skeleton

node {baseDir}/scripts/novel-script.mjs seed <outline.json> --eps 1-3 > <workdir>/script.json

Deterministic transfer: target duration (episode minutes × 60), hooks, cliffhangers, per-episode satisfaction beat claims, candidate scenes & characters (put into seedNote). Do not make the model rethink these facts. Leave scenes empty — that's the job of writing the drama.

Step 2 — Write Each Episode's Drama

One task per episode, can run in parallel if possible. Each task receives:

  • {baseDir}/references/script-pass.md and {baseDir}/references/schema.md (read them, follow them)
  • That episode's seed skeleton + the synopsis/satisfaction beats/character group plan from the outline
  • Scene cards (anchors, lighting states from art.json) and character info (personality, speech patterns — better with cast.json)
  • The previous episode's closing cliffhanger (this episode's opening must connect to it)

The core requirements are all in script-pass.md, with the four heaviest being: action beats only describe common actions (carrying a pole onto a boat, putting a hand on a pole and unloading — actions AI has seen millions of times; delicate moves like stretching a pole to block, or a fluttering eyelash, will cause generation failures); duration budget comes first (a three-minute episode has ~50 beats; after writing, run validation to check the seconds); dialogue should be conversational, one breath per line, each character sounds like themselves (use cast.json for personality and speech patterns); the very first beat of each episode must be a cold open concretizing the hook (hookBeat claims it; the gate checks position), and the last beat must be the cliffhanger.

After writing, delete seedNote.

Step 3 — Validation ⛔ Must Not Skip

node {baseDir}/scripts/novel-script.mjs validate <script.json> \
  --outline <outline.json> --art <art.json>

10 quality gates, all code: per-episode duration within ±15% of target (lines converted at 4.5 chars/sec, actions at 2.5 sec/beat, params adjustable), single line ≤ 35 characters, speaker is in the scene's character list or marked VO, every episode has a hook and cliffhanger on paper, the hook's concrete form happens within the first 3 beats of the episode (hookBeat claims it, params.hookWindow adjustable), at least one action beat per scene, action narrative prose doesn't mix with quoted dialogue, satisfaction beat claim, character reconciliation, and scene/lighting/prop reconciliation.

Fix any violations one by one, then rerun until it passes. If over budget, cut action beats first, then compress dialogue. If under budget, add drama without padding — add conflict, not small talk. If you need a lighting state that art hasn't registered, go add that state to art.json first, then come back — don't bypass the gate.

Step 4 — Output & Report

cd <output directory>
node {baseDir}/scripts/novel-script.mjs render <series name>-script.json --md \
  --outline <outline.json> --art <art.json> > <series name>-script.md
node {baseDir}/scripts/novel-script.mjs render <series name>-script.json --html \
  --outline <outline.json> --art <art.json> --cast <cast.json> > script-report.html
# English interface: add --lang en (default is Chinese, or follows the `lang` field at the top of script.json)

The report includes: KPI dashboard (with dialogue ratio), duration gauge (per-episode bar within the target duration band, under/over marked in red), per-episode script (two episodes side by side, scene info fades and truncates after 300px, click to expand), sequence-of-scenes table, dialogue book (two columns, aggregated by character, list six lines high with scrollable container, copyable as a group; with --cast each character group header has a voice timbre prompt button — dialogue and timbre on one page ready to run TTS), quality gate panel, and exportable JSON (downloads the original script.json).

The report summary says in one sentence: how many episodes, scenes, lines; estimated total duration vs target; which episodes are near tolerance edges; the report file path; any failed gates are explicitly stated.

Final deliverables:

<output directory>/
├── <series name>-script.json
├── <series name>-script.md
└── script-report.html             ← Can be opened by double-clicking

The Four-Skill Relay

novel-outline    → outline.json (what: structure & episodes)
novel-characters → cast.json    (who: character assets)
novel-art        → art.json     (where + what's in hand: art assets)
novel-script     → script.json  (drama: scenes, beats, dialogue)

seed consumes outline.json; validate/render's --outline --art handle reconciliation and display names. All four JSON reports have export buttons; after editing, they can be fed back into their respective render/validate. The next layer is storyboarding: shot numbers, per-shot duration, first-frame prompts, and generation batch sheets live there.

Boundaries

  • Report interface built-in bilingual (--lang, default Chinese, or follows the lang field in script.json); dialogue language follows the drama
  • Duration is an estimate, not a stopwatch — the ±15% tolerance accounts for this; params.charsPerSecond can be adjusted based on voice actor speed
  • VO is the universal marker for voice-over; whose inner thoughts it is goes in delivery; in the dialogue book, VO lines form a separate group
  • No per-episode scene count limit — AI scene changes cost nothing; scene change count only goes into KPI statistics, not a gate

Self-Test

node {baseDir}/scripts/selftest.mjs

154 assertions, no model call, no compute credit spent. Each of the 10 quality gates has a break-case test. Run this after modifying the script.

Built-In Example

{baseDir}/examples/渡口-script.json: Ferry Crossing complete 6-episode script (9 scenes, 123 lines of dialogue, each episode's cold open delivers the hook, all within 120 seconds ±15%). All quality gates pass against the novel-outline and novel-art examples. Serves as both a quality benchmark and a test fixture.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Related Skills