Manim Community Edition 在 2026 年 10 月 8 日发布了 v0.22.0。
这个版本的主线不太显眼,但对日常使用影响很大:它没有堆多少新动画,而是把命令行上堆积多年的输出开关、跑偏的渲染生命周期、以及小字号排版错乱的老问题,一次性清了一遍。
代价是破坏性变更不少,尤其是如果你有用脚本批量渲染的习惯,升级前最好先花十分钟看一眼。
1. 输出配置大一统:一堆开关合并成一个 --format
以前要告诉 Manim"这次渲出来的东西是啥",得在 --write_to_movie、-g、-i、save_last_frame、--force_window 之间挑一个,还得记清楚它们互相覆盖的优先级。
现在只有一句 --format,一次只选一种产物,既可以放命令行,也可以写在配置文件的 [CLI] 段里。
迁移对应关系很简单,照着换就行:
| 以前 | 现在 |
|---|---|
--write_to_movie |
默认 auto,或者显式写 mp4 / mov / webm / gif |
write_to_movie = False |
--format none(场景照跑,不落任何文件) |
-g / --save_pngs |
--format png-sequence |
-i / --save_as_gif |
--format gif |
save_last_frame |
--format png |
--force_window |
-l / --live-preview |
除了"选什么产物",还剩一件事:看。
-p/--preview是渲完拿成品文件打开(Cairo 和 OpenGL 都能用)-l/--live-preview才是 OpenGL 那个边渲边看的实时窗口。
顺带的副作用是 OpenGL 渲染器现在也会默认写文件了,行为跟 Cairo 对齐。
有三个行为变化值得留意:
--format png只保存最后一帧;- 场景里没有任何
play或wait却显式指定了视频格式会直接报错(auto则退化为存一张 PNG); - 透明背景只支持
auto、mov、webm三种。
另外输出设置是在 Scene 构造那一刻就固定下来的,所以场景必须在 tempconfig 块内部实例化,写在块外面拿不到新配置。
渲染过程也不再往 config.output_file 里回填结果,脚本里想拿最终文件名,改读 scene.renderer.file_writer.final_file_path。
2. 输出路径与文件名的几处调整
--custom_folders 这个预设连同 config.custom_folders 和 [custom_folders] 配置段一起被移除了,官方的理由是它一次改太多位置、又不透明。
替代方案是直接把每个目录逐个写在 [CLI] 里,等价于旧预设的写法是:
properties
[CLI]
media_dir = videos
video_dir = {media_dir}
sections_dir = {media_dir}
images_dir = {media_dir}
text_dir = {media_dir}/temp_files
tex_dir = {media_dir}/temp_files
log_dir = {media_dir}/temp_files
partial_movie_dir = {media_dir}/partial_movie_files/{scene_name}
文件命名上也有两处要注意。
-o在同时渲染多个场景(用了-a或者给了多个场景名)时会被直接拒绝,想分别命名就分开跑。- 后缀是由解析后的
format决定的,所以-o movie.mov --format mp4最终得到的是movie.mov.mp4。
段落视频的文件名现在会带上段落名,例如 MyScene_0000_create-square.mp4。
如果下游脚本以前是靠拼字符串找这些文件的,改从段落 JSON 的 video 字段里读,比自己拼可靠。
3. 视频编码终于可以自己配了
以前编码参数是内部写死的,想调个码率基本没门。
现在编什么容器、用什么编码器、要不要开并行,全都由命令行和配置段说了算。
bash
manim render --format mp4 \
--video-codec libx264 \
--pixel-format yuv420p \
--encoder-option crf=18 \
--encoder-option preset=slow \
scene.py SalesTrendScene
--encoder-option 可以重复传,任意 FFmpeg 参数都能塞进去;对应的配置段是 [video_encoder]。
还有一个 --encoder-queue-size 用于限制每个编码器手里攒着待处理的帧数,非并行编码时也会限制队列长度以抑制内存占用。
配套的几处改动:
--flush_cache被移除,换成manim cache clear;- 配置段
[ffmpeg]改名为[media],config.ffmpeg_loglevel对应改成config.media_loglevel; SceneFileWriter.clean_cache()和flush_cache_directory()换成了manim.utils.caching里的prune_segment_cache()和clear_segment_cache()。
比较重要的一点是缓存键现在把编码设置也算进去了,所以改动 codec 或 encoder-option 之后,之前缓存好的动画片段会重新编码一次,看到缓存全部失效不要惊慌。
4. Manager:渲染生命周期有了唯一的协调者
这个改动发布说明里写得有点抽象,但它是后续大重构的第一步,值得单独说。
在 v0.22.0 之前,渲染一个场景要干的活散落在 Scene、Renderer、Camera、SceneFileWriter 四个地方,互相之间还有反向依赖:Scene 的 render() 里塞满了调度逻辑,而文件写入器又要回头去读全局 config。
现在多了一个 Manager 对象,挂在 scene.manager 上,拥有原本实现在 Scene.render 里的渲染生命周期。Scene 的 render、play、next_section、add_subcaption、add_sound 全部转为对它的委托调用。渲染循环本身还没完全重构完,后续版本会继续把渲染执行和文件写入搬进 Manager,届时 Scene 和 Renderer 之间残存的相互依赖就能彻底拆掉。
对你的影响取决于你怎么用 Manim:普通场景(没有自定义相机、渲染器或文件写入器)不用改一行代码 。只有那些重写或 patch 过 Scene.render 内部的人才需要改------别再去直接驱动 renderer 或 file writer,调 Scene 的公开方法。顺带一个小变化:日志里那句 "Rendered ... Played N animations" 现在来源于 manager 模块而不是 scene,如果你有脚本在匹配这条日志的前缀,注意调整。
5. 小字号文本排版修好了
一个看起来很小但很影响观感的修复。新版依赖 ManimPango 0.7.0,修掉了极小字号下字距(kerning)计算失准的老问题。
以前 Text("hello world", font_size=1) 渲出来字母忽宽忽窄、局部叠在一起,整行像是歪的。现在按排版预期走,做图表里密集的坐标轴刻度标签、地图类场景的名称注记、一屏几十行的表格都不用再靠调大字号硬凑了。这个修复只依赖升级 ManimPango,代码不用动。
6. 破坏性变更速查
| 变更 | 迁移方式 |
|---|---|
--write_to_movie / -g / -i / --force_window / save_last_frame |
统一用 --format |
--custom_folders、config.custom_folders、[custom_folders] |
逐个配置 [CLI] 下的目录项 |
--flush_cache |
manim cache clear |
[ffmpeg] / config.ffmpeg_loglevel |
[media] / config.media_loglevel |
config.movie_file_extension |
config.format |
is_mp4_format 等 manim.utils.file_ops 里的格式辅助函数 |
读 scene.session_spec 或 scene.manager.output_spec |
SceneFileWriter.clean_cache() / flush_cache_directory() |
prune_segment_cache() / clear_segment_cache() |
自定义渲染器和文件写入器的改动最多:它们现在必须声明 capabilities,init_scene 的签名变成 init_scene(scene, session_spec, file_writer_settings),帧数据改为左上角原点、形状 (height, width, 4) 的 uint8 RGBA 数组。
7. 其他改进与 bug 修复
性能优化集中在 mobject 的增删和 family 计算上:list_update / list_difference_update 改用集合做成员判断并新增了 key 参数以支持不可哈希元素,get_family 的去重逻辑提速同时修好了成环的 family。
易用性方面,throw_error_if_no_points 的报错信息更清楚并抛 ValueError,Graph 和 DiGraph 允许不带顶点初始化。
bug 修复数量最多,主要是补 OpenGL 那些一直没跑到的代码路径(此前拿字符串 "opengl" 做比较压根没匹配上),以及 MathTypst 捕获组的布局、Text / MarkupText 的 color 参数、BarChart 忽略 y_axis_config 里的 include_numbers、SVG 中 stroke="none" 被误加白色描边、四元数转轴角时角度大于 π 返回反向旋转等。文档部分补了 Typst 安装说明和 Windows 上装 C++ 生成工具的指引。
8. 如何更新
升级本身的命令很简单:pip install -U manim。
真正的活在处理命令行和配置文件的改动,建议按这个顺序来:
第一步,把所有旧的产物开关替换掉:--write_to_movie 删掉(默认就是 auto)、-g 改成 --format png-sequence、-i 改成 --format gif、save_last_frame 改成 --format png、--force_window 改成 -l。
第二步,检查有没有用 --custom_folders 或 -o 批量渲染的习惯,前者换成逐个写好 [CLI] 目录项,后者拆分渲染命令。
第三步,如果有下游脚本在拼输出文件路径,改成从 scene.renderer.file_writer.final_file_path 和段落 JSON 的 video 字段里读取。
第四步,跑一次 manim cache clear,让旧的缓存片段重新生成一遍。
总的来说,v0.22.0 是个典型的"清理包袱"版本:短期你会为改命令行付出一点成本,长期拿到的是一套只有单一入口、可读可扩展的配置体系,以及一个正在成型的渲染架构。