2026-10-30

用 Claude Code 做一条「Vibe 知识大赏」:从原理到成片的完整教程

拆解最近刷屏抖音、B 站、小红书的「Vibe 知识大赏」类知识短片:需要的背景知识、工具与环境、SVG 代码视频「画面 = f(t)」的工作原理,以及用 Claude Code 从选题、分镜、逐帧渲染到混音成片的完整步骤。


国庆之后,你大概率刷到过这样的视频:深蓝近黑的背景,没有人出镜,也常常没有旁白;屏幕中央一条金色曲线自己”长”出来,底部一行中文字幕配一行英文斜体小字,背景是一段 77 BPM 左右的钢琴 pad。两三分钟讲完一个”信息论”“秘书问题”“邓巴数”,看完像刷了一支 MV,还顺手学到了点东西。

这就是 「Vibe 知识大赏」。它最反直觉的一点是:画面里没有一帧是”生成”出来的像素,全部是代码画的。 作者用自然语言指挥 Claude 写 HTML/SVG/Canvas 动画,再让无头浏览器逐帧截图,最后用 ffmpeg 压成 MP4。

这篇文章讲清楚三件事:

  1. 这类视频为什么能用代码做,SVG 视频的核心原理是什么;
  2. 要做它,需要准备哪些知识、工具和环境;
  3. 用 Claude Code 从一个选题走到一条成片,每一步该做什么、该对 Agent 说什么。

说明:本文是方法教程,文中的代码片段和命令是用来解释原理和流程的示意代码,写作时没有在本机实际渲染过视频。各开源 Skill 的安装方式迭代很快,动手前请以各仓库 README 的最新说明为准。

0. 先认识一下:什么是「Vibe 知识大赏」

0.1 一个由模型能力撬开的内容风口

时间线大致是这样的:

同一篇报道给了一个很说明问题的对比:过去回形针 PaperClip 这种知识可视化头部团队,一条 5 分钟视频要 4–5 人做 2–4 周;而现在,一个熟练的个人创作者一天就能迭代出一条。门槛被压低的不是”审美”,而是”把审美变成画面”的那部分手艺。

0.2 这类视频长什么样

社区里有人对 8 条爆款原片做了逐帧逆向(见 vibe-knowledge-video 的风格规范),归纳出的”风格 DNA”大致如下:

维度 典型取值
规格 1920×1080 横屏,30fps,H.264 + AAC
时长 2–3 分钟居多(实测 119–166 秒,中位约 130 秒)
声音 多数无旁白;纯器乐 BGM,76–78 BPM,小调
配色 深蓝黑背景 #050510~#12122a,白字 + 一种强调色(暖橙 / 金色)
字幕 底部中文主句 + 一行英文斜体小字,每句 ≤ 20 字
结构 先抛问题(钩子)→ 15–20 秒处落片名卡 → 演示 / 模拟 → 泛化到生活 → 引用与声明
动效 画面”一直在动”;ease-in-out 缓动,禁止匀速;转场是”长出来的”,极少黑场硬切
严谨性 年份、人名、数字上屏;历史文献复原标”图为示意”;结尾给学术引用

也有带旁白的流派——比如 andyhuo520/vibe-knowledge 默认使用 TTS 旁白、44 套风格。但”代码逐帧画面 + 字幕 + 音乐”的骨架是一样的。

1. 需要提前了解的背景知识

不需要你是前端工程师,但下面这几块概念最好心里有数——你不用自己写代码,但你得看得懂 Agent 在干什么,并且能准确地提出修改意见。

1.1 两条完全不同的 AI 视频路线

  代码动效(本文) 视频生成模型(Sora、可灵等)
画面来源 代码按时间逐帧绘制 模型从噪声中生成像素
文字和数字 永远清晰准确,可以逐字改 容易错字、变形
写实人物 / 实景 弱,天然偏图形化 强
时长 不受限 单段通常十几秒,需拼接
修改方式 改一行代码重新渲染,结果确定 重新抽卡,结果随机

知识类视频的核心是概念、数据、文字和图表,这正是代码动效的主场。这也是为什么这个赛道是被一个”写代码的模型”引爆的,而不是被一个”生成视频的模型”引爆的。

