【学习笔记】拆解 huashu-art-motion:把"审美"做成门禁的动画 skill 体系

26 min

前面拆过 HyperFrames 这种工业级渲染 skill,也拆过 side_pro 那种方法论仓库,这一篇拆一个更”感性”的物种:huashu-art-motion,花叔(@AlchainHust)开源的艺术动画 skill——让 coding agent 用代码画会动的画,35 种艺术风格、9 种解说动画语法,发布即爆火(OpenTrend 记录 24 小时 2600+ star)。

我把它仓库里能读的文本全部读了:SKILL.md、12 篇编号方法文档、36 张风格配方卡、9 张语法卡、CHANGELOG 全史,以及 14k 行 JS 动画引擎和 6 个 Python 工具的源码。读完的结论可以先用一句话给出:它表面是一套”用代码画动画”的 skill,内核是一个用真实项目喂养、用数字和一手考据写死、用迁移测试压测、再通过 lint / 引擎默认值 / 交付门禁三层固化的 agent 质量治理体系。动画只是题材,质量治理才是资产。

一、来历:8 天,从复刻一支 15 秒的片子到一套工程体系

2026 年 10 月初,X 用户 Tak(@cherry_mx_reds)发了一支 15 秒动画《Art History Speedrun》:一位少女和一只猫穿越四万年艺术史,每个时代只有一秒左右,但画里的东西全都在动——梵高的星空在转,马赛克的颜色从石块上流过去。

花叔让 Claude 复刻它。第一版是”一张张画之间做转场”,被他否了:

原片每个时代可能就一秒,但画中的元素完全是流动的……牺牲太多了。

于是改成:先拆解(量转场、拟合节拍网格、看每段哪里在动),再用代码一层层把画画出来、让它动起来。10 月 4 日复刻完成,当天沉淀出 skill 的 v0.1(拆解法、五层机制、一帧先行、纯代码绘制、节奏配乐、16 张风格卡、完整引擎)。之后又派了 4 组只读 skill 的 agent去做 skill 没见过的 20 种风格,把它们各自造的轮子收成统一库;再加上 8 种 YouTube 解说动画语法。10 月 6 日开源,10 月 12 日已经迭代了五轮大改。从”复刻一支片”到”开源一个带质量门禁的工程体系”,只用了 8 天,而 CHANGELOG 显示开源之后的重心几乎全在质量治理上——这是后面几节的主角。

安装和依赖都极简:npx skills add alchaincyf/huashu-art-motion,本机有 uv、ffmpeg、Playwright Chromium 即可。

二、总体架构:路由层、知识层、执行层

整个 skill 是一个三层结构:

SKILL.md(路由层)按模型能力分档、按任务路由、红线与"导演人设"
references/(知识层)12 篇方法文档 + 36 张风格配方卡 + 9 张语法卡 + 正面经验库
scripts/(执行层)14k 行 JS 动画引擎 + 6 个 Python 工具(拆解/验收/门禁/交付/镜头表 lint)

按模型能力分档,是它路由上最巧的设计

SKILL.md 开篇第一件事不是介绍功能,而是”先分档:你按哪一档读”:

  • 开阔档:你是 Claude Opus 5.5 或更强的模型。全文都适用,库可以自己组合,渲染器可以自己写,lint 可跑可不跑;
  • 轨道档:其它模型,或判断不出自己是谁。只走一条路:写镜头表 → 过 lint → 逐镜渲染 → 拼接 → qa → deliver,而且”只读这条路点名的文件,其余 reference 先不读”。

这是为强/弱模型分别设计信任级别的显式降级策略,同时管理两个约束:上下文预算(弱模型别把 token 浪费在读不完的文档上)和模型可靠性(弱模型必须走刚性流水线兜底)。相比之下,很多 skill 默认所有模型都配得上全部自由度,结果弱模型在自由发挥里翻车。

