@dsh-gis/dsh-video-studio-skill 0.9.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +424 -0
  2. package/README.md +287 -327
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/package.json +9 -10
  5. package/schemas/design.schema.json +722 -0
  6. package/schemas/film.schema.json +4 -15
  7. package/schemas/proposal.schema.json +133 -0
  8. package/skills/video-studio/SKILL.md +1316 -1123
  9. package/skills/video-studio/assets/design_fixture.json +141 -0
  10. package/skills/video-studio/assets/film.json +1 -2
  11. package/skills/video-studio/assets/golden_frames.json +11 -8
  12. package/skills/video-studio/assets/scenes.py +67 -22
  13. package/skills/video-studio/assets/voice_loudness.json +16 -0
  14. package/skills/video-studio/references/audio-variation.md +15 -11
  15. package/skills/video-studio/references/audio.md +36 -34
  16. package/skills/video-studio/references/change-impact.md +3 -3
  17. package/skills/video-studio/references/frame-qa.md +2 -2
  18. package/skills/video-studio/references/proposal.md +177 -0
  19. package/skills/video-studio/references/quality-gates.md +1 -1
  20. package/skills/video-studio/references/scene-grammar.md +28 -23
  21. package/skills/video-studio/references/sfx-design.md +1 -1
  22. package/skills/video-studio/references/style-packs.md +95 -257
  23. package/skills/video-studio/references/v08-quality.md +8 -8
  24. package/skills/video-studio/references/web-engine.md +1 -1
  25. package/skills/video-studio/references/word-timeline.md +2 -2
  26. package/skills/video-studio/scripts/designkit.py +2120 -0
  27. package/skills/video-studio/scripts/filmcheck.py +7 -33
  28. package/skills/video-studio/scripts/filmkit.py +153 -78
  29. package/skills/video-studio/scripts/grammar.py +67 -7
  30. package/skills/video-studio/scripts/musicgen.py +2043 -0
  31. package/skills/video-studio/scripts/preflight.py +10 -3
  32. package/skills/video-studio/scripts/previewkit.py +849 -0
  33. package/skills/video-studio/scripts/propose.py +825 -0
  34. package/skills/video-studio/scripts/qa_frames.py +45 -10
  35. package/skills/video-studio/scripts/qavmaf.py +77 -11
  36. package/skills/video-studio/scripts/render.py +472 -154
  37. package/skills/video-studio/scripts/scorekit.py +50 -1748
  38. package/skills/video-studio/scripts/selfcheck.py +658 -131
  39. package/skills/video-studio/scripts/stagewatch.py +21 -5
  40. package/skills/video-studio/scripts/stylekit.py +265 -741
  41. package/skills/video-studio/scripts/voicekit.py +502 -380
  42. package/skills/video-studio/scripts/webengine.py +15 -14
  43. package/tools/audio_similarity.py +57 -30
  44. package/tools/ci_check.py +7 -1
  45. package/tools/estimate.py +14 -8
  46. package/tools/golden_frames.py +56 -11
  47. package/tools/silhouette_qa.py +521 -168
  48. package/docs/demo-pil-sheet.png +0 -0
  49. package/docs/styles/demo-results.json +0 -76
  50. package/docs/styles/sheet-8-styles.png +0 -0
  51. package/docs/styles/sheet-ai.png +0 -0
  52. package/docs/styles/sheet-before-after.png +0 -0
  53. package/docs/styles/sheet-craft.png +0 -0
  54. package/docs/styles/sheet-night.png +0 -0
  55. package/skills/video-studio/assets/score_demo.json +0 -307
