Communitygithub.com

liangruibupt/explainer-video-pipeline

制作带旁白的解说视频(Opus 故事板、代码绘帧、Polly 语音、单词字幕、音乐、音效),并支持可切换的渲染器。

explainer-video-pipeline 是什么?

此技能构建一条完整的自动化流水线,用于生成时长 1–3 分钟的解说视频,涵盖从故事板、脚本编写到最终 MP4 输出的全流程。用户只需提供主题,其余参数均有智能默认值,并可通过表格清晰列举的选项进行调整。技能支持多种渲染引擎(Remotion、HTML/Canvas、Manim)和视频引擎(Opus 5.5 代码绘图、Seedance AI 视频生成),适应不同技术需求和视觉效果。流水线集成 Amazon Polly 语音合成、Whisper 词级字幕、合成音效与背景音乐,并包含事实核查、参考图像边缘检测等质量保证步骤,确保视频准确且专业。该技能设计为在 Claude Code 或类似 AI 代理环境中运行,但通过其清晰的步骤化和参数化接口,也可适配其他支持任务分发的代理平台。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/liangruibupt/explainer_video_platform/tree/HEAD/skills/explainer-video-pipeline

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

explainer-video-pipeline(自动生成)

使用时机

用户希望制作一个 1–3 分钟的解说视频,内容涉及某个主题(科学、产品、技术),最终输出为一个包含语音、字幕、音乐和音效的 MP4 文件。

参数与默认值

只需询问主题;除非用户指定其他值,否则使用所有默认值。用一句话说明你使用了哪些值。

参数默认值其他值
topic必需—
storyboard_modelclaude-opus-5.5 编写脚本、旁白和故事板kiro-cli chat --list-models 中的任意模型 ID
video_engineopus-5.5:claude-opus-5.5 为每个场景编写绘制每一帧的代码其他代码模型,例如 claude-sonnet-5.5;seedance(BytePlus ModelArk API,需设置 ARK_API_KEY);hybrid(代码绘制场景中嵌入 Seedance 片段)
rendererremotion(React/SVG;Remotion 逐帧驱动无头 Chromium)html(Canvas 2D / SVG / GSAP / p5.js 页面,通过 Playwright 捕获);manim(Manim Community 场景;最适合几何、图形、向量和逐步推导)
seedance_modelseedance-1-5-pro-251215用户 ModelArk 账户中启用的任意 Seedance 模型
ttspolly,神经语音 Zhiyu,cmn-CN,us-east-1gtts(免费,无需密钥,语音较平淡);其他任何 Polly 语音/语言
captions开启:Whisper 单词时间戳,以逐词高亮字幕形式嵌入关闭
whisper_modelsmall(CPU,int8;10 秒语音约需 5 秒处理)base(更快),medium(更准确的时间戳)
musicsynth(使用 ffmpeg 合成的免版税振荡器背景音)none;用户拥有的音乐文件路径
sfx开启:scenes.json 中列出的事件会被合成并放置在对应帧上关闭:从每个场景中省略 sfx
language普通话Polly 和 Whisper 同时支持的任何语言
size, fps1920×1080,30 fps1080×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/ 文件夹中。

  1. 项目。 在用户工作区的一个 git 仓库中创建项目文件夹。对于 renderer=remotion,手动创建 package.json、tsconfig.json(resolveJsonModule: true)、src/index.ts、src/Root.tsx,并运行 npm i remotion @remotion/cli react react-dom。
  2. 脚本和故事板(由 storyboard_model 完成)。编写 scenes.json:每个场景一个对象,包含 id、narration(口播台词)、visual(屏幕上显示的内容)、可选的 manim(Scene 类名)和可选的 sfx:[{"at": FRAME_IN_SCENE, "kind": "whoosh|hiss|pop|rise|thud|PATH"}]。使用 6–10 个场景,每个场景一个想法,包括一个标题场景和一个结束卡片。通过网络搜索检查事实,并在 README 中注明来源。
  3. 参考图像。 当视频展示一个真实物体时,寻找或获取一张清晰的照片,并保存在 ref/ 中。永远不要凭记忆绘制真实物体的形状:对照片进行边缘检测,测量关键点,然后使用仓库中的小脚本根据这些点生成形状。
  4. 旁白驱动时间。 运行 narrate.py scenes.json . --tts polly。它会生成 durations.json(每个场景的帧数,基于实际语音长度加上填充)、narration.wav 和 audio/sNN.mp3。场景代码会读取 durations.json,因此每个场景的时长正好与其台词时长相等。
  5. 场景代码(由 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 小时后过期)。
  6. 在完整渲染之前检查静态帧。 从每个关键场景渲染 4–6 帧,将它们合并成一个缩小后的接触印相片,然后查看这张图片。为了独立检查,启动一个只拥有该印相片和 scenes.json 的全新审阅者。
  7. 音效。 如果任何场景有 sfx,运行 sfx.py scenes.json .。然后运行 mix_bgm.py . --music <music>:它会将音乐在语音下方闪避,添加 sfx.wav,写入 narration_bgm.wav,并打印 RMS 电平。纯音乐的前导部分应在 −20 到 −30 dB 之间;−55 dB 或更低意味着听不见。
  8. 字幕。 captions.py scenes.json . --size <WxH> 使用 faster-whisper 逐词时间戳转录每一行,并将其映射到脚本自身的字符上,因为 Whisper 会误听同音字(例如,它将“气体”听成了“漆体”)。它会写入 captions.ass(每个字符在说出时高亮显示)和 words.json(每个字符的时间,可在步骤 5 中用于屏幕强调)。
  9. 渲染(无声画面)。
    • 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。它会渲染每个类,并将其精确填充或裁剪到其帧数。
  10. 使用 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 帧并查看它们,包括一个句子中间的字幕高亮效果。
  11. 交付。 提交到功能分支,打开一个 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 可避免此限制。

相关技能