1.2 前端三件套:够用就行

1.3 视频与音频的基础概念

概念 你需要知道的
帧率(fps) 30fps 意味着 130 秒的片子要画 3900 帧
编码 / 封装 视频常用 H.264(libx264),音频 AAC,封装成 .mp4;像素格式用 yuv420p 才能在手机上正常播放
BPM / 拍 77 BPM ≈ 每拍 0.78 秒。爆款片的关键动作通常卡在拍点或小节头上
响度(LUFS) 短视频平台常用 −14 LUFS 左右做标准化,太小声会被淹没、太大声会被压缩

1.4 Claude Code 的几个关键概念

Claude Code 是 Anthropic 的终端 Agent,它能读写文件、执行命令、自己看截图再改。做视频时会频繁用到:

2. 需要安装的工具与环境

2.1 清单

工具 用途 是否必需
Claude Code + Claude 订阅(Pro / Max)或 API 写脚本、写动画代码、跑渲染、看图改图 必需
Node.js 20+ 跑本地预览服务、Node 版渲染脚本 视 Skill 而定,建议装
Python 3.11+ 多数 Skill 的渲染 / 混音脚本用 Python 建议装
Playwright + Chromium 无头浏览器,逐帧截图 必需
ffmpeg 图片序列 → 视频,混音,响度标准化 必需
开源字体(Noto Sans SC / Noto Serif SC / EB Garamond 等) 中文粗黑体、衬线标题、英文斜体 必需(字体决定一半的质感)
numpy / scipy 程序化合成 BGM 与音效 视 Skill 而定
TTS 服务 做有旁白的版本时生成配音 可选
图像 / 视频生成 MCP 少数写实镜头的”增强档” 可选

2.2 安装参考(以 macOS 为例)

下面的命令只是参考,具体以各工具官网为准:

# 1. Claude Code(官方原生安装脚本;也可以 brew install --cask claude-code)
curl -fsSL https://claude.ai/install.sh | bash
claude --version

# 2. 基础运行时与 ffmpeg
brew install node python@3.12 ffmpeg

# 3. 建一个独立的 Python 虚拟环境,装渲染依赖
python3 -m venv ~/.venvs/vibe
~/.venvs/vibe/bin/pip install playwright numpy scipy pillow
~/.venvs/vibe/bin/python -m playwright install chromium

Windows 用户建议直接在 WSL 里完成上面这些步骤,路径和命令几乎一致。

几个容易忽略的点:

2.3 选一个现成 Skill,还是从零搭

你完全可以从零让 Claude Code 搭一套渲染管线(第 4 节会给提示词),但更省事的做法是先装一个社区 Skill,看懂它的结构,再按自己的审美改。截至本文写作时比较有代表性的几个:

仓库 特点 绘图技术
andyhuo520/vibe-knowledge 带旁白、每句有出处;44 套风格;三次人工确认点;含 OCR 质检 SVG 分层插画 + three.js 引擎
HeyChengC/vibe-knowledge-film 无旁白;”夜曲 / 寓言”两套外观;极其强调”先找形象再写文案”的讲解设计 Canvas + seek(t)
wchhywizd/vibe-knowledge-interactive 168 拍固定节奏;互动式”先下注”开场;附 100 条爆款样本数据 Canvas 2D
xiazhuo123456789/vibe-knowledge-video 逆向 8 条原片得到的风格 DNA 文档,适合当风格参考 —

通用的”HTML 转视频”框架如 HyperFrames、Remotion 也能做,但它们不包含知识片特有的讲解方法论。

Skill 的安装通常就是把目录拷进 ~/.claude/skills/,例如:

git clone https://github.com/HeyChengC/vibe-knowledge-film.git ~/.claude/skills/vibe-knowledge-film

版权提醒:有些仓库附带的 BGM 或示例分镜版权不属于仓库作者(README 里通常写明了),只能用于学习复现,公开发布前必须替换。

3. SVG 视频的工作原理

这一节是全文的核心。理解了它,你就能看懂所有同类 Skill,也能在 Agent 卡住时给出正确的指令。

3.1 一句话原理:画面是时间的确定性函数