@@ -0,0 +1,177 @@
1
+ # 提案层(Proposal)与设计 DSL —— v1.0.2
2
+
3
+ > 一句话:**出片之前先出方案;方案由用户拍板;拍板的那份设计被冻结成 design.json,渲染只认它。**
4
+ > v1.0.2 起还有一条:**交付过的设计会进台账**,下一次提案主动避开——这是"不同片不重复"的落地机制。
5
+
6
+ ## 0. 为什么要有这一层
7
+
8
+ v0.9 及以前,`style: "auto"` 会让 `pick_style` 按关键词 + 指纹**自动挑一套**内置风格。
9
+ 这带来两个后果(都有实测):
10
+
11
+ | 后果 | 实测 |
12
+ |---|---|
13
+ | 同一份内容的身份是确定的 —— 改不出第二种样子 | 8 个不同题材只命中 5/8 套风格,其中 3 个都落进 tech-deep |
14
+ | 不写 `style` 就直接落到 legacy —— 全片只有一套皮肤 | 8/8 题材全落 legacy:120BPM / Dm / 同一套配色 |
15
+
16
+ v1.0 把这条路径**整条删掉**:剧本不再决定长相,长相由 `design.json` 决定;
17
+ `design.json` 只能由「用户确认过的提案」产生。v1.0.1 又把残留的风格表全部删除,
18
+ 所以现在**没有"以某套预设为起点"这回事**——每次都是现场采样。
19
+
20
+ ## 1. 三个产物
21
+
22
+ | 文件 | 谁写 | 语义 |
23
+ |---|---|---|
24
+ | `work/proposal.json` | `propose.py` | 一版提案:N 个候选(含 design + 静帧 + 成本 + 差异度 + 台账比对结果)+ 确认状态 |
25
+ | `work/design.json` | `propose.py --confirm` | **冻结**后的那一份设计(唯一真源,渲染只认它) |
26
+ | `work/proposals/revN/proposal.json` | `propose.py` | 每一版的快照(rev 不覆盖,可 diff、可回滚) |
27
+
28
+ ## 2. 流程(零拷贝:脚本留在技能目录里直接跑)
29
+
30
+ ```bash
31
+ # 1) 出一版方案(离线,不联网,秒级)
32
+ python <SKILL_DIR>/scripts/propose.py --brief "AI 大模型的三年,30 秒科普" --script film.json --work work --n 3
33
+
34
+ # 产物:work/proposal.json + work/proposals/rev1/{A,B,C}/_sheet.png + _compare.png
35
+ # 每个候选带:立意一句话、每个候选 4 张静帧、与其它候选的设计距离(n = 不同的维度数)
36
+
37
+ # 2) 不满意就提要求重出(新 rev,不覆盖旧的)
38
+ python <SKILL_DIR>/scripts/propose.py --revise "太冷了,要暖一点、女声、节奏快一点" --work work
39
+
40
+ # 3) 对比两版
41
+ python <SKILL_DIR>/scripts/propose.py --diff 1 2 --work work
42
+
43
+ # 4) 确认其中一个 -> 冻结 design.json(同时记进片间去重台账)
44
+ python <SKILL_DIR>/scripts/propose.py --confirm --candidate B --work work
45
+
46
+ # 5) 现在才允许出片。--scenes 不写就用剧本同目录 / 技能内置的渲染器
47
+ python <SKILL_DIR>/scripts/render.py --script film.json --work work --out out/film.mp4 --stage all
48
+ ```
49
+
50
+ ## 3. 提案闸(frames 之前)
51
+
52
+ `render.py` 在 `frames` / `all` 之前会调 `_proposal_gate()`,判定五档:
53
+
54
+ | 状态 | 含义 | 默认行为 |
55
+ |---|---|---|
56
+ | `confirmed` | 已确认,且 `design.json` 指纹与确认时一致 | 放行(记 pass) |
57
+ | `absent` | 没有任何提案 | 警告(`--require-proposal` 下失败) |
58
+ | `draft` | 有提案但没确认 | 同上 |
59
+ | `stale` | 确认过但 `design.json` 被改过 | 同上 |
60
+ | `broken` | `proposal.json` 坏了 | 同上 |
61
+
62
+ 为什么默认只警告:`--stage frames` 是开发期高频命令(改一帧看一帧)。要硬拦就加 `--require-proposal`。
63
+
64
+ `design.json` 同时是 stagewatch 的**第三个源头输入**(另外两个是 `film.json` 与 `scenes.py`):
65
+ 改了设计但没重跑 `frames`,`--stage explain` 会直接报出来。
66
+
67
+ ## 4. design.json 的形状
68
+
69
+ 六块:`structure`(几段/什么用途/目标时长)、`visual`(配色/字体/母题/转场/动效/重心/版式/版式轮换/HUD/字幕/画幅)、
70
+ `audio`(声音/配乐/音效)、`pacing`(留白与停留)、`id`/`pitch`(标识与立意)。
71
+
72
+ 完整契约见 `<REPO>/schemas/design.schema.json`;校验器是 `designkit.validate_design()`,
73
+ 命令行入口 `python <SKILL_DIR>/scripts/designkit.py --lint work/design.json`。
74
+
75
+ ### 4.1 fail-closed(这条最重要)
76
+
77
+ 设计里**缺字段、枚举越界、对比度不达标**,一律报错,**绝不静默回落默认值**。
78
+ 理由:v0.5–v0.9 最大的病就是「改了不生效也不报错」——审计实测出 11 个静默失效的旋钮
79
+ (`voice` 写字符串时 map/jitter 全失效、`theme_overrides.ease` 被视觉语言遮住、
80
+ `sfx.cues[].seed` 必崩、`pan` 对立体声配方无效……)。设计层不允许重演这一幕。
81
+
82
+ ### 4.2 visual.subtitle(v1.0.2,可选)
83
+
84
+ 字幕样式不再写死在 `filmkit` 里。所有字段可选,**不写 = 补齐默认值且与过去逐像素一致**:
85
+
86
+ | 字段 | 默认 | 取值 | 说明 |
87
+ |---|---|---|---|
88
+ | `size` | 46 | 20–96 | 字号 |
89
+ | `y` | null | 0–1030 | 字幕带基准线;null = 默认贴底安全区 |
90
+ | `align` | center | center / left | 对齐 |
91
+ | `plate_alpha` | 170 | 0–255 | 背板透明度(0 = 无背板) |
92
+ | `radius` | 10 | 0–48 | 背板圆角 |
93
+ | `family` | null | sans / serif / kai / round | null = 跟随大标题字族 |
94
+ | `color` | null | [r,g,b] 或 #rrggbb | null = 默认墨色 |
95
+ | `max_lines` | 2 | 1–3 | 最多折几行 |
96
+
97
+ 渲染侧只读 `designkit.subtitle_of(design)` 这一份口径(`filmkit`、参考帧渲染共用),避免"字幕样式在两处漂移"。
98
+
99
+ ### 4.3 visual.layout_cycle(v1.0.2,可选)
100
+
101
+ 按**章节**轮换版式:同一章内版式固定,换章才换。元素取 `left-stack` / `center-stack` / `split-right`,
102
+ **至少 2 种不同版式**(只写一种会被 `validate_design` 拒绝)。不写时 `design_to_plan` 按设计指纹自动派生
103
+ **2–3 种**——默认就不会"全片一张版式"。`--stage layout` 会把每段选的版式写进 `work/storyboard.json` 的
104
+ `layout` 字段,可逐段审计。
105
+
106
+ ### 4.4 配色不是随便取色
107
+
108
+ 采样器的配色走**对比度求解**:定一个色相锚点,在 (s,v) 网格里找「最接近设计意图且满足
109
+ `theme_lint` 全部对比度门槛」的颜色。实测:纯 HSV 随机取色的通过率 **21/60 = 35%**(不可用);
110
+ 改成网格求解后 **60/60 = 100%**。配色是**连续色相空间**里的一点,不是"8 个命名配色族"。
111
+
112
+ ## 5. 采样器(sample_designs)
113
+
114
+ 输入 brief(题材 + 可选时长/必须有/不要),输出 N 个**两两可区分**的设计:
115
+
116
+ - **默认每次都不一样**(v1.0.1):不传 `seed` 就生成新的 nonce,同一 brief 跑两次得到不同设计;
117
+ 传 `--seed` 才逐字节可复现。这是"每条视频都不一样"的来源。
118
+ - 所有选择由 `sha1(nonce + brief + index + seed + attempt)` 派生,**禁 random / time**。
119
+ - **两两必须在 ≥2 个设计维度**上不同(10 个离散轴:配色 / 母题 / 转场 / 缓动 / 编号 / **配乐(调式+BPM 档+情绪)** /
120
+ 声线 / 情绪 / 版式 / 调式),否则视为「伪多方案」(只换颜色不算)。
121
+ - **底色还要拉开色相**:色相差 < 6° 一律重采;< 12° 时要求结构差异 ≥ 3 个轴。
122
+ v1.0.2 修掉了旧实现按 24° 分桶判重的坑——带 `--brief "深蓝"` 这类约束时窗口只有 52°,
123
+ 旧实现 n=3 近一半概率失败;现在实测带约束的 brief **10/10 成功**。
124
+ - **片间去重台账**(见 §6):候选还要与"最近交付过的设计"至少差 2 维。
125
+ - 每个候选自带一句中文立意 `pitch`,写进提案卡。
126
+
127
+ ## 6. 片间去重台账(v1.0.2,默认开启)
128
+
129
+ "每条视频都不一样"不能只靠随机:同题材连拍三部仍可能撞到相近的配色/版式组合。
130
+ `propose.py` 现在把**确认过(= 真要出片)的设计**记进用户级台账,提案时主动避开:
131
+
132
+ | 项 | 值 |
133
+ |---|---|
134
+ | 默认路径 | `~/.dsh/video-studio/design-ledger.json`(最多保留 500 条) |
135
+ | 环境变量 | `VIDEO_STUDIO_LEDGER` 改路径;设为 `off` / `0` / `false` / `no` 即关闭 |
136
+ | CLI | `--no-ledger`(本次不读不写)/ `--show-ledger`(打印路径与最近 20 条) |
137
+ | 判据 | 候选与最近交付设计的最小距离 < **2 维** → 换新 nonce 重采(最多 4 轮),并输出告警 |
138
+ | 记录时机 | `--confirm` 时才记(草稿候选不进台账) |
139
+
140
+ 读写失败/文件损坏一律当空表处理——**台账永远不会阻塞出片**。
141
+ 封锁测试或写文档时把 `VIDEO_STUDIO_LEDGER` 指到临时目录,不要动用户真实台账。
142
+
143
+ ## 7. 离线预览(previewkit)
144
+
145
+ **不联网、不合成旁白**:用 `FAKE_VOICE_DUR=2.0` 的合成时间轴排轴(同 `tools/golden_frames.py` 的口径),
146
+ 渲 3–4 帧/候选 + 联系表 + N 个候选纵向并排的对比图。
147
+
148
+ 成本(作者机器 2026-11-11 实测):单候选 3 帧 **0.6–0.9 s**;3 个候选含并排对比图 **约 2.1 s**;
149
+ 全程离线。成本大头是每个候选的首帧准备(主题/母题派生),同一候选内多渲几张几乎不要钱。
150
+ 换机会有波动,**别把这里的秒数当承诺**。
151
+
152
+ > 为什么不用 `--stage stills`:它缺 `tts.json` 时会**自动联网合成旁白**。
153
+ > 提案阶段不该付这个网络成本,也不该往用户的 TTS 缓存里写东西。
154
+
155
+ ## 8. 常见误用
156
+
157
+ | 现象 | 原因 | 修法 |
158
+ |---|---|---|
159
+ | 改了 design.json 但画面没变 | 没重跑 frames(或没确认) | `python render.py --stage explain` 看是否 `source-changed` |
160
+ | `--confirm` 报「设计没过校验」 | 手改过 design.json 或采样器版本变了 | 按报错逐条修,或 `--revise` 重出 |
161
+ | 候选都「太像」 | 采样器的差异度约束被放宽了 | 看 `--show` 里的 `diversity.vs[].n`,< 2 就是伪多方案 |
162
+ | 提案闸一直 WARN | 没跑过 `propose.py --confirm` | 按提示两步走;要硬拦加 `--require-proposal` |
163
+ | 预览图和成片不一致 | 预览用合成时长,成片用实测时长 | 正常现象:静帧只用于看构图/配色,节奏以成片为准 |
164
+ | 「这批候选和上一部太像」告警 | 片间去重台账命中(< 2 维) | 自动重采过 4 轮仍撞:`--revise "换个完全不同的方向"`,或 `--no-ledger` 忽略 |
165
+ | 带「深蓝」这类要求时提案失败 | 约束把可选空间收窄到不可行 | v1.0.2 已修(色相距离判重);仍失败就放宽 brief 或 `--n 2` |
166
+
167
+ ## 9. 已删除的东西(迁移须知)
168
+
169
+ | 旧写法 | 现在 |
170
+ |---|---|
171
+ | `style: "auto"` 自动选风格 | **已删除**(v1.0.1)。没有 design 就不出片 |
172
+ | `stylekit.THEMES/STYLES/VISUAL_LANGUAGES` 8 套 | **已全部删除**(v1.0.1):没有内置风格表 |
173
+ | `--preset <id>` 以出厂预设为起点 | **已删除**(v1.0.1):只有现场采样一条路,想复现用 `--seed` |
174
+ | legacy(不写 style 走 v0.4 绘制器) | **已删除**(v1.0.1):老片复现只能靠当年留存的 `work/` 快照 |
175
+ | `scorekit.MUSIC_STYLES` 9 套 | **已删除**(v1.0.1):配乐改由 `musicgen.py` 参数化编排 |
176
+ | `voicekit.VOICE_PERSONAS` 9 个 | **已删除**(v1.0.1):换成裸 edge voice id + 实测响度补偿表 |
177
+ | `stylekit.py --list/--show/--lint` | **已移除**:明确说明「内置风格表已删除」并 **exit 2**(不再 NameError / 假绿) |
@@ -192,7 +192,7 @@ python qa_frames.py out/film.mp4 --cues work/cues.json \
192
192
  | 响度曲线 | 无 >12 s 低于 -40 LUFS | `loudness[]` | warning:长段无声 |