第二层的路由是任务表:用户口语精确映射到文件。「复刻这个动画」→ 读 01 → 02 → 04;「做个梵高那种」→ 03 → 04 → 风格 INDEX;「做解说视频的动画段」→ 09 + 对应语法卡。每个入口都窄口径,避免读串。

“导演人设”承载参数化不了的判断力

SKILL.md 里我最喜欢的一节是”你先是导演”,它把无法参数化的审美判断写成对镜头和画风的两节导演课,且每条规则都锚定一个真实的作者反馈:

一支 102 秒的解说短片推近约 48 次、全部往里推,作者原话:「有非常非常多 zoom in 的镜头运动。次数太多,而且节奏太快了,一点都不 smooth」。

每镜匀速慢推被作者说过「完全是放 ppt 的感觉」。

作者否过一版「背景太特么素了,毫无观看欲望」的片子。

负面反馈的密度远大于正面,而且每条都对应一条可操作的规则(“推进去之后要拉出来""画面里一直有事在发生”)。这比”注意节奏感”这类正确的废话有效得多——LLM 需要的是边界样本,不是口号。

三、动画引擎:一个确定性的世界

技术选型非常克制:不用 Manim、不用 Remotion,自建一个 确定性 HTML5 Canvas 引擎——engine.js 全文只有 278 行,加上 17 个 lib 模块(相机、运动、笔刷、渲染器、骨架、图表、排版、拼贴、卡通、媒体……)共 14k 行。几个核心设计值得细看。

时间 t → 一帧,纯函数式渲染

引擎的第一条注释就立了规矩:同一个 t 永远画出同一帧,随机数全部用种子。时间轴由节拍网格驱动:EIGHTH = 60/BPM/2(默认 128 BPM,八分音符 0.234 秒),每段用八分音符数或秒数定义长度。确定性带来的是工程上的全面收益:可任意跳帧、可复现、qa 可以做”冷渲热渲两次逐像素比对”、转场期”上一镜的相机继续推”天然成立。

转场用双离屏缓冲实现:A 缓冲画上一段、B 缓冲画下一段,转场函数 TRANSITIONS[type](ctx, bufA, bufB, p, ...) 拿两个成品层做合成。转场自带”拍点冲击”——场景层缩放 1 + 0.03·(1-k/20)^1.5,20 帧回落,且必须同时作用于新旧两层(v1 审片量到只作用新层时拖拍 0.1–0.17 秒)。

世界画布 + 相机,而不是”一段段画加转场”

解说片的引擎里,相机库 camera.js 的设计最能看出作者懂感知:

  • 缩放全部用对数插值 z0·(z1/z0)^e——“每帧放大同样的倍数,观众感到匀速穿越尺度;线性插值会前慢后猛”;
  • 相机只由时间算出,场景每帧按相机矢量重画——“缩放转场永远清楚,不会把 1920 的位图放大 20 倍糊掉”,这就是 Kurgesagt 式”尺度穿行”的实现基础;
  • CAM.coverZoom(r) 精确算出”从半径 r 的圆形开口穿进去、转场结束前盖满屏”所需的最小放大倍数——小了最后一帧会跳。

渲染管线:错误即失败

render.py 的链路是:起本地 HTTP 服务 → 无头 Chromium 逐帧调 window.renderFrame(t) 抓 canvas 像素 → PNG 管道喂 ffmpeg。三个细节:

  1. 素材白名单:spec 里点名的本地素材通过 /__file__/<绝对路径> 服务,且只服务白名单内的文件——一个渲染脚本里做了访问控制;
  2. 面向下游管线设计:片段模式每秒一个关键帧(GOP=fps,供口播管线按秒 seek 不冻帧)、--alpha 出 ProRes 4444 透明底、竖屏整片支持;
  3. 任何 console.error / pageerror 都让渲染非零退出,缺素材、缺字形直接拒绝渲染——“不出空白帧”。整套体系里”静默降级”被消灭得很彻底,这是它能被 agent 可靠使用的前提。

