ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ManimGX语音同步教程:用self.say()制作逐字对齐旁白的动画视频

ManimGX语音同步教程:用self.say()制作逐字对齐旁白的动画视频

【免费下载链接】manimgx

The animation engine for agents: blazingly fast math and 3D videos with Manim's Python API, on a Rust GPU core.

项目地址:https://gitcode.com/gh_mirrors/man/manimgx
点击查看免费下载

ManimGX 是运行在 Rust + GPU 引擎上的数学动画引擎,它提供了self.say()语音同步功能:你用一行 Python 就能让 AI 旁白逐字对齐画面,自动把动画卡进每一个单词说出的瞬间,并自动生成字幕,是制作带配音讲解的动画视频的完整方案。

🎯 为什么手动卡点很难?

做讲解类视频时,最痛苦的一步是卡点:先录旁白,再逐帧把动画挪到对应词句出现的位置,改一句台词就要重调一遍时间轴。

ManimGX 的思路完全反过来——让语音驱动动画:

  1. 语音合成时同时返回每个单词的起止时间(逐字时间轴);
  2. self.say()用方括号把台词和动画一一对应;
  3. 渲染时每个动画自动在它对应单词开口的瞬间开始,时长随语音时长自适应。

你只管写台词,时间轴由引擎自动算好,改词即改点。

⚙️ 安装与准备(3 步到位)

第 1 步:安装 ManimGX(需要 Python 3.13+):

pip install manimgx

第 2 步:配置语音服务密钥。默认语音来自 fal.ai 平台的 ElevenLabs Eleven v3 模型,需要把 fal.ai 的 API key 设为环境变量FAL_KEY(在 fal.ai 控制台创建)。

第 3 步:写一个最小场景。完整的语音指南见 sound-and-voice.md,核心示例如下。

📝 核心用法:方括号脚本 + 逐字对齐

self.say()的签名是say(script, *animations, voice=None),实现见 scene.py。规则只有一条:台词里用[...]框住的片段,按顺序依次对应一个动画,方括号本身不会被读出来。

import manimgx as m class Derivative(m.Scene): def construct(self) -> None: square = m.MathTex("x^2", font_size=96).shift(2 * m.LEFT) derivative = m.MathTex("2x", font_size=96).shift(2 * m.RIGHT) self.add(square) self.say( "The derivative of [x squared] is [two x].", m.Indicate(square), # 说到 "x squared" 时高亮 x² m.Write(derivative), # 说到 "two x" 时写出 2x )

几个关键行为:

  • 动画随词开始:m.Indicate(square)会在 "x squared" 第一个词开口的瞬间启动,并持续约等于说这两个词的长度(若动画本身run_time更长,则以动画为准);
  • 自动等待:整个场景会等到这句旁白说完才继续construct,台词之间永远不会互相叠音;
  • 台词改动自适应:换词后动画自动跟随新词的起止时间重新对齐,无需手动改时间轴;
  • 不写方括号:动画会横跨整句旁白播放;空方括号[]表示动画在句中该位置立即开始。

⚠️ 常见报错:方括号段数与动画数量不一致会直接抛出ValueError(例如2 bracketed spans for 1 animations),这其实是在帮你少卡点。

🔍 逐字对齐是怎么做到的?

say()背后返回一个Speech对象——一种"知道自己说了什么、每个词何时说"的声音。每个词是一个Word(text, start, end)元组,比如仓库里缓存的这个真实样例 the-derivative-of-x-squared-is-two-x-5d32e55fc7.json:

"words": [ ["The", 0.0, 0.08], ["derivative", 0.131, 0.64], ["two", 2.08, 2.32], ["x.", 2.56, 2.8] ]

这正是逐字对齐的时间数据来源:动画的播放窗口直接取自这些start/end。如果某个模型不返回单词时间,引擎还会用音量包络 + 字符权重估算每个词的位置(见 estimate),所以换模型也不失同步能力。

缓存机制让迭代成本几乎为零:每句旁白合成后,音频和时间轴会存到场景文件旁的voice/目录(音频 + 上面的 JSON)。之后每次重新渲染直接读缓存,离线也能渲染,只有改动的台词才会再次调用语音服务。想用真人录音?用同名的音频文件替换缓存里的音频即可,时间轴会自动重新测算(cached 实现)。

🎙️ 选择与更换语音

  • 整场换音色:在场景类里设置voice属性,例如:
class Narrated(m.Scene): voice = m.voices.Fal( "fal-ai/minimax/speech-2.8-hd", voice_setting={"voice_id": "Calm_Woman", "emotion": "happy"}, )
  • 单句换音色(对白):self.say("Hello!", voice=other)只为这一句指定说话人;
  • 支持的模型:fal.ai 上的 5 个 TTS 模型(ElevenLabs Eleven v3、MiniMax、Gemini、Inworld、Qwen),配置项全部有类型提示,编辑器会提示合法参数,详见 fal.py。

另外self.speech(text)可以只合成为播放,方便你先试听某句话再决定怎么安排动画。

🎵 旁白下铺背景音乐的完整配方

self.play()里的声音会阻塞时间轴,而self.add_sound()是"立即起播、不占时间"的,正是背景音乐该用的方式。配合duck()(闪避)让音乐在有人说话时自动压低音量:

# 音乐垫底:音量 -18dB,2 秒淡入,循环播放 self.add_sound(m.Sound("theme.mp3").gain(-18).fade_in(2).loop().duck()) self.say("Here is [a circle].", m.Create(circle))

duck()会在旁白开始前 0.15 秒平滑下压、结束后 0.5 秒回升(mix 混音逻辑),听感像专业节目混音里的"闪避"效果。

📼 自动字幕与补充说明

manimgx render scene.py渲染视频时,会把旁白自动写成.srt字幕文件放在视频旁边,主流播放器与视频平台都能直接识别——逐字时间轴复用的就是同一份词级数据,字幕零成本白送。

需要手动插入不来自语音的字幕(比如章节标题、引用文字)时,用self.add_subcaption(content, duration, offset),例如:

self.add_subcaption("Chapter 2: The Proof", duration=2)

✅ 新手常见疑问速查

问题解答
动画数量和方括号段数不一致怎么办必须一一对应,否则抛ValueError;整句配动画就别写方括号
渲染时要联网吗要,但仅限新台词;已缓存的旁白离线可重复渲染
能换成自己的录音吗能,同名替换voice/缓存音频,时间轴自动重算
竖屏视频怎么出manimgx render -r 1080x1920 scene.py
想快速看效果manimgx preview scene.py,保存即热重载

小结

ManimGX 的self.say()把"配音 + 卡点 + 字幕"三件事压缩成一段带方括号的台词:语音服务负责逐字时间轴,引擎负责让动画随词起舞,manimgx render负责产出视频与.srt字幕。加上voice/目录缓存与duck()混音,一套流程即可产出可发布的讲解视频。更多场景代码见 examples/ 与 用户指南。

【免费下载链接】manimgx

The animation engine for agents: blazingly fast math and 3D videos with Manim's Python API, on a Rust GPU core.

项目地址:https://gitcode.com/gh_mirrors/man/manimgx
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进