---
name: short-drama-script
description: "Short-drama / short-video script workbench (upstream creative layer): concept → skeleton (a beat sheet metered in seconds) → words (verbatim dialogue), including de-AI-flavored dialogue, shootability checks (AI generation constraints) and voiceover pacing estimates, with output that plugs directly into the S0 four tables of video-production-pipeline. Use when the user asks to \"write a script\", \"write dialogue\", \"make up a story\", \"think of a short drama\", says \"this dialogue sounds unnatural\", \"the lines sound AI-written\", \"help me revise the lines\", or asks for \"episode breakdown\", \"write an outline\", \"design characters\"."
---

> Original skill · commissioned by the user · English edition, 2026-11-12

# Short-Drama Script Workbench (Creative Layer)

## 0. Role and boundaries (**read this section first so you do not collide with the production pipeline**)

| Layer | Skill | Owns |
|---|---|---|
| **Creative layer (this skill)** | `short-drama-script` | **What to write**: concept, structure, characters, **verbatim dialogue** |
| Production layer | `video-production-pipeline` | **How to shoot it**: aspect-ratio lock, anchor images, keyframes, image-to-video, voiceover and music, compositing and delivery |

**Files in this skill**: `SKILL.md` (workflow) · `references/01–04` (craft detail) ·
`scripts/check_script.py` (deterministic dialogue-level checks) · `tests/` (regression cases, to prevent rollback) · `templates/` (formats for the three tables) ·
**`LESSONS.md` (cross-project lessons ledger, see §8)**

**There is exactly one handoff point: the S0 four tables.** The output of this skill = the input for Table 1 (script revision) / Table 2 (character card) / Table 3 (sound design); Table 4 (aspect-ratio lock) is set by the user or the production layer, but **you must already know it while writing the script** (see §4).

> ⚠️ **Do not discuss model parameters, cost or APIs in this skill** — that is the production layer's business.
> ⚠️ **Do not improvise dialogue in the production layer either** — that is exactly the root cause of "audio and picture out of sync" and "robot tone".

---

## 1. Three stages (**the order cannot be swapped**)

```
P1 Concept  →  P2 Skeleton  →  P3 Words
(one sentence)  (beats metered in seconds)  (verbatim dialogue)
   ↓            ↓             ↓
 logline     beat sheet / episode map   script table → S0 four tables → handoff to the production pipeline
```

### P1 Concept (4 lines out, no more than half a page)

1. **Logline**: one sentence containing "who + in what situation + wants what + who blocks it + what it costs".
   *Counter-example*: "a girl's love story" (no person, no resistance, no cost)
2. **Premise and theme**: the **premise** (the causal assumption the story rests on) and the **theme** (the sentence the ending proves).
   *Example*: premise "he believes silence is consideration"; theme "care you never say out loud counts as no care at all".
3. **Three character questions** (answer for every main character):
   - What he **wants** (external goal)
   - What he **fears** (internal fear)
   - What he **refuses to admit** (self-deception) → **every piece of subtext in the dialogue grows from here**
4. **Audience and platform**: Douyin/WeChat Channels (vertical, 3-second hook, one peak every 10–15 seconds) or Bilibili/YouTube (horizontal, can be slow).

> The concept stage **delivers text only, no dialogue lines**. Move to P2 only after the user confirms the concept.

### P2 Skeleton (**short video must be metered in seconds, not in "scenes"**)

Produce a **beat sheet**, one beat per row: `second range | beat name | visible change that happens | emotion value (-9~+9) | hook type`

- **Golden 3 seconds**: the first beat must be one of **conflict / suspense / anomaly**; it cannot be scene-setting.
- **Pacing**: shot lengths of 1–4 seconds alternate; **an even pace across the whole piece is forbidden** (all 2-second shots = commercial pacing, see production-layer gate 7).
- **Peak placement**: one emotional peak every 10–15 seconds; end on an **unclosed** hook (to drive following the series).
- **Emotion curve**: write the value for every beat and **make the curve rise and fall**; three consecutive beats with the same sign (all below -5) = viewers will swipe away.

For multiple episodes, produce the **episode map first** (one sentence per episode + an episode-end hook), then write a single episode. **If the episode map is not confirmed, do not write the body of episode 1.**

### P3 Words (**verbatim dialogue + performance notes**)

Use `templates/script_table_template.csv`, one line per utterance:

