← 返回实验室

开源 · MIT · Calvin @ ArchAstro · 静态致敬

Clapper

用 React 写片子。渲成 MP4。像片场一样过审。每一帧都是帧号的纯函数,配乐是代码,审片的是带着联系表的智能体。

npx skills add ArchAstro/clapper --skill clapper --global
由帧号驱动的开场片舞台 开场 · 纯函数 · 无原片素材
第 000 帧 · 0.00 秒
开场片 · 6 秒循环 · 30fps · 原谱概念 画面由帧号算出,不是时钟

核心一念

每一帧,只是帧号的函数

没有墙上的钟。场景读 useFrame(),自己画出自己。所以渲染器可以直接去第 212 帧,而不必先播完 0 到 211;预览可以前后随便拖;同一份源码渲两次,字节都一样。拖下面的滑杆——画面只由这个数字算出来。

第 000 帧 · 0.00 秒
0 179

试试往后拖。靠墙上时钟走的时间轴做不到;帧号的纯函数可以。

// 一场戏,按帧号来写
function Bounce() {
  const f = useFrame();
  const t = f / 179;
  const x = lerp(70, 500, ease(t));
  const hop = Math.abs(Math.sin(t * Math.PI * 4)) * 110;
  const squash = (f % 32) < 3 ? 0.8 : 1;
  return <Dot x={x} y={250 - hop} scaleY={squash} />;
}

// 时间写在场次表里,不写在组件里
const SCENES = defineScenes({
  hook:  { seconds: 2 },
  proof: { seconds: 4, fade: 8 },
});

怎么渲出来

进去的是 React,出来的是 MP4

命令行用 Vite 打包,在无头 Chromium 里打开,把帧号设进去,截一张 JPEG,再把帧流推进 ffmpeg。声音也是 React 元素:它们登记提示点,离线合成器做成立体声,最后再叠进片子。

  1. src/index.tsx登记根组件、一场 Composition、场次表、一份总谱
  2. vite build和片场预览打开的是同一份包
  3. 逐帧截图setFrame(n),JPEG q96
  4. ffmpeglibx264 画面,提示点离线混成一条音轨
  5. out/spot.mp4h264 + aac,每次字节都一样

clapper preview

片场:实时缩略图、安全框、按音色分轨的时间轴、提示点预听,还有一块在浏览器里编译 TSX 的草稿台。

clapper still

一场戏的首、中、末帧,或每隔十帧抽一张。还没花渲染的钱,先看这一拍落不落得住。

clapper review

联系表、每个剪辑点附近的九宫运动条、频谱、波形、检查报告,再加一份审片提示。交给人,或交给子智能体。

配乐即代码

总谱是一份 TypeScript

总谱里有速度表、拍号、分轨和片段。每条轨点一份 CC0 采样乐器,本地采样器渲成分轨,再压到广播响度。片场把钢琴卷帘放在画面旁边:点一个音,片子就跳到那儿。

// 致敬页自己的小调,不是仓库里的那首华尔兹
export default defineScore({
  title: "灯还亮着",
  tempo: [{ at: 0, bpm: 96 }, { at: 8, bpm: 88 }],
  meter: [4, 4], seed: 11, tail: 2,
  tracks: [
    track("keys", {
      instrument: "upright", gain: 0.58,
      clips: [{ notes: phrase("C5 D5 E5 G5 A5 G5 E5 D5", { beats: 0.5 }) }],
    }),
    track("pluck", {
      instrument: "pizz", pan: 0.2,
      clips: [{ at: 2, notes: chord(["C4", "E4", "G4"]) }],
    }),
  ],
});
keys · 第 1–2 小节 4/4 · 96 bpm · C 宫
78份编目过的 CC0 预设:弦、管、铜、键、打击,外加三套摇滚
960每四分音符的脉冲;乐时和视频帧各走各的
−18LUFS 母带;分轨、MIDI 导入导出都在
0条垫底音轨;片子里每个音都写在总谱文件里

审片联系表

同一函数,抽出六张静帧

真正的 Clapper 会把联系表交给独立审片人。这里用同一套 draw(f) 抽出六张静帧——点一张就跳到那一帧。没有官方成片,也不搬运原仓库素材。

片子用来干什么

产品片、学习片、给自己看的片

原帖里 Calvin 说:让编程智能体装上这个 skill,它会写 React 来生成视频,也能作曲、也能旁白。下面四张是致敬页自己的示意海报,用来讲用途,不是仓库里那七部成片。

产品说明

刚做好的工具,先拍一条

把刚上线的页面、CLI、内部平台讲清楚。画面是代码,配乐也是代码,版本和哈希可以对上。

论文 / 笔记

把一篇机器学习论文做成片子

给自己看的那种。公式、图、一条旁白轨。智能体写场景,你负责说「这一镜再慢半拍」。

片场预览

拖时间轴,而不是干等渲染

因为画面是帧号的函数,预览可以来回搓。拍板落下的那一下,和谱面上的音头对齐。

智能体过审

渲完不等于过了

空白尾、切在空帧上、文案出安全框——检查器自己能抓一批;听感则交给谱面、采样和信号,不装懂。

像片场那样过审

渲完,还要过一轮

成片不是终点。官方流程会把联系表交给按创意总监briefs的独立审片人,必要时再加音频指导和信息流策略。下面是致敬页归纳的过审逻辑,不是原站那张记分板的逐行复制。

检查器自己能抓到的

  • 硬切后前八帧里出现空白或死画面
  • 文案叠文案,或跑出安全框
  • 源码里出现墙上时钟、定时器、未播种的随机数
  • 每个剪辑点附近的响度,免得压音把效果声吞掉

它不会假装能做的

  • 智能体听不见。音频审查看谱面、采样表和信号,每次都写明这一点。
  • 结论要写清看过哪些帧、哪些时段,以及哪些没核。
  • 通过的成片用哈希钉住。源码一改,就要新哈希、新一轮审。
  1. 屏幕上的一切都是 useFrame() 的函数。不要墙上时钟,不要定时器,不要 Math.random,用带种子的助手。
  2. 合成抛错,渲染就失败,错误要写清场次和局部帧。
  3. 每场硬切在局部第 0 帧就必须有东西:眉题、一条线、一个字幕框。
  4. 声音在序列挂载时登记,渲染器会走遍每一帧,提示点不会漏。

去试

你的智能体,就是整组摄制组

给编程智能体装上这个 skill。它会装好 Clapper,备好 Node、Chromium 和 ffmpeg,建项目,再带你走视觉和音频审查。不用另开一套环境。

npx skills add ArchAstro/clapper --skill clapper --global
然后新开一轮:「用 Clapper skill 做一条带原创配乐的视频。需要的都帮我装好。」