检查与渲染(paint-mv-render)

SkillWeb & browsing

Checks and renders a paint-mv music video with its render.mjs (Puppeteer drives studio.html in headless Chrome, ffmpeg encodes): contact sheets and stills for visual checks, short clips with audio, the full parallel and resumable frame render, re-rendering a fixed time range, encoding frames plus the song into the final MP4, verifying the result and troubleshooting Chrome/WebGL/ffmpeg problems. Use when previewing, rendering, re-rendering or exporting an MV made with paint-mv, or when render.mjs fails.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the 检查与渲染(paint-mv-render) skill

What this skill tells your AI

The instructions your AI receives, as published by lintsinghua/paint-mv-skills in skills/paint-mv-render/SKILL.md and read by ahel’s review.

所有命令都在项目根目录运行。render.mjs 从 src/song.js 读时长和音频;帧率默认 24(整个引擎按 24 fps 设计: 震动按 24 fps 变化、线条每秒"沸腾"12 次),不要改。

前置条件

  • Node.js ≥ 18、ffmpeg(在 PATH 上)、Google Chrome;项目里跑过 npm ci(new_project.mjs 默认会跑)。
  • Chrome 路径和 WebGL 后端按平台自动选:Windows d3d11、macOS metal、Linux 默认(无 GPU 时加 --angle=swiftshader)。 找不到 Chrome 时加 --chrome=<路径>。

命令

用途命令
联系表(最快的目检,打印每帧 ms)node render.mjs --sheet=23,23.5,24 [--cols=3] [--w=640] --out=out/check/x.jpg
全分辨率 PNG 静帧node render.mjs --stills=0.8,3,23.8 --out=out/check/stills
带音轨的短片node render.mjs --clip=20:35 --out=out/check/clip.mp4
全片逐帧(并行、可续渲)node render.mjs --frames=0:<时长> --workers=4 → out/frames/f00000.jpg …
帧 + 歌曲 → MP4node render.mjs --encode --out=out/mv.mp4
角色模型表(characters.js 里的 LOOPS.cast)node render.mjs --loop=cast --sheet=0.3,1.3,2.3,3.3,4.3,5.3 --cols=3 --out=out/check/cast.jpg
独立循环(GIF 素材)node render.mjs --loop=recursion --out=out/loop_recursion

联系表和静帧用 Read 工具打开来看。怎么判断好坏见 paint-mv-animate 的"检查你的作品"。 多个代理可以同时渲染(各自起一个 headless Chrome)。

浏览器里直接打开 studio.html(不带 ?render)有拖动条,可以逐帧预览;studio.html?t=42.5 从指定时刻开始。

节拍与歌词的人工确认

智能体听不到声音。速度或首拍有歧义(分析报告里 AMBIGUOUS)或歌词是自动对齐的时候,渲一段短片请用户看:

node render.mjs --clip=<某段副歌开始>:<+15 s> --out=out/check/timing.mp4

章节还是占位画面时,画面中央的小 Clawd 按拍弹跳(placeholder(),只是引擎自带的节拍器,与本片角色无关), 卡拉 OK 按歌词时间出现和扫字,正好用来确认。 拍点整体早/晚:改 src/song.js 的 offset(首拍有歧义时先试报告里列出的备选 offset);舞步太快/太慢一倍或 3:2:换 bpm (重新跑 analyze_audio.mjs --bpm=N 取对应的 offset);歌词整体偏:lyrics_to_ly.mjs --shift=秒 重新生成。

全片渲染

  1. 渲染前先用联系表把每个章节交界(交界时刻 ±0.1 s)、每个 wipe、每章中点看一遍,确认没有 [page error]。
  2. node render.mjs --frames=0:<SONG.duration> --workers=4。每 24 帧打印一次 ms/frame effective 和 ETA。 总帧数 = ceil(duration × 24)(156.6 s 的歌是 3759 帧)。工作线程多于 GPU 能喂饱的数量不会更快;Apple Silicon 上 4–6 个合适。 实测参考:Apple M5、4 个 worker,一段 24 s 的两章测试片有效约 0.27 s/帧(576 帧 2 分半);画面越满越慢,按联系表的 ms 估算。
  3. 中断了就重跑同一条命令:已存在且大于 1 KB 的帧会跳过,帧是先写 .tmp 再改名,不会留下半张图。
  4. 直到输出 0 frames to render 再编码。ffmpeg 读到第一个缺失的帧号就停,缺帧会让视频提前结束。

改了某个章节之后只重渲那一段:先删掉该时间段的帧,再跑同一条 --frames 命令(只补缺的):

node -e "const [a,b]=[23,38.5],fs=require('fs');for(let i=Math.round(a*24);i<Math.round(b*24);i++)fs.rmSync('out/frames/f'+String(i).padStart(5,'0')+'.jpg',{force:true})"

删帧的范围和补渲的范围要一致:--frames=a:b 渲染的是 round(a×24) 到 round(b×24)−1,多删的帧不会被补上, 编码就会在缺口处提前结束。最保险的做法是补渲时直接跑全片 --frames=0:<duration>(已有的帧会跳过), 编码后用 ffprobe 确认时长等于歌曲时长。

改了 song.js 的 duration、bpm、offset 或歌词:整个 out/frames 删掉重渲(打点和卡拉 OK 全变了)。

编码与验收

node render.mjs --encode --out=out/mv.mp4

libx264(preset slow、CRF 17、yuv420p)+ AAC 192k、+faststart、-shortest。然后验收:

ffprobe -v error -show_entries format=duration:stream=codec_name,width,height,r_frame_rate -of compact out/mv.mp4
for t in 5 30 60 90; do ffmpeg -v error -y -ss $t -i out/mv.mp4 -frames:v 1 out/check/mp4_$t.jpg; done
  • 应有 h264 1920×1080 24/1 和 aac 两路流,时长约等于歌曲时长(差不到一帧)。
  • 抽帧(每章中点、几个转场)用 Read 看一遍,确认画面和卡拉 OK 正确。
  • 体积参考(实测):每帧 JPEG 约 0.7 MB,3 分钟的歌约 3 GB 帧文件;水彩纹理让成片码率约 20–25 Mbps,3 分钟约 500 MB。

排错

现象原因与处理
[page error] Error creating webgl context,随后 Waiting failed: 60000ms exceededWebGL 后端不对:换 --angle=metal / d3d11 / gl / swiftshader;或 Chrome 路径不对:--chrome=<路径>
[page error] <某个 JS 错误>章节代码在该时刻抛异常,这一帧会画坏;定位到对应章节修复
[page] WebGL: INVALID_OPERATION: uniform…: location is not from the associated program无害。原作引擎画占位画面(placeholder())时也会打出,帧是正确的
文字字体不对字体从 Google Fonts 加载,需要联网;离线会回退到系统字体
视频比歌短缺帧(见上);补渲到 0 frames to render 再编码
画面整体和节拍差一点调 song.js 的 offset(单位秒,一帧约 0.042 s)后重渲
某些帧超过 4 s在对应章节里减少 fill 形状和顶点数(见 paint-mv-animate 的性能规则)
ffmpeg exited 1ffmpeg 不在 PATH,或 SONG.audio 指向的文件不存在

Signals

GitHub stars
25
Forks
5
Last commit
Sep 2026
Advanced
Item type
skill
Key
paint-mv-render
Source
github.com/lintsinghua/paint-mv-skills