--- name: cs-code-video description: "用代码做动画视频:页面暴露 render(t),Playwright 逐帧截图 + FFmpeg 合成 mp4,可接合成配乐、出图和配音。通用模式先明确主题、规格、风格和声音,出风格卡、分镜与关键帧后逐镜制作;Vibe知识大赏模式额外查证来源、记录真实素材许可、先渲 10 秒样片。触发词包括 $cs-code-video、用代码做视频、知识解说动画、Vibe知识大赏、来源可核查的代码科普片、KAI 教程片、像素动画、片头。固定暗夜星空系列用 cs-knowledge-film,固定像素解说系列用 cs-pixel-explainer;真实网页演示、电商视频和 ChatCut 策划各用对应 skill。" --- # CS 代码视频 模型不直接生成视频。它写一个网页,网页暴露 `window.render(t)` 画出第 t 秒,脚本逐帧截图,再用 FFmpeg 合成 mp4。配乐和音效用 numpy 合成,配音用 edge-tts。 一句话提示词做视频是抽卡,效果不可控,也复现不了。本 skill 的做法:**先把规划摆到用户面前,确认了再动手**。5 项输入 → 导演层 → 三张风格卡 → **分镜表(等确认)** → **3 张关键帧(等确认)** → `brief.md` → 逐镜头制作 → 自评 ≥8 分 → 交付。 用户明确要 **Vibe 知识大赏或来源可核查的代码科普片**时,按 [references/vibe-knowledge.md](references/vibe-knowledge.md) 的六步模式执行。它在研究、真实素材、输入默认值、KAI 角色和 10 秒样片上的规则优先于下文通用模式;渲染和 QA 仍用本 skill 的工具。 **管线固定,画面不固定。** 渲染、配音、混音、QA 每次一样;画面语言每次从选题里长出来,再套上陈硕的签名层。不要先拿模板再塞内容。 ## 交付边界 - 默认值(只在用户明确说「你定」或无人值守时才用,并写进风格卡让用户改):单个 HTML 工程 + 一支 mp4,1920×1080、30fps、30 秒、代码合成配乐、不配音。 - 通用模式的画面由代码生成,或由 GPT 按资产清单出图后代码做动画(见 hybrid.md);不从网上下载图片或视频素材。Vibe 知识模式可使用来源和许可可追溯的真实证据图,按对应参考文件记录。 - GPT 出图要花钱:真正出图前先 `gen_image.py --dry-run` 把张数和模型给用户看,确认后再出。 - 通用模式的事实来自用户给的原材料,不确定的不写;Vibe 知识模式必须主动联网核对,建立逐条来源表。 - 参考视频只学结构、节奏和手法,不照搬别人的素材、外观和文案;学到的手法记进 `signature.md` 的吸收清单。 - 不上传、不发布。 - 路由:真实网页演示片 → `$cs-web-promo-film`;电商对标复刻、Seedance/Flow 生成包 → `$cs-auto-videl`;剪辑已有素材、ChatCut 策划 → `$cs-chatcut`。**教程类视频默认做成 KAI 教程片**(见 tutorial.md)。像素解说(`cs-pixel-explainer`)和暗夜知识片(`cs-knowledge-film`)是**系列皮肤**,只在用户确认是该系列续集时使用,见 director.md ⑥。 ## 导演铁律(每支片都适用,写进 brief 的 ``) 1. 整片一套风格、一套配色;同一个角色或元素在每个镜头里长得一样。 2. 每个镜头只讲一件事;画面上的字少而大,每段文字至少停 2.5 秒。 3. 动画用缓动或弹簧,不用匀速。 4. 转场从画面内容里长出来(一条线变成下一个场景的地平线、一个点放大成下一场的月亮),不用默认淡入淡出。 5. 镜头跟着内容动:推近、拉远、跟随,主体在画面里足够大(至少三分之一)。 6. 禁止:居中大字 + 渐变背景的默认风格、所有元素同时淡入、满屏小字、任何看起来像模板的东西;每支片再按情况补充。 ## 先读什么 按阶段读最少的资料: - 想画面、配风格、出风格卡:[references/director.md](references/director.md),开工前同时看 [style-log.md](style-log.md) - Vibe 知识大赏、来源可核查的代码科普片:[references/vibe-knowledge.md](references/vibe-knowledge.md) - 陈硕的个人风格(不变层):[references/signature.md](references/signature.md) - 选代码路线、绿幕人物:[references/code-stack.md](references/code-stack.md) - **教程类视频 → KAI 教程片**:[references/tutorial.md](references/tutorial.md)(系列皮肤,结构和画风已锁定,跳过风格卡) - GPT 出图 × 代码动画(镜头类型、分工、角色一致性、提示词):[references/hybrid.md](references/hybrid.md) - 写 brief:[references/brief-template.md](references/brief-template.md) - 制作规则(render(t)、弹簧、字体、WebGL、像素纯度、声音、渲染速度):[references/craft-rules.md](references/craft-rules.md) - 自评和验收:[references/qa.md](references/qa.md) 把 [scripts/](scripts/) 和 [assets/](assets/) 拷到工程目录。`assets/template.html` 只提供骨架(render(t)、弹簧、时间表、字幕函数),顶部的 `STYLE` 和全部镜头都按风格卡重写,不要沿用模板自带的配色和示例镜头。 ## 工具 ```bash node scripts/render.mjs index.html out/final.mp4 --size 1920x1080 --fps 30 [--duration 30] [--start 0] [--audio audio/mix.wav] [--subframes 4] [--workers 2] [--draft] node scripts/render.mjs index.html qa/s1.png --still 2.0 # 单帧 python3 scripts/audio.py sfx cues.json audio/sfx.wav # [{"t":1.2,"type":"click|pop|whoosh|thud|ding|riser|glitch|type","gain":1}] python3 scripts/audio.py music audio/music.wav --bpm 120 --bars 16 python3 scripts/audio.py beats music.mp3 > source/beats.json # bpm / beats / downbeats / hits python3 scripts/audio.py vo spec.json # 逐句配音 → audio/vo.wav + timeline.js python3 scripts/audio.py mix audio/mix0.wav audio/vo.wav audio/music.wav:0.25 audio/sfx.wav:0.8 --len 30 # --len = 成片时长 python3 scripts/audio.py normalize audio/mix0.wav audio/mix.wav # -14 LUFS ±0.5,真峰值 ≤ -1 dBTP python3 scripts/qa.py out/final.mp4 qa # 抽帧、手机抽帧、切镜连续帧、波形、打分表 python3 scripts/gen_image.py assets.json --dry-run | --draft | --final | --pick id=2 | --export-md # GPT 出图(在有 OPENAI_API_KEY 的电脑上跑) ``` - `assets/template.html`:render(t) 骨架,自带缓动、闭式弹簧 `spring/springTo`、带种子随机、版式缩放 `S`、`STYLE` 风格变量、可关闭的打字机字幕;有 `timeline.js` 时按配音时长自动排镜头。 - `assets/layers.js`:把 GPT 图变成动画:`illustration`(运镜)、`parallax`(分层视差)、`grid` / `card` / `promptBox` / `bigStep`(讲解界面)、`avatar`(头像对口型)、`subtitle`(box / plain 两种字幕)。用法见 hybrid.md 第三节。 - `assets/kai-boy-3d.js`:主角 KAI 男孩 3D 版,`KaiBoy3D(w,h).render({t, yaw, mode, pose, expr, bg})`。每支片的主角,和 KAI 猫同框时都用透明底叠加。 - `assets/kai-cat-3d.js`:宠物 KAI 猫 3D 版(WebGL2 光线步进,零依赖),`KaiCat3D(w,h).render({t, yaw, mode, pose, expr, bg})`,白模 / 上色两种模式,透明底可叠进任何画面。 - `assets/kai-cat.js`:KAI 猫代码版角色组件,`drawKaiCat(g, {x, y, size, t, pose, expr, style})`,4 种姿势、5 种表情、4 种画风。每支片都要出场,规则见 signature.md 第五节。 - `assets/crt.js`:WebGL2 老电视后期层,`template.html` 里 `USE_CRT = true` 即开。只在风格卡选了复古质感时用。 - `assets/voice/`:`tts.py` + `配音.bat`(Windows 双击即可),读同目录 `spec.json` 逐句生成 `audio/line_XXX.mp3`。 - 像素风参考实现:[`assets/reference-wizard.html`](assets/reference-wizard.html)(调色板索引缓冲、整数倍放大、10 张/秒姿势量化、固定步长重放的 render(t)),像素复古风格从它起步。 依赖:node + playwright、ffmpeg、python3 + numpy、中文字体(Noto Sans CJK 等);出图另需 `pip install openai pillow` 和 `OPENAI_API_KEY`。 ## 工作方式 ### 1. 通用模式先明确 5 项输入(Vibe 知识模式按专用参考文件) 接受三种原材料,可以混着给:想法、原内容(文章、口播稿、产品网址、代码库)、参考视频。先用一条消息问清下面 5 项,**用户没给的不要自己编**;原材料里已经能确定的项直接写出来请用户确认,不重复问: 1. **主题**,以及看完以后希望观众记住的**一句话**;顺带问:这是某个系列的续集(沿用风格),还是独立单片? 2. **时长和画幅**:__ 秒,1920×1080 / 1080×1920 / 1080×1080,30 / 60 帧 3. **风格**:像素 / 扁平插画 / 界面动效 / 彩铅手绘 / 复古电视 / 3D / 让我按选题提方案;有参考视频或截图就发来 4. **配色和字体**:主色 #……,字体 ……(也可以「按风格卡定」) 5. **声音**:用户提供的音乐文件 / 代码合成配乐;要不要配音 - 主题和那一句话必须由用户给,模型只能帮忙改写,不能代填。 - 用户回答「你定」的项,才在风格卡里给默认值并标注「待确认」。 - 无人值守时:主题来自原材料,其余用交付边界里的默认值,并在报告最前面列出所有假设。 - 给了音乐就先 `audio.py beats` 测节拍;给了参考视频:抽帧拼图 `ffmpeg -i ref.mp4 -vf "fps=1,scale=320:-1,tile=6x5" -frames:v 1 source/ref-sheet.png`,或直接 `qa.py ref.mp4 source/ref` 拿抽帧和切镜点。写下它的**手法**(镜头结构、节奏、转场、隐喻方式),不是外观。值得长期用的手法补进 `signature.md` 吸收清单。 ### 2. 导演层 → 三张风格卡 按 [references/director.md](references/director.md) 走:核心冲突 → A 稳妥 / B 跨界 / C 疯狂三个隐喻 → 各配一种风格 → 套 KAI 签名层 → 三张风格卡。 - 三张卡的隐喻必须不同;用户在第 3 项指定了风格时,三张卡共用这个风格,只比隐喻和镜头;否则风格至少两种不同。只换配色不算不同方案。 - 单片不能和 `style-log.md` 里最近 3 支用同一种风格(用户指定风格时除外)。 - 卡片下面写推荐哪张、一句理由,等用户选(可以混搭)。 ### 3. 分镜表(等用户确认) 选定风格卡后先写分镜表,**不写代码**。每个镜头一块,格式固定: ``` 镜头 [N]|[开始–结束秒] 画面:构图、元素、文字(文字 ≤ 一句,停留 ≥ 2.5 秒) 动作:进场、主要动作、出场(缓动或弹簧,写明哪一档) 镜头:推 / 拉 / 跟随 / 固定 声音:这一段的音乐和音效(音效写到具体动作) 转场:怎么从画面内容里长到下一个镜头 ``` - 有音乐:先分析节拍,镜头切换和关键动作都标出落在第几拍,重拍放最大的变化。 - 有配音:按旁白句子排镜头,时间先按每字 0.235 秒估。 - 标出签名动作所在的镜头。 - 自查一遍导演铁律(每镜一件事、字停留、转场不是淡入淡出、主体够大),再发给用户,**等确认**。 ### 4. 3 张关键帧(等用户确认) 分镜表确认后,预览页从 `template.html` 骨架起步,按风格卡重写 `STYLE`,只做 3 个最能代表全片的瞬间(通常:开场第一眼、签名动作那一刻、收尾定版): - `render.mjs previews/plan.html previews/k1.png --still ` × 3,拼成一张给用户看风格。 - 卖点在运动本身(变形、卡点、转场)时,额外出 2–4 秒小样:`--duration 3 --draft`。 - 自己先看一遍,字溢出、挤、空的先修,再给用户;不满意就回到风格卡换方向。 - 用单帧耗时估算正式渲染时间。 ### 5. 写 brief.md 按 [references/brief-template.md](references/brief-template.md) 把 7 块全部填实(`` 直接放确认过的分镜表)。之后的制作严格按它来;用户只要提示词时,交 brief.md 即结束。 ### 6. 出图(用到 GPT 图时) 按 [references/hybrid.md](references/hybrid.md):从 brief 的分镜表整理 `assets.json`(每镜要哪张图、参考哪个角色)→ `--dry-run` 给用户确认张数 → `--draft` 每张 2 个候选 → 用户挑图(`--pick`)或 `--final` 出定稿。没有 Key 就 `--export-md` 导出提示词,用户在 ChatGPT 手动出图后放进 `images/`。图片到齐再进入下一步。 ### 7. 逐镜头制作 - 画面只由 t 决定(规则见 craft-rules.md):不用计时器,随机数带固定种子,帧和帧之间不保存状态。用到 GPT 图时页面先 `KAILayers.load({...})`,字体和资源加载完再设 `window.ready = true`,之后才截图。 - 用了 WebGL:先渲一帧确认着色器真的生效,再往下做。 - 有配音:写 `spec.json`(`scenes[{id, lines}]`,`id` 对应 template 里 SHOTS 的 id),在能访问语音服务的电脑上跑 `assets/voice/配音.bat` 或 `python tts.py`,拿回 `audio/` 后 `audio.py vo spec.json` 整段合成,画面对旁白,不要一句一句拼。 - 没配音:先定节拍网格,镜头按拍排。 - 音效放在画面动作发生的那一帧:`cues.json` 的时间点直接从镜头关键帧抄。 - **每做完一个镜头渲 3 张静帧**(开头/中间/结尾)自己检查:文字有没有溢出、元素有没有重叠、画面够不够满、主体够不够大,修好了再做下一个镜头。 - 30 秒以上先出 `--draft --size 960x540` 看节奏,对了再精修。 ### 8. 渲染与自评 1. 混音:`mix --len <成片秒数>` → `normalize`(先裁到成片时长再调响度,否则裁掉安静尾巴后会偏响)。 2. 听不到声音:用 `audio.py check` 把波形画成图自己看,确认没有削顶爆音、意外静音、低频一直轰。 3. 正式渲染:`render.mjs … --audio audio/mix.wav`。 4. `qa.py out/final.mp4 qa`,按 [references/qa.md](references/qa.md) 8 项打分,列最严重的 3 个问题和时间点,只重渲出问题的那几秒,重复到每项 ≥8。 ### 9. 交付 报告:成片路径、`brief.md`、`qa/review_log.md`、关键创作决定、已知不足、渲染用时、需要用户核对的事实。 收尾三件事:在 `style-log.md` 最上面追加一行;效果好的风格卡存成模板;踩到的新坑补进 craft-rules.md。 ## 验证 - 渲染器退出码 0,没有页面报错(有报错时退出码为 2,并打印前 5 条)。 - 分镜表和 3 张关键帧都经过用户确认(无人值守时在报告里写明跳过)。 - `qa.py` 打分表每项 ≥8,验收清单全部勾上。 - 规格与 brief 一致:时长、画幅、帧率、声音。 - 波形图已看过,无削顶。 - `style-log.md` 已追加。