排错 - ZLHad/OpenVideoHarness GitHub Wiki

English · 中文

下面是仓库文档里记录过的问题:现象、原因、怎么办。遇到问题先跑 bin/vh doctor。如果是几天前装的,先 git pull:有不少修复(Linux、声音、渲染)已经在 main 上,只是还没打版本。

安装与环境

现象 原因 怎么办
install.sh 停下,提示"✗ node is required"(或 ffmpeg、git) 缺少必需的工具 装好 git、Node.js ≥ 22 和 FFmpeg 后重跑
安装时打印 skip <仓库> (clone failed) 某个上游参考仓库连不上;现在会跳过它,不会中断安装 之后重跑 references/fetch.sh,或者用 references/fetch.sh <目录> 单独拉一个
在 styles/_swatch 里 npm ci 失败,报 registry.npmmirror.com 的错 旧的 lockfile 把源写死成了这个镜像 git pull(已修复),再 cd styles/_swatch && npm ci
doctor 显示"✗ chrome" 找不到 Chrome 或 Chromium macOS:装 Google Chrome。Linux:sudo apt install chromium 或 npx playwright install chromium。也可以设 CHROME_PATH
doctor 显示"! no WebGL with the GPU flags" 无头 Chrome 用不了 GPU 渲染时加 node render.mjs --soft-gl(软件模拟 WebGL)。如果 doctor 说加了 --soft-gl 也没有 WebGL,这台机器就渲不了 WebGL 场景
doctor 显示"! AGENTS.md out of sync" 改了 CLAUDE.md,没重新生成 AGENTS.md 运行 bin/vh sync-agents
下载(npm、PyPI、Hugging Face、Chrome)很慢或失败 第一次运行要连境外的服务器 各自的镜像设置见国内网络;GitHub 本身连不上时,用 --no-refs 安装,参考仓库用到哪个再拉哪个
在别的目录说"做个视频",agent 找不到这里 agent 还没重新加载 skill bin/vh install-skill 之后重启 Claude Code 或 Codex
Linux 上 bin/vh new … --effort studio 仍写成 standard;样片渲完就报错退出;确定性检查卡在 md5 上 旧版本用了只有 macOS 才有的 sed -i ''、stat -f、md5 -q git pull,main 上已修复
bin/vh setup -h 开始整套安装,bin/vh sync-agents -h 重写了 AGENTS.md,或者某个命令把 -h 当成了文件名 旧版本把 -h、--help 原样交给了命令 git pull:现在 bin/vh <命令> -h 只打印这个命令的用法就退出,不会真的运行

渲染

