explainer-video-pipeline(自动生成)
使用时机
用户希望制作一个 1–3 分钟的解说视频,内容涉及某个主题(科学、产品、技术),最终输出为一个包含语音、字幕、音乐和音效的 MP4 文件。
参数与默认值
只需询问主题;除非用户指定其他值,否则使用所有默认值。用一句话说明你使用了哪些值。
| 参数 | 默认值 | 其他值 |
|---|---|---|
topic | 必需 | — |
storyboard_model | claude-opus-5.5 编写脚本、旁白和故事板 | kiro-cli chat --list-models 中的任意模型 ID |
video_engine | opus-5.5:claude-opus-5.5 为每个场景编写绘制每一帧的代码 | 其他代码模型,例如 claude-sonnet-5.5;seedance(BytePlus ModelArk API,需设置 ARK_API_KEY);hybrid(代码绘制场景中嵌入 Seedance 片段) |
renderer | remotion(React/SVG;Remotion 逐帧驱动无头 Chromium) | html(Canvas 2D / SVG / GSAP / p5.js 页面,通过 Playwright 捕获);manim(Manim Community 场景;最适合几何、图形、向量和逐步推导) |
seedance_model | seedance-1-5-pro-251215 | 用户 ModelArk 账户中启用的任意 Seedance 模型 |
tts | polly,神经语音 Zhiyu,cmn-CN,us-east-1 | gtts(免费,无需密钥,语音较平淡);其他任何 Polly 语音/语言 |
captions | 开启:Whisper 单词时间戳,以逐词高亮字幕形式嵌入 | 关闭 |
whisper_model | small(CPU,int8;10 秒语音约需 5 秒处理) | base(更快),medium(更准确的时间戳) |
music | synth(使用 ffmpeg 合成的免版税振荡器背景音) | none;用户拥有的音乐文件路径 |
sfx | 开启:scenes.json 中列出的事件会被合成并放置在对应帧上 | 关闭:从每个场景中省略 sfx |
language | 普通话 | Polly 和 Whisper 同时支持的任何语言 |
size, fps | 1920×1080,30 fps | 1080×1920(竖屏) |
“Made with Opus 5.5” 表示 Opus 5.5 是创作者:它编写脚本和绘图代码,然后由渲染器将这些代码转换为像素。没有文本模型能直接输出视频,只有 Seedance 可以。在第一次回复中说明这一点。
如果当前会话已经在 claude-opus-5.5 上运行,则自行完成编写。否则,为故事板(第 2 步)生成一个带有 model="claude-opus-5.5" 和 keep=true 的任务,然后使用 spawn_continue 在同一运行中继续场景代码(第 5 步),最后审阅其输出。
设置(每台机器一次)
将工具保存在稳定的缓存目录中(例如 ~/.cache/explainer-video/),绝对不要放在 $KIROCREW_SCRATCH 中,因为后者会在会话之间被回收。
- ffmpeg:一个完整的静态构建版本,包含
aevalsrc、anoisesrc、tremolo、sidechaincompress和ass/libass。Remotion 自带的 ffmpeg 缺少这些功能。将FFMPEG/FFPROBE指向它。 - Python venv(
boto3 gTTS playwright faster-whisper pillow numpy),然后在该 venv 中运行python -m playwright install chromium-headless-shell。faster-whisper 1.2.x 在 PyAV 19 上会报错(unexpected keyword argument 'metadata_errors'):请锁定av==16.1.0。将HF_HOME设置为缓存目录,以便 Whisper 模型只下载一次。 - Manim(仅用于
renderer=manim):pip 无法在 aarch64 上构建它(没有 pycairo、manimpango、moderngl 的 wheels)。在没有 root 权限的情况下,使用 micromamba:micromamba create -p <cache>/manim-env -c conda-forge python=3.12 manim。带 CJK 字体的Text()可以正常工作。MathTex/Tex需要 LaTeX 发行版和dvisvgm;conda-forge 的texlive-core在 aarch64 上没有latex.fmt,因此公式在那里会失败。使用Text()编写公式(Unicode:F = m·a, x², √, →),或者在用户那里安装一个系统级 TeX Live。
步骤
辅助脚本位于此技能的 scripts/ 文件夹中。
- 项目。 在用户工作区的一个 git 仓库中创建项目文件夹。对于
renderer=remotion,手动创建package.json、tsconfig.json(resolveJsonModule: true)、src/index.ts、src/Root.tsx,并运行npm i remotion @remotion/cli react react-dom。 - 脚本和故事板(由
storyboard_model完成)。编写scenes.json:每个场景一个对象,包含id、narration(口播台词)、visual(屏幕上显示的内容)、可选的manim(Scene 类名)和可选的sfx:[{"at": FRAME_IN_SCENE, "kind": "whoosh|hiss|pop|rise|thud|PATH"}]。使用 6–10 个场景,每个场景一个想法,包括一个标题场景和一个结束卡片。通过网络搜索检查事实,并在 README 中注明来源。 - 参考图像。 当视频展示一个真实物体时,寻找或获取一张清晰的照片,并保存在
ref/中。永远不要凭记忆绘制真实物体的形状:对照片进行边缘检测,测量关键点,然后使用仓库中的小脚本根据这些点生成形状。 - 旁白驱动时间。 运行
narrate.py scenes.json . --tts polly。它会生成durations.json(每个场景的帧数,基于实际语音长度加上填充)、narration.wav和audio/sNN.mp3。场景代码会读取durations.json,因此每个场景的时长正好与其台词时长相等。 - 场景代码(由
video_engine完成)。remotion:每个场景一个 React 组件,使用useCurrentFrame和interpolate/spring相对于场景起始帧进行动画。html:一个index.html,包含window.seek = async (frame) => {...},该函数根据帧编号和durations.json数组精确绘制该帧。不要使用requestAnimationFrame、挂钟时间或未设置种子的Math.random。将durations.json数组粘贴到页面中作为常量:以file://方式打开的页面无法fetch()本地文件,且静默失败。GSAP:暂停时间线 +tl.seek(frame / fps)。p5.js:noLoop()+ 在seek中使用redraw()。manim:一个scenes.py,每个场景对应一个 Scene 类。从os.environ["SCENE_SECONDS"]读取目标时长,并以self.wait(max(0.04, secs - self.renderer.time))结束;同时根据secs调整长时间动画的尺寸。保持帧底部 15% 的区域空白以用于字幕。seedance:设置ARK_API_KEY后运行seedance_clips.py scenes.json .;它会下载clips/<id>.mp4(URL 在 24 小时后过期)。
- 在完整渲染之前检查静态帧。 从每个关键场景渲染 4–6 帧,将它们合并成一个缩小后的接触印相片,然后查看这张图片。为了独立检查,启动一个只拥有该印相片和
scenes.json的全新审阅者。 - 音效。 如果任何场景有
sfx,运行sfx.py scenes.json .。然后运行mix_bgm.py . --music <music>:它会将音乐在语音下方闪避,添加sfx.wav,写入narration_bgm.wav,并打印 RMS 电平。纯音乐的前导部分应在 −20 到 −30 dB 之间;−55 dB 或更低意味着听不见。 - 字幕。
captions.py scenes.json . --size <WxH>使用 faster-whisper 逐词时间戳转录每一行,并将其映射到脚本自身的字符上,因为 Whisper 会误听同音字(例如,它将“气体”听成了“漆体”)。它会写入captions.ass(每个字符在说出时高亮显示)和words.json(每个字符的时间,可在步骤 5 中用于屏幕强调)。 - 渲染(无声画面)。
remotion:npx remotion render src/index.ts <Comp> out/silent.mp4。html:capture_html.py index.html out/silent.mp4 --frames <durations.json 帧数总和>。manim:manim_scenes.py scenes.py . --manim <manim-env>/bin/manim --quality h。它会渲染每个类,并将其精确填充或裁剪到其帧数。
- 使用 FFmpeg 合成。 带字幕:
ffmpeg -i silent.mp4 -i narration_bgm.wav -vf "ass=captions.ass" -c:v libx264 -crf 18 -pix_fmt yuv420p -c:a aac -b:a 192k -shortest final.mp4(不带字幕时,使用-c:v copy并去掉-vf)。检查视频和音频时长是否匹配在 0.1 秒以内,然后从最终 MP4 中抽取 4–5 帧并查看它们,包括一个句子中间的字幕高亮效果。 - 交付。 提交到功能分支,打开一个 PR,合并后使用
gh api repos/<o>/<r>/git/trees/<base>?recursive=1确认文件已成功上传。
注意事项
- 绝对不要在 SVG 路径
d=字符串内放置/* */注释;Chromium 会在/处停止解析。请使用 6 位十六进制颜色。 - 使用硬编码绝对帧编号的代码可能会在场景结束后出现高潮。
- 在 Manim 中,标签和箭头要在对象移动之后定位(或者使用
always_redraw/add_updater附加它们),否则它们会停留在旧位置。DashedVMobject本身没有点:需要从普通形状中获取位置。 - 通过 pip 安装的 Playwright 可能需要比缓存版本更新的 Chromium 构建。
- 不要使用多个并行的
strReplace调用编辑同一个文件,编辑内容会丢失。不要通过 shell heredoc 编写代码,护栏可能会阻止它们。 - Seedance 2.x 模型需要激活账户,并拒绝带有真实人脸图像的参考图片。Seedance 1.5 pro 片段时长为 4–12 秒。
- Remotion 许可证:对于个人和最多 3 人的公司免费;更大的公司需要付费的公司许可证。
html和manim可避免此限制。