@dsh-gis/dsh-video-studio-skill 0.9.1 → 1.0.4
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.
- package/CHANGELOG.md +473 -0
- package/README.md +263 -327
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/package.json +9 -10
- package/schemas/design.schema.json +722 -0
- package/schemas/film.schema.json +31 -42
- package/schemas/proposal.schema.json +133 -0
- package/skills/video-studio/SKILL.md +1216 -1123
- package/skills/video-studio/assets/design_fixture.json +141 -0
- package/skills/video-studio/assets/film.json +2 -4
- package/skills/video-studio/assets/golden_frames.json +13 -10
- package/skills/video-studio/assets/scenes.py +153 -65
- package/skills/video-studio/assets/voice_loudness.json +16 -0
- package/skills/video-studio/references/appearance.md +123 -0
- package/skills/video-studio/references/audio-variation.md +74 -93
- package/skills/video-studio/references/audio.md +64 -66
- package/skills/video-studio/references/change-impact.md +5 -5
- package/skills/video-studio/references/{v08-quality.md → delivery-gates.md} +16 -18
- package/skills/video-studio/references/frame-qa.md +48 -16
- package/skills/video-studio/references/pipeline.md +4 -4
- package/skills/video-studio/references/pitfalls.md +22 -3
- package/skills/video-studio/references/proposal.md +160 -0
- package/skills/video-studio/references/quality-gates.md +11 -11
- package/skills/video-studio/references/scene-authoring.md +2 -2
- package/skills/video-studio/references/scene-grammar.md +40 -42
- package/skills/video-studio/references/sfx-design.md +8 -6
- package/skills/video-studio/references/web-engine.md +8 -8
- package/skills/video-studio/references/word-timeline.md +9 -9
- package/skills/video-studio/requirements.txt +9 -13
- package/skills/video-studio/scripts/designkit.py +2115 -0
- package/skills/video-studio/scripts/filmcheck.py +22 -48
- package/skills/video-studio/scripts/filmkit.py +2980 -2904
- package/skills/video-studio/scripts/gates.py +4 -4
- package/skills/video-studio/scripts/grammar.py +73 -13
- package/skills/video-studio/scripts/musicgen.py +2042 -0
- package/skills/video-studio/scripts/preflight.py +14 -7
- package/skills/video-studio/scripts/previewkit.py +848 -0
- package/skills/video-studio/scripts/propose.py +825 -0
- package/skills/video-studio/scripts/qa_frames.py +73 -39
- package/skills/video-studio/scripts/qaasr.py +26 -7
- package/skills/video-studio/scripts/qavmaf.py +89 -23
- package/skills/video-studio/scripts/render.py +545 -231
- package/skills/video-studio/scripts/scorekit.py +55 -1755
- package/skills/video-studio/scripts/selfcheck.py +815 -215
- package/skills/video-studio/scripts/sfxkit.py +27 -26
- package/skills/video-studio/scripts/stagewatch.py +24 -8
- package/skills/video-studio/scripts/stylekit.py +207 -888
- package/skills/video-studio/scripts/voicekit.py +508 -387
- package/skills/video-studio/scripts/webengine.py +71 -72
- package/tools/audio_similarity.py +64 -37
- package/tools/ci_check.py +20 -14
- package/tools/estimate.py +34 -29
- package/tools/golden_frames.py +72 -28
- package/tools/silhouette_qa.py +520 -168
- package/docs/demo-pil-sheet.png +0 -0
- package/docs/styles/demo-results.json +0 -76
- package/docs/styles/sheet-8-styles.png +0 -0
- package/docs/styles/sheet-ai.png +0 -0
- package/docs/styles/sheet-before-after.png +0 -0
- package/docs/styles/sheet-craft.png +0 -0
- package/docs/styles/sheet-night.png +0 -0
- package/skills/video-studio/assets/score_demo.json +0 -307
- package/skills/video-studio/references/style-packs.md +0 -283
package/docs/demo-pil-sheet.png
DELETED
|
Binary file
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"generated": "2026-11-09",
|
|
3
|
-
"demos": [
|
|
4
|
-
{
|
|
5
|
-
"demo": "ai",
|
|
6
|
-
"title": "科技深蓝",
|
|
7
|
-
"style": "tech-deep",
|
|
8
|
-
"bpm": 116,
|
|
9
|
-
"key": "Em",
|
|
10
|
-
"mood": "steady",
|
|
11
|
-
"duration": 17.26,
|
|
12
|
-
"personas": [
|
|
13
|
-
"young_male",
|
|
14
|
-
"narrator_male",
|
|
15
|
-
"narrator_female"
|
|
16
|
-
],
|
|
17
|
-
"tones": [
|
|
18
|
-
"emphasis",
|
|
19
|
-
"body",
|
|
20
|
-
"quote",
|
|
21
|
-
"outro"
|
|
22
|
-
],
|
|
23
|
-
"layouts": [
|
|
24
|
-
"left-stack",
|
|
25
|
-
"split-right"
|
|
26
|
-
],
|
|
27
|
-
"spectral_centroid_hz": 5784
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
"demo": "craft",
|
|
31
|
-
"title": "手绘纸感",
|
|
32
|
-
"style": "paper",
|
|
33
|
-
"bpm": 88,
|
|
34
|
-
"key": "G",
|
|
35
|
-
"mood": "hopeful",
|
|
36
|
-
"duration": 19.855,
|
|
37
|
-
"personas": [
|
|
38
|
-
"narrator_female",
|
|
39
|
-
"warm_female"
|
|
40
|
-
],
|
|
41
|
-
"tones": [
|
|
42
|
-
"hook",
|
|
43
|
-
"body",
|
|
44
|
-
"outro"
|
|
45
|
-
],
|
|
46
|
-
"layouts": [
|
|
47
|
-
"left-stack",
|
|
48
|
-
"center-stack"
|
|
49
|
-
],
|
|
50
|
-
"spectral_centroid_hz": 4899.4
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
"demo": "night",
|
|
54
|
-
"title": "暖灰薄荷",
|
|
55
|
-
"style": "lo-fi",
|
|
56
|
-
"bpm": 84,
|
|
57
|
-
"key": "F",
|
|
58
|
-
"mood": "calm",
|
|
59
|
-
"duration": 20.108,
|
|
60
|
-
"personas": [
|
|
61
|
-
"warm_female",
|
|
62
|
-
"narrator_female"
|
|
63
|
-
],
|
|
64
|
-
"tones": [
|
|
65
|
-
"hook",
|
|
66
|
-
"body",
|
|
67
|
-
"outro"
|
|
68
|
-
],
|
|
69
|
-
"layouts": [
|
|
70
|
-
"left-stack",
|
|
71
|
-
"split-right"
|
|
72
|
-
],
|
|
73
|
-
"spectral_centroid_hz": 5573.8
|
|
74
|
-
}
|
|
75
|
-
]
|
|
76
|
-
}
|
|
Binary file
|
package/docs/styles/sheet-ai.png
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"generator": "scorekit 0.3.0",
|
|
4
|
-
"note": "scorekit 演示配乐(48 s,4 段,120 BPM,D 小调)。anchors 自动分段:段落边界吸附小节线,交界处 1 小节过门(鼓加花/反向镲/上升音/重击)+ 自动吸气;峰值 -1.5 dBFS、结尾 2 s 淡出;同一 seed 逐采样一致(无采样、全合成)。",
|
|
5
|
-
"reproduce": {
|
|
6
|
-
"json": "python - <<PY\nimport json, scorekit as K\nanchors = [{\"id\": \"d01\", \"kind\": \"hook\", \"start\": 0.0, \"end\": 8.0}, {\"id\": \"d02\", \"kind\": \"body\", \"start\": 8.0, \"end\": 24.0}, {\"id\": \"d03\", \"kind\": \"drive\", \"start\": 24.0, \"end\": 40.0}, {\"id\": \"d04\", \"kind\": \"outro\", \"start\": 40.0, \"end\": 48.0}]\nx, rep = K.render(48.0, bpm=120, key='Dm', anchors=anchors, seed=7)\nK.save('work/score_demo.wav', x)\nPY",
|
|
7
|
-
"cli": "cd skills/video-studio/scripts && python scorekit.py --duration 48 --bpm 120 --key Dm --seed 7 --anchors work/score_demo_anchors.json --out work/score_demo.wav --report work/score_demo.json",
|
|
8
|
-
"anchors_file_example": [
|
|
9
|
-
{
|
|
10
|
-
"id": "d01",
|
|
11
|
-
"kind": "hook",
|
|
12
|
-
"start": 0.0,
|
|
13
|
-
"end": 8.0
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
"id": "d02",
|
|
17
|
-
"kind": "body",
|
|
18
|
-
"start": 8.0,
|
|
19
|
-
"end": 24.0
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"id": "d03",
|
|
23
|
-
"kind": "drive",
|
|
24
|
-
"start": 24.0,
|
|
25
|
-
"end": 40.0
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
"id": "d04",
|
|
29
|
-
"kind": "outro",
|
|
30
|
-
"start": 40.0,
|
|
31
|
-
"end": 48.0
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
},
|
|
35
|
-
"meas": {
|
|
36
|
-
"wav": "work/score_demo.wav # 用 reproduce 里的命令自己生成",
|
|
37
|
-
"peak_dbfs": -1.5,
|
|
38
|
-
"lufs_approx": -19.8,
|
|
39
|
-
"true_peak_dbtp": -1.4,
|
|
40
|
-
"real_lufs_ffmpeg_demo48": -18.45,
|
|
41
|
-
"real_lufs_ffmpeg_60s": -19.09,
|
|
42
|
-
"real_lufs_ffmpeg_389s": -18.52,
|
|
43
|
-
"real_true_peak_60s_dbtp": -1.4,
|
|
44
|
-
"real_true_peak_389s_dbtp": -1.44,
|
|
45
|
-
"lra_389s_lu": 4.9,
|
|
46
|
-
"render_s": 5.115,
|
|
47
|
-
"render_389s_s": 8.18,
|
|
48
|
-
"note": "389 s 实测:渲染 8.18 s(含并行负载;空载 6.7 s)、峰值 -1.5 dBFS、ffmpeg loudnorm -18.52 LUFS / -1.44 dBTP;48 s demo 实测 -18.45 LUFS。",
|
|
49
|
-
"render_s_note": "本机实测值,随机器/负载浮动;不是承诺"
|
|
50
|
-
},
|
|
51
|
-
"bpm": 120.0,
|
|
52
|
-
"key": "Dm",
|
|
53
|
-
"key_name": "D 小调",
|
|
54
|
-
"sr": 48000,
|
|
55
|
-
"duration": 48.0,
|
|
56
|
-
"seed": 7,
|
|
57
|
-
"bar_s": 2.0,
|
|
58
|
-
"beat_s": 0.5,
|
|
59
|
-
"sections": [
|
|
60
|
-
{
|
|
61
|
-
"name": "d01",
|
|
62
|
-
"start": 0.0,
|
|
63
|
-
"end": 8.0,
|
|
64
|
-
"energy": 0.3,
|
|
65
|
-
"bars": 4,
|
|
66
|
-
"target_db": -5.95,
|
|
67
|
-
"target_lufs": -21.9,
|
|
68
|
-
"layers": [
|
|
69
|
-
"pad",
|
|
70
|
-
"bass"
|
|
71
|
-
],
|
|
72
|
-
"chords": [
|
|
73
|
-
"i",
|
|
74
|
-
"VI",
|
|
75
|
-
"iv",
|
|
76
|
-
"v"
|
|
77
|
-
]
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
"name": "d02",
|
|
81
|
-
"start": 8.0,
|
|
82
|
-
"end": 24.0,
|
|
83
|
-
"energy": 0.55,
|
|
84
|
-
"bars": 8,
|
|
85
|
-
"target_db": -3.82,
|
|
86
|
-
"target_lufs": -19.8,
|
|
87
|
-
"layers": [
|
|
88
|
-
"pad",
|
|
89
|
-
"bass",
|
|
90
|
-
"kick",
|
|
91
|
-
"hat",
|
|
92
|
-
"arp"
|
|
93
|
-
],
|
|
94
|
-
"chords": [
|
|
95
|
-
"i",
|
|
96
|
-
"VI",
|
|
97
|
-
"III",
|
|
98
|
-
"VII",
|
|
99
|
-
"i",
|
|
100
|
-
"VI",
|
|
101
|
-
"III",
|
|
102
|
-
"V"
|
|
103
|
-
]
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
"name": "d03",
|
|
107
|
-
"start": 24.0,
|
|
108
|
-
"end": 40.0,
|
|
109
|
-
"energy": 0.8,
|
|
110
|
-
"bars": 8,
|
|
111
|
-
"target_db": -1.7,
|
|
112
|
-
"target_lufs": -17.7,
|
|
113
|
-
"layers": [
|
|
114
|
-
"pad",
|
|
115
|
-
"bass",
|
|
116
|
-
"kick",
|
|
117
|
-
"hat",
|
|
118
|
-
"arp",
|
|
119
|
-
"melody"
|
|
120
|
-
],
|
|
121
|
-
"chords": [
|
|
122
|
-
"i",
|
|
123
|
-
"VII",
|
|
124
|
-
"VI",
|
|
125
|
-
"V",
|
|
126
|
-
"i",
|
|
127
|
-
"VII",
|
|
128
|
-
"VI",
|
|
129
|
-
"V"
|
|
130
|
-
]
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
"name": "d04",
|
|
134
|
-
"start": 40.0,
|
|
135
|
-
"end": 48.0,
|
|
136
|
-
"energy": 0.35,
|
|
137
|
-
"bars": 4,
|
|
138
|
-
"target_db": -5.53,
|
|
139
|
-
"target_lufs": -21.5,
|
|
140
|
-
"layers": [
|
|
141
|
-
"pad",
|
|
142
|
-
"bass",
|
|
143
|
-
"kick"
|
|
144
|
-
],
|
|
145
|
-
"chords": [
|
|
146
|
-
"i",
|
|
147
|
-
"VI",
|
|
148
|
-
"I",
|
|
149
|
-
"I"
|
|
150
|
-
]
|
|
151
|
-
}
|
|
152
|
-
],
|
|
153
|
-
"transitions": [
|
|
154
|
-
{
|
|
155
|
-
"t": 8.0,
|
|
156
|
-
"from": "d01",
|
|
157
|
-
"to": "d02",
|
|
158
|
-
"fill_start": 6.0,
|
|
159
|
-
"fill_s": 2.0,
|
|
160
|
-
"kinds": [
|
|
161
|
-
"鼓加花",
|
|
162
|
-
"反向镲",
|
|
163
|
-
"上升音"
|
|
164
|
-
],
|
|
165
|
-
"suck_db": -4.75
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"t": 24.0,
|
|
169
|
-
"from": "d02",
|
|
170
|
-
"to": "d03",
|
|
171
|
-
"fill_start": 22.0,
|
|
172
|
-
"fill_s": 2.0,
|
|
173
|
-
"kinds": [
|
|
174
|
-
"鼓加花",
|
|
175
|
-
"反向镲",
|
|
176
|
-
"上升音",
|
|
177
|
-
"重击"
|
|
178
|
-
],
|
|
179
|
-
"suck_db": -4.75
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"t": 40.0,
|
|
183
|
-
"from": "d03",
|
|
184
|
-
"to": "d04",
|
|
185
|
-
"fill_start": 38.0,
|
|
186
|
-
"fill_s": 2.0,
|
|
187
|
-
"kinds": [
|
|
188
|
-
"鼓加花",
|
|
189
|
-
"反向镲"
|
|
190
|
-
],
|
|
191
|
-
"suck_db": null
|
|
192
|
-
}
|
|
193
|
-
],
|
|
194
|
-
"sucks": [
|
|
195
|
-
{
|
|
196
|
-
"t": 8.0,
|
|
197
|
-
"db": -4.75,
|
|
198
|
-
"dur": 0.24,
|
|
199
|
-
"source": "过渡吸气"
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
"t": 24.0,
|
|
203
|
-
"db": -4.75,
|
|
204
|
-
"dur": 0.24,
|
|
205
|
-
"source": "过渡吸气"
|
|
206
|
-
}
|
|
207
|
-
],
|
|
208
|
-
"beats": [
|
|
209
|
-
0.0,
|
|
210
|
-
0.5,
|
|
211
|
-
1.0,
|
|
212
|
-
1.5,
|
|
213
|
-
2.0,
|
|
214
|
-
2.5,
|
|
215
|
-
3.0,
|
|
216
|
-
3.5,
|
|
217
|
-
4.0,
|
|
218
|
-
4.5,
|
|
219
|
-
5.0,
|
|
220
|
-
5.5,
|
|
221
|
-
6.0,
|
|
222
|
-
6.5,
|
|
223
|
-
7.0,
|
|
224
|
-
7.5,
|
|
225
|
-
8.0,
|
|
226
|
-
8.5,
|
|
227
|
-
9.0,
|
|
228
|
-
9.5,
|
|
229
|
-
10.0,
|
|
230
|
-
10.5,
|
|
231
|
-
11.0,
|
|
232
|
-
11.5,
|
|
233
|
-
12.0,
|
|
234
|
-
12.5,
|
|
235
|
-
13.0,
|
|
236
|
-
13.5,
|
|
237
|
-
14.0,
|
|
238
|
-
14.5,
|
|
239
|
-
15.0,
|
|
240
|
-
15.5,
|
|
241
|
-
16.0,
|
|
242
|
-
16.5,
|
|
243
|
-
17.0,
|
|
244
|
-
17.5,
|
|
245
|
-
18.0,
|
|
246
|
-
18.5,
|
|
247
|
-
19.0,
|
|
248
|
-
19.5,
|
|
249
|
-
20.0,
|
|
250
|
-
20.5,
|
|
251
|
-
21.0,
|
|
252
|
-
21.5,
|
|
253
|
-
22.0,
|
|
254
|
-
22.5,
|
|
255
|
-
23.0,
|
|
256
|
-
23.5,
|
|
257
|
-
24.0,
|
|
258
|
-
24.5,
|
|
259
|
-
25.0,
|
|
260
|
-
25.5,
|
|
261
|
-
26.0,
|
|
262
|
-
26.5,
|
|
263
|
-
27.0,
|
|
264
|
-
27.5,
|
|
265
|
-
28.0,
|
|
266
|
-
28.5,
|
|
267
|
-
29.0,
|
|
268
|
-
29.5,
|
|
269
|
-
30.0,
|
|
270
|
-
30.5,
|
|
271
|
-
31.0,
|
|
272
|
-
31.5,
|
|
273
|
-
32.0,
|
|
274
|
-
32.5,
|
|
275
|
-
33.0,
|
|
276
|
-
33.5,
|
|
277
|
-
34.0,
|
|
278
|
-
34.5,
|
|
279
|
-
35.0,
|
|
280
|
-
35.5,
|
|
281
|
-
36.0,
|
|
282
|
-
36.5,
|
|
283
|
-
37.0,
|
|
284
|
-
37.5,
|
|
285
|
-
38.0,
|
|
286
|
-
38.5,
|
|
287
|
-
39.0,
|
|
288
|
-
39.5,
|
|
289
|
-
40.0,
|
|
290
|
-
40.5,
|
|
291
|
-
41.0,
|
|
292
|
-
41.5,
|
|
293
|
-
42.0,
|
|
294
|
-
42.5,
|
|
295
|
-
43.0,
|
|
296
|
-
43.5,
|
|
297
|
-
44.0,
|
|
298
|
-
44.5,
|
|
299
|
-
45.0,
|
|
300
|
-
45.5,
|
|
301
|
-
46.0,
|
|
302
|
-
46.5,
|
|
303
|
-
47.0,
|
|
304
|
-
47.5,
|
|
305
|
-
48.0
|
|
306
|
-
]
|
|
307
|
-
}
|
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
# 风格包(Style Packs):让每部片的画风 / 配乐 / 旁白都不一样
|
|
2
|
-
|
|
3
|
-
> v0.5.0 新增。读这一篇之前先读 SKILL.md 的 §5.6。
|
|
4
|
-
> 一句话:**一个 style id 同时决定画风、配乐、旁白声音和节奏**,不能三样各自乱配。
|
|
5
|
-
|
|
6
|
-
## 0. 为什么需要它(v0.4 的病)
|
|
7
|
-
|
|
8
|
-
v0.4 及以前,所有"身份参数"都是模块级常量:
|
|
9
|
-
|
|
10
|
-
| 层 | 被写死的地方 | 结果 |
|
|
11
|
-
|---|---|---|
|
|
12
|
-
| 画风 | assets/scenes.py 的 THEME 字典 + 3 个绘制函数 | 每部片都是深蓝底 + 橙强调 |
|
|
13
|
-
| 配乐 | scorekit 的 4 个小调 + 3 套和弦进行 + 固定动机 | 每部片都是 Dm / 120BPM 那一套 |
|
|
14
|
-
| 旁白 | render.py 的单个 voice/rate/pitch | 每部片都是同一个声音、同一语速 |
|
|
15
|
-
| 流程 | SKILL.md 教的是 "cp 模板 -> 改 lines[].text" | 模型自然只会改文案 |
|
|
16
|
-
|
|
17
|
-
结果就是:**内容换了,气质没换**。用户的原话是"背景音乐风格都差不多、旁白声音都差不多、整体画风也差不多"。
|
|
18
|
-
|
|
19
|
-
## 1. 三层结构
|
|
20
|
-
|
|
21
|
-
film.json style: "auto" | "tech-deep" | ... | "legacy"
|
|
22
|
-
|
|
|
23
|
-
v
|
|
24
|
-
stylekit.resolve_script_style(script) <- 纯函数,确定性
|
|
25
|
-
| +- 关键词打分(title/chapter/text/items)
|
|
26
|
-
| +- 三级内容指纹(full / tempo / style)
|
|
27
|
-
| +- 显式覆盖(visual.theme / music.style / voice.map / pacing)
|
|
28
|
-
v
|
|
29
|
-
work/style.json <- 审计产物:能看到"为什么是这套风格"
|
|
30
|
-
| +- style / theme_id / chapter_layout
|
|
31
|
-
| +- music{bpm,key,mood,seed_effective}
|
|
32
|
-
| +- voice{map,policy}
|
|
33
|
-
| +- pacing{lead,tail,min_dur,item_stagger}
|
|
34
|
-
v
|
|
35
|
-
画面(scenes.py 读主题) 配乐(scorekit 读风格) 旁白(voicekit 读 persona/tone)
|
|
36
|
-
|
|
37
|
-
## 2. 8 套内置风格
|
|
38
|
-
|
|
39
|
-
| id | 中文 | 画风 | 配乐 | 旁白 | 适合内容 |
|
|
40
|
-
|---|---|---|---|---|---|
|
|
41
|
-
| tech-deep | 科技深蓝 | 深蓝渐变 + 橙 | 小调 100–124 / 琶音 + 铃声 | 男声叙述 + 青年开场 | AI、工程、数据、科普 |
|
|
42
|
-
| magazine | 杂志暖白 | 米白 + 朱红,衬线体 | 大调 88–100 / 电钢 | 女声叙述 + 权威男声引用 | 报告、复盘、研究 |
|
|
43
|
-
| paper | 手绘纸感 | 牛皮纸 + 靛青,楷体 | 大调 84–92 / 马林巴 | 软糯女声 + 男声引用 | 手工、自然、历史 |
|
|
44
|
-
| vivid | 活力撞色 | 深紫 + 柠檬黄,大字 | 大调 120–132 / 短促和弦 | 活泼女声开场 | 活动、营销、上新 |
|
|
45
|
-
| mono | 极简黑白 | 纯白 + 黑,超宽字距 | 极简 60–68 / 钢片琴 | 沉稳男声 + 女声引用 | 观点、演讲、思辨 |
|
|
46
|
-
| cinema | 电影青橙 | 近黑 + 青橙,扫描线 | 小调 76–84 / 弦乐铺底 | 纪录片男声 + 女声引用 | 纪录、叙事、城市 |
|
|
47
|
-
| lo-fi | 暖灰薄荷 | 暖灰 + 薄荷绿 | 大调 72–84 / 电钢 + 轻鼓 | 温柔女声 | 日常、学习、专注 |
|
|
48
|
-
| epic | 深黑鎏金 | 近黑 + 金,衬线体 | 小调 88–96 / 铜管 + 人声铺 | 有力男声 + 男声开场 | 史诗、宣传、高潮 |
|
|
49
|
-
|
|
50
|
-
外加 legacy:不写 style 字段时的兼容档,画风/配乐/旁白全部等于 v0.4(配乐逐样本一致)。
|
|
51
|
-
|
|
52
|
-
查表:
|
|
53
|
-
|
|
54
|
-
python stylekit.py --list # 8 套风格 + 主题 + 对比度
|
|
55
|
-
python stylekit.py --show cinema # 单套风格的全部字段
|
|
56
|
-
python stylekit.py --lint # 主题对比度门禁(CI 会跑)
|
|
57
|
-
|
|
58
|
-
## 3. film.json 怎么配
|
|
59
|
-
|
|
60
|
-
最小配置(推荐,几乎不用写):
|
|
61
|
-
|
|
62
|
-
{"style": "auto"}
|
|
63
|
-
|
|
64
|
-
自动模式:命中题材关键词就锁定对应风格;零命中时按内容指纹稳定落桶
|
|
65
|
-
(同一份稿子永远同一个风格,不同稿子大概率不同)。
|
|
66
|
-
|
|
67
|
-
想锁定:
|
|
68
|
-
|
|
69
|
-
{"style": "cinema"}
|
|
70
|
-
|
|
71
|
-
想只改某一块(其余跟着风格走):
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
"style": "magazine",
|
|
75
|
-
"visual": {
|
|
76
|
-
"theme": "paper",
|
|
77
|
-
"layout": "split-right",
|
|
78
|
-
"theme_overrides": {"vignette": 0.18, "grain": 8.0}
|
|
79
|
-
},
|
|
80
|
-
"music": {
|
|
81
|
-
"style": "lo-fi",
|
|
82
|
-
"bpm": "auto", "key": "auto", "mood": "calm",
|
|
83
|
-
"seed": 7, "seed_from_content": true
|
|
84
|
-
},
|
|
85
|
-
"voice": {
|
|
86
|
-
"map": {"hook": "bright_female", "body": "narrator_female"},
|
|
87
|
-
"jitter": 0.35,
|
|
88
|
-
"max_distinct": 3
|
|
89
|
-
},
|
|
90
|
-
"pacing": {"lead": 0.6, "tail": 0.9, "item_stagger": 0.3}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
逐句覆盖(最高优先级):
|
|
94
|
-
|
|
95
|
-
{"id": "l03", "kind": "body", "text": "他说:「这不可能」",
|
|
96
|
-
"voice": "authority_male", "tone": "quote", "lead": 0.8}
|
|
97
|
-
|
|
98
|
-
### 字段速查
|
|
99
|
-
|
|
100
|
-
| 字段 | 默认 | 说明 |
|
|
101
|
-
|---|---|---|
|
|
102
|
-
| style | 无(= legacy) | 风格 id / "auto" / "legacy" |
|
|
103
|
-
| visual.theme | — | 等价于锁 style;与 style 1:1 |
|
|
104
|
-
| visual.layout | 风格默认 | left-stack / center-stack / split-right |
|
|
105
|
-
| visual.theme_overrides | — | 深合并覆盖主题单字段 |
|
|
106
|
-
| music.style | 跟随 style | 只换配乐风格 |
|
|
107
|
-
| music.bpm | "auto" | 数字或 "auto"(按风格梯度 + 指纹) |
|
|
108
|
-
| music.key | "auto" | 调名或 "auto"(按风格调池 + 指纹) |
|
|
109
|
-
| music.mood | 风格默认 | calm/reflective/hopeful/steady/driving/tense/uplifting |
|
|
110
|
-
| music.seed_from_content | 非 legacy 时 true | 音色细节由内容指纹派生 |
|
|
111
|
-
| voice.map | 风格默认 | kind -> persona 名 |
|
|
112
|
-
| voice.jitter | 0.35 | 语速/音高微扰,0 = 关 |
|
|
113
|
-
| voice.max_distinct | 3 | 全片最多几把声音 |
|
|
114
|
-
| pacing.* | 风格默认 | 语前留白/语后留白/最短段长/条目落位步长 |
|
|
115
|
-
| lines[].persona / lines[].voice / lines[].tone | — | 逐句覆盖(最高优先级,voicekit 真的读这三个) |
|
|
116
|
-
| lines[].lead | — | 逐句语前留白(filmkit.build_timeline 读) |
|
|
117
|
-
| lines[].rate / pitch / volume / tail | — | **当前不生效**(保留字段):voicekit 只认 persona/voice/tone,filmcheck 会对这三个报"未知键";要改语速/音高请换 persona 或 tone,或在顶层写 rate/pitch/volume |
|
|
118
|
-
|
|
119
|
-
## 4. 三级指纹:改错别字不会换整首曲子
|
|
120
|
-
|
|
121
|
-
| 指纹 | 由什么算 | 决定 |
|
|
122
|
-
|---|---|---|
|
|
123
|
-
| full | 标题 + 全部台词 | 音色细节(seed 派生) |
|
|
124
|
-
| tempo | 标题 + kind 序列 + 体量桶 | BPM 与调性 |
|
|
125
|
-
| style | 标题(配合关键词评分破平) | 风格 id |
|
|
126
|
-
|
|
127
|
-
所以:改一个错别字 -> full 变(音色纹理微变),tempo/style 不变(还是同一首曲子、同一个调);
|
|
128
|
-
换一部片 -> 三个都变。`music.seed_from_content: false` 只锁住 **seed 派生**(音色细节);
|
|
129
|
-
`full` 指纹仍会传给 scorekit 参与结构变奏(和弦替换/动机偏移/鼓型 ghost,见
|
|
130
|
-
[audio-variation.md](audio-variation.md) §3.3)。要把声音完全锁回 v0.4 行为,只能不写 `style`(legacy)。
|
|
131
|
-
|
|
132
|
-
## 5. 片内变化:整体是一套,但每段有呼吸
|
|
133
|
-
|
|
134
|
-
**锁三件事**(全片一致,否则会"花"):
|
|
135
|
-
|
|
136
|
-
1. 明暗族(全深色 or 全浅色)
|
|
137
|
-
2. accent 色相
|
|
138
|
-
3. 字体族与字号阶梯
|
|
139
|
-
|
|
140
|
-
**其余可以按章节变**:
|
|
141
|
-
|
|
142
|
-
- 版式骨架轮换(同一 chapter 内不变):left-stack / center-stack / split-right
|
|
143
|
-
- 背景明度微移、纹理强度、accent 出现的面积
|
|
144
|
-
- 配乐:逐小节能量弧线、配器进出(1 小节渐入渐出)、主奏轮换、动机变形
|
|
145
|
-
- 旁白:hook/body/quote/outro 的语气档(语速、音高、停顿)
|
|
146
|
-
|
|
147
|
-
**禁止**:同一部片里跨明暗族换主题(深蓝段直接切暖白段)。实测这会精确触发
|
|
148
|
-
qa_frames 的单帧闪烁门禁(阈值 6.0 灰度,整屏换底可达 100+ 级),而且观众看着像"换了一部片"。
|
|
149
|
-
真需要强对比,把它做成两个片子,或登记成带 visual_at 的视觉事件。
|
|
150
|
-
|
|
151
|
-
## 6. 门禁:主题必须过对比度体检
|
|
152
|
-
|
|
153
|
-
stylekit.theme_lint(theme) 在 --stage style 就拦,不用等渲完 300 帧:
|
|
154
|
-
|
|
155
|
-
| 角色 | 对背景的最低对比度 | 理由 |
|
|
156
|
-
|---|---|---|
|
|
157
|
-
| ink(正文/标题) | 7.0 | WCAG AAA 正文线 |
|
|
158
|
-
| muted(副标) | 4.5 | WCAG AA |
|
|
159
|
-
| dim(HUD 小字) | 3.0 | 装饰级 |
|
|
160
|
-
| accent / accent2 | 4.5 | 强调色常当文字用 |
|
|
161
|
-
| good / bad | 3.0(对卡片底) | 只承载图形,靠位置+颜色双编码 |
|
|
162
|
-
| bg 与 bg2 亮度差 | >= 0.002 | 防纯色底 |
|
|
163
|
-
|
|
164
|
-
加第 9 套风格时:先写 _theme(...),再跑 python stylekit.py --lint,过了再进 STYLES。
|
|
165
|
-
|
|
166
|
-
## 7. 加一套自己的风格(5 步)
|
|
167
|
-
|
|
168
|
-
1. stylekit.THEMES["my-style"] = _theme(...)(配色 + 材质 + 排版 + 版式 + 动态 + HUD)
|
|
169
|
-
2. stylekit.STYLES["my-style"] = {...}(theme / layouts / music{bpm_ladder,keys,mood} / voice / pacing)
|
|
170
|
-
3. STYLE_IDS 元组末尾追加(只追加不改顺序,否则指纹映射会漂)
|
|
171
|
-
4. python stylekit.py --lint 全绿;配乐侧在 scorekit.MUSIC_STYLES 里加同名条目
|
|
172
|
-
5. 用 3 段样片跑 --stage stills 亲眼看(铁律 6:能出图 != 没问题)
|
|
173
|
-
|
|
174
|
-
## 8. 常见误用
|
|
175
|
-
|
|
176
|
-
| 现象 | 原因 | 修法 |
|
|
177
|
-
|---|---|---|
|
|
178
|
-
| 画面换了、配乐还是老的 | 只改了 visual.theme 没改 music.style | 直接改 style,或两个都写 |
|
|
179
|
-
| 同一部片前后像两部片 | 段界跨了明暗族 | 用同族主题;或拆成两部 |
|
|
180
|
-
| 改台词后配乐变了 | 改了标题或 kind 结构 -> tempo 指纹变(BPM/调性跟着换) | 写死 music.key / music.bpm(`seed_from_content:false` 只管音色 seed,压不住 BPM/调性变化) |
|
|
181
|
-
| 旁白听感像广播剧 | max_distinct 太大 / 相邻句频繁换人 | 降到 2,靠 tone 而不是换人做变化 |
|
|
182
|
-
| 字幕在浅色主题上看不清 | 用了 v0.4 的黑底白字 | 传 theme= 给 draw_subtitle(render.py 已自动传) |
|
|
183
|
-
|
|
184
|
-
## 9. 视觉语言包(v0.9):结构签名,不只是配色
|
|
185
|
-
|
|
186
|
-
### 9.1 为什么还要这一层
|
|
187
|
-
|
|
188
|
-
v0.5 的 `STYLES` / `THEMES` 管的是**皮肤**:配色、字体族、纹理、颗粒、字距、缓动、HUD、
|
|
189
|
-
3 种版式几何。8 套风格共用同一批绘制器与同一套装饰,于是"换风格"在画面上只剩换色——
|
|
190
|
-
灰度量出来的构图骨架(前景占比 / 重心 / 边缘占用 / 左右对称)几乎不动。
|
|
191
|
-
|
|
192
|
-
`stylekit.VISUAL_LANGUAGES` 补的是**结构签名**:同一段内容在两套风格下,剪影必须能区分。
|
|
193
|
-
它是纯数据(不 import PIL / filmkit,否则与 `scenes.py` 成环),与 `STYLES` 同层,
|
|
194
|
-
`--stage style` 一起体检。
|
|
195
|
-
|
|
196
|
-
### 9.2 五组签名字段
|
|
197
|
-
|
|
198
|
-
| 组 | 字段 | 取值 / 例子 | 谁读它 |
|
|
199
|
-
|---|---|---|---|
|
|
200
|
-
| `motion` | `ease` | `out3` / `out5` / `inOut3` / `outBack` | `scenes.py`(所有绘制器的入场缓动) |
|
|
201
|
-
| | `breathe_hz` | 0.28–1.10(Hz) | `scenes.py`(强调线/下划线/光点呼吸频率) |
|
|
202
|
-
| | `enter` | `(起, 止)` 秒,如 `(0.70, 1.20)` | **已声明、visual_lint 会查、绘制器暂未读** |
|
|
203
|
-
| | `push` | 0–0.16(背景缓推幅度) | **已声明、visual_lint 会查、绘制器暂未读**(主题自带的 `push` 仍生效) |
|
|
204
|
-
| `motif` | `kind` | `brackets` / `hairlines` / `handdrawn` / `slabs` / `minimal` / `letterbox` / `signal` / `rays` | `scenes._motif_layer` 烘焙母题、`scenes._plate` 合成进背景底版;v0.9.1 起逐帧只 copy/EXTENT(约 1.3–2.0 ms),不再逐帧 paste(实测 5.6 ms) |
|
|
205
|
-
| | `density` | 0–1(母题浓度;0 只允许 `minimal`) | `scenes._decor_scale`(再乘片内密度档 0.55/0.75/1.0) |
|
|
206
|
-
| | `detail` | 母题专属参数(`corner`/`rule_step`/`wobble`/`top`/`bars`/`rays` …) | 同上 |
|
|
207
|
-
| `transition` | `kind` | `dip` / `wash` / `paper` / `wipe` / `cut` / `iris` | `scenes._apply_veil`(段首 ≤0.45 s 内生效) |
|
|
208
|
-
| | `dur` | 0–0.60 秒 | 同上;超过 0.60 s 会糊掉 3–6 s 节奏下限 |
|
|
209
|
-
| `typography` | `tracking` | 0–8 px(字距;与主题自带字距相加) | `scenes._tracking` |
|
|
210
|
-
| | `line_gap` | 1.15–1.55(行高倍数) | `scenes._gap` |
|
|
211
|
-
| | `number` | `dim` / `serif` / `cn` / `block` / `roman` / `timecode` / `dot` / `gilt` | `scenes._number_text`(章节编号、列表序号、流程节点号) |
|
|
212
|
-
| | `align` / `ratio` | `left`/`center`/`right`;display:body 字号比 1.0–3.6 | **已声明、visual_lint 会查、绘制器暂未读** |
|
|
213
|
-
| `bias` | `x` / `y` / `inset` | px,如 `{"x": -150, "y": 80, "inset": 40}` | `scenes._bias`(整体重心偏移;`inset` 只作用于左对齐起点) |
|
|
214
|
-
|
|
215
|
-
两条设计约束(改的时候别破):
|
|
216
|
-
|
|
217
|
-
1. **每条签名都要"能被剪影看出差别"**:只改颜色/字重/描边的项不算签名。
|
|
218
|
-
2. **受单帧预算约束**:装饰必须在烘焙阶段合成进底版(`_plate`),逐帧只剩 copy/EXTENT;
|
|
219
|
-
禁每帧全屏 GaussianBlur(实测 30–60 ms)、全屏双线性 resize(29 ms)与全屏 RGBA paste
|
|
220
|
-
(实测 5.6 ms——0.9.0 就是栽在这,0.9.1 才改掉),预算 25 ms。
|
|
221
|
-
|
|
222
|
-
### 9.3 8 套风格的签名摘要
|
|
223
|
-
|
|
224
|
-
| 风格 | motion(ease / 呼吸) | motif(母题 / 密度) | transition | typography(字距 / 行高 / 编号) | bias(x,y,inset) |
|
|
225
|
-
|---|---|---|---|---|---|
|
|
226
|
-
| tech-deep | out3 / 0.85 | brackets / 1.00(四角 L 括角 + 刻度尺 + 扫描线) | dip 0.28 s | 0 / 1.30 / dim | (0, 0, 0) |
|
|
227
|
-
| magazine | out5 / 0.50 | hairlines / 0.85(双横线页眉 + 栏间线 + 页码位) | wash 0.35 s | 2 / 1.34 / serif | (+60, −20, 0) |
|
|
228
|
-
| paper | inOut3 / 0.42 | handdrawn / 1.00(手绘内框 + 胶带 + 印章) | paper 0.35 s | 1 / 1.36 / cn(一、二、三) | (−150, +80, 40) |
|
|
229
|
-
| vivid | outBack / 1.10 | slabs / 1.00(粗色块 + 斜切 + 贴纸) | wipe 0.20 s | 1 / 1.26 / block | (0, +40, 0) |
|
|
230
|
-
| mono | inOut3 / 0.35 | minimal / 0.55(极细线 + 直角框) | cut 0.00 s | 6 / 1.40 / roman | (0, 0, 0) |
|
|
231
|
-
| cinema | inOut3 / 0.30 | letterbox / 1.00(上下遮幅 + 光斑) | dip 0.45 s | 3 / 1.38 / timecode | (0, +30, 0) |
|
|
232
|
-
| lo-fi | out3 / 0.60 | signal / 0.90(信号条 + 时间戳) | wash 0.30 s | 1 / 1.36 / dot | (+60, −70, 0) |
|
|
233
|
-
| epic | out5 / 0.28 | rays / 1.00(放射射线 + 金线框) | iris 0.40 s | 4 / 1.32 / gilt | (0, −30, 0) |
|
|
234
|
-
| legacy | out3 / 0.85 | brackets / 1.00(detail 为空) | cut 0.00 s | 0 / 1.30 / dim | 不参与(走老绘制器) |
|
|
235
|
-
|
|
236
|
-
`layout_cycle` 字段也写在每套里(版式轮换顺序),但**当前没有消费者**——
|
|
237
|
-
按章节轮换版式的逻辑在 `STYLES[style]["layouts"]` 那一层(见 §5 与 SKILL §5.5)。
|
|
238
|
-
|
|
239
|
-
### 9.4 `visual_lint` 查什么
|
|
240
|
-
|
|
241
|
-
在 `--stage style` 就拦(`render.py` 解析风格时调用,坏配置直接 `SystemExit`),
|
|
242
|
-
不用等渲到第 300 帧才发现"每段转场糊 1 秒":
|
|
243
|
-
|
|
244
|
-
| 检查 | 线 |
|
|
245
|
-
|---|---|
|
|
246
|
-
| `motif.kind` | 必须在 `VISUAL_MOTIFS` 的 8 个里 |
|
|
247
|
-
| `transition.kind` | 必须在 `VISUAL_TRANSITIONS` 的 6 个里 |
|
|
248
|
-
| `transition.dur` | 0–0.60 s |
|
|
249
|
-
| `typography.number` | 必须在 `NUMBER_STYLES` 的 8 个里 |
|
|
250
|
-
| `typography.ratio` | 1.0–3.6 |
|
|
251
|
-
| `typography.tracking` | 0–8 px |
|
|
252
|
-
| `typography.line_gap` | 1.15–1.55 |
|
|
253
|
-
| `motif.density` | 0–1;为 0 只允许 `minimal` |
|
|
254
|
-
| `motion.enter` | `(起, 止)` 且 0 < 起 ≤ 止 ≤ 1.6 s |
|
|
255
|
-
| `motion.push` | 0–0.16(超过会把内容推出安全区) |
|
|
256
|
-
|
|
257
|
-
`selfcheck` 第 53 条另查两件 `visual_lint` 查不到的:8 套签名齐全(motion / typography 都有),
|
|
258
|
-
且**母题 / 转场 / 重心三元组不重复**(全同 = 这套语言只是复制粘贴)。
|
|
259
|
-
|
|
260
|
-
剪影是否真的可区分,由 `tools/silhouette_qa.py`(门禁 G13)量:同内容同段落在两套风格下
|
|
261
|
-
各渲 3 帧 → 灰度 → 480×270 → 四角亮度中位数三值化 → 比前景占比 F / 质心 (Cx,Cy) /
|
|
262
|
-
四边覆盖率 B / 左右对称度 S;五项里任一项达标即 PASS(ΔF≥6pp、|ΔCx|≥8pp、|ΔCy|≥8pp、
|
|
263
|
-
ΔB≥14pp、ΔS≥0.20),同一指标必须 3 帧全达标。当前实测 **28 对全过(同明暗族 12/12)**;
|
|
264
|
-
改造前基线同族只过 8/12。
|
|
265
|
-
|
|
266
|
-
### 9.5 加第 9 套风格时,视觉语言要补什么
|
|
267
|
-
|
|
268
|
-
主题与风格包的 5 步见 §7;v0.9 起还要多做四步,**否则新风格在剪影上仍然只是换色**:
|
|
269
|
-
|
|
270
|
-
1. **`stylekit.VISUAL_LANGUAGES["my-style"]` 写全五组**:motion(ease / enter / push /
|
|
271
|
-
breathe_hz)、motif(kind + density + detail)、transition(kind + dur)、
|
|
272
|
-
typography(tracking / line_gap / align / number / ratio)、bias(x / y / inset)。
|
|
273
|
-
照抄一套现有签名再改配色 = 白做,第 53 条会报"母题/转场/重心完全相同"。
|
|
274
|
-
2. **母题不要临时发明新名字**:`motif.kind` 必须是 `VISUAL_MOTIFS` 里的 8 个之一。
|
|
275
|
-
确实需要新图形语言时,先在 `scenes._motif_layer` 里实现一个分支、加进 `VISUAL_MOTIFS`,
|
|
276
|
-
再在风格里引用——顺序反了会 `visual_lint` 直接拦。
|
|
277
|
-
3. **跑 `python stylekit.py --lint`**(主题对比度)与**单独跑 `visual_lint`**
|
|
278
|
-
(写个三行的 `.py` 调 `stylekit.visual_lint("my-style")`,或直接 `--stage style`)。
|
|
279
|
-
4. **跑剪影门禁**:`python tools/silhouette_qa.py --styles my-style,tech-deep,...`,
|
|
280
|
-
确认新风格与其余 8 套两两可区分;再跑 `selfcheck`(第 53 条会要求三元组不重复)。
|
|
281
|
-
5. **看片**:`--stage stills` 渲 3 段亲眼确认母题/转场/字距不是"看着像另一套"——
|
|
282
|
-
数字过了不等于观感对了(铁律 6)。
|
|
283
|
-
|