YAML Screenplay Schema v1.0

适用于电影 (movie)、电视剧 (tv_series)、短剧 (short_drama) 三种格式的结构化剧本定义。

快速示例

yaml
meta: format: movie title: "流浪地球" genre: [sci-fi] characters: - id: CH-001 name: "刘启" category: main gender: male description: "地下城居民" scenes: - id: SC-001 source_chapter: 1 heading: interior: false location: "地下城 - 公路" time_of_day: day blocks: - type: dialogue character_id: CH-001 text: "希望,像钻石一样珍贵。" delivery: voice_over - type: transition text: "CUT TO:"

设计理念

三层分离

meta(元信息)→ characters(角色表)→ scenes(场景集),对应剧本工业标准的"故事大纲 → 人物小传 → 场次表"。

单一数据源

角色通过 CH-001 格式 ID 引用。改角色名只需改一处,杜绝数据不一致。

discriminatedUnion

3 种 block 类型(action / dialogue / transition),每种只携带自己的字段。Zod 在编译期拒绝非法组合。

格式靠 Schema,内容靠 Prompt

LLM 输出 JSON + Zod 校验保证格式正确;Prompt 专注于内容决策(切场景、提角色、转对白)。

枚举归一化

AI 枚举输出不稳定 → 后端别名映射表自动修正(如 protagonist→main, evening→dusk),转换不因枚举值偏差而失败。

系统字段注入

language / version / generated_at / generator 由后端注入,LLM 不负责生成,减少无效认知负担。

meta — 元信息

字段类型必填说明
formatenummovie | tv_series | short_drama — 顶层分支开关,决定 episode 字段是否必填、幕结构、场景粒度
titlestring剧本标题
subtitlestring副标题
genrestring[]类型标签:sci-fi / romance / mystery / history / fantasy / other
sourceobject改编来源:{ type, title, author? }
languagestring语言代码,默认 zh-CN(系统注入)
versionstringSchema 版本号(系统注入)
generated_atstringISO 8601 生成时间(系统注入)
generatorstring生成工具标识(系统注入)
三种格式的 Schema 差异:
电影 (movie):episode 字段省略,按 act(1/2/3 幕)组织,8-20 个场景,transition 用 CUT TO
电视剧 (tv_series):episode 字段必填(从 1 递增),每集 5-10 个场景,每集末 transition 用 FADE OUT 或 END OF EPISODE
短剧 (short_drama):episode 固定为 1,5-10 个场景,action block 极度精简(1-2 句),全用 CUT TO 快速切换

characters — 角色表

字段类型必填说明
idstringCH-001 格式,全局唯一引用键
namestring角色名
aliasesstring[]别名/化名/绰号
categoryenummain | supporting | guest | cameo | extras
genderenummale | female | other
age_displaystring展示年龄,如 "28岁"
archetypestring角色原型:hero / mentor / love_interest / villain…
traitsstring[]性格标签
descriptionstring一句话角色简介
arcstring角色弧光简述
relationshipsarray重要关系:[{ target, type, description? }]
notesstring自由文本扩展口
为什么用 ID 引用而非内联? 一个角色可能出现在 30 个场景中。ID 引用 = 数据库范式化在剧本领域的应用。改一处生效全局。

scenes — 场景集

字段类型必填说明
idstringSC-001 格式
scene_numberint显示序号
episodeint所属集号(电影格式省略)
actint幕号(1/2/3)
source_chapterint来源章节号(小说改编核心字段)
headingobject场景标题(见下方)
summarystring本场一句话概括
characters_presentstring[]出场角色 ID 列表
propsstring[]重要道具
blocksarray剧本内容块(顺序执行)

heading 子字段

字段类型必填说明
interiorbooleantrue = INT.(内景)/ false = EXT.(外景)
locationstring"大地点 - 具体位置"
time_of_dayenumdawn / morning / afternoon / dusk / day / night
extrastring闪回 / 梦境 / 蒙太奇(开放文本)
time_of_day 可选值: dawn(拂晓)、morning(晨)、afternoon(午后)、dusk(黄昏)、day(日)、night(夜)。默认 day。

blocks — 剧本内容块

三种类型,通过 Zod discriminatedUnion 按 type 字段分发校验:

action — 动作/场景描写

yaml
- type: action text: "窗外大雨倾盆。张三坐在沙发上,盯着手中的信。"
字段类型说明
textstring动作/环境/人物入场描述

dialogue — 对白

yaml
- type: dialogue character_id: "CH-001" text: "你终于来了。" parenthetical: "(低声)" # 可选:表演提示 delivery: on_screen # 可选:on_screen | voice_over | off_screen emotion: "压抑的愤怒" # 可选:情感标注 continuation: false # 可选:被 action 打断后继续
字段类型说明
character_idstring引用 characters[].id
textstring对白内容
parentheticalstring(低声) 等表演提示
deliveryenumon_screen | voice_over | off_screen
emotionstring情感标注,比自由 parenthetical 更结构化
continuationboolean对白被 action 打断后继续同一角色
V.O. 硬约束: voice_over 旁白必须在原文有对应文字。禁止将"她很不安"这类概括性心理描述改写为具体独白。

transition — 转场

yaml
- type: transition text: "FADE OUT."
字段类型说明
textstringCUT TO: / FADE OUT / DISSOLVE TO / MATCH CUT TO
为什么只有 3 种? character_cue(角色出场)并入 action,parenthetical(表演提示)并入 dialogue。类型越少 → LLM 决策负担越小 → 输出一致性越高。

episodes — 剧集(电视剧/短剧)

字段类型必填说明
idstringEP-01 格式
numberint集号
titlestring本集标题
cold_openboolean是否有冷开场(片头前悬念场景)
synopsisstring本集一句话概要
电影格式不使用此字段。 不输出 episodes: null 或 episodes: [],直接省略整个键。场景属于哪一集由 scenes[].episode 字段标注,不设反向引用,避免双向数据不一致。

ID 格式规范

实体格式示例Zod 正则
角色CH-001CH-001, CH-042/^CH-\d{3}$/
场景SC-001SC-001, SC-099/^SC-\d{3}$/
剧集EP-01EP-01, EP-12/^EP-\d{2}$/

枚举归一化

AI 输出的枚举值可能不稳定(如把 main 写成 protagonist,把 dusk 写成 evening)。 后端预处理层内置了别名映射表,自动将非标准值修正为合法枚举,确保转换不会因枚举不匹配而失败。

字段AI 可能输出(示例)自动修正为
characters[].categoryprotagonist, antagonist, villain, heromain, supporting
characters[].genderman, woman, 男, 女, m, fmale, female, other
heading.time_of_dayevening, sunset, midnight, sunrisedusk, night, dawn
relationships[].typefriend, brother, teacher, husbandally, family, mentor_student, lover
meta.genrescience_fiction, thriller, wuxiasci-fi, mystery, history
归一化策略: 精确匹配 → 小写匹配 → 别名映射 → 关键词模糊匹配 → 保留原值让 Zod 报错(兜底)。定义见 lib/converter.ts 中的 normalizeEnum() 函数。

向后兼容

未来新增 block 类型(如 montage、lyrics)时,在 Zod discriminatedUnion 末尾加 fallback 对象:

typescript
// 允许未知 type 通过而不报错 z.discriminatedUnion('type', [ ActionBlockSchema, DialogueBlockSchema, TransitionBlockSchema, z.object({ type: z.string(), text: z.string() }), // catch-all ]);

也可通过 meta.version 字段判读版本,选择对应 Zod Schema 进行校验。