1实现原理 · 为什么它能做到
核心是「把整部短片压成一个自包含 HTML」:画面每个像素由代码算,无图片、无字体文件、无库;再由无头浏览器逐帧 seek 成 MP4——确定性来自「每帧是帧号的纯函数」。
Make short animated films where every pixel is computed: no images, no fonts to load, no libraries. One HTML file holds the whole piece; a headless browser seeks it frame by frame into an MP4.
默认流程刻意「不停下来问」:推断形式/时长/画幅后直接跑完,只在交付时说明还能改什么;只有完全没有主题时才先问。
Run straight through. Pick sensible defaults and mention alternatives at delivery. Ask *before* starting only if there is no subject at all (e.g. "make an animation", nothing else).
画面与声音由同一份数据驱动:节拍网格、分镜表与调度先写成页面里的 BPM/SECTIONS/SHOTS/EVENTS,场景、相机与配乐都读它,于是声画对齐是结构性的。
These go into the page as `BPM`, `SECTIONS`, `SHOTS`, `EVENTS`: the scenes, camera and soundtrack all read them, so picture and sound line up by construction.
画法纪律针对手绘动画的典型失败模式:纯帧号函数(禁 rAF 状态/CSS 动画/累积物理)、boil 每 4 帧换种子而非每帧抖、身体用椭圆与圆角矩形、按最能读出姿势的角度取景、显式规定前后绘制顺序。
- **Boil, don't jitter.** Change the wobble seed every 4 frames (`BOIL`), not every frame. Every frame reads as noise; ~7.5 changes a second reads as hand-drawn.
自查是脚本门禁 + 两遍人眼:先 asset-audit / layout-check / sync-check,再走 storyboard conformance 与 director pass(2fps 接触表打分)。
Scripts first: `asset-audit` CLEAN, `layout-check` CLEAN, `sync-check` passing (a remaining STARTLE is acceptable only on a deliberate stinger you can name). Then the two passes by eye below.
文本碰撞由工具判定而非靠看:starter 的 claim()/placeFree() 登记每个文本框与关键物体的包围盒,layout-check 逐采样帧列出重叠与发生时刻。
- **Text never collides.** Claim every text box and key object; `layout-check` must print CLEAN. A caption overlapping a monitor edge or a face looks careless, and eyes on a contact sheet miss it.
真人照片被限制在「本地看」:按特征提取法把人物画成风格化角色,明确要求从不上传、不嵌入、不放进任何发布物——这是本 skill 唯一的隐私条款,且是硬指令。
Photos stay local: never upload them or put them in anything published.
2核心能力
3外部依赖
| 类型 | 依赖 |
|---|---|
| package | playwright-core(脚本用它启动 Chrome 逐帧 seek 页面);另需 Chrome 或 `npx playwright install chromium` |
| cli | ffmpeg(jpeg 管道编码 H.264、拼接触表、把离线渲染的 WAV 混进 MP4) |
| cli | 兄弟 skill 的同步检查:node ../soundtrack/scripts/sync-check.mjs(跨 skill 调用其 ffmpeg/ffprobe 分析) |
| network | 无执行期外部端点:交付页面的契约就是「不加载任何东西」,由 asset-audit 的静态规则 + 实跑网络记录双向证明 |
| package | Web Audio(浏览器内置的 OfflineAudioContext,用于离线渲染页面内合成的配乐;由 soundtrack 模板提供) |
4风险提醒 风险提醒:蓝色 · 知晓即可
- 运行前需要在用户项目安装 playwright-core(必要时下载 Chromium) — 属远程包与浏览器二进制获取,版本由用户项目锁定;安装位置被要求是用户项目而非 skill 目录。离线环境需预装。
- 成片质量强依赖模型能力,文档自己也这么写 — SKILL.md 明说用 Claude Opus 5.5 开发测试、弱模型更粗糙;视觉自查还要求模型能读图,无视觉能力时这条验证实际缺失(文档要求主动告知用户)。
- 跨 skill 委派:调用 ../soundtrack/scripts/sync-check.mjs — 路径假定两个 skill 同仓同装;单独分发本 skill 时该命令会失败。按分级范式,跨 skill 委派不改变本 skill 档位,但使用者应知道这一点。
- 事实与版权仍需人工把关 — qc.md 要求「屏幕上每个事实都要有能说出来的来源」,但没有校验机制;零资产意味着无第三方素材,但叙事中的事实、商标、真实人物形象仍需发布方自行确认。
5第二遍独立确认
- [ok] 脚本是否真的无网络外发(蓝档的关键) — 三个 .mjs 逐个读过:render.mjs 只 spawn ffmpeg 与 playwright 打开 file:// 页面;asset-audit.mjs 的 live check 只监听请求并打印;layout-check.mjs 只 evaluate window.draw/LAYOUT。skill 目录内无 fetch/http 调用点。
- [ok] 是否有凭证/环境变量读取 — `process.env|API_KEY|TOKEN|SECRET|Authorization` 在本仓命中仅一处:skills/soundtrack/references/ai-music.md 的 $OPENROUTER_API_KEY(属 soundtrack)。本 skill 内零命中,credential_reads 为空成立。
- [ok] 是否有更高的触发条件被漏掉(红档特征) — `sandbox|automationcontrolled|no-verify|stealth|bypass|dangerously` 全仓零命中;浏览器以默认方式启动(`chromium.launch({ channel: 'chrome' })`,无 stealth 补丁、无关 TLS/沙箱开关)。
- [ok] SKILL.md 引用的脚本与模板是否都真实存在(有无示意命令) — 四条命令逐条核对到真实文件:scripts/render.mjs、scripts/asset-audit.mjs、scripts/layout-check.mjs、templates/starter.html 均在 skill 目录内;跨 skill 的 ../soundtrack/scripts/sync-check.mjs 在同仓兄弟 skill 目录内存在。无空引用。
- [ok] 「zero-asset」是否是可执行契约而非口号 — asset-audit.mjs 有 13 条静态规则(含 data: URI、@font-face、动态 import、base64 大块)与一次实跑网络记录,命中即 exit 1;qc.md 把 'asset-audit CLEAN' 列为交付前第一道门禁。契约可执行。
- [ok] 「照片只本地」的隐私声明是否两处一致且可定位 — SKILL.md 触发条件表内 'Photos stay local: never upload them or put them in anything published.';character.md 第 6 步 'Photos are for looking at locally. Never upload them, embed them, or put them in anything published.' 两处同口径,无矛盾。
- [ok] 「每帧是帧号的纯函数」是否与 starter/render 实现相符 — starter.html 顶部注释写死契约(不许 Math.random/Date,用 rng(seed)/hash2,任意帧可单独渲染),render.mjs 只调用 window.draw(f) 取 dataURL、不做时间推进;两侧一致,声明属实。
6结论
cf575d5199b6a4ed…deb46e0eff