ManimGL(manimgl)
ManimGL(manimgl)在 Debian 上的开发环境搭建与常见坑位排查(含真实问题复盘)
本文面向希望在 Debian 上使用 3Blue1Brown 原版 Manim(ManimGL / manimgl)进行动画开发与视频导出的同学。内容包含:
- ManimGL(manimgl)与 Manim Community(manim)的区别
- Debian(物理机 + SSH 远程执行)下的推荐安装方式
- 无需弹窗直接写出视频文件的正确命令
- 我实际遇到的报错链路、根因分析与最终解决方案(可复用)
1. ManimGL(manimgl)是什么,它和 manim 有什么关系
1.1 “3Blue1Brown 原版 Manim”指的是什么
“3Blue1Brown 原版 Manim”通常指 GitHub 上的 3b1b/manim 仓库(也常被称为 manimlib),对应的 pip 包名是:
ManimGL(manimgl):
pip install manimgl- 原版 Manim(Grant Sanderson / 3Blue1Brown 使用的体系)
- 渲染后端以 OpenGL 为主
- 代码 API 与社区版不同
1.2 Manim Community(manim)是什么
Manim Community Edition(manim):
pip install manim- 社区维护的主线版本
- 文档、生态更完善
- API 与 ManimGL 不兼容
- 同样支持 OpenGL 后端,但它不是 ManimGL
1.3 最容易混淆的点:导入方式不同
- ManimGL(manimgl)必须使用:
from manimlib import *
- Manim Community(manim)使用:
from manim import *
两者不能混用。你用 manimgl 运行脚本时,如果写了 from manim import *,场景发现与运行都会出问题。
2. 我的环境说明(本文复盘的真实环境)
- 操作系统:Debian(物理主机)
- 主机接了显示器(本地有桌面环境)
- 使用方式:通过 SSH 远程登录,在远程 shell 里运行
manimgl - Python 环境:Miniconda(base 环境),Python 3.12
- 执行用户:root
- OpenGL:AMD GPU,Mesa 驱动
glxinfo -B显示 direct rendering = Yes,OpenGL 4.6,硬件加速正常
这类环境非常常见:机器在机房或办公室接着显示器,但开发者通过 SSH 远程跑渲染。
3. ManimGL 环境搭建(Debian)
下面是更偏“可跑通”的配置建议。即使你使用 conda,也建议把系统依赖装齐。
3.1 系统依赖(建议安装)
apt update
apt install -y ffmpeg libgl1-mesa-dri libglx-mesa0 libgl1 mesa-utils
说明:
ffmpeg:ManimGL 输出视频需要- Mesa / GLX:提供 OpenGL 运行时
mesa-utils:提供glxinfo方便排查
如需 LaTeX 公式渲染(不是所有项目都需要),再考虑安装 TeX 发行版(Debian 的 texlive 套件较大,可按需选择)。
4. ManimGL 安装(conda 方式示例)
这里给出你当前风格的一套流程(conda + pip)。更稳的做法是新建独立环境,避免 base 环境依赖杂糅。
conda create -n manimgl python=3.12 -y
conda activate manimgl
pip install manimgl
如果你会用到音频/视频后处理(非必须),可按需安装:
pip install moviepy requests
5. SSH 远程执行但显示器在本机:如何让 ManimGL 连接到本地显示器
你在 SSH 会话里运行 manimgl,默认没有显示环境变量,最典型报错是:
pyglet.display.xlib.NoSuchDisplayException: Cannot connect to "None"
这是因为 pyglet 需要连接 X11 Display 才能创建 OpenGL 上下文,但 SSH 会话里没有 DISPLAY。
5.1 连接到本机桌面显示(本机屏幕显示)
在 SSH 会话里指定:
export DISPLAY=:0
同时还要解决 X 权限问题。最简单的处理方式是在“物理机本地桌面”执行一次(允许 root 连接 X server):
xhost +SI:localuser:root
然后再从 SSH 里运行 manimgl。
说明:
- 如果你不是 root 执行,把
root换成你 SSH 登录使用的用户名 DISPLAY=:0是常见桌面 display;少数机器可能是:1,可通过本地桌面环境确认
6. 写文件而不弹窗:ManimGL 的正确命令
在 ManimGL 里,如果你只是要导出视频,不想开实时窗口,核心是使用 -w 写文件。
你要求本文只介绍一种写文件方式,这里给出你最终确认使用的命令格式:
manimgl -ql -w scene07_gl.py Scene07
说明:
-ql:低质量(开发预览更快)-w:写文件(生成 mp4)scene07_gl.py:脚本文件名(建议不要以数字开头)Scene07:你定义的场景类名
你期望的产物路径为:
ls videos/Scene07.mp4
如果你的项目中输出目录不同,通常是配置或工作目录造成的,但本文以你的目标路径为准。
7. 真实踩坑复盘:我遇到的问题与最终解决方案
这一节把我在真实环境里遇到的报错链路完整记录下来,便于你在同类型环境里快速定位。
7.1 第一阶段:NoSuchDisplayException(没有 DISPLAY)
初始运行命令类似:
manimgl -ql 07.py
报错特征:
Cannot connect to "None"
根因:
- SSH 会话里没有
DISPLAY - pyglet 无法创建 shadow window
解决:
- 使用本机 X display:
export DISPLAY=:0 - 并处理 X 权限:本地桌面
xhost +SI:localuser:root
这一步解决后,程序不再报 “Cannot connect to None”,但进入下一阶段。
7.2 第二阶段:Could not create GL context(OpenGL 上下文创建失败)
在设置好 DISPLAY=:0 后,出现类似:
pyglet.gl.ContextException: Could not create GL context- 以及
libGL error: MESA-LOADER ...
此时第一反应往往是“显卡驱动没装”,但我验证了 OpenGL 正常:
glxinfo -B | sed -n '1,60p'
输出显示:
direct rendering: Yes- AMD GPU / Mesa / OpenGL 4.6
Accelerated: yes
结论:
- 系统 OpenGL 栈正常
- 问题不是“没驱动”,而是“某个进程加载了错误的运行时库”
7.3 第三阶段:关键根因定位(conda 的 libstdc++ 与系统 LLVM/Mesa 不兼容)
进一步运行时,出现非常关键的错误信息:
libGL error: MESA-LOADER: failed to open swrast:
.../miniconda3/.../libstdc++.so.6: version `GLIBCXX_3.4.30' not found
(required by /usr/lib/x86_64-linux-gnu/libLLVM-15.so.1)
这条信息说明:
- Mesa 的驱动(例如 swrast 或 radeonsi)会依赖系统的 LLVM(如
libLLVM-15.so.1) - 系统 LLVM 是用较新的 GCC ABI 编译的,需要
GLIBCXX_3.4.30 - 但你运行
manimgl时,进程优先加载了 conda 里的libstdc++.so.6 - conda 这份
libstdc++.so.6版本不够新,不包含GLIBCXX_3.4.30 - 结果 Mesa 驱动加载失败,OpenGL context 创建失败
一句话总结:
- OpenGL 没坏
- 被 conda 的 C++ 运行时库劫持后,系统 Mesa/LLVM 无法正常加载
- 最终导致 pyglet / moderngl 无法创建 GL context
8. 最终解决方案:运行时强制使用系统 libstdc++(方案 2)
在不调整 conda 包、不重建环境的前提下,我最终采用的解决方案是:
- 保持 conda 环境其它库路径不变
- 仅强制让进程使用系统的
libstdc++.so.6与libgcc_s.so.1
执行方式如下:
export DISPLAY=:0
LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6:/lib/x86_64-linux-gnu/libgcc_s.so.1 \
/root/miniconda3/bin/manimgl -ql 07.py
这一方式可以稳定绕过:
- conda 的旧 libstdc++ 与系统 LLVM/Mesa 的 ABI 冲突
- 同时不破坏 conda 环境中 Python 包的加载
然后就可以正常运行(包括写文件导出)。
如果你希望以“写文件不弹窗”的方式导出,结合本文第 6 节命令即可:
export DISPLAY=:0
LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6:/lib/x86_64-linux-gnu/libgcc_s.so.1 \
/root/miniconda3/bin/manimgl -ql -w scene07_gl.py Scene07
最后确认输出文件:
ls videos/Scene07.mp4
9. 为什么不建议在这类场景里直接用 root + base conda
这不是“不能用”,而是“更容易踩坑”。
- 图形栈(Mesa/LLVM/GLX)是系统级依赖
- conda 环境常常自带
libstdc++、libgcc、甚至libGL相关库 - 一旦 conda 的这些库版本与系统图形栈编译 ABI 不匹配,就会出现你遇到的这种“系统 glxinfo 正常,但 Python 程序创建 context 失败”的情况
如果你要长期维护,建议:
- 新建独立 conda 环境(不要污染 base)
- 或者使用系统 python + venv,把图形依赖尽量留给系统包管理器
但在现有约束下,本文给出的 LD_PRELOAD 方案已经足够实用。
10. 附:ManimGL 最小可运行脚本示例(可直接复制)
保存为 scene07_gl.py:
# -*- coding: utf-8 -*-
from manimlib import *
class Scene07(Scene):
def construct(self):
self.camera.background_color = WHITE
title = Text("Hello ManimGL", font="DejaVu Sans", color=BLACK).to_edge(UP)
dot = Dot(color=BLUE).shift(DOWN)
self.play(FadeIn(title))
self.play(GrowFromCenter(dot))
self.wait(1)
运行写出视频(结合本文的环境修复方式):
export DISPLAY=:0
LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6:/lib/x86_64-linux-gnu/libgcc_s.so.1 \
manimgl -ql -w scene07_gl.py Scene07
ls videos/Scene07.mp4
字体提示:
- 如果你想用中文字体(例如
SimHei、Noto Sans CJK SC、WenQuanYi Micro Hei),请确保系统已安装对应字体,否则会报字体找不到。可以用fc-list | grep -i搜索已安装字体名。
11. 常见问题速查
11.1 glxinfo 正常,manimgl 仍然创建 context 失败
优先怀疑:
- conda 的
libstdc++与系统 LLVM/Mesa ABI 冲突 - 用本文的
LD_PRELOAD方案先验证
11.2 SSH 里 DISPLAY 为空
export DISPLAY=:0- 本地桌面执行
xhost +SI:localuser:root或对应用户
11.3 想导出视频但不想弹窗
- 使用
manimgl -ql -w scene07_gl.py Scene07 - 最终检查
videos/Scene07.mp4