现象 原因 怎么办
HyperFrames 渲染卡住不动,日志为空,也不报错 页面从 CDN 加载 GSAP 或 three.js,而加载时没有网 把依赖装进项目(npm i -D --save-exact),script 标签或 importmap 指向 node_modules。bin/vh hf-init 已经对 GSAP 这样处理,并会提示剩下的 CDN 引用。渲染外面再套一层看门狗
HyperFrames 渲染停在 5% 的 "Compiling composition",或者 snapshot、check 什么都不输出 字体栈里有没用 @font-face 声明的字体,HyperFrames 每次运行都会去 Google Fonts 请求(缓存了字体文件也照样请求),连不上就挂住。它别名表里的名字(Arial、Helvetica Neue、Menlo……)没写 @font-face 时,会被换成 Inter 或 JetBrains Mono,同样去取 每个字体都用 @font-face 加 src: local(…) 声明;#35 起 bin/vh hf-init 生成的脚手架已经这样写。网页字体想通过 npm 自己托管,见 README 的国内网络一节
第一次 hyperframes render 只显示 "Checking browser…",转了很久 它在下载 HyperFrames 自己管理的 chrome-headless-shell(约 100 MB,解压后约 200 MB,放在 ~/.cache/hyperframes/chrome),非交互的 shell 里不会显示进度;装了 Google Chrome 也一样要下 第一次渲染之前,在 HyperFrames 项目里先跑一次 npx hyperframes browser ensure:它会写明在下什么、多大。下不了就用上面的镜像设置
bin/vh new 提示"hyperframes init failed (offline?)" 脚手架要用 npx 联网拉取 联网后重跑 bin/vh hf-init <项目目录>,画幅参数用 portrait、landscape 或 square
~/.claude/skills 里多出了 HyperFrames 的 skill 它的 init 和 skills update 会装到全局 每次跑 npx hyperframes 之前先 export HYPERFRAMES_SKIP_SKILLS=1,也不要运行 npx hyperframes skills update。bin/vh hf-init 已经替你设好了
规格写了 font-weight: 800,PingFang SC 渲出来却不比 600 粗 macOS 的 PingFang SC 只有 6 个字重(100–600),700、800、900 都落到 600,逐像素相同,也不报错 写 600,并在 STYLE.md 里记下;真要 800,带一个有这个字重的字体(Noto Sans SC),或者换有更粗字重的系统字体(Songti SC 有 900)
--format png-sequence 出的帧背景是透明的,psnr 命令读数偏高约 1.25 dB PNG 是 RGBA,html、body 和根元素的背景都没有画出来(alpha = 0),所以用它编出的 mp4 是黑底;psnr 把 alpha 通道当成零误差的第四个分量 做确定性检查时要心里有数;用 format=rgb24 逐对比较的写法在 playbook/02
hyperframes snapshot 把帧发给了 Gemini 环境里有 GEMINI_API_KEY(或 GOOGLE_API_KEY)时,snapshot 默认给每一帧生成描述:帧离开你的电脑,还要计费 一律加 --describe false,仓库的文档和提示里本来就带着。check 不受影响
HyperFrames 渲染突然都慢了 3 倍左右 HyperFrames 把这台机器切到了较慢的截帧路径 设 HF_DE_PARALLEL_ROUTER=true
有一段画面一直停在 t=0,渲染却显示成功 renderAt 里抛了异常,比如在声明之前就读了一个 const 把每一帧和第 0 帧比 PSNR,或者在 draft 画面角落常驻一个时间读数;修掉异常
每个 worker 负责的那段,开头 1–2 帧是空的 异步构建还没完成就截了图 在普通 <script>(不是 module)里同步注册一个就绪 promise,第一帧画完后再 resolve
Three.js 里的视频屏幕渲出来是黑的 VideoTexture 没有更新 每一帧都设 texture.needsUpdate = true;视频按 t 跳转,并等跳转完成
镜头推近后字发虚 will-change: transform 让浏览器按小尺寸栅格化了 要被放大的元素不加 will-change,或者按放大后的尺寸排版
等宽字在 MP4 里变成了比例字体,快照里却是对的 ui-monospace, monospace 能过 lint,渲染时却不生效 用 @font-face 显式声明,src: local("SF Mono"), local("Menlo");判断字体要看渲出来的帧
合上音轨后画面被截短,或者丢了最后几帧 用了 ffmpeg 的 -shortest 用 bin/vh mux 合成,它会把音频补齐或截到视频的长度
饱和色在浏览器或手机上和在 ffmpeg、剪辑软件里看到的不一样 mp4 没写色彩标签,或写的是 BT.601 的标签:旧的手绘引擎写的是 bt470bg,浏览器读错(饱和色偏 24–40 个色阶),ffmpeg 却读得对 编成有限范围的 BT.709,四个标签写全;不合格的 bin/vh check 会报出来。ffprobe 检查和 ffmpeg 命令见 playbook/02
看的其实是上一次的渲染结果 旧的输出文件还在 渲染前先删旧文件,或者核对文件的修改时间
bin/vh check 报出黑场、冻帧或静音 暗色背景、有意的停顿和静音片子都会触发 逐条看一遍再判断

确定性

