SpeedPainter 任务产物拆解(两次真实任务)
#一、真实任务产物拆解
#真实任务产物拆解报告(2026-07-21)
用授权账号跑了一条 10 秒中文任务,把整条流水线的产物全部落盘。这一条把渲染引擎的护城河基本拆穿了。
- taskId:
252e3f9b-2502-4f8c-bf83-5152c07c172d - 输入:一段 79 字中文 +
durationSeconds=10 / 16:9 / zh-CN / subtitles=burn - 计费:
{"creditsCost": 0, "status": "waived"}—— 这条没扣积分(免费额度或 MCP 通道豁免) - 全程返回原文:
任务全程返回.json
#一、最重磅的发现:每个视觉元素是「三件套」
返回的 assets[] 里每个元素都带三个 URL:
| 文件 | 是什么 | 实测 |
|---|---|---|
*_raster.png |
生图模型的原始输出 | 1536×1536 RGB,可爱扁平插画风、粗黑描边、浅色平涂、带颗粒噪点纹理 |
*_outline.svg |
矢量化后的轮廓路径 | viewBox 100 98 1345 1367,只有 11–15 条 <path>,无 stroke 无 fill 属性(默认黑色填充),典型 potrace/vtracer 风格的填充轮廓而非中心线 |
*_color.png |
抠出来的颜色层 | RGBA 1345×1367 —— 尺寸严格等于 SVG 的 viewBox,两层像素级对齐 |
这就证实了两段式渲染:先按 outline.svg 的路径把黑线一条条"描"出来,再把 color.png 铺上去。之前只是从 sketchDuration/colorFillDuration 参数名和 tools 描述里推断,现在是直接拿到了产物。
我们的复刻直接照这个数据结构做:清洗后的插画 → 分离 outline(矢量化)+ color(RGBA 色层)→ 两段渲染。连"color 层裁到内容 bbox、SVG viewBox 与之对齐"这个细节都可以照抄。
#二、渲染器是 ffmpeg,不是浏览器
video: h264 (avc1) 1920×1080 30fps yuv420p 713 kb/s
audio: aac 44100Hz MONO 116 kb/s
TAG:encoder = Lavc59.37.100 libx264 ← 视频流编码器
TAG:encoder = Lavf59.27.100 ← 容器封装器Lavc59 / Lavf59 = FFmpeg 5.1.x。没有任何 Chromium / Remotion / Puppeteer 的痕迹。
⇒ 印证了计划文档里"排除 headless 浏览器截帧路线、走纯栅格化 + ffmpeg"的选型是对的。
#三、BGM:确认没有(功能藏着没开)
silence_start: 1.09 → 1.58 silence_start: 3.00 → 3.54
silence_start: 4.50 → 4.95 silence_start: 5.41 → 5.83
silence_start: 6.39 → 10.01 ← 最后 3.6 秒完全无声
Noise floor dB: -inf ← 绝对数字静音句子之间和片尾都是绝对静音(-inf 本底)。有任何 BGM 都不可能出现这个。加上音轨是单声道 —— 就是一条纯 TTS 人声。
⇒ 和之前从测试文件里推断的"BGM 代码里有、产品上藏着"完全吻合。
#四、白捡的一个设计缺陷(我们可以做得比它好)
旁白 6.39 秒就结束了,视频却是 10 秒 —— 尾部 3.6 秒空转无声。
说明它是按 targetDurationSeconds 硬出片,音频不够就干等。而我们计划文档里定的"音频时长是唯一权威时钟,画面去匹配音频",在这一点上比它更严谨。这条要在文档里标成我们的差异化优势,别跟着它抄。
#五、各阶段真实耗时(timings 原文)
| 阶段 | 秒 | 说明 |
|---|---|---|
| narrativeSeconds | 72.19 | LLM 分镜规划,占了全程一半以上 |
| visualSeconds | 24.22 | 视觉规划 |
| imageSeconds | 23.66 | 生图 2 张 |
| voiceSeconds | 10.05 | TTS |
| vectorizeSeconds | 2.56 | 矢量化,很快 |
| assetUploadSeconds | 3.84 | 传 R2 |
| renderSeconds | 4.65 | 渲染 10 秒 1080p 视频只要 4.65 秒 |
| postSeconds | 1.07 | 后处理 |
| uploadSeconds | 2.08 | 传成片 |
端到端约 145 秒出一条 10 秒视频。
两条关键情报:
- 瓶颈是 LLM(72 秒),不是渲染(4.65 秒)。79 字输入、36 字输出却花了 72 秒 —— 要么是慢的推理型模型,要么是多轮调用。我们用云雾的快模型这一段能压到 10 秒内,总时长直接就能赢它。
- 渲染 4.65 秒/10 秒成片 ⇒ 约 0.5× 实时。我们 8 核 VPS 多进程完全够,计划里"60 秒视频渲染 10–30 秒"的预算是合理的。
#六、成片的视觉设计(照抄清单)
看 关键帧拼图.png 和 frames/:
- 画布不是纯白,是米白(约
#F7F5EF),更耐看不刺眼 - 左上角常驻标题("白板视频制作"),深灰细体,全片不动
- 字幕居中偏下,字号偏小,白底黑字无描边
- 手是浅肤色右手握铅笔,笔尖在左上 —— 和我们用 gpt-image-2 生成的素材构图一模一样,说明我们的提示词方向完全正确
- 一幕里可以有多个视觉元素(本例 2 个:主插画 + play 按钮符号),按确定性网格排布,依次绘制;这就是
validate_explainer_manifest里说的 "deterministic layout" - 绘制顺序肉眼可见是先画外框、再画内部细节,和我们计划里"连通域按行分桶 + 桶内按面积从大到小"的排序策略同一个思路
#七、字幕:句级不是词级
sub.srt 只有 4 条,按中文逗号断句:
00:00:00,041 --> 00:00:01,057 假设要教「泡茶」,
00:00:01,057 --> 00:00:02,804 把步骤拆成四张草图,
00:00:02,804 --> 00:00:04,307 程序一笔笔描,
00:00:04,307 --> 00:00:07,182 加旁白,视频完成。时间戳精确到毫秒且首尾相接,说明 TTS 至少给到了句级/标点级时间戳,但没有做逐词卡拉OK高亮。
⇒ 我们用 edge-tts 的 WordBoundary 能拿到逐词时间戳,字幕精细度可以直接超过它。
#八、仍然没拿到的
- LLM 供应商:分镜文本反推不出模型,返回的元数据里也没有模型名。只知道它慢(72 秒)。
- 生图模型:
raster.png是 1536×1536 —— 这不是 OpenAI gpt-image 的标准尺寸(1024²/1536×1024/1024×1536),风格上有 GPT-Image 特征的颗粒噪点但尺寸对不上,可能是 Z-Image-Turbo 之类或做过放大。无法定论。 - 笔画排序的具体算法:只能从成片肉眼观察(先框后细节),拿不到代码。
#九、存储路径规律(顺带)
https://storage.speedpainter.org/<YYYYMMDD>/mcp-<32位hash>/
mcp-<hash>_whiteboard.mp4
mcp-<hash>_whiteboard.srt
assets/ai-<12位id>_{raster.png,outline.svg,color.png}mcp- 前缀说明它按调用来源(MCP / 网页)分目录。这些 URL 无签名、公开可访问。
#二、英文60秒任务拆解
#第二条任务:英文 60 秒(2026-07-21)
输入:一段 76 词的英文(讲 spaced repetition / SM-2),durationSeconds=60 / 16:9 / en / burn。
taskId bf2ee81a-9c47-4ce2-8258-dc0c3bf633b0,产物全在本目录。
#⭐ 最重要的发现:把它的笔画排序算法逆向出来了
这条任务拿到了 7 个 outline.svg(第一条只有 2 个)。统计每个 SVG 里 <path> 的文档顺序 vs 各 path 起点坐标:
| 样本 | path 数 | 起点 y 递增比例 | 起点 x 递增比例 | 首个 path 是否最复杂 |
|---|---|---|---|---|
ai-4a2a97bcc924 |
19 | 89% | 56% | 否(最复杂的在第 12 位) |
ai-ad84dfbbe7d7 |
31 | 100% | 47% | 是 |
ai-14ebecc2da60(中文那条) |
11 | 80% | 50% | 是 |
结论:它的绘制顺序就是「按 path 起点的 y 坐标从上到下排」。x 完全不参与(50% 等于随机),面积/复杂度也不参与。
第一条 path 通常是覆盖全画面的大结构(子路径数 73–204 个,d 字符串 4 万–8 万字符),因为它的起点 y 最小。
这就是所谓的护城河。它比 VideoScribe 那种"完全靠人工排图层"进了一步,但也就是一次 sort by y 而已 —— 没有骨架、没有连通域分组、没有语义、没有 TSP。
补充:一个
<path>元素内部包含大量子路径(M命令),说明它是把矢量化结果按颜色/区域合并成少数几个 path,再对这几个 path 排序。所以真正被排序的单元只有 11–31 个,粒度很粗。
#其他实测数据
分镜:60 秒出了 5 幕,不是它自己文档里写的 ceil(60/10)=6 幕 —— 服务端并不严格执行公开文档的公式。
| 幕 | 标题 | 视觉数 | 旁白词数 |
|---|---|---|---|
| s1 | Cramming Doesn't Work | 1 | 13 |
| s2 | The Forgetting Curve | 2 | 12 |
| s3 | Spaced Repetition | 1 | 14 |
| s4 | Intervals Grow | 1 | 18 |
| s5 | Long-Term Memory | 2 | 16 |
每幕约 12 秒却只有 12–18 词,低于它文档里"10 秒 18–22 词"的密度。说明服务端的实际语速设定比文档保守(或者文档那个数是给客户端用的上限)。
时长:timings = narrative 68.72s / visual 21.07s / image 58.09s(7 张)/ voice 9.64s / vectorize 4.93s / assetUpload 5.79s / render 22.36s / post 4.96s / upload 1.46s。
- 端到端约 197 秒出 60 秒片
- 渲染 22.36 秒 / 60 秒成片 ≈ 0.37× 实时(比 10 秒那条的 0.47× 还快,说明有固定开销摊薄)
- LLM 依然是最大头(68.7s),且跟输入长度无关(中文那条 72s,这条 68.7s)—— 基本是个固定的慢
成片:1920×1080@30fps h264,60.00 秒整;SRT 15 条;静音段 9 段(依然无 BGM)。
版式(见 关键帧拼图.png):
- 每幕左上角标题会随幕切换(
Cramming Doesn't Work→The Forgetting Curve→ …) - 插画居中单张,即使
visuals有 2 个也是合成在同一区域,没有出现左右分栏 - 字幕在插画下方居中,跟着句子走
- 画布依然是米白
- 手依然是浅肤色右手握铅笔
插画风格:英文这条的图明显更精致(水彩感、多角色、带手写英文单词 gato/mo/mi/nla),和中文那条的四格漫画风格不同 —— 说明视觉规划阶段会根据内容自适应,不是死模板。
#对我们的直接影响
- 排序算法我们可以轻松超过它:它只做了 sort by y。我们哪怕只加"连通域分组 + 组内骨架走笔",观感就会明显更像手绘。
- 它的分镜密度可以直接抄:12 秒 / 12–18 英文词 ≈ 1.2 词/秒,中文那条是 35 字 / 6.4 秒 ≈ 5.5 字/秒。这两个数比它文档里写的更可信,因为是实测。
- 60 秒片 5 幕说明幕数不必死守公式,可以让 LLM 按内容自然分段,只约束上下限。
- LLM 是固定的慢(~70 秒),与输入长度无关 —— 我们换快模型这一段的收益是确定的。
来源:沉淀/explainer-video-逆向素材/06-真实任务产物/00-拆解报告.md;沉淀/explainer-video-逆向素材/07-英文60秒任务/00-拆解报告.md(整理于 2026-08-18)