参数化片段(口播管线的”动画段”)走一份 JSON spec:{ grammar, duration, fps, theme, cues: [{at, kind, text, data}] } → 一段时长精确到帧的动画。cue 的 at 被定义为”揭开那一帧”,帧对齐约定直接写死在运行时代码里。

四、质量工程:这个 skill 最独特的地方

如果只看”能渲出漂亮的片”,市面上动画 skill 已经不少。这个项目真正的前沿在质量治理。它的核心洞察写在 12 号文档里:

反复出现的坑提炼为开工检查,做成引擎能力后减少文字规则。

翻译过来:文字规则对 LLM 的约束力最弱,所以规则要沿一条阶梯不断”硬化”——

文字规则(SKILL.md)
   ↓ 硬化
开工检查(storyboard_lint.py,红灯不许写代码)
   ↓ 硬化
引擎默认值(让坏做法在代码层面做不出来)
   ↓ 硬化
交付门禁(film_gate.py,红灯物理上不出片)

下面从时间顺序上看这条流水线上的四个工具。

事前:镜头表 lint

storyboard_lint.py 纯标准库实现,16 条规则几乎每条都能对应一次真实翻车:

  • 物列不能是”标题、要点、文字、列表”这类抽象词,也不能是”空镜、纯色、黑场”(没有具体的物 = 概念堆砌);
  • 屏上字 ≤ 8 字;单镜 2–6 秒;文字主导镜头 ≤30%;最后一镜不能是居中金句卡;
  • 连续三镜往里推、重音超过三分之一 → 黄灯;
  • 给了口播文稿时,屏上的阿拉伯数字必须能在文稿里找到(“查屏上数字和口播是不是同一个数”——数字对不上是解说片最经典的穿帮)。

红灯未清,不许开始写代码。也就是说”内容设计”这一步就有机械验收,而不是等到渲完才发现片子是 PPT。

事中:量化验收 qa.py

qa.py 对每一段做五项测量,每项的设计都踩过具体的坑:

  1. 稳定性:同一时刻冷渲 + 热渲两次逐像素比对(确定性);
  2. 效率:每帧毫秒数——计时包含一次 getImageData(1×1) 强制 GPU 画完,注释写着”只量 JS 同步时间会报出假的 1ms”;
  3. 动感:运动面积均值 + 静止帧对比例(“迁移测试 A 发现只看首尾差会漏掉一卡一卡”);
  4. 流畅:区分”跳变”与”镜头事件”——0.35 秒内平滑单调的推拉横移是镜头语言不算 bug,孤立的闪帧、闪过去又回来的才算;
  5. 文字框景:hook 住 fillText/strokeText 记录每个字的外框,报半截字、叠字、字进字幕带——而且是”线索不是错误”,qa 不因此失败。

注意第 4 条的演化:2026-10-12 之前 qa 只认 0.35 秒以内的镜头动作,缓推会被整串记成跳变,“等于逼着模型把镜头改快”——一个测量工具的判定口径,直接塑造了产出物的镜头风格。这是整个体系里我最感慨的一点:你度量什么,agent 就变成什么。

事前拦截成品:反 PPT 门禁 film_gate.py

film_gate.py 只读成片 mp4,三条红灯:

  1. 快速运动帧占比 < 0.035:整片几乎没有镜头内快动作 = 翻页 PPT,红灯;
  2. 中段连续 0.3 秒空画面:判法是”梯度 >24 的像素不到 0.2%“——按边缘判、不按颜色判,因为黑底 3b1b 的细线和白板笔画都是边缘,按”大面积纯色”判会把认可的好片误杀;
  3. 蓝紫底画面占比 ≥ 30%:HSV 色相 225°–300°、饱和度 ≥0.30 算蓝紫像素——直击”深紫星空 + 霓虹青紫”这种最典型的 AI slop 配色。题材真需要蓝紫(赛博朋克、星月夜)可以 --allow-blue-purple "理由" 降黄,理由原样写进交付说明。

