[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f3fk0ub9ncu9un":3},{"_id":4,"slug":5,"title":6,"subtitle":7,"kind":8,"cards":9,"tags":57,"categories":58,"source":59,"lang":62,"author":63,"audioState":66,"stats":67,"publishedAt":70,"renderer":71},"6aba309aca21c797c7e98332","skill-f1b23590","分享一个做视频的skill，这条白板视频，每一笔都是代码画的","我对 AI 说了一句话：「做一期白板视频：为什么定了计划总是坚持不下去。」","news",[10,12,17,22,27,32,37,42,47,52],{"headline":6,"body":7,"imageUrl":11,"sourceImageUrl":11},"https:\u002F\u002Fp6-xtjj-sign.byteimg.com\u002Ftos-cn-i-73owjymdk6\u002Fcbefb3445d054a1281250d0c1d92720c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oCV5rWq54yr:q75.awebp?rk3s=f64ab15b&x-expires=1791177129&x-signature=syAIMUIAqtRYju%2BgwZYc8ZNsNwg%3D",{"headline":13,"body":14,"imageUrl":15,"images":16},"一条 1920×1080 的成片 ，131.9 秒，7 个场景，74 条字幕，配了音、烧了字幕、压了配乐；横竖两张封面，4:3 和","一条 1920×1080 的成片 ，131.9 秒，7 个场景，74 条字幕，配了音、烧了字幕、压了配乐；横竖两张封面，4:3 和 3:4，同一个函数一次出；一份发布稿，五个候选标题挑一个主用，视频号简介、小红书、B 站、公众号摘要、推特各写一版；一份资料来源，哪个数字来自哪篇论文、哪句是估算，逐条列清。全程没有打开过剪辑软件。画面上每一笔，都是代码画的。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F1.webp",{"local":15},{"headline":18,"body":19,"imageUrl":20,"images":21},"，131.9 秒，7 个场景，74 条字幕，配了音、烧了字幕、压了配乐；横竖两张封面，4:3 和 3:4，同一个函数一次出；一份发布稿，五个候选标题挑一个主用，…","，131.9 秒，7 个场景，74 条字幕，配了音、烧了字幕、压了配乐；横竖两张封面，4:3 和 3:4，同一个函数一次出；一份发布稿，五个候选标题挑一个主用，视频号简介、小红书、B 站、公众号摘要、推特各写一版；一份资料来源，哪个数字来自哪篇论文、哪句是估算，逐条列清。全程没有打开过剪辑软件。画面上每一笔，都是代码画的。 这个技能叫 whiteboard-video，开源在 github.com\u002Ftrustfuture\u002Fsimon-skills 的 skills\u002Fwhiteboard-video 目录下，MIT 协议。 成片前 20 秒，未加速、未抽帧。线条是一笔一笔长出来的，人物贴纸是\"擦\"出来的，字幕跟着人声走。 第 20–40 秒。第一个场景画满之后，镜头切到第二个场景，三圈模型从外圈往内圈逐笔成形。 这就是这个技能要解决的全部问题：让一个不会画画、也不想开剪辑软件的人，把\"讲清一件事\"变成一条能发的视频。 一、先说结论：它不是\"生成视频\"，是一条可拆的流水线 现在讲\"AI 做视频\"的产品不少，但绝大多数是黑盒——你给它提示词，它给你一段画面，中间发生了什么你不知道，想改一个细节只能重新抽卡。 whiteboard-video 是反过来的：它是一条十步的流水线，每一步都能单独跑、单独看、单独改。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F2.webp",{"local":20},{"headline":23,"body":24,"imageUrl":25,"images":26},"| 环节 | 用什么 | 备注 | |","| 环节 | 用什么 | 备注 | | --- | --- | --- | | 手绘线条 | rough.js（Excalidraw 的底层库） | 场景同时导出 Excalidraw 格式，装 Obsidian 插件能直接打开改 | | 逐笔动画 | Playwright 在 Chromium 里逐帧截图 | 4 路并行，2.5 分钟的片子渲染约 35 秒 | | 人物与道具贴纸 | 本地 codex CLI 生图 | 一次 2×2 四宫格同风格，自动抠白底、去杂点 | | 公司 \u002F 产品 Logo | Wikimedia Commons 官方 SVG | 出处自动记录 | | 配音与字幕 | 火山引擎语音合成 | 原生 1.2 倍语速，返回逐字时间戳直接对字幕 | | 合成 | ffmpeg | 拼帧、烧字幕、说话时自动压低配乐 | 绿框那三步决定\"画面长什么样\"，其余七步是纪律性工序。整条链跑完约 40 秒（TTS 命中缓存时），渲染整期只跑 35 秒——比大多数人的导出时间短一个量级。 关键差别在于：这里的每一步都是一个可以单独调用的命令。 stills 这一步是整个技能最\"反 AI\"的设计：它不让你一路跑到底，而是逼你在渲染前先用静态图确认每一屏的排版。 排版错了，改的是代码，不是抽卡。 官方给每期的交付定义是\"四件套\"：成片 + 两张封面 + 发布稿 + 资料来源。后两件经常被忽略，但恰恰是对做内容的人最值钱的部分。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F3.webp",{"local":25},{"headline":28,"body":29,"imageUrl":30,"images":31},"上面这张是横版（4:3）与竖版（3:4）两张封面，由同一个 cover 函数一次生成，不是做两遍。左图那行\"道理都懂 \u002F…","上面这张是横版（4:3）与竖版（3:4）两张封面，由同一个 cover 函数一次生成，不是做两遍。左图那行\"道理都懂 \u002F 为什么没变化？\"是脚本里的两行字符串，绿色高亮和马克笔底色是自动加的；右下角的 \"Your Brand\" 是占位品牌，改 config.json 一处就换成你自己的。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F4.webp",{"local":30},{"headline":33,"body":34,"imageUrl":35,"images":36},"发布稿那一份更实用——它按平台拆好了：视频号简介、小红书标题+正文+标签、B 站标题、公众号摘要、置顶评论，另外给五个候选标题标好类型（数字反差 \u002F 结论前置…","发布稿那一份更实用——它按平台拆好了：视频号简介、小红书标题+正文+标签、B 站标题、公众号摘要、置顶评论，另外给五个候选标题标好类型（数字反差 \u002F 结论前置 \u002F 生活单位换算 \u002F 提问）。这是把一个内容团队里\"运营岗\"的活，固化进了模板。 整条链上最反直觉的一条规矩，写在 SKILL.md 第 3 条： 先旁白后画面。 旁白按 | 切 beat，每 beat 34 句配一组元素；68 个场景，成片 2~2.5 分钟。 旁白按 | 切 beat，每 beat 34 句配一组元素；68 个场景，成片 2~2.5 分钟。 每个 beat 都要有能画出来的东西，抽象句并入相邻 beat。 每个 beat 都要有能画出来的东西，抽象句并入相邻 beat。 这句话看着像写作建议，其实是给内容做减法的手术刀。它意味着：任何一句\"没有画面可画\"的旁白，不允许只当文字存在——要么给它配个画面，要么把它并进旁边那句。 结果就是这类视频里不太会出现\"综上所述，我们可以看出……\"这种句子，因为它画不出来。内容是倒逼出来的，不是先写文案再找配图。 旁白和场景写在同一个文件里，scenes.js 是这一期唯一的手写源：","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F5.webp",{"local":35},{"headline":38,"body":39,"imageUrl":40,"images":41},"看第四行那个 |——它就是 beat 的分界。坐标是写死的（zones(s, 640, 560, 520)…","看第四行那个 |——它就是 beat 的分界。坐标是写死的（zones(s, 640, 560, 520) 是三个同心圈的圆心和半径），贴纸按名字引用（s.image(1560, 400, 'stuck')）。一行代码一个元素，不需要任何可视化编辑器。 这是全篇技术含量最高的一段，也是我认为这个技能真正不可替代的地方。 普通做法是\"把一张画好的图加上手绘滤镜\"，看起来像白板，但没有过程。而这个技能要的是\"边画边讲\"——线条必须按人手的顺序长出来。 先看这一段单独的逐笔动图（11 秒，同样未加速）： 一个场景从空板到画满的全过程。左上角那支黄色铅笔会跟着当前正在描的路径移动——这个细节是渲染器算出来的，不是贴上去的装饰。 上面是同一场景在 0.6 秒、3.2 秒、6.4 秒、9.6 秒的四个状态：空白 → 主视觉逐笔描出 → 圈线和标签 → 卡片、箭头落位。左上角那支铅笔会跟着当前正在描的路径移动。 要做到这个效果，渲染器里有三件事必须做对，而这三件事都是踩出来才知道的： 第一，按子路径顺序描边。 rough.js 画出来的每条线是 toPaths 的结果，而一条\"线\"内部往往由多个子路径组成。描边顺序错了，就会出现这一笔还没画完、下一笔已经冒出来的错位。 第二，双描边拆 A\u002FB 层。 Excalidraw 风格的手绘线是\"双描边\"效果（看起来像用笔描了两遍）。这两遍不能同时动画，否则会像两条线在赛跑。 第三，也是最硬的一条坑，SKILL.md「已知坑」里原话是： SVG dash 在每个子路径 M 处重起，rough.js 又双描边：整条 path 一起 dashoffset 会\"所有边同时长、每边描两遍\"。渲染器已按子路径拆节点、双描边拆 A\u002FB 层，别回退。 SVG dash 在每个子路径 M 处重起，rough.js 又双描边：整条 path 一起 dashoffset 会\"所有边同时长、每边描两遍\"。渲染器已按子路径拆节点、双描边拆 A\u002FB 层，别回退。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F6.webp",{"local":40},{"headline":43,"body":44,"imageUrl":45,"images":46},"翻译一下：如果你偷懒，把整条路径当成一个对象做\"描边进度\"动画，你会得到一屏幕同时伸长、每边描两遍的线。要解决它，必须把路径按 M 命令拆成节点逐个控制。…","翻译一下：如果你偷懒，把整条路径当成一个对象做\"描边进度\"动画，你会得到一屏幕同时伸长、每边描两遍的线。要解决它，必须把路径按 M 命令拆成节点逐个控制。 并行出帧靠两点，别动：render.html 的 seek()每帧把底色矩形原地重插，强制整屏重画（否则 Chromium 只重画变化区域，帧会跟出帧顺序有关）。 并行出帧靠两点，别动：render.html 的 seek()每帧把底色矩形原地重插，强制整屏重画（否则 Chromium 只重画变化区域，帧会跟出帧顺序有关）。 浏览器为了省算力只重绘变化区域，这在交互场景里是优点；但在\"逐帧截图\"的场景里，它会让每一帧的内容取决于你截图的顺序——并行之后，帧序就乱了，视频会闪。 解法是每帧强制整屏重画。 这几条加起来，解释了为什么这个技能能把\"2.5 分钟的片子\"压进\"35 秒渲染\"：4 路并行，每路一个独立 Chromium，再配上逐帧一致性校验（ffmpeg -f framemd5 对比必须 0 帧不同）。 这些不是\"用 AI 生成视频\"，这是把渲染工程做扎实。 绝大多数自动配音加字幕的流程是这样的：先算这句話大概几秒，再按字数把字幕平均切进去。结果是字幕永远比声音慢半拍或快半拍。 这个技能绕开了这个猜测环节——火山引擎的语音合成会返回逐字时间戳，字幕直接用真实时间戳排。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F7.webp",{"local":45},{"headline":48,"body":49,"imageUrl":50,"images":51},"| 环节 | 具体做法 | | --- |","| 环节 | 具体做法 | | --- | --- | | 切句 | lib\u002Fcaptions.cjs 按 6~20 字切成短句，不按标点硬切 | | 烧录 | 底部字幕区（y≥960）烧进画面 | | 导出 | 同时出一份 字幕.srt | | 校验 | tts-volc.mjs 按逐字数校验，半段音频自动重试 | 字幕文本必须用原文。 TTS 会把 @grok 念成 \"atgrok\"——所以字幕不能跟着 TTS 的发音走，得用你写的那份原文。 TTS 会把 @grok 念成 \"atgrok\"——所以字幕不能跟着 TTS 的发音走，得用你写的那份原文。 改旁白必须重跑 TTS。 时间戳来自配音，旁白改了不重跑，字幕就会全体错位。 时间戳来自配音，旁白改了不重跑，字幕就会全体错位。 缓存键包含文本 + 音色 + 语速。 换语速会触发全部重配——所以\"把语速从 1.2 调到 1.15\"不是免费操作。 换语速会触发全部重配——所以\"把语速从 1.2 调到 1.15\"不是免费操作。 这是第 2 场景完全画完的样子：三圈模型、三行说明、右下角卡片、左下角人物贴纸全部到位，字幕压在最底部。注意最下方那条字幕带——那片区域是禁区，下一节讲。 这是我认为这个技能最值得抄的一点。它没有写一本\"内容规范手册\"，而是把规矩变成了会报错的代码。 元素压进去就报警告，而 wb scenes 输出的警告必须清零才算过关。这比\"请注意不要遮挡字幕\"这种文档约定有效一百倍。 右上角的手写水印（第一个场景里逐笔画入）、片尾品牌卡（5.5 秒、静音）、封面上的品牌标——这三个都由工具自动生成，不用每期写。名字、品牌色、slogan 在 config.json 的 brand 字段里。 换账号的成本是：改 brand.name（水印与片尾的手写名）、brand.accent（品牌色）、brand.slogan 三行。 期目录就是工程目录，scenes.js 是唯一手写源。scenes\u002F、旁白稿.md、字幕.srt、封面-*.png 全是生成物——不手改、不外拷。只有 README.md（资料来源）和","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F8.webp",{"local":50},{"headline":53,"body":54,"imageUrl":55,"images":56},"发布.md（文案）是人写的。 这条规矩解决的是所有自动化流程最经典的死法：改了一次生成物，下次重跑就覆盖，然后没人知道哪份是真的。…","发布.md（文案）是人写的。 这条规矩解决的是所有自动化流程最经典的死法：改了一次生成物，下次重跑就覆盖，然后没人知道哪份是真的。 数字、日期、价格必须有来源，出处写进期目录的 README.md；估算值在旁白和文案里都要标\"据报道 \u002F 估算\"。而且旁白、字幕、封面、发布文案里的数字，从同一处取。 公司、产品、模型用真实 Logo；人物、器械、物件用贴纸。 公司、产品、模型用真实 Logo；人物、器械、物件用贴纸。 理由也很直白：AI 画的拟人机器人和通用小人，观众认不出是谁。 所以讲到具体公司时主角用 Wikimedia Commons 上的官方 SVG（wb logo 去取），讲到公众人物时用真人照片参考生成的漫画像。","\u002Fapi\u002Fmedia\u002Fposts\u002Fskill-f1b23590\u002F9.webp",{"local":55},[],[],{"name":60,"url":61},"Juejin","https:\u002F\u002Fjuejin.cn\u002Fpost\u002F7690026779798208547","zh",{"handle":64,"displayName":65},"spots","Spots",null,{"views":68,"likes":69,"saves":69,"shares":69,"completions":69,"opens":69,"skips":69,"depthSum":69},5,0,"2026-09-28T09:17:14.963Z","local"]