一个科普主题 → 一期 Vox 拼贴风科普短视频
参考样片:ep21-nobel-physics(2026 诺贝尔物理学奖:南极冰下抓中微子)。用户认可的效果就是这一期:口播像聊天、开头有钩子、结尾有余味;黑卡大字和真实素材交替硬切;配乐有律动、跟着剪辑走。
一口气做完第 0~8 步,中途不等用户确认,每步做完用一两句话同步进度。不导出、不提交 git,除非用户另外要求。动手前先读工程根目录的 CLAUDE.md、src/library/README.md。所有 npm / npx / node 命令前先 export NODE_OPTIONS=--max-old-space-size=4096。
依赖(开源版说明)
配音和字幕两步用的是作者的私人工具,仓库里没有带:
- 配音:
scripts/tts_expressive.py需要一个豆包语音合成的封装模块,用环境变量DOUBAO_VOICE_PY指向它、DOUBAO_TTS_SPEAKER_ID指定复刻音色(见脚本开头说明);不用豆包就换成任何能输出 mp3 的 TTS,或者真人录音。 - 字幕:第 5 步提到的
weilanx-doubao-voice-srt是作者的私人 Skill,换成任何能输出 SRT 的语音识别工具。 - 其余步骤(查资料、找素材的
commons.py、出片、配乐)都在仓库里。
规格
| 项 | 默认 |
|---|---|
| 画面 | 横屏 16:9(1920×1080),VoxShow 骨架,无主持人 |
| 时长 | 约 1 分钟(稿子 400~430 字,配音 58~63 秒),用户另说时按用户的 |
| A-roll | 黑卡大字(BlackCard) |
| B-roll | 钉在桌面上的真实素材(VoxFootage):视频、实拍照片、官方插图 |
| 配音 | 豆包复刻音色 + 语气提示 + 语速 +30,不做后期 1.2 倍加速 |
| 配乐 | 124 BPM 电子律动,侧链呼吸,切点重击,level 0.071(压在人声下) |
| 封面 | 16:9 首帧 + 3:4 竖版 |
0. 定期数和目录
- 期号取
src/episodes/里最大的下一个,作品 IDepNN-英文短名,下面记作<期>。 - 代码
src/episodes/<期>/,素材public/footage/<期>/(不进 git),音频public/audio/<期>/,原始材料和文稿materials/<期>/。 - 在
materials/选题候选池.md的「已做」表补一行,状态 🎬。
1. 调研:只用权威来源
- 用 WebSearch 查主题,优先一手来源:官方新闻稿(如 nobelprize.org 的 press-release / popular-information)、NASA、机构官网、顶刊;新闻媒体只做交叉核对。
- 官网对 WebFetch 返回 403 时,用
curl -A "Mozilla/5.0 ..."抓页面,再用 Python 去标签取正文。 - 把要讲的每个数字、年份、说法和出处记进
materials/<期>/调研.md。不确定的说法不进稿(例:「第一次……」这类绝对说法要先查是否真是第一次)。
2. 找真实素材(B-roll 的底子)
详见 references/素材.md。要点:
- 来源优先级:NASA / 美国政府机构(公有领域)> Wikimedia Commons(CC0 / CC BY / CC BY-SA)> 官方新闻稿插图(看清使用条款,常见是「非商业免费、需署名」)。不用来路不明的图,不扒 YouTube 视频。
- 用
scripts/commons.py search / info / get搜索、查授权和真正的作者(Artist字段,不是上传者用户名)、下载原图。 - 视频先每 5 秒抽一帧拼成联系表,挑出要用的片段,再细抽确认画面真的在那几秒,然后剪成 720p H.264 小段(
-an -vf scale=1280:720,fps=30 -c:v libx264 -crf 20 -pix_fmt yuv420p -movflags +faststart)。 - 大图用
sips -Z 1800缩小;全部放public/footage/<期>/。 - 每个素材的文件名、内容、作者、授权写进
materials/<期>/素材来源.md;画面上每个素材左下角都标「作者 / 授权」。
3. 写口播稿:像跟朋友聊天
详见 references/语气与写稿.md。硬规则:
- 强钩子:第一句把观众拉进现场,用「就在你听我说这句话的这一秒……」「你一点感觉都没有,对吧?」这类和观众本人有关的反差。
- 带语气:每 1~2 段放一个口语抓手——问句(「那怎么抓一个幽灵呢?」)、反转(「听起来很疯狂,可他们真干了。」)、引导(「你想啊,……」)。
- 深度结尾,不说「OK 本期视频就到这里」:最后两三句从事实上升到意义(「这个诺奖奖励的不只是一台仪器,而是人类看宇宙,多了一双不靠光的眼睛」),结尾那句要短、要能单独成立。
- 400~430 字;数字写成阿拉伯数字(TTS 读得准),但「两千多米」这类约数用汉字;不用冒号、括号、破折号。
- 稿子存
materials/<期>/口播稿.txt,在回复里贴全文和字数。
4. 配音:语气提示 + 模型语速
python3 .claude/skills/weilanx-creator-vox-video/scripts/tts_expressive.py \
--text-file materials/<期>/口播稿.txt --output materials/<期>/<期>-口播-自然版.mp3
- 默认语气提示是「自然、松弛、像跟朋友聊天的科普博主,有轻重缓急;问句带好奇和调侃;惊人处有惊叹;结尾放慢带感慨;不要播音腔」,默认语速 +30。
- 不要再
atempo=1.2:后期硬加速会让语调发僵;要变快就提高--rate或删字。 - 时长目标 58~63 秒:超了先删修饰语,再把
--rate提到 35~40;短了反过来。 - 用
scripts/voice_stats.py量一下(uv run --with numpy python ...):音高范围 ≥15 半音、停顿 40 次左右算合格;两版对比时把数字报给用户。 - 声音只能用户自己听:保留试音,告诉用户文件位置。
5. 转字幕、处理人声
- 用
weilanx-doubao-voice-srt的三个脚本识别这份 mp3(转 16k 单声道再识别),用稿子校对,每行 6~16 字、一个完整意思,输出materials/<期>/字幕.srt和字幕稿.md。识别和稿子对不上的地方记下来让用户去听。 - 人声:
ebur128测响度 →volume=<增益>dB,alimiter=limit=0.8:level=false调到 −16 LUFS(±0.5)→ 48kHz 立体声 16-bit →public/audio/<期>/voice.wav。 - 结尾留余韵:
cues.ts的VOICE_SECONDS设为最后一条字幕结束 + 约 2 秒,并用apad=whole_dur=<VOICE_SECONDS>把 voice.wav 补到同样长,这样配乐能铺满余韵再淡出。 npm run cues -- materials/<期>/字幕.srt src/episodes/<期>/cues.json,然后打印每条字幕的起止帧,后面排镜头用。
6. 画面:A-roll 黑卡 + B-roll 真实素材,按字幕硬切
详见 references/画面.md,代码照抄 src/episodes/ep21-nobel-physics/film.tsx 的骨架。核心:
- 整片是一张镜头表
SHOTS: {from, kind: 'A' | 'B', C}[],Film只渲染当前镜头,镜头之间全是硬切,切点落在字幕开头(cf(n),最多提前 2~6 帧)。 - A-roll 黑卡用来接住口播里的「钩子数字、名词揭晓、问句、反转、结论」:一句一张,字号 150~330,关键词用黄色字 + 红色手画下划线(黑卡上不要用
Highlight荧光笔,叠在黑底上看不见)。 - B-roll 是
VoxFootage钉在旧纸桌面上(白边、两条胶带、左下角署名),整个镜头慢推 5%,旁边配 Vox 批注:Label黑底标签、IndexCard索引卡、PostIt便利贴、Stamp盖章、RedCircle红圈、HandLine手画箭头 / 对勾、手写红字。 - 节奏:每 2~4 秒一个切点;黑卡和实拍交替,不要连续三个以上同类镜头;视频镜头必须传
start(开始播放的全局帧)。 - 抽象的道理配一张手画图解(例:光被尘埃挡住、中微子笔直穿过),元素按口播分步出现。
- 每个镜头配音效(
paper切实拍、stamp切黑卡、ding数字落定、magic揭晓、question问句)。
7. 配乐:有律动、跟着剪辑走
详见 references/配乐.md,代码照抄 audio/episodes/ep21-nobel-physics.mjs(用 audio/score.mjs 的乐器),只跑 node audio/episodes/<期>.mjs。核心:
- 全片一条 124 BPM 的节拍网格从头走到尾,段落切换吸附到离字幕最近的小节线(
snapBar)。 - 四拍底鼓 + 二四拍军鼓 + 十六分踩镲;铺底和方波琶音做侧链式呼吸(每拍压下去再放开)。
- 解释概念的段落转半速;结尾前留白(「你想啊」那种转折句只留铺底),再起拍一路推到最后一句落重击,余韵铺满再淡出。
- 每次切到黑卡前推 0.9 秒渐强、切点落一下低频重击;全片挑 3~4 个高潮词(揭晓、震撼数字、结论)加镲 + 重击。
level 0.071、depth 0.7,整轨约 −32~−34 LUFS;用户想让律动更突出时再整体调大。
8. 封面、文案、预览
- 写
src/episodes/<期>/Cover.tsx:16:9 首帧封面(左黑卡大标题 + 右侧两张真实素材 + 一个贴纸)和 3:4 竖版封面,在Root.tsx注册<期>-cover-tall的Still;渲染存为materials/<期>/封面-16x9.png、封面-3x4.png(导出脚本会自动带上)。 Ep*.tsx用VoxShow,cover: {C, frames: 第一句开始帧 − 5},subY: 965,keywords放本期高亮词;仿tests/episodes/ep21-nobel-physics.test.ts加测试;npm run typecheck、npm test都要过。- 抽帧自查:每个镜头至少一帧(
--scale=0.25,按顺序一帧一帧渲,bash -c包循环),拼图看:视频是不是黑的、字有没有压到素材或字幕、句尾词挂的元素是不是一闪而过、黑卡下划线有没有压字。 - 用
dbs-xhs-title出主标题 1 个、备选 2 个(注明公式编号,≤20 字);描述第一句是钩子,然后要点清单,末尾写素材来源和授权,最后一行话题。存materials/<期>/发布文案.md。 lsof -i :3000 -sTCP:LISTEN看 Studio,没开就后台npm run studio。把http://localhost:3000/<期>给用户,汇报:稿子全文和字数、时长、人声响度、语气统计、字幕条数、镜头表、配乐结构、素材授权(尤其非商业条款)、需要用户确认的事实和读音。提醒用户:听感只能自己听。- 用户确认后再
npm run export -- <期>,检查时长、1920×1080、−16 LUFS、峰值 < −1 dBFS,并把成片复制一份到materials/<期>/,候选池改 ✅。
踩过的坑
- NASA 等长视频里画面会切好几次:按 5 秒抽的联系表定位后,还要在目标附近每秒抽一帧确认,否则剪出来的可能是黑场或别的画面。
- 署名用 Commons 的
Artist(真正的作者),不是上传者用户名。 cw(n, '词')挂在句尾的元素会一闪而过:改挂到句首cf(n) + k,或让下一个镜头晚几帧切。- 镜头的
start和镜头的from要一致,否则视频会从中间开始播。 - 配乐长度跟着 voice.wav 走,所以要给 voice.wav 补静音到
VOICE_SECONDS,不然结尾余韵没有音乐。 - 「不只是 X,而是 Y」这种句子,别给 X 加删除线(会被读成「不是 X」),把 X 调暗就行。