返回 html-video
2026-05-26-spec-04-storyboard-workflow.md
根目录 / research / 2026-05-26-spec-04-storyboard-workflow.md
1 # RFC-04:Storyboard-first 工作流(产品形态修订)
2
3 > **Status**: Draft v0.1 · **Supersedes部分前 3 份 RFC 假设**
4 > **Date**: 2026-05-26 (after Joey clarification mid-session)
5 > **Scope**: 修订 html-video 的核心用户工作流,从"agent 填 vars 一步 render"改为"资产 → HTML 分镜 → 用户审 → MP4"两段式
6
7 ---
8
9 ## 关键澄清(来自 Joey)
10
11 > 产品内支持上传各种图文资产,整合起来,生成 HTML 的分镜,用户可以先看分镜,确认分镜效果,之后再导出为 MP4。
12
13 这条话改变了 html-video 三层关键定位:
14
15 | 维度 | 前 3 份 RFC 假设 | 修订后 |
16 |---|---|---|
17 | **入口** | 用户已有 template id + 结构化 vars | 用户上传**散落资产**(图片 / 文字 / 数据) |
18 | **中间产物** | 无(直接 render MP4) | **HTML Storyboard**(多个 HTML 分镜,可在浏览器审) |
19 | **审批 gate** | 无 | Storyboard 阶段,用户必须确认才能 render MP4 |
20 | **创作姿态** | 工程师 fill schema | 创作者上传素材 + agent 编排 |
21 | **跟 HF / Remotion 差异** | meta-aggregator + 模板池 | **+ asset-to-storyboard 创作链路**(HF/Remotion 都没有) |
22
23 **这是 html-video 真正的护城河**:HF / Remotion / Motion Canvas 都假定用户已经知道想做什么;html-video 假定用户**只有素材 + 一句话意图**。
24
25 ---
26
27 ## 修订后的核心数据流
28
29 ```
30 ┌─────────────────────────────────────────────────────────────────┐
31 │ Stage 1:资产上传 │
32 │ 用户: 图片 N 张 + 文字段落 + 数据表 + 音频(可选) + 一句话意图 │
33 │ 输出: AssetBundle (项目目录下结构化存放) │
34 └──────────────────────────────┬──────────────────────────────────┘
35
36 ┌─────────────────────────────────────────────────────────────────┐
37 │ Stage 2:分镜生成(agent 主导) │
38 │ agent: 根据意图 + 资产 → 选 templates → 编排 scenes │
39 │ 输出: Storyboard(一组 HTML 分镜 + scene metadata) │
40 └──────────────────────────────┬──────────────────────────────────┘
41
42 ┌─────────────────────────────────────────────────────────────────┐
43 │ Stage 3:分镜审核(用户主导) │
44 │ 用户: 浏览器里逐 scene 看,文字/图片/顺序/时长可改 │
45 │ 工具: html-video preview-storyboard 启 dev server │
46 │ 操作: inline 编辑 / 替换图 / 删 scene / 调时长 / 调顺序 │
47 └──────────────────────────────┬──────────────────────────────────┘
48 ↓ 确认
49 ┌─────────────────────────────────────────────────────────────────┐
50 │ Stage 4:MP4 导出 │
51 │ 输入: 确认后的 Storyboard │
52 │ 操作: 对每个 scene 调对应 EngineAdapter.render() │
53 │ 后处理: 跨 scene 拼接(ffmpeg concat)+ 整体音轨 mux │
54 │ 输出: 最终 MP4 │
55 └─────────────────────────────────────────────────────────────────┘
56 ```
57
58 ---
59
60 ## 新核心概念
61
62 ### Asset
63
64 用户上传的原始物料。**不**经 agent 解读就先入库。
65
66 ```ts
67 // core/types.ts (additions)
68
69 export interface Asset {
70 id: string; // sha1(content),content-addressed
71 type: 'image' | 'text' | 'data' | 'audio' | 'video' | 'reference-link';
72 path?: string; // 本地文件路径(image/audio/video)
73 content?: string; // text / data 内联(小文件)
74 metadata: {
75 filename?: string;
76 mimeType?: string;
77 sizeBytes?: number;
78 width?: number; // image/video
79 height?: number;
80 durationSec?: number; // audio/video
81 /** Joey 给的 caption / 用户标注 */
82 userCaption?: string;
83 };
84 /** 用户上传时的意图标签(自由文本) */
85 userTags: string[];
86 }
87
88 export interface AssetBundle {
89 /** Bundle 唯一 id,对应 project workDir 子目录 */
90 id: string;
91 /** 用户的一句话意图("做个 25 天涨 5 万的曲线视频") */
92 intent: string;
93 /** 用户偏好(aspect / duration target / mood / 商用否) */
94 preferences: UserPreferences;
95 /** 全部资产 */
96 assets: Asset[];
97 /** 上传时间 */
98 createdAt: string;
99 }
100
101 export interface UserPreferences {
102 aspect?: '16:9' | '9:16' | '1:1' | string;
103 durationTargetSec?: number;
104 format?: 'mp4' | 'webm';
105 resolution?: { width: number; height: number };
106 fps?: number;
107 mood?: string; // 自由文本:'energetic' / 'calm' / 'corporate' / 'playful'
108 brandColors?: string[];
109 fontFamilies?: string[];
110 language?: string; // 'zh-CN' / 'en-US'
111 commercial?: boolean;
112 }
113 ```
114
115 ### Storyboard / Scene
116
117 分镜是**多个 scene 拼接**而成的"半成品 HTML 序列",每个 scene 是 RFC-01/02 的 template 渲染产物(HTML 形态而非 MP4)。
118
119 ```ts
120 export interface Storyboard {
121 id: string;
122 bundleId: string; // 来自哪个 AssetBundle
123 intent: string; // 复制 bundle.intent 备查
124 scenes: Scene[];
125 /** 跨 scene 全局音轨(背景乐 / 旁白) */
126 globalAudio?: AudioTrack[];
127 /** 全局 transitions 偏好 */
128 defaultTransition?: TransitionId;
129 /** 总预计时长(所有 scene durationSec 之和) */
130 estimatedDurationSec: number;
131 /** 状态机 */
132 status: 'draft' | 'ready-for-review' | 'approved' | 'rendered';
133 createdAt: string;
134 updatedAt: string;
135 }
136
137 export interface Scene {
138 id: string;
139 /** 这个 scene 用哪个 template + 哪个 engine(RFC-02) */
140 template: { id: string; engine: EngineId };
141 /** 填好的 inputs(RFC-02 inputs.schema 兼容) */
142 variables: Record<string, unknown>;
143 /** 用了哪些 asset (id 引用) */
144 assetRefs: string[];
145 /** 在 storyboard 时间线上的位置(秒) */
146 startSec: number;
147 /** 时长(秒) */
148 durationSec: number;
149 /** 跟下一个 scene 之间的过渡 */
150 transitionToNext?: TransitionId;
151 /** Agent 给这个 scene 的解释(用户审稿时看得到) */
152 agentNote: string;
153 /** scene-level 静态预览 */
154 previewHtmlPath: string; // 渲染好的 HTML 文件
155 previewPosterPath?: string; // 截图
156 }
157
158 export interface AudioTrack {
159 assetId: string; // 指向 AssetBundle.assets 中的 audio asset
160 startSec: number; // 在最终视频中的开始时刻
161 fadeInSec?: number;
162 fadeOutSec?: number;
163 volumeDb?: number;
164 }
165
166 export type TransitionId = 'cut' | 'fade' | 'slide-left' | 'slide-right' | 'zoom' | string;
167 ```
168
169 ---
170
171 ## 修订 EngineAdapter 接口(RFC-01 增量)
172
173 每个 adapter 需要新增一个能力:**把单 scene 渲染成 HTML 而不是 MP4**。这是 storyboard 阶段的快速预览。
174
175 ```ts
176 // 增量加到 RFC-01 的 EngineAdapter interface
177
178 export interface EngineAdapter {
179 // ... 之前的 id / capabilities / validate / render / preview ...
180
181 /** 新增:渲染单 scene 到 HTML(不是 MP4),用于 storyboard 阶段 */
182 renderToHtml?(input: RenderInput, ctx: RenderContext): Promise<HtmlSceneOutput>;
183 }
184
185 export interface HtmlSceneOutput {
186 /** 主 HTML 文件路径 */
187 htmlPath: string;
188 /** 引用的资产(agent 可以用这些做 "替换图片" 操作) */
189 referencedAssets: { assetId: string; usagePath: string }[];
190 /** 单帧静态截图(用作 storyboard grid 缩略) */
191 posterPath: string;
192 /** 这个 scene 在浏览器里的预估时长(用户调整能改) */
193 durationSec: number;
194 }
195 ```
196
197 **fallback**:如果 adapter 没实现 `renderToHtml`,core 提供 default 实现——直接 render MP4 然后 ffmpeg 抽 1 帧 + 包一个 video tag 的 HTML。这条路径慢但能用,鼓励 adapter 自己优化(HF / Remotion 都能直接出 HTML 不出 MP4)。
198
199 ---
200
201 ## 修订 CLI Contract(RFC-03 增量)
202
203 ### 新增命令
204
205 ```bash
206 # 1. 上传资产,建 bundle
207 html-video assets upload \
208 --intent "做个 25 天涨 5 万的曲线视频" \
209 --aspect 16:9 \
210 --commercial true \
211 --files "assets/*.png" \
212 --files "data/stars.csv" \
213 --json
214 # → 输出 bundle_id
215
216 # 2. agent 主导生成 storyboard
217 html-video storyboard generate \
218 --bundle <bundle_id> \
219 --json
220 # → 输出 storyboard_id + scenes 列表
221
222 # 3. 修改 storyboard(agent 受用户指令调用)
223 html-video storyboard edit <storyboard_id> \
224 --op add-scene --template <id> --vars-file scene-vars.json --at 30
225 html-video storyboard edit <storyboard_id> \
226 --op remove-scene --scene <scene_id>
227 html-video storyboard edit <storyboard_id> \
228 --op reorder --scenes <id1>,<id2>,<id3>
229 html-video storyboard edit <storyboard_id> \
230 --op set-duration --scene <scene_id> --duration-sec 8
231 html-video storyboard edit <storyboard_id> \
232 --op replace-asset --scene <scene_id> --old-asset <id> --new-asset <id>
233
234 # 4. 启 storyboard 浏览器预览(不是单 scene preview,是整个 timeline)
235 html-video storyboard preview <storyboard_id> --json
236 # → 输出 url(页面里有 timeline + 每 scene 内嵌 iframe + 编辑控件)
237
238 # 5. 用户确认 → render 全片
239 html-video storyboard render <storyboard_id> \
240 --output ~/Desktop/final.mp4 \
241 --stream-progress --json
242 ```
243
244 ### 修订原来的 `render` 命令
245
246 `html-video render --template ... --vars-file ...` 仍保留,但定位改为 **"开发者直跑单模板"**(template 测试 / CI 用)。**用户主流程不该走这个**——agent 应该用 `storyboard generate / edit / render` 三件套。
247
248 ---
249
250 ## 修订 SKILL.md 工作流(RFC-03 增量)
251
252 新版 SKILL.md 的"Standard workflow"段落:
253
254 ```markdown
255 ## Standard workflow
256
257 ### 1. Initial check
258 `html-video doctor --json` → 处理依赖缺失
259
260 ### 2. Collect assets + intent
261 - If user already has files: `html-video assets upload --files ... --intent ...`
262 - If user gives a vague intent: ask **one batched question**: aspect / mood / duration target / commercial usage
263 - Always extract intent into one sentence to feed into the bundle
264
265 ### 3. Generate storyboard
266 `html-video storyboard generate --bundle <id>`
267
268 The CLI internally:
269 - Searches templates per scene need (intro / data viz / CTA / outro etc)
270 - Selects engines based on RFC-01 capabilities + license filter
271 - Fills inputs using user's assets
272 - Returns scene list with agent_note for each
273
274 ### 4. Show user the storyboard
275 Open `html-video storyboard preview <id>` URL in browser. Tell user:
276 - Estimated total duration
277 - Number of scenes + 1-line agent_note per scene
278 - "Click each scene to view, edit text inline, or tell me what to change"
279
280 ### 5. Iterate on storyboard (multi-turn)
281 User: "把第二个 scene 里的图换成 logo.png"
282 → `html-video storyboard edit <id> --op replace-asset --scene <scene_id> --new-asset <asset_id>`
283
284 User: "缩短到 30 秒以内"
285 → Calculate which scenes to trim, run multiple edit commands
286
287 User: "我觉得 OK 了"
288 → Move to step 6.
289
290 ### 6. Final render to MP4
291 `html-video storyboard render <id> --output <path> --stream-progress`
292
293 Surface progress every 25%. On done, paste output path + open in default player.
294
295 ### Anti-patterns
296 - ❌ Don't render MP4 before user approves storyboard
297 - ❌ Don't skip the storyboard preview link — even if user says "你看着办"
298 - ❌ Don't quietly add scenes the user didn't mention — propose first, edit after confirm
299 - ❌ Don't render same storyboard twice without explicit user request (it's slow)
300 ```
301
302 ---
303
304 ## Storyboard 文件存储约定
305
306 ```
307 project-root/
308 └── .html-video/
309 ├── bundles/
310 │ └── <bundle_id>/
311 │ ├── bundle.json # AssetBundle metadata
312 │ └── assets/
313 │ ├── <asset_id>.png # 内容寻址
314 │ ├── <asset_id>.csv
315 │ └── <asset_id>.txt
316 ├── storyboards/
317 │ └── <storyboard_id>/
318 │ ├── storyboard.json # Storyboard metadata
319 │ └── scenes/
320 │ ├── <scene_id>/
321 │ │ ├── scene.json
322 │ │ ├── preview.html
323 │ │ ├── poster.png
324 │ │ └── source/ # adapter-rendered intermediates
325 └── outputs/
326 └── <storyboard_id>-<timestamp>.mp4
327 ```
328
329 `.html-video/` 放在用户项目根,跟 `.git/` 平级。`.gitignore` 默认 ignore(避免大文件入 git)。
330
331 ---
332
333 ## 跟 RFC-01/02/03 的关系(明确)
334
335 | 修订项 | RFC-01 | RFC-02 | RFC-03 |
336 |---|---|---|---|
337 | EngineAdapter 加 `renderToHtml` | ✅ 修订(增量) | — | — |
338 | Template metadata 加 `scene_role`(intro / data / cta / outro) | — | ✅ 修订(v0.2 加) | — |
339 | Template metadata 加 `assets_consumed`(声明吃哪类 asset) | — | ✅ 修订(v0.2 加) | — |
340 | CLI 加 `assets upload` / `storyboard generate / edit / preview / render` | — | — | ✅ 修订 |
341 | SKILL.md 的工作流改成 storyboard-first | — | — | ✅ 修订 |
342 | `html-video render --template ...` 降格为 dev-mode 命令 | — | — | ✅ 修订 |
343
344 后续会话写代码时按这份 RFC-04 的优先级实现。
345
346 ---
347
348 ## v0.1 MVP 范围(修订后)
349
350 按"两段式工作流"重排优先级:
351
352 - ✅ `@html-video/core`:Asset / AssetBundle / Storyboard / Scene 数据结构 + sqlite 存储 + content-addressed asset store
353 - ✅ `@html-video/adapter-hyperframes`:实现 `renderToHtml` + `render`
354 - ✅ `@html-video/cli`:`doctor` / `assets upload` / `storyboard generate` / `storyboard preview` / `storyboard render`
355 - ✅ `@html-video/storyboard-ui`:浏览器里的 storyboard preview 页面(**新增**,原 RFC-03 没考虑)
356 - timeline 视图
357 - scene grid + 内嵌 iframe
358 - inline edit 文字 / 替换图 / 调时长 / 删 / 重排
359 - 全屏播放 mock(每个 scene HTML loop 起来串)
360 - ✅ 5 个 reference templates(覆盖 intro / data-chart / image-pan / text-card / outro 五种 scene role)
361 - ✅ Claude Code SKILL.md(按 storyboard-first 工作流)
362
363 **不**进 MVP(推到 v0.2+):
364 - ❌ adapter-remotion / motion-canvas / revideo(先把 HF 路径 + storyboard 闭环跑通)
365 - ❌ AI 智能编排(v0.1 agent 是 LLM 即兴选 template,v0.2 加规则 + ML 优化)
366 - ❌ 协作(多人审稿)
367 - ❌ 云端 storyboard 持久化(先纯本地)
368
369 ---
370
371 ## 给 Joey 的话
372
373 这条澄清把 html-video 从"meta-aggregator + agent CLI" 升级成 **"asset-to-video 创作流水线"**——后者是真正有差异化的产品形态,HF / Remotion 都没做这件事,因为他们假设用户是开发者。**新护城河 = 资产理解 + storyboard 编排 + 跨引擎渲染**,三层一起才是 html-video。
374
375 下一步如果你点头,我会按修订后的 v0.1 MVP 范围动手写代码骨架(core 数据结构 + adapter-hyperframes + CLI 几个命令 + storyboard-ui 草稿)。
376
377 ---
378
379 ## Open Questions(v0.2 待定)
380
381 1. **资产理解** —— agent 拿到一堆图,怎么知道哪张是 logo / 产品 / 人物头像?v0.1 用 mime + 文件名启发;v0.2 接 vision model
382 2. **AI 写文案** —— 用户没给文字只给图,agent 是否自动生成 caption?v0.1 提示用户补;v0.2 LLM 生成
383 3. **音频自动选** —— 用户没传 BGM,是否从 license-free 库自动选?v0.1 不做;v0.2 接 Pixabay / FreePD API
384 4. **数据自动可视化** —— 用户上传 CSV,agent 直接选 chart 类型?v0.1 让用户选;v0.2 用 grammar-of-graphics 启发
385 5. **Storyboard 模板**(meta-template) —— 不只是单 scene,整片节奏("先 intro 再 3 个 data 最后 cta")也能模板化?v0.2 加 `storyboard-template` 概念
386
386 lines MARKDOWN