传统动画是”让它动起来”;代码视频是“告诉我第 t 秒长什么样”。

整个工程只需要遵守一个约定——页面暴露一个函数:

window.DUR = 130;              // 片长(秒)
window.render = (t) => { ... } // 给定任意时刻 t,把画面摆成那一帧的样子
window.READY = true;           // 字体、图片都加载完了,可以开拍

只要 render(t) 是确定性的——同一个 t 永远画出同一帧,不依赖上一帧的状态、不读系统时间、不用不带种子的随机数——那么:

这就是为什么绝对不要用录屏:录屏受电脑性能影响,复杂场景会掉帧;逐帧渲染则完全不受影响。

3.2 为什么是 SVG

SVG(Scalable Vector Graphics)是用 XML 描述的矢量图。一条曲线、一个圆、一行字,都是 DOM 里的一个元素,位置和样式都是属性:

<svg viewBox="0 0 1920 1080">
  <circle cx="960" cy="540" r="12" fill="#fff"/>
  <path d="M 260 760 C 700 760 760 300 960 300" stroke="#C9A96A" fill="none"/>
  <text x="960" y="960" text-anchor="middle">运气,是有形状的</text>
</svg>

做”动画”,本质就是在 render(t) 里根据 t 改这些属性。SVG 之所以特别适合知识片:

  1. 矢量、与分辨率无关:用 viewBox="0 0 1920 1080" 定义坐标系后,同一份代码可以渲 1080p,也可以把截图倍率调成 2 直接出 4K,线条和文字依然锐利;
  2. 文字排版是一等公民:中英双语字幕、书名号片名卡、文献复原件里的衬线斜体,在 SVG/HTML 里都是真文字,不是图片;
  3. 自带几何 API:getTotalLength()、getPointAtLength() 能直接拿到路径长度和路径上任意一点,”曲线自己长出来”“小球沿曲线走”几行就能写;
  4. 结构化、好修改:每个元素有 id,你可以对 Agent 说”把 #curve 的颜色改成暖橙、线宽加粗到 8”,它改起来很准;
  5. 模型写得特别好:大模型见过海量 SVG/图标/图表代码,写 SVG 插画(人物剪影、印章、纸卡、地图)的成功率很高。

3.3 SVG 动画的三种驱动方式

SVG 本身有好几种”动起来”的写法,但做视频时,最终都要能被 t 精确控制:

方式 写法 能否 seek 到任意 t 做视频是否推荐
SMIL <animate attributeName="cx" dur="3s" .../> 可以:svg.pauseAnimations() + svg.setCurrentTime(t) 一般,复杂编排难维护
CSS / Web Animations @keyframes 或 el.animate() 可以:遍历 document.getAnimations(),pause() 后设置 currentTime = t * 1000 可以,适合简单元素
GSAP 时间线 tl.to('#dot', {x: 500, duration: 2}) 可以:tl.pause(); tl.seek(t) 推荐,缓动丰富、编排方便
纯函数 render(t) 自己算每个属性 天然支持 最推荐,最可控、最易排错

前三种都是”先让它自己播,再想办法把时钟按住”;第四种是从一开始就没有时钟,只有 t。社区里成熟的 Skill 基本都走第四种,或者在第四种外面包一层小工具函数。

3.4 一个最小可运行的 SVG 视频页面(示意)