最了不起的是阈值的来源:全部用作者真实评判过的片子标定。13 支表态片(9 认可 4 否定)里,快速运动占比是”唯一单独就能把两组干净分开、阈值两侧都有余量的指标——认可的最低 0.068,否定的最高 0.021”;蓝紫阈值用 88 支片标定(认可的最高 0.10,否掉的 0.46–1.00)。而且注释诚实到罕见:

样本只有 13 支,读作「这 13 支里没有反例」,不是已经证明。 阈值不要随手改:改了要用新的表态片重标。

把”审美”做成可执行门禁,同时清楚知道自己标定集的边界——这两件事同时出现,我在 skill 里还是第一次见。

事后可审计:交付协议 deliver.py

deliver.py 是最后一道闸:红灯不复制成片、非零退出;绿灯/黄灯才复制成片并生成交付说明。关键设计是事实与陈述的强制分离:

  • 事实段(时长、分辨率、门禁各项、最差 30 秒窗口、qa 结果、有没有独立审片记录)全部由脚本写入,末尾带 sha256 指纹,deliver.py --verify 能查出事实段被人改过;
  • 制作者(人或 agent)只能在”制作说明”段填主观内容:用了哪些语法、黄灯项逐条理由、六种做坏方式自查。

它甚至会检查 qa 的新鲜度:spec 在 qa 之后改过,就在交付说明里写”这份 qa 结果可能已经过期”。这份交付说明本质上是一份机器签名的验收单——把”agent 说做完了”变成”机器可验证的事实 + 可追责的陈述”,这个模式可以平移到几乎任何 agent 交付场景。