| Column | Requirement |
|---|---|
| Shot no. | S01 |
| Speaker | Unique (with ID; identical spelling across shots) |
| **Verbatim line** | **Every character fixed**, no paraphrasing |
| Performance note | A **physiological reaction** (inhale, throat moving, fingers clenching), not "sad" or "angry" |
| On-screen / off-screen | Full-face speaking / voice-over / reaction shot (determines the production layer's lip-sync plan) |
| Estimated duration | Estimated at **4.3 characters/second**; the formula is in §4 |

**Dialogue naturalization** (the core craft of this skill, in a separate book): → `references/02-dialogue-naturalization.md`
**Shootability check** (hard constraints of AI generation): → `references/03-shootability-and-ai-constraints.md`
**Structure and beat template library**: → `references/01-structure-and-beats.md`

---

## 2. Dialogue hard rules (**six, each checkable**)

The user's exact words were "it does not feel like a real person". Real-person feel does not come from prose skill; it comes from these six rules:

| # | Hard rule | What breaking it looks like |
|---|---|---|
| 1 | **Speak like a person, not like written prose**. Spoken language has no "therefore / however / whether / moreover / extremely" | the line reads like a public notice |
| 2 | **One idea per sentence; split long sentences**. Vertical single line ≤12 characters (production-layer subtitle limit) | two turns packed into one sentence |
| 3 | **Answering beside the point, interrupting, talking over** is what real people do | every question answered, every sentence complete |
| 4 | **Subtext > saying it plainly**. Characters rarely state their real need | "I'm sad, because I waited for you so long" |
| 5 | **No explaining**. A character is not responsible for briefing the audience on the setup | "After all, we dated for two years, you've always been like this" |
| 6 | **Every line must land on a physical action**; if it cannot, it is exposition | the whole scene has only a moving mouth |

**AI-flavor sentence blacklist** (deterministic and detectable; `check_script.py` blocks it):

`not X, but Y` | `no X, no Y, and no Z` (negation parallelism) | em-dash close used as an uplift `——`
| dense `as if / seemingly / inexplicably / cannot help but / a trace of / slowly / slightly` | `actually ... after all ...` deliberative wrap-up
| rule-of-three parallelism | symmetrical antithesis | explanatory connectives `because / so / after all / in the end`

> Source: `story-deslop` in `zenstory-ai/oh-story-claudecode` (its sentence-pattern taxonomy for writing lint);
> this skill **adapts it from a fiction context to a dialogue context**; the rules are in `references/02`.

---

## 3. Shootability gate (**must pass after writing; no handoff without it**)

In an AI-generated short drama, every line in the script must be "shootable". Ask four questions per shot:

1. **Can this shot be expressed as "one image + one line of dialogue"?** If not → split the shot or change the expression.
2. **Are there elements AI always fails at?** Multi-person interaction in one frame, precise hand actions, readable text on screens,
   crowd scenes, complex prop interaction → rewrite (see `references/03`).
3. **Is a full-face speaking shot necessary?** A full face carries real-person-detection risk; **change it to "voice-over + reaction shot" whenever you can**;
   when a full face is required, use a **medium shot** (a close-up full face has the highest rejection rate).
4. **Are there "common-sense error" risks?** Which side of the phone faces up, how many fingers, what shape the container is,
   whether food gives off steam — **write it into the prompt, do not wait to fix it after generation** (production-layer gate 11).

---

## 4. Voiceover pacing estimate (**it determines shot length; you do not compress the speaking rate the other way round**)

| Parameter | Value | Use |
|---|---|---|
| Chinese natural speaking rate | **4.3 characters/second** | estimate spoken duration |
| Korean natural speaking rate | **4.5 syllables/second** (conservative baseline; measured about 5.5–6.0, take the smaller value so shot length stays generous) | Korean lines are estimated in **syllables**; one Hangul syllable block counts as 1 |
| Target band | 3.5–5.5 characters/second | outside it = change the words, not the rate |
| Newscaster-tone red line | **> 6.5 characters/second** | must split sentences |
| Pause between sentences | **0.25–0.5 s** | write it into the sound design table |
| Vertical subtitle single line | ≤ 12 characters | determines line breaks |
| Korean subtitle single line | horizontal ≤ 20 syllables / vertical ≤ 15 | Korean line breaking; the script is capped by `--maxchars`; the language comes from `--lang` or autodetection |

**Shot length formula**: `shot length ≥ dialogue character count ÷ 4.3 + 0.4s (silent tail beat)`

- If the shot is too short → **change the words or split the shot**; do not compress the speaking rate (compressing it turns the read into newscaster tone).
- **The start and end of speech must be measured** (write a line, read it once, record the real seconds); counting characters only gives an "estimate".

---

## 5. Deliverables and handoff (**the script is not written until you get here**)

| Output of this skill | Handed to | Use in the production layer |
|---|---|---|
| Script table (verbatim lines + speaker + on/off screen) | S0 **Table 1** | the lines are the verbatim voiceover script and may not be changed again |
| Character card (look + voice + **matching rationale** + source of subtext) | S0 **Table 2** | anchor image (look) + voiceover (voice) |
| Sound design table (per-shot speech in/out / lip-sync plan / ambience / foley / BGM intent) | S0 **Table 3** | voiceover and music |
| Beat sheet | S1 storyboard | shot length and peaks |

**Run the check once before handoff**:

```powershell
python scripts/check_script.py --script script_table.csv --out review/script_lint.md
```

It checks: AI-flavor sentence patterns / line length and estimated duration / whether the shot is long enough / whether speaker spelling is consistent /
shootability risk words / whether performance notes contain only emotion words and no action. **Any blocking item means no handoff.**

---

## 6. Anti-pattern list (pitfalls from past runs, check against them one by one)

| Anti-pattern | Consequence | Correct approach |
|---|---|---|
| Generate images before writing dialogue | audio and picture out of sync, lip-sync mismatch | **write the words first, then generate images** |
| Dialogue written only as a paraphrase | the voiceover improvises, adds and drops words | **fix every character** |
| Dialogue is all explanatory lines | looks like an ad / a notice | subtext + action |
| The scene says "two people chatting in the living room" | random results, missing characters | state **who is where, doing what, and what is visible** |
| A 30-character line | does not fit vertical, the voiceover rushes | split or reword |
| Even 2-second shots throughout | commercial feel | design the rhythm in seconds |
| Writing "she smiled a little" | image-to-video cannot render it | write "the corner of her mouth lifts halfway, the eyes do not follow" |

---

## 7. Reference sources (external projects, **cite, do not copy**)

| Project | What was borrowed |
|---|---|
| [jtydhr88/screenwriting-skills](https://github.com/jtydhr88/screenwriting-skills) | the craft system for structure / character / dialogue / scene (distilled from 19 theory books) → the beat and character parts of `references/01` |
| [zenstory-ai/drama-skills](https://github.com/zenstory-ai/drama-skills) | "five documents, each owning one layer", "continuity lock" and **deterministic checks** → the handoff table in §5 and `check_script.py` |
| [zenstory-ai/oh-story-claudecode](https://github.com/zenstory-ai/oh-story-claudecode) | the sentence-pattern taxonomy for **de-AI-flavoring** (em-dash / not-X-but-Y / negation parallelism / verbal-tic density) → the blacklist in §2 |

> All three projects are independent, complete workflows. **This skill extracts only the parts that connect to "AI short-drama production"**
> and does not carry over whole sets (installing a whole set adds 20+ skill descriptions to every conversation round and conflicts with the production-layer rules).

## 8. Lessons feedback protocol (**required after every project delivery, 5 minutes**)

> **This section covers what to record; "how" is in the `project-retro` skill** (evidence collection → three-way attribution → rule audit → change table → approval → lock-in).

This skill **accumulates experience project by project**; it is not written completely in one pass. Everything accumulates in `LESSONS.md`.

**Trigger**: after a project delivery (or when the user says "retrospective" or "sum it up").

**Follow these three questions; do not improvise**:

1. **Where did this round get reworked?** (rework = a missing rule, or a rule that existed but did not fire)
2. **What did it cost?** (money / number of reworks / manual labour) — **anything with a real cost can be upgraded on a single occurrence**
3. **Which existing rule failed to fire?** If the rule existed but did not catch it, the **landing spot is wrong**: something that belongs in a script was written as prose.

**Then**: append one row to `LESSONS.md` (`Observing`); do not rush to change rules.

| Status transition | Threshold |
|---|---|
| `Observing` → `Upgraded` | **reproduced ≥2 times**, or **once only but with a real cost** (rework / wasted generation spend / a rejected delivery) |
| `Upgraded` → `Deprecated` | not reproduced across 3 consecutive projects (to stop the skill bloating as it is edited) |

**Where to upgrade to** (choose by nature; do not stuff everything into `SKILL.md`):

| Nature of the lesson | Landing spot |
|---|---|
| sequence / timing ("must do A before B") | a `SKILL.md` hard rule or stage description |
| craft-level how-to-write and how-to-fix | the matching `references/` subsection |
| **mechanically checkable** (sentence pattern / character count / ratio / share) | add a check to `scripts/check_script.py` |
| merely "bad luck this time" | leave it in `LESSONS.md`, **do not upgrade** |

> ⚠️ **Two hard constraints**
> 1. **A lesson must not exist only in the conversation.** A past round lost this way: several valuable findings sat scattered in the conversation
>    and only entered the skill after the user pushed for it. **A lesson not written into `LESSONS.md` = not captured.**
> 2. **Before editing, read §5 "Correction history of the skill itself" in `LESSONS.md`.** Some changes were settled only after a pitfall
>    (for example, the length check moved from "whole-sentence character count" to "clause level"); reverting them during a refactor brings the false positives straight back.

**Self-check when editing this skill (hard requirement)**: after touching `check_script.py` or any threshold you **must run**

```powershell
python tests/run_tests.py      # 12 assertions; done only when all green
```

It freezes the historic false positives and misses from `LESSONS.md` §5 as test cases (including positive assertions such as "an accepted good line must not be blocked").
**"Do not change it back" written only in a document does not work** — the counter-example must be re-runnable with one command.

---

## Working discipline (three hard rules, **read before changing anything**)

**① Research first** — before creating or heavily changing a skill or a process, you must first check the **skills already on this workstation** and the **online space (GitHub / plugin marketplaces)** for an existing solution, and give the three-part conclusion: **what was found → adopt / do not adopt → why**.

- A reason for not adopting must be specific (license restriction / conflict with existing rules / maintenance cost / context burden); "not suitable" is not allowed
- When a reusable solution is found, **reuse it or borrow only the method**; do not rewrite it
- Basis: three recurrences (an audio round asking "what open-source options exist", a script skill asking "check whether one already exists before building", a retro skill asking "online and offline")

**② Do not expand scope on your own** — scope expansion the user did not ask for is **proposed only, never executed**;
a proposal must **state the cost explicitly** (skill list +N items, per-round context +X, how many files added), and the user decides.

- Exception: when not expanding scope would lead to a **wrong conclusion or a safety risk**, stop and explain instead of continuing on your own initiative
- Basis: the round-trip where "operate a body-copy-level lint" was borrowed and then reverted

**③ Budget first** — **make the budget → report the budget → plan within the approved amount → keep the ledger → reconcile**, a five-step loop.
**You may not start until ① and ② are done; you may not call any paid interface until ③ is passed.**

| Step | Action | Hard requirement |
|---|---|---|
| ① **Make the budget** | `python <PIPELINE>/scripts/budget_plan.py --budget <amount> --durations <shot seconds> --plan-out <PROJECT>/spend_plan.md` | must include a **rework reserve** (default 25%, not optional) and a **tier lock** |
| ② **Report the budget** | hand the plan to the user and obtain an **explicitly approved amount** | an empty "approved amount" field in the plan = **not approved = do not start** |
| ③ **Plan within the amount** | scope / shot count / duration / tier are **back-solved from the amount** | amount too small → **cut scope** (lower tier → fewer shots → shorter duration); **do not exceed the budget** |
| ④ **Keep the ledger** | book every charge immediately, **including rejected ones at 0** | planning without booking actuals = the easiest place to fail (a past run overspent because of it) |
| ⑤ **Reconcile** | settle: plan vs paid | more than **10%** over plan → stop and re-request approval; **changing tier = changing the plan = re-requesting approval** |

```powershell
# 1) make the budget (amount -> plan; the price table reuses cost_preflight.py, single source of truth)
python <PIPELINE>/scripts/budget_plan.py --budget 6 --durations 4,4,4 --anchors 1 --plan-out spend_plan.md
# 2) when you only know the amount, first solve for the maximum number of shots
python <PIPELINE>/scripts/budget_plan.py --budget 6 --max-shots --duration-each 4
# 3) ledger / audit / gate (over budget exits with code 1)
python <PIPELINE>/scripts/cost_ledger.py add --ledger <PROJECT>/cost_ledger.json --item "clip_01" --cost 1.20
python <PIPELINE>/scripts/cost_ledger.py check --ledger <PROJECT>/cost_ledger.json
```

- Measured: with a budget of 6 units, **a single 4-second shot at the main tier (14.96) already overspends by 2.5x** — planning without counting money guarantees rework
- Division of labour between the three tools: `budget_plan.py` amount → plan | `cost_preflight.py` storyboard → money | `cost_ledger.py` actuals → ledger
- Basis: **most past projects kept no ledger**; a past round paid far over plan