193
193
 
194
194
  > **画面静止的判据在 v0.4 换过**:旧版用"全帧平均亮度 3 s 波动 < 2%",对逐字入场/数字滚动这类
195
- > 局部动画天生不敏感(自带模板片误报 4 段)。现在看的是"最活跃 8×8 块在 0.5 s 内的漂移",
195
+ > 局部动画天生不敏感(自带示例片误报 4 段)。现在看的是"最活跃 8×8 块在 0.5 s 内的漂移",
196
196
  > 详见 `references/frame-qa.md` §2.4b。**别再按旧公式调阈值。**
197
197
 
198
198
  ### 单帧闪烁的判据(照抄实测有效的做法)
@@ -29,9 +29,9 @@ v0.9 的做法不是"再加几套风格",而是把"内容 → 构图"这条选
29
29
  │ ① 场景语法:这段内容该长什么样(由内容决定,不由风格决定)
30
30
  ▼
31
31
  scene_type ∈ {hero, statement, list, stat, compare, process, quote, chapter, chart, outro}
32
- │ ② 视觉语言包:这套风格怎么画(motion / motif / transition / typography / bias)
32
+ │ ② 设计(design.json):这套设计怎么画(motion / motif / transition / typography / bias)
33
33
  ▼
34
- stylekit.VISUAL_LANGUAGES[style_id]
34
+ work/design.json 的 visual 五组签名(designkit.design_to_plan 转成 plan)
35
35
  │ ③ 片内编排:同一部片里连续段落怎么不"复制粘贴"(变体轮换 / 装饰密度 / 相位,确定性)
