prod-by-claude
Use when an agent needs to make a HyperFrames video of a Strudel live-coding track, where the code itself is the picture and every token lights up on the note it plays. Trigger on: "strudel video", "live coding video", "show my code playing", "make a video of this track with the code", "prod by claude". Covers composing the track, recording it offline from pinned Strudel, and building the 1080x1080 video (typed opener, parts powering on, real Strudel theme switches, graffiti ASCII drops, typed sign-off).
1How It Works & Mechanism
Unified source for audio and visual: Strudel tracks are first rendered offline into audio, and each note event is mapped back to the code token that generated it. The video is driven by these events—ensuring that every highlight lands precisely on its own note rather than relying on post-production alignment.
The music is rendered offline from the code, and the video is driven by Strudel's own note events, so every highlight lands on its note.
Recording pipeline: record.mjs spins up a static server on 127.0.0.1 serving strictly recorder.html and node_modules. It uses a muted headless Chrome instance to evaluate each part individually, exporting the timestamp, parent part, value, and source code character range of every note, followed by offline rendering of the full mix (with an optional ending) and solo stems for ._scope() parts.
// Serves recorder.html (the pinned @strudel/web build from node_modules) on 127.0.0.1, opens it in a … // muted headless Chrome, and for the track named in <project>/video.json: … // 1. evaluates every labelled part on its own and exports each note event with its time, part,
Key to offline consistency: recorder.html only loads a pinned version of @strudel/web from local node_modules and fetches nothing from strudel.cc; the sample track is purely synthesized without samples, so the initial run requires no additional network requests for samples.
nothing is fetched from strudel.cc. Samples are only fetched if the track itself calls samples(...).
Timelines are generated, not handwritten: build-data.mjs converts Strudel cycles into video seconds, generates window.SQ (token highlights, section power-ons, widgets, energy curves), writes the total duration back to data-duration in index.html, and sets the audio start point as pre.
const sec = (c) => +(PRE + c * SPC).toFixed(4); // strudel cycle -> video seconds … fs.writeFileSync(path.join(project, "data/events.js"), "window.SQ = " + JSON.stringify(out) + ";\n"); … // stamp the length into index.html; the audio stays the length of the recording
Camera plans are automated by default: Without explicit camera instructions, framing follows section power-ons, zooms in on the all( block during builds, reveals new sections post-drop, and zooms out to the sign-off at the end; explicit camera lines in video.json are only needed for custom overrides.
Leave `camera` out to get the automatic plan: frame each part as it powers on, push in on the `all(` block during builds, reveal the newest part after a drop, pull wide after the last drop, and zoom to the sign-off.
Recording quality acts as a gatekeeper rather than an afterthought: The recording logs audio levels every 4 bars and triggers warnings, requiring repeated recordings until drop peaks are ≤ -2 dBFS without clipping; track modifications require rewinding to steps 5–7 to re-record, while video.json edits only require repeating steps 6–7.
Fix the track and record again until the drops peak at or below -2 dBFS with no clipped samples.
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | HyperFrames CLI(钉版 0.8.70,经 npx --yes 调用;check/snapshot/render/cloud render) |
| package | @strudel/web 1.3.0(AGPL-3.0,从 npm 装,不进仓库) |
| package | puppeteer-core 25.12.0 + @puppeteer/browsers 3.2.3 与 OFL 字体(@fontsource/jetbrains-mono、rubik-mono-one) |
| package | Chrome for Testing 149.0.7827.22(录音用;可用 CHROME=<path> 覆盖) |
| network | 成片构图在载入时从 jsDelivr 取 GSAP 3.14.2(故渲染并非完全离线) |
| api | HyperFrames 云渲染(可选,消耗用户账户额度,须用户显式同意才可走) |
| network | 轨道自身若调用 samples(...),录音时会去轨道写明的采样 URL 取音频(示例轨道无采样) |
4Recommended Governance & Evidence
- scripts/: Execute local script or command: node scripts/new-project.mjs <dir> (pure local file copying: template + track + 4 tools files)
- 网络端点: Declared external network access: npm install (npm registry; dependency versions pinned by tools/package.json)
- 本地工作目录: File I/O and artifact output: Strictly confined to <project-dir>: data/events.json, data/events.js, assets/bgm.wav, assets/st
5Second-Pass Verification
- [ok] 『No credentials.』声明是否成立 — SKILL.md Rights/Side effects 段明写 'No credentials.';目录内 process.env 命中只有 record.mjs 的 CHROME 与 CFG 类入参,未见 key/token/cookie/keychain 读取,也无 .env 解析。
- [discrepancy] 『录音离线』是否等于全流程离线 — 录音段确实离线(127.0.0.1 静态服务 + 本地无头 Chrome + node_modules 里的 @strudel/web;recorder.html 注释明写 nothing is fetched from strudel.cc),但建仓(npm install、Chrome for Testing 下载)与渲染期构图载入 GSAP(cdn.jsdelivr.net)都要联网。SKILL.md 自己把这些写进 Side effects,故非隐瞒;只是『离线』的适用范围仅限录音。据此把档位定为蓝(官方源固定版本安装 + 产物期 CDN,与同 repo 先例 hyperframes-animation / hyperframes-core 同口径)。
- [ok] 高亮是否真由音符事件驱动(而非后期对齐) — 链路可读通:record.mjs 导出每音符的 locs(代码字符区间)→ build-data.mjs 用 byLoc 汇总成 token 时间表与段落/widget 时间 → 写成 window.SQ → 模板 app.js 消费。音画同源成立,不是后期对轨。
- [discrepancy] 是否误把 ffmpeg 列为依赖 — 本 skill 目录内不调用 ffmpeg:录音与 mix 走 Strudel 的离线渲染器,编码由 HyperFrames CLI 负责。故 external_deps 不列 ffmpeg(同批姊妹 skill 有列,本 skill 没有)。
- [ok] 大写 S 标签的拒绝逻辑是否真在代码里 — record.mjs 实有 'const soloing = labels.filter((l) => l.length > 1 && l.startsWith("S"));' 并在命中时 fail 提示改名——不是文档空话。
- [unlocatable] 录制耗时与云渲染额度的具体数值 — 『约 5-7 分钟/32 小节』与云渲染『消耗多少额度』只有文档声明,源码内无可复现依据;本次为只读侦查,未运行录音或渲染,故不作为已核事实使用。
6Verdict & Scenarios
90eabb744789abe6…