📚 离职知识库

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>,无 strokefill 属性(默认黑色填充),典型 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 秒视频。

两条关键情报:

  1. 瓶颈是 LLM(72 秒),不是渲染(4.65 秒)。79 字输入、36 字输出却花了 72 秒 —— 要么是慢的推理型模型,要么是多轮调用。我们用云雾的快模型这一段能压到 10 秒内,总时长直接就能赢它
  2. 渲染 4.65 秒/10 秒成片 ⇒ 约 0.5× 实时。我们 8 核 VPS 多进程完全够,计划里"60 秒视频渲染 10–30 秒"的预算是合理的。

#六、成片的视觉设计(照抄清单)

关键帧拼图.pngframes/

  • 画布不是纯白,是米白(约 #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 WorkThe Forgetting Curve → …)
  • 插画居中单张,即使 visuals 有 2 个也是合成在同一区域,没有出现左右分栏
  • 字幕在插画下方居中,跟着句子走
  • 画布依然是米白
  • 手依然是浅肤色右手握铅笔

插画风格:英文这条的图明显更精致(水彩感、多角色、带手写英文单词 gato/mo/mi/nla),和中文那条的四格漫画风格不同 —— 说明视觉规划阶段会根据内容自适应,不是死模板。


#对我们的直接影响

  1. 排序算法我们可以轻松超过它:它只做了 sort by y。我们哪怕只加"连通域分组 + 组内骨架走笔",观感就会明显更像手绘。
  2. 它的分镜密度可以直接抄:12 秒 / 12–18 英文词 ≈ 1.2 词/秒,中文那条是 35 字 / 6.4 秒 ≈ 5.5 字/秒。这两个数比它文档里写的更可信,因为是实测。
  3. 60 秒片 5 幕说明幕数不必死守公式,可以让 LLM 按内容自然分段,只约束上下限。
  4. LLM 是固定的慢(~70 秒),与输入长度无关 —— 我们换快模型这一段的收益是确定的。

来源:沉淀/explainer-video-逆向素材/06-真实任务产物/00-拆解报告.md;沉淀/explainer-video-逆向素材/07-英文60秒任务/00-拆解报告.md(整理于 2026-08-18)