36
36
  ▼
37
37
  draw_frame(...) → PIL.Image
@@ -40,9 +40,9 @@ v0.9 的做法不是"再加几套风格",而是把"内容 → 构图"这条选
40
40
 
41
41
  | 层 | 由谁决定 | 落在哪 | 改它会怎样 |
42
42
  |---|---|---|---|
43
- | 叙事 kind | 作者写 `lines[].kind` | hook / body / quote / outro / emphasis / calm | 换旁白语气与配乐能量(voicekit / scorekit 读它) |
43
+ | 叙事 kind | 作者写 `lines[].kind` | hook / body / quote / outro / emphasis / calm | 换旁白语气与配乐能量(voicekit / musicgen 读它) |
44
44
  | 场景 type | grammar 按内容打分,或作者显式写 `lines[].type` | `work/storyboard.json`、timeline 的 `scene_type` | 换构图(10 个绘制器之一) |
45
- | 视觉语言 | 风格 id(`style`) | `work/style.json` 的 `language` | 换这套风格的骨架参数(母题 / 转场 / 字距 / 重心) |
45
+ | 设计 visual | `work/design.json`(由 `propose.py --confirm` 冻结) | `work/style.json` 的 `language` 与 `layout_cycle` | 换母题 / 转场 / 字距 / 重心 / 版式轮换 / 字幕样式 |
46
46
 