现象 原因 怎么办
同一帧每次渲得不一样 用了 Math.random()、Date.now()、CSS transition 或 @keyframes,或者在帧之间保存了状态 随机用带种子的 hash(i),一切都从 t 算出来
用 --soft-gl 时,每次启动渲出的帧都不同(约 39 dB) Chrome 给 canvas 读回加了噪声 main 上已修复,git pull 即可
两次渲染的 MP4 一比,像是不确定(约 42 dB) x264 会放大 GPU 光栅化的细微差异 比无损 PNG 帧:逐像素相同,或 PSNR ≥ 45 dB 且肉眼看不出,就算通过
同一个 HyperFrames 项目渲两次,文字边缘有几个像素不同,或者编码大小在体积上限处来回跳 GPU 光栅化文字,每个 Chrome 进程都略有不同;带体积上限的 x264 用帧线程编码不可重复 hyperframes render --no-browser-gpu(走 CPU,慢一些)能让像素可重复,x264 用 -threads 1 能让码流可重复。样片渲染器两样都用了:研究笔记 03 有测量数据
手绘场景里静止的东西跟着抖 前面某个运动物体打乱了共用的随机数流 给每个元素设独立的 boilSeed()

字体

现象 原因 怎么办
canvas 上的中文缺字,或者变成了系统字体,但 document.fonts.ready 已经就绪 中文网页字体是按分片加载的,某个字第一次画到时才去下载它所在的分片 每个字重调一次 document.fonts.load(…),把片中用到的所有字一次交给它;加载被拒、返回为空或超时都要大声报错
第一帧用了回退字体,排版跳了一下 字体还没加载完就截了图 第一次截图前先 await document.fonts.ready
HyperFrames 的 lint 不接受中文字体 Noto Sans SC 不在它的自动字体列表里 用 Google Fonts 的 <link> 引入,或者把字体文件放进 assets/ 并写 @font-face

Blender

来自冒烟测试和介绍片开场的实测,更多见 engines/blender.md。

现象 原因 怎么办
Blender 一开渲就两分钟左右一行日志都没有,被看门狗杀掉 第一次在 Metal 上渲要静默编译内核(约 110 秒) 给 Blender 放宽静默阈值(样片渲染器用 300 秒)
套上沙箱后,Metal 每帧从 2 秒变成 13 秒 Blender 没法把编好的着色器存进本用户缓存目录里它自己的子目录 放行 $(getconf DARWIN_USER_CACHE_DIR)org.blenderfoundation.blender 的写入
在一个进程里逐帧渲,某个物体有一段帧全黑,单独渲那一帧又正常 render.use_persistent_data 把状态带到了下一帧 每帧都由脚本改场景时关掉它,或者拿乱序重渲的帧来比对
长渲染挂在 agent 的后台任务上,渲到一半就断了 Claude Code 的后台任务 30 分钟会被收掉 分块渲,每块一个新进程,已经存在的帧跳过,用 nohup caffeinate -i … & disown 脱离会话,showcase/04-intro-film/tools/bl_render.sh 就是这样写的
星点被抹成一团团糊 OIDN 降噪 星空关掉降噪,靠采样数
叠在一起的玻璃卡片渲成黑块 光线穿过的层数超过了透射反弹上限 不需要玻璃的卡片把玻璃收掉
镜头接近垂直俯视时画面扭、抖 to_track_quat 在接近垂直时不稳定 自己算 forward 和 up 来构造旋转,相邻两帧的四元数取同号(q.dot(prev) < 0 就取反)
Blender 里的字字重不对 bpy.data.fonts.load() 只读 .ttc 的第一个字形 把要用的那一面写成单独的字体文件(styles/_swatch/blender_prep.py 用 fontTools 做)

配音与混音