门禁拦不住的(每镜换画风的拼贴、页框、前紧后松),交给一张”六种做坏方式”清单(带作者原话证据)让 agent 抽帧自查,再加一道独立审片:派一个没参与制作的 agent 只看成片挑问题,结论写进 审片/*.md,deliver.py 只认文件存在性、不替审片人下结论。

五、知识管理:把经验回流做成制度

references/ 不是普通的提示词集合,而是一个带证据链的方法论库,几个设计值得单独说。

风格配方卡带质量元数据。36 张卡统一格式”管线 → 关键参数 → 母题动画 → 签名转场 → 坑”,参数精确到 hex 色值和笔触三元组(梵高卡里墙 8 色、星空 6 色逐色列出,三遍笔触各自的 cell/len/w 都有数)。INDEX 给每张卡标星级和当前短板——伦勃朗 ★(“人物扁平,最该重做”)——并明说”短板就是下一次做它时先超越的目标”。还预先打了防滥用疫苗:35 张样片同一构图是速通片的机制,做新题材要重新构图,“卡里的渲染器可以拿走,房间里的坐标不要搬过去”。

语法卡的一手考据严谨到罕见。3b1b 卡考证背景纯黑 #000000”来自 Grant 自己的 custom_config.yml,网上流传的深海军蓝是营销博客的说法”;run_time 统计来自 manim 源码(“2s 出现 481 次 > 3s 333 次”);Kurzgesagt 卡全文用【实测】【一手】【归纳】【本片】四类标签区分每个数字的来源。甚至实测出”深紫底是 Kurzgesagt 的常用色”之后立刻反手封禁:“成片不要照抄——作者原话是『我们需要规避下蓝、紫渐变的垃圾配色,这种非常 ai slop』”。

07-正面经验.md 是经验回流的主库,38 条经验每条强制四件套:做法、证据(量到什么/谁复用成功了)、为什么有效、什么时候用。复用成功加一笔,失败写边界。

两条生产经验的机制尤其值得抄:

  1. 迁移测试就是最好的需求文档:派 4 组只读 skill 的 agent 去做 skill 没见过的 20 种风格,收回 60 多条问题——“这些在作者自己用时一条都没暴露”。盲测用户永远是比作者本人更好的需求来源;
  2. 验收工具也要被验收:qa.py 曾全绿但根本不执行转场代码(段内取帧用 renderSolo,转场代码一次都没跑到)。之后每个检查项都”故意制造一次失败,确认它真的会红”,tests/ 里有端到端测试用三支合成片验证门禁判定本身——slow(每镜匀速慢推)必须红灯、punch(停住 + 一次快推)必须绿灯、smooth(缓推)不能红灯。

六、CHANGELOG 里的一部规则自我纠错史

CHANGELOG 逐日记录了这套体系如何被证据推动着演化,最精彩的是 2026-10-12 那条。早期一次”四样同时改”(满幅素材、真实环境、去页框、脉冲镜头)的成功被过度泛化成”每个口播节点都快推”的全局规则,然后被窄桥、引擎默认值、lint、门禁层层加固成系统性病:一支 102 秒的片子推近 48 次、全部往里推,作者:“次数太多,而且节奏太快了,一点都不 smooth”。

修复方式堪称科学方法示范:同一个模型(DeepSeek)、同一段 28 秒口播和素材,隔离沙盒里跑改前与改后两版对照——推近 15→8 次、0.5 秒内快推 14→2 次——再让作者并排盲看,作者选了改后版。随后镜头哲学整体重写为”镜头是标点,不是每句话的修饰”。

这条记录暴露了一个对所有 skill 作者都重要的教训:当你从一次成功里提炼规则时,先确认那次成功里改了几个变量。“四样一起改、分不清哪样起作用”的成功被写成全局规则,又经过多层机制加固,最后病根恰恰是这条规则本身。规则要带证据、可被推翻、硬化之前先做对照实验——花叔另有”达尔文”skill 专门做这种进化治理,这个仓库就是它的活样本。

七、评价

亮点:

  • 把”审美”这种最不可量化的东西做成用真实评判标定的可执行门禁,且对样本量和阈值边界保持罕见的诚实;
  • 确定性渲染 + 素材白名单 + 错误即失败,“静默降级”被系统性消灭——这是 agent 能可靠使用它的前提;
  • 模型分档路由是对”skill 该信任模型到什么程度”的先行探索;
  • 指纹化事实段的交付协议,可迁移到任何 agent 交付场景。

局限也很清楚:

  • 渲染链(uv/ffmpeg/Playwright)对普通用户偏重,主战场是 macOS/Unix,Windows 并发加载问题靠社区 PR 修复;
  • 内容全中文,语法卡的”一手参考”也以英文频道为主,但方法论表述对英文使用者有门槛;
  • 风格场景只按横屏画过,风格卡质量参差(作者自认 1 张 ★);
  • 门禁标定样本来自一位作者的口味——skill 把花叔的品味编码成了阈值,换一个导演需要重新标定。这既是它的魔力(品味真的被固化了),也是它的边界(品味不通用)。

八、对写 skill 的启示

拆完这个仓库,我觉得有五条可以直接带走:

  1. 规则要硬化。文字规则 → lint → 引擎默认值 → 交付门禁的阶梯,每一层都比上一层更不可绕过。写 skill 时问自己:这条规则能不能从”叮嘱”变成”代码里做不出来”?
  2. 负面反馈是最有价值的数据。作者每一次否稿的原话都被保留、被结构化成规则和阈值。skill 的迭代史应该由边界样本驱动,而不是由成功案例驱动。
  3. 给弱模型修轨道,给强模型留开阔地。一份 SKILL.md 承认模型能力有差异,并为此设计两条路径,比假装所有模型一样聪明更诚实也更有效。
  4. 验收工具本身要有测试。“故意制造一次失败,确认检查真的会红”,否则你的验收只是绿色的安慰剂。
  5. 交付物要区分机器事实和主观陈述。事实由脚本写、带指纹;陈述分区填写、可追责。agent 的”我做完了”从一句话变成一份可验证的验收单。

花叔在 README 结尾写了三句话:“女娲造 Skill,达尔文让 Skill 进化,艺术动画让画动起来。“工具会过时,但这套让坏结果渲不出来、而不是劝 agent 别这么做的治理思路,会比任何一张风格卡都活得久。

参考链接