47
47
  **为什么没有新增 kind 值**:kind 同时是 voicekit 的语气 id 与 filmcheck 的 `KINDS`
48
48
  (两者是同一组 6 个值)。把 hero/stat 塞进 kind 会撞语气枚举,也让"引语"和"引语构图"
@@ -54,7 +54,7 @@ v0.9 的做法不是"再加几套风格",而是把"内容 → 构图"这条选
54
54
  坐标基于 1920×1080;正文底界 860(下方是字幕带),HUD 顶部 ≤96。
55
55
  "最短时长"是 `grammar.MIN_DUR`(`skills/video-studio/scripts/grammar.py:49`)的硬门槛,
56
56
  低于它按降级表换类型(见 §3.3)。类型名单与顺序在 `grammar.SCENE_TYPES`(grammar.py:30),
57
- 绘制器注册表在 `assets/scenes.py:1979`(`_DRAWERS`)。
57
+ 绘制器注册表在 `assets/scenes.py` 的 `_DRAWERS`(搜这个名字,行号会漂)。
58
58
 
59
59
  | 类型 | 构图 / 重心 | 吃哪些字段 | 持续动效 | 自动选型特征 | 最短 |
60
60
  |---|---|---|---|---|---|
@@ -111,7 +111,7 @@ v0.9 的做法不是"再加几套风格",而是把"内容 → 构图"这条选
111
111
 