下面这个页面演示了知识片里最常见的三个动作:曲线描边自绘、小点沿曲线移动、字幕淡入上移。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
  @font-face { font-family: "NotoSansSC"; src: url("fonts/NotoSansSC-Bold.woff2"); }
  html, body { margin: 0; background: #07070f; overflow: hidden; }
  text { font-family: "NotoSansSC", sans-serif; }
</style>
</head>
<body>
<svg id="stage" width="1920" height="1080" viewBox="0 0 1920 1080">
  <defs>
    <filter id="glow">
      <feGaussianBlur stdDeviation="6" result="blur"/>
      <feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge>
    </filter>
  </defs>
  <path id="curve" d="M 260 760 C 700 760 760 300 960 300 S 1220 760 1660 760"
        fill="none" stroke="#C9A96A" stroke-width="6" filter="url(#glow)"/>
  <circle id="dot" r="12" fill="#EAEAF2"/>
  <text id="sub" x="960" y="960" text-anchor="middle" font-size="46" fill="#EAEAF2"></text>
</svg>

<script>
  // ---------- 工具函数:全部是 t 的纯函数 ----------
  const clamp = (x, a = 0, b = 1) => Math.min(b, Math.max(a, x));
  const easeInOut = x => (x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2);
  // 把 t 映射到 [t0, t1] 区间内的 0→1 进度,并加上缓动
  const prog = (t, t0, t1) => easeInOut(clamp((t - t0) / (t1 - t0)));

  const curve = document.getElementById("curve");
  const dot = document.getElementById("dot");
  const sub = document.getElementById("sub");
  const L = curve.getTotalLength();
  curve.style.strokeDasharray = L;

  // 字幕表:[开始秒, 结束秒, 文本]
  const SUBS = [
    [0.5, 4.0, "运气,是有形状的"],
    [4.5, 9.0, "它长得像一座山"],
  ];

  window.DUR = 10;
  window.READY = false;

  window.render = (t) => {
    // 1. 曲线在 1s→6s 之间"长"出来:dashoffset 从 L 减到 0
    const p = prog(t, 1, 6);
    curve.style.strokeDashoffset = L * (1 - p);

    // 2. 小点永远停在曲线的"笔尖"上
    const pt = curve.getPointAtLength(L * p);
    dot.setAttribute("cx", pt.x);
    dot.setAttribute("cy", pt.y);

    // 3. 当前字幕:淡入 0.4s,同时上移 8px
    const s = SUBS.find(([a, b]) => t >= a && t < b);
    sub.textContent = s ? s[2] : "";
    const k = s ? prog(t, s[0], s[0] + 0.4) : 0;
    sub.setAttribute("opacity", k);
    sub.setAttribute("transform", `translate(0, ${8 * (1 - k)})`);
  };

  // 字体就绪后才允许开拍,避免前几帧字体闪变
  document.fonts.ready.then(() => { window.render(0); window.READY = true; });
</script>
</body>
</html>

几个值得记住的技巧:

// mulberry32:一个常用的小型带种子 PRNG
function mulberry32(seed) {
  return function () {
    seed |= 0; seed = (seed + 0x6D2B79F5) | 0;
    let r = Math.imul(seed ^ (seed >>> 15), 1 | seed);
    r = (r + Math.imul(r ^ (r >>> 7), 61 | r)) ^ r;
    return ((r ^ (r >>> 14)) >>> 0) / 4294967296;
  };
}
const rand = mulberry32(42);
const STARS = Array.from({ length: 200 }, () => ({ x: rand() * 1920, y: rand() * 1080, phase: rand() * 6.28 }));
// render(t) 里:opacity = 0.3 + 0.2 * Math.sin(t * 1.5 + star.phase)

星点”闪烁”也只是 sin(t + phase)——依然是 t 的纯函数。

3.5 逐帧捕获:让无头浏览器当摄像机

有了 render(t),”拍摄”就是一个循环:设置时间 → 等浏览器画完 → 截图。用 Playwright(Node 版)示意:

// capture.mjs —— 示意代码
import { chromium } from "playwright";
import { mkdirSync } from "node:fs";

const FPS = 30;
mkdirSync("frames", { recursive: true });

const browser = await chromium.launch();
const page = await browser.newPage({
  viewport: { width: 1920, height: 1080 },
  deviceScaleFactor: 1,          // 改成 2 即输出 3840×2160
});
await page.goto("http://localhost:8080/index.html");
await page.waitForFunction(() => window.READY === true);

const dur = await page.evaluate(() => window.DUR);
const total = Math.round(dur * FPS);

for (let i = 0; i < total; i++) {
  await page.evaluate((t) => {
    window.render(t);
    // 等下一次绘制完成,确保截到的是新画面
    return new Promise((r) => requestAnimationFrame(() => r()));
  }, i / FPS);
  await page.screenshot({ path: `frames/${String(i).padStart(5, "0")}.png` });
}
await browser.close();

为什么要起一个本地 HTTP 服务(localhost:8080)而不是直接打开 file://?因为字体、图片、fetch 读 JSON 在 file:// 协议下经常撞上跨域限制。

并行:因为每一帧互相独立,把 [0, total) 切成 4 段交给 4 个浏览器实例同时跑,速度近似线性提升。社区 Skill 普遍支持 --jobs 4 之类的参数,还支持中断后续跑。

3.6 合成:ffmpeg 把帧和声音缝起来

# 1. 响度标准化(-14 LUFS,峰值 -1 dBTP)
ffmpeg -i mix.wav -af loudnorm=I=-14:TP=-1:LRA=11 mix_norm.wav

# 2. 图片序列 + 音轨 → MP4
ffmpeg -framerate 30 -i frames/%05d.png -i mix_norm.wav \
  -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p \
  -c:a aac -b:a 192k -shortest -movflags +faststart film.mp4

想省磁盘的话,可以不落地 PNG,而是把截图的二进制直接写进 ffmpeg 的标准输入(-f image2pipe -i -)。

3.7 全景图

把上面拼起来,一条 Vibe 知识片的技术管线是这样的:

               ┌───────────────────── 时间轴(唯一事实来源) ─────────────────────┐
               │   SUBS 字幕表 · 场景表 · 音效事件表 EV(都以秒或"拍"为单位)        │
               └───────┬───────────────────────┬───────────────────────┬────────┘
                       │                       │                       │
                ┌──────▼──────┐         ┌──────▼──────┐         ┌──────▼──────┐
                │ 画面 render(t)│        │ BGM(采样 /  │         │ 音效:在事件 │
                │ SVG / Canvas │        │ numpy 合成) │         │ 时刻生成拟音 │
                └──────┬──────┘         └──────┬──────┘         └──────┬──────┘
                       │ Playwright 逐帧截图     └────────── 混音 ─────────┘
                ┌──────▼──────┐                          │ loudnorm -14 LUFS
                │ frames/*.png │                          ▼
                └──────┬──────┘                      mix_norm.wav
                       └─────────────── ffmpeg ──────────┘
                                          ▼
                                       film.mp4

时间轴是唯一的事实来源:字幕什么时候出、音效什么时候响、哪个动作落在第几拍,都从同一张表里读。这样改一句字幕的时长,画面和声音会一起跟着动,不会错位。

3.8 SVG 还是 Canvas?

你会发现不少 Skill 其实用的是 Canvas。两者并不冲突,按画面内容选:

  SVG Canvas 2D
模型 保留模式:DOM 元素,改属性 立即模式:每帧清空重画
擅长 线条、图标、图表、文字排版、插画 成千上万的粒子、手绘笔触、像素风、逐像素特效
缺点 元素多了(数千个)或大面积滤镜时变慢 文字排版、点击区域都要自己管
修改体验 对 Agent 说”改 #curve“很准 要定位到某个绘制函数里

实践中常见的组合是:背景星空 / 粒子用 Canvas 画在底层,主体插画、图表、字幕用 SVG 叠在上面。只要两层都由同一个 render(t) 驱动,就依然是确定性的。

4. 用 Claude Code 制作一条视频:完整步骤

技术管线只占这类视频的一半。另一半,也是决定一条片子是”爆款”还是”PPT 动画”的部分,是讲解设计。下面的步骤融合了几个社区 Skill 的流程,每一步都给出过关标准和可以直接对 Claude Code 说的话。

第 1 步:选题与事实表

好选题的三个检验(来自 vibe-knowledge 的流程):

另一个值得参考的数据结论来自 vibe-knowledge-interactive 的样本统计:条数最多的题材往往不跑量,认知心理类的单条均值明显高于社会经济类。囚徒困境、熵增、墨菲定律这类题已经被讲烂了,避开它们。

选定后,先建事实表 facts.md:每个年份、人名、数字、引文都要有出处和把握程度。

我想做一期 Vibe 知识大赏,主题是「秘书问题 / 37% 法则」。
先不要写代码。请帮我:
1. 用一句话写出本片的论点;
2. 列出 3–8 个要讲的概念,每个写清"要观众明白什么"和"外行卡在哪";
3. 建 facts.md,列出所有要上屏的年份、人名、数字和出处,标注把握程度;
   查不到可靠出处的,换例子,不要编。

过关标准:论点一口气说得完;每个概念你自己能不用术语讲给外行听。

第 2 步:给每个概念找”形象”

这是 vibe-knowledge-film 最强调的一步,也是大量跟风作品失败的原因:屏上的东西只是”配图”,而不是在”讲解”。

它举过一个自己失败的例子:讲蛋白质折叠,全片主体是一串星点连成的折线,颜色、字体、节奏都很像爆款,但观众从头到尾没见过蛋白质是什么——”那串星点换给任何一段文案都成立”。重做后,镜头钻进血管里的红细胞,找到一串珠子,第 6 颗变色,细胞随之弯成镰刀。

找形象时依次问:它本身是个东西吗?是个过程吗?是个量吗?是观众脑子里的事吗?是条规律吗?都不是,才上纯文字。

对 facts.md 里的每个概念,找一个外行在生活里认得的形象来"演"它:
- 屏上的主体必须叫得出日常名字,长得像它本身(不要用点、线、圈、方框代替);
- 字幕里的动词,屏上要真的发生;
- 定下全片唯一的"世界"、一把贯穿的"尺子",以及哪些道具会回场;
- 告诉我全片哪一下最让人"哦——"。
给我 3 个开场钩子方向和你的推荐。

第 3 步:文案和分镜表一起写

没有分镜表,不建工程。 分镜表一句字幕一行:

时间 字幕(中 / 英) 画法 屏上是什么、在干什么 小字注释 观众明白了什么 声音
0:00 你该在第几个人,停下来? / When should you stop looking? 不画 晾衣绳上一排背面朝上的卡片,轻轻摆动 — 这是一个”顺序选择”的问题 pad 进
0:04 一张一张翻,错过了不能回头 / … 演示 卡片从左到右依次翻开,翻过的变灰 注意:只能往前 不可逆 每翻一张一声轻响

几条硬规矩:

第 4 步:定外观,写进 CLAUDE.md

外观跟着题材走:讲心理 / 行为机制,适合”寓言”式的暖色纸艺;讲抽象概念,适合”夜曲”式的深色辉光。定下来以后写进工程根目录的 CLAUDE.md,让每次对话、每一期都遵守:

# 本系列视觉规范
- 画布 1920×1080,30fps;背景 #07070f,主文字 #EAEAF2,强调色 #C9A96A(全片只表示"最优 / 关键")
- 字体:中文 Noto Sans SC 700,片名 Noto Serif SC 900,英文 EB Garamond Italic,全部本地加载
- 纵向 80%–95% 只放字幕;中文 46px,英文 26px #8A8AA0
- 动效只用 ease-in-out;禁止匀速滑动、禁止黑场转场;任何一刻只有一个主体在动
- render(t) 必须确定性:禁用 Date.now(),随机数用带种子的 PRNG
- 示意画面标"图为示意";不加水印以外的署名

第 5 步:建工程,先做最难的一镜

如果装了 Skill,Agent 会用 Skill 自带的脚手架建工程;如果从零开始,可以这样说:

按 CLAUDE.md 的规范,在 ./ep01 下建一个代码视频工程:
- index.html + film.js,暴露 window.DUR / window.render(t) / window.READY;
- 用 SVG 画主体,底层用一个 Canvas 画星点背景,都由同一个 render(t) 驱动;
- 写一个 Playwright 渲染脚本,支持:--sheet 拼接若干时刻的缩略图、--stills 原尺寸截几帧、
  --clip 起止秒 只渲一段、--jobs N 并行渲全片、--det 同一帧渲两次比对是否一致;
- 先只实现分镜表里最难画的那一镜,截静帧给我看。

为什么先做最难的一镜?因为如果最难的那个形象画不出来,就得回第 2 步换形象,越早发现越便宜。

第 6 步:看图改图,至少两轮

这类片子是看着图改出来的,不是写完代码就完了的。Claude Code 能读取自己截的图,要充分利用这个闭环:

用 --sheet 截 3、8、15、22 秒四帧拼图,你自己先看一遍:
遮住字幕和小字,回答"这是什么 / 它在干什么 / 我明白了什么";
检查主体够不够大、缩到手机横屏还认不认得出、有没有东西伸进字幕区、
颜色是否发白、是否有两样东西同时抢着动。
把问题列出来,改完重截同样的时刻,确认改掉了、没改坏别的。至少两轮后再给我看。

你作为导演,给反馈时要具体到时间点和元素:

第 7 步:先交付 30 秒样片,再铺全片

开头 30 秒只讲一件事,让它在屏上完整发生一遍。确认节奏、外观都对了,再按”一个概念一个函数”铺全片,长片按章节拆文件。每做完两三个概念就拼一张缩略图自查:相邻两段是不是长得一样?该回场的道具回来了没有?

第 8 步:声音

第 9 步:终检与发布

整片渲完后做三遍检查:

  1. 静音、遮住字幕看一遍:每一段在讲什么,看得出来吗?
  2. 只读字幕一遍:通顺吗?句子里的名词,屏上都找得到吗?
  3. 对照技术门槛:--det 确定性检查通过;1920×1080 / 30fps;屏上每个数字和 facts.md 一致;响度约 −14 LUFS;没有冻结帧。

发布包可以一起让 Agent 生成:

为成片生成发布包:标题(「Vibe知识大赏 | 《片名》+ 一句钩子」)、2–3 句简介(含年份、人名、反直觉结论)、
5–8 个话题标签、封面(取最有冲击力的那一帧,叠片名)、评论区置顶(学术引用 + 本片由 AI 代码生成的说明)。

5. 常见坑

现象 原因 解决
前几帧字体闪一下 字体没加载完就开拍 document.fonts.ready 之后才置 READY = true;字体本地化
星空每帧都在”跳” 用了 Math.random() 带种子的 PRNG,位置在初始化时算一次
预览正常、成片错乱 render 依赖上一帧状态(比如累加 x += v) 改成 x = f(t) 的纯函数,用 --det 检查
字幕整体错位 时间单位混用(有的用秒、有的用”拍”) 全工程统一单位,在 CLAUDE.md 里写死
渲染越来越慢 大面积 SVG 滤镜、几千个 DOM 元素 粒子挪到 Canvas;滤镜只加在小元素上
手机上播放黑屏 / 花屏 像素格式是 yuv444 ffmpeg 加 -pix_fmt yuv420p
深色背景出现色带 码率太低 降低 crf(18 左右),背景加极淡噪点
片子”像 PPT” 只有配图、没有讲解;画面静止超过 4 秒 回到第 2 步找形象;保证持续微动画
一期 token 烧得很快 反复全片重渲、上下文过长 用 --clip 只重渲出问题的段落;阶段之间 /clear,靠 facts.md 和分镜表传递状态

6. 版权、合规与”模型味”

7. 总结

把整篇文章压缩成一张清单:

  1. 本质:Vibe 知识大赏是”代码即画面”——模型写网页,网页里的每一帧都是时间 t 的确定性函数,无头浏览器逐帧截图,ffmpeg 合成,不调用任何视频生成模型;
  2. SVG 的价值:矢量、分辨率无关、文字排版强、自带路径几何 API、模型写得好;描边自绘、路径跟随、辉光滤镜三板斧覆盖了大部分知识片画面;
  3. 环境:Claude Code + Node/Python + Playwright(Chromium) + ffmpeg + 本地开源字体,就够出片;
  4. 流程:选题与事实表 → 找形象 → 文案与分镜表 → 定外观写进 CLAUDE.md → 先做最难的一镜 → 看图改图 → 30 秒样片 → 铺全片 → 声音 → 三遍终检 → 发布;
  5. 真正的门槛:不在代码,而在讲解设计——屏上的东西观众要认得出、看得见它在变、看完讲得出”因为……所以……”。

技术管线是可以复制的,一个 Skill 就能装好;但”一个概念该用什么形象来演”这件事,没法复制。这也是这股风潮退去以后,真正能留下来的东西。

参考资料


分类:AI / 教程 · 标签:Claude Code / Vibe知识大赏 / SVG / 代码动画 / Playwright / ffmpeg / AI视频 / Agent Skill