现象 原因 怎么办
qwen 念一句英文短句,念完还拖几秒含糊声 Qwen3-TTS 0.6B 停不下来,用 Ryan 音色时最明显 默认音色已换成 Aiden。加 --align gemini 把这种句子标出来,然后重跑、换 1.7B 模型(QWEN_TTS_MODEL)或改用 gemini
Linux 上 say 或 qwen 用不了 say 只有 macOS 有;qwen 需要 Apple Silicon 改用 edge 或云端 provider
--align gemini 停了一分钟左右又接着跑 Gemini Tier 1 每分钟只能转写 10 次(HTTP 429) 不用管:它会按接口要求的时间等待,最多重试 5 次。要求等 90 秒以上的是日配额用完了,会直接报错
--align gemini 跑到一半停了(日配额、网络) 有一次转写彻底失败了 已经合成的配音保留,命令以退出码 1 结束并说明原因。用同一条命令加 --resume:只补缺的部分,已经成功的句子不会再花一次钱
提示"set GEMINI_API_KEY" 环境变量里没有这个 key 在 shell 里 export GEMINI_API_KEY=…,不要写进仓库里的任何文件
bin/vh tts <p> --provider edge 报错"No such file or directory: 'edge-tts'" 旧版 bin/vh 只按位置参数选依赖 git pull(已修复),或者把 provider 写成位置参数:bin/vh tts <p> edge
bin/vh qa 因为片中的数字静音不通过 戏剧性的停顿用了真静音 保留一层垫音(sub 或 pad),把滤波收下来,撤掉鼓,再用渐强拉进下一个重拍
bin/vh qa 报抽吸,或者音乐在句间掉下去 每个音效都接进了 ducker,或者 duck_ratio 太高 用默认值(duck=voice、duck_ratio=1.6);用 duck=on 时把 ratio 降到 2–3。给 qa 加 --voice voiceover.wav,旁白下面设计好的让位就不会被算进去
bin/vh qa 打印的混音报告里有 LOW、HIGH、OVER-VOICE、MASKS-VOICE 或 BURIED 用 profile= 混的音,某一句、某个音效或某个词出了范围;BURIED 是指卡点对上了、但听不见 先看"why"那一列。按标记怎么改,见 playbook/04 的"怎么读混音报告":重录那一句或让配乐在那里收一收,挪动音效或重新分类(role),提高 gain_db,低频的重击要加一层 1–4 kHz 的起音,不要靠增益
AAC 编码后的文件真峰值高于 −1.5 dBTP AAC 编码会抬高真峰值,密一点的音乐在 128k 下最多约 +1.4 dB 用 ffmpeg -i final.mp4 -af ebur128=peak=true -f null - 量编码后的文件,用更低的 tp= 重混;样片渲染器会自己做这一步
浏览器要等整个视频下完才开始播 索引(moov)在文件末尾 用 bin/vh mux 重新封装,它现在会把索引写在开头
画面里烧了字幕,播放器却又打开了一条字幕轨 MP4 封装器总会把第一条字幕轨标成启用 bin/vh mux --subs-off
bin/vh readcheck 判重复旁白的烧录字幕不合格 它们被按上屏文字的规则查了,那条规则假定读得更慢 在字幕元素或它所在的场景上标 data-read="subtitle",就按字幕的阅读速度查
一条字幕不到 1.8 秒就闪过去了 念的那一句太短 重新跑 bin/vh captions:它会把短字幕往后面的空白里延长,最多到下一条字幕或画面结束
bin/vh qa 列出了一些 click 机器分不清设计好的尖锐起音和真正的故障 这只是警告:用耳朵把最严重的 10 处听一遍
bin/vh qa 提醒某个声音在重复 同一个声音连着三次以上一样:钉死了 variant,或者用的是同一个文件 去掉钉死的 variant,几个 take 轮着用,或者换一个转场家族;bin/vh sfx audition 可以先听几个选项
bin/vh mix 报告限幅器压了很多峰 音效或人声的峰值太高 调低 sfx_db,不要靠限幅器硬压

这里没有的问题,请开一个 issue,附上命令、输出和 bin/vh doctor 的结果。

⚠️ **GitHub.com Fallback** ⚠️