112
112
  几个刻意的取舍(都是实测反例逼出来的,别"优化"掉):
113
113
 
114
- - **关键词只看叙述文字,不看 `items`**。反例:模板片第 3 段正文讲"画质三件事",
114
+ - **关键词只看叙述文字,不看 `items`**。反例:示例片第 3 段正文讲"画质三件事",
115
115
  条目里写的是 `rawvideo -> libx264 CRF17`,`->` 命中顺序词表,整段被误判成"流程轴"——
116
116
  画面上一条横轴连着四个不相干的要点。条目是载荷不是叙事。
117
117
  - **`hero`/`outro` 的结构分刻意低于字段分**:开场如果带 5 条要点,观众要看的是要点,
@@ -217,19 +217,25 @@ timeline 顶层再加一个 `storyboard: {"type_counts": ...}` 摘要。
217
217
  变体号、密度档、相位都**不按时间/帧号/随机数**派生——同一稿子同一结果,
218
218
  这是"可复现"的一部分。改 `chapter` 字段会改变 `variant_of` 的输入,进而改变变体号。
219
219
 
220
- ## 7. legacy 边界:不写 `style` = v0.4 三个老绘制器
220
+ ## 7. 没有 design 就没有画面(v1.0.1 起没有 legacy 路径)
221
221
 
222
- `film.json` 不写 `style` 字段时整条 v0.9 链路都不参与:
222
+ v1.0.1 删掉了 legacy 外观:不写 `style` 不再「走 v0.4 三个老绘制器」,而是**直接报错**并给两步迁移指引。
223
+ 现在整条链路只认 `work/design.json`:
223
224
 
224
- - `render.st_layout` 不调用 `grammar.plan_scenes`,不写 `work/storyboard.json`,
225
- timeline 里也不会出现 `scene_type` 等字段;
226
- - `scenes.draw_frame`(`assets/scenes.py:2003`)读 `plan["legacy"]` 为真,
227
- 直接走 `_LEGACY_DRAWERS`(scenes.py:232,hook / body / outro 三个 v0.4 绘制器),逐字节不变;
228
- - 金帧基线(`skills/video-studio/assets/golden_frames.json`)就是钉这条的:
229
- legacy 项目跑出来的 3 帧像素与基线一致,改坏了立刻红。
225
+ - `render.st_layout` 调 `grammar.plan_scenes`,按 `design.visual.layout_cycle` 做**按章节的版式轮换**,
226
+ 写 `work/storyboard.json`(每段的 type / variant / decor / layout / reason 都可审计);
227
+ - `scenes.draw_frame` 只走 10 类构图绘制器(`_DRAWERS`),没有 legacy 分支;
228
+ - 字幕样式来自 `design.visual.subtitle`(v1.0.2),字号/位置/背板/圆角不再写死;
229
+ - 金帧基线 `assets/golden_frames.json` 绑的是固定 fixture 设计(`assets/design_fixture.json`),
230
+ 不是「某套内置风格」——改绘制代码后按 `tools/golden_frames.py --write` 重录。
230
231
 
231
- 想让老项目享受新构图,写 `"style": "auto"` 或任意风格 id 即可;
232
- 但注意这会同时换掉配色/配乐/旁白(v0.5 的风格包是整体生效的),做好重看一遍的准备。
232
+ 没有 design 时的正确做法(脚本留在技能目录里,零拷贝):
233
+
234
+ ```bash
235
+ python <SKILL_DIR>/scripts/propose.py --brief "题材/要求" --script film.json --work work
236
+ python <SKILL_DIR>/scripts/propose.py --confirm --candidate A --work work
237
+ python <SKILL_DIR>/scripts/render.py --script film.json --work work --out out/film.mp4 --stage all
238
+ ```
233
239
 
234
240
  ## 8. 加第 11 类构图(8 步)
235
241
 
@@ -256,17 +262,17 @@ timeline 顶层再加一个 `storyboard: {"type_counts": ...}` 摘要。
256
262
  7. **`selfcheck.py` 第 54 条(`scripts/selfcheck.py:1526`)会自动兜底**:它断言 grammar / filmcheck / scenes.`_DRAWERS` /
257
263
  schema enum 四处**集合相等**(顺序允许不同)。这四份真值来源必须同时改,漏一处立刻红。
258
264
  8. **`tools/silhouette_qa.py` 的 `SCENE_CONTENT` 补一段合成内容**(给足该类型的原料字段),
259
- 再跑一次剪影门禁确认新类型在 8 套风格下也"看得出来"。这一步不做,等于新加的构图
265
+ 再跑一次剪影门禁(`--selftest` / `--designs N`)确认新类型在不同现场设计下也"看得出来"。这一步不做,等于新加的构图
260
266
  没有进入 G13 的覆盖范围。
261
267
 
262
- 跑完的验证顺序:`python selfcheck.py`(52–55 条)→ `python tools/ci_check.py`
263
- (语法/包内容/文档路径)→ `python tools/silhouette_qa.py`(28 对仍全过)。
268
+ 跑完的验证顺序:`python selfcheck.py`(**67 条**,第 52–55 条专盯场景语法/视觉语言/单真值/剪影)
269
+ → `python <REPO>/tools/ci_check.py`(语法/包内容/文档路径)→ `python <REPO>/tools/silhouette_qa.py`(不同设计两两仍可区分)。
264
270
 
265
271
  ## 9. 常见误用
266
272
 
267
273
  | 现象 | 原因 | 修法 |
268
274
  |---|---|---|
269
- | 分镜表里一段都没变,全是 list | 没有写 `style`(走 legacy),grammar 根本没跑 | 写 `"style": "auto"` 或某个风格 id |
275
+ | 分镜表里一段都没变,全是 list | 没有 `work/design.json`,或 grammar 没跑 | 写 先 `propose.py --confirm` 冻结设计;再 `--stage layout` 看分镜表 |
270
276
  | 某段想要数字卡,结果画成列表 | 没有 `stats[]`,文本里的数字是"2024 年"(年份被排除)或没有单位 | 显式写 `stats[]`;或让那句话带"数字 + 单位" |
271
277
  | 写了 `type: "stats"` 却没生效,还报错 | `type` 是枚举,`stats` 才是字段名;写错值 filmcheck 报 ERROR | 改 `type` 为 10 类之一,数据放 `stats[]` |
272
278
  | 对比段左右两栏一栏空 | 只有 1 条 `items`(对半分不出来),或 `sides{}` 只写了一侧 | 补到 ≥2 条,或显式写 `sides` 两侧 |
@@ -294,8 +300,7 @@ timeline 顶层再加一个 `storyboard: {"type_counts": ...}` 摘要。
294
300
  但当前只有 hero / statement / list / stat 用它,其余六类构图唯一。
295
301
  这条不修的话,"每类型 3 个变体"只在四类上成立。
296
302
  - **部分视觉语言字段"已声明、已体检、但绘制器没读"**:`motion.enter`、`motion.push`、
297
- `typography.align`、`typography.ratio`(以及 `layout_cycle`)在
298
- `stylekit.VISUAL_LANGUAGES` 里声明、`stylekit.visual_lint` 会查范围,
303
+ `typography.align`、`typography.ratio`由 `designkit.validate_design` 校验范围,
299
304
  但 `assets/scenes.py` 当前不读它们——写了不会报错,也不会改变画面。
300
305
  详见 [style-packs.md](style-packs.md) 的"视觉语言包"一节。
301
306
  - **场景数据超容量会被截断**:`stats` >3 / `series` >6 / `steps` >5 / `sides` 每侧 >3
@@ -303,4 +308,4 @@ timeline 顶层再加一个 `storyboard: {"type_counts": ...}` 摘要。
303
308
  `skills/video-studio/scripts/filmcheck.py:652`),但**不阻断渲染**——
304
309
  WARN 不是通过,也不是失败,是"画面上没有"。
305
310
  - **`work/storyboard.json` 是审计产物,不是输入**:改它不会改变渲染结果;
306
- 想要固定构图请改 `film.json` 的 `lines[].type`。
311
+ 想要固定构图请改 `film.json` 的 `lines[].type`。
@@ -217,7 +217,7 @@ CUE_ALIASES # 语义别名表
217
217
  `build_audio()` 逐条 `SX.render(type, seed=1000+i, **params)`,按 `pan` 展开立体声、
218
218
  按 `CUE_BASE_DB` 与 `gain` 落位到音频总线;未知 type 告警一次并跳过。
219
219
  2. **web 引擎**:页面 `window.getCues()` 导出同 schema 的 `work/cues.json`(CONTRACT §4.2)。
220
- 3. **配乐(scorekit)**:`import sfxkit as S`,直接用 `sine/saw/supersaw/fm/pluck/adsr`、
220
+ 3. **配乐(musicgen)**:和自己写音效一样,直接用 sfxkit 原语;`import sfxkit as S`,有 `sine/saw/supersaw/fm/pluck/adsr`、
221
221
  `lowpass/highpass/tv_filter`、`white/burst/exp_decay/attack_decay`、`smooth_random`、`Mix`。
222
222
 
223
223
  ## 11. 自检