ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

浏览器10分钟跑通Manim:极坐标与三维XYZ动画实战

2026/9/20 10:47:40 拓冰建站 浏览量
浏览器10分钟跑通Manim:极坐标与三维XYZ动画实战 先给结论想 10 分钟在浏览器里跑通第一个 Manim 动画这件事现在真的不难你不需要先装 Python、不用折腾 Conda、也不用跟 FFmpeg 和 LaTeX 较劲。只要电脑上有一个不算太老的 Chrome、Edge 或 Firefox打开一个网页左边写代码、右边出动画完事。这个极坐标⋅XYZ的新手教程就是围绕极坐标曲线和三维 XYZ 坐标这两类动画来展开的入门路线。我第一次接触 Manim 是看 3Blue1Brown 的视频当时想照着做一条极坐标曲线在本地装环境就折腾了一晚上。后来换成浏览器方案10 分钟确实能跑通。这篇就把完整过程、我的踩坑记录和可以直接抄的代码一起放出来。之所以把极坐标和 XYZ 放在同一个教程里是因为这两类内容最能体现 Manim 的优势极坐标画出来是二维的漂亮曲线三维坐标则能让你体会到场景、相机、旋转这些东西。两个方向分别推进代码量又不大特别适合刚开始接触 Manim 的人建立信心。1. 为什么先选浏览器跑而不是本地装环境1.1 本地 Manim 环境的真实门槛先说本地安装。Manim 本质上是一个 Python 库装一个manim包本身不难难的是后面的渲染链。你要让动画最终变成视频系统里得有 FFmpeg想让公式显示得漂亮需要 LaTeX想用中文标注字体也得配好。这一套下来不同操作系统、不同 Python 版本之间还会有各种小差异。我见过不少人卡在装了 manim 但渲染报错找不到 ffmpeg这一步然后就放弃了。不是说本地方案不好而是对新手的第一个项目来说这个门槛实在是太高了。Manim 的核心价值在于快速验证想法我想看一下这条极坐标曲线长什么样我想让相机绕着三维坐标转一圈。这些场景需要的是改了代码马上能看到结果的反馈循环。如果改一行代码就要等环境报错、重新装依赖那学习热情很快就被磨没了。1.2 浏览器方案解决的痛点浏览器方案把前面说的那些障碍全部挪到了后台。页面上已经内置好了 Python 运行时和 Manim 库你要做的只是写代码、点运行、看结果。这个体验非常接近 Jupyter Notebook但比 Notebook 更简单——不用在本地启动任何服务。从跨平台角度看浏览器方案的优势也很明显。Windows、macOS、Linux甚至一些受限设备上只要浏览器能跑Manim 就能跑。这一点对于团队协作也很有意义你可以给同事发一个链接大家打开同一个页面做实验而不是让每个人都在自己电脑上配一套环境。另外浏览器端对分享更友好。本地渲染出来的视频要存文件、传网盘才能给别人看浏览器方案下你把代码块发给对方对方直接运行就能看到一样的动画这比传视频方便得多。1.3 极坐标与 XYZ 这个组合的特别之处这个教程选极坐标和 XYZ 三维坐标作为切入点是有原因的。极坐标在大学数学里是一个容易让人困惑的概念同样的点换成(r, θ)表示之后很多曲线形状会发生非常大的变化心形线、玫瑰线、阿基米德螺旋线都是经典例子。光看公式很难想象这些曲线长什么样但你用 Manim 画出来一眼就懂。这是极坐标视觉化的最大价值。XYZ 三维坐标则是另一个维度的问题。二维坐标只需要看平面三维坐标需要处理透视、视角、翻转这对很多人的空间想象能力是挑战。Manim 提供了ThreeDScene和ThreeDAxes可以让相机自动旋转把难以想象的三维形状展示清楚。从这个角度说极坐标⋅XYZ这个组合其实是在用可视化帮人建立数学直觉。2. 浏览器跑 Manim 的三种主流路线怎么选2.1 路线一页面内置 Python 运行时第一种方案是在网页里内嵌一个 Python 运行时通过在浏览器中运行的 Python 实现来执行 Manim 代码。它的原理是浏览器下载一个编译成 WebAssembly 的 Python 解释器然后在页面里的虚拟环境中安装并运行manim库。这个方案的好处是代码和结果是完全闭环的你在一个页面里写完代码、执行、渲染、看到动画不需要跳转到任何外部工具。缺点是首次加载会慢一些因为需要下载整个运行时。另外受浏览器内存和 GPU 能力的限制渲染特别大的场景时性能会略有下降不过对我们做曲线、做坐标系动画来说完全够用。这种路线很适合教学场景。入门阶段不用关心环境专注学 Manim 的 API 本身。2.2 路线二社区 Web 编辑器第二种方案是使用社区现成的在线编辑器。这类编辑器通常采用左侧代码、右侧预览的布局有些还能直接导出视频。它们背后可能是预置的云渲染服务也可能是在浏览器内执行体验上通常都比较顺手。对新手来说这类编辑器的最大好处是敢上手。页面已经帮你配好了一切你只需要把示例代码改成自己的内容点运行就能看到效果。我推荐第一次尝试 Manim 的人优先走这条路它能让你在几分钟内体会完整的操作流程。不过要注意社区编辑器质量参差不齐尽量选择官方维护或社区活跃度高的项目。有的编辑器对 Python 版本、Manim 版本有特定要求打开页面后先确认一下当前支持的版本避免在后面写代码时踩到 API 差异的坑。2.3 路线三预渲染视频再嵌入页面第三种路线其实已经到了生产环境层面先在本地或 CI 服务里用命令行把 Manim 动画渲染成 mp4/WebM 视频再把视频嵌入网页中播放。这种方式适合做在线课程、文章配图、产品演示因为性能最好、效果可控也完全不要求访问者有编程环境。缺点是它不提供实时交互修改动画需要重新渲染迭代速度慢。在某些场景下这个方案可以和浏览器内执行方案配合使用开发阶段用浏览器方案快速验证内容和效果确定最终版本后用命令行渲染成高质量视频再放到网页里。这样兼顾了开发效率和最终表现。2.4 三种方案横向对比与选型建议对比项页面内置运行时社区 Web 编辑器预渲染视频首次加载速度较慢需下载运行时快或中等取决于实现快直接加载视频文件代码修改到出效果秒级到十几秒取决于所在网络需要重新渲染量大动画渲染性能受浏览器限制一般够用取决于实现本地渲染性能最好适用场景教学、快速验证思路新手入门、在线合作课程、文章、产品演示我的建议是如果目标是10 分钟跑通第一个动画优先选择第二种社区 Web 编辑器或者第一种内置运行时二选一皆可。如果目标是做一个正式发布的内容选择第三种。不过从学习角度讲我强烈建议你把三种方案都大概了解一下因为在后面自己写项目的时候很可能需要根据场景切换方案。3. 10 分钟实战第一个极坐标动画3.1 打开页面后要做的三件事进入在线编辑器之后先别急着写代码我习惯先做三件事。第一确认 Manim 版本。页面文档里一般会标注例如 Community Edition 0.18 或 0.19。不同版本的 API 有微小差异尤其是早期版本和社区版之间的差异比较大后面的代码我会按社区版习惯来写。第二找一个能运行的示例代码先原样执行一次。这样做是为了确认页面自身工作正常、渲染链路通畅。很多编辑器自带教学示例随便选一个运行如果看到动画出来说明环境没问题。第三关掉其他占网速的应用。浏览器执行环境需要从网络加载 Python 运行时如果网络太慢第一步就会卡住。等环境加载完成后后面执行代码就不太依赖网络了。这三件事听着琐碎但能帮你省掉后面一半的排查时间。3.2 极坐标动画的完整代码与逐行拆解下面这段代码就是我们的第一个极坐标动画。它画的是著名的笛卡尔心形线在极坐标下的形式r 1 cos(θ)。from manim import * import numpy as np class PolarHeart(Scene): def construct(self): # 创建极坐标系 plane PolarPlane( radius_max3, size(6, 6), background_line_style{stroke_opacity: 0.3}, ).add_coordinates() self.add(plane) # 极坐标曲线r 1 cos(theta) curve plane.plot_polar_graph( lambda theta: 1 np.cos(theta), theta_range[0, 2 * np.pi, 0.01], colorYELLOW, ) self.play(Create(curve), run_time3) self.wait(1)逐行说几个关键点。PolarPlane是 Manim 提供的极坐标网格组件radius_max3表示坐标网格半径范围最大画到 3size(6, 6)控制这个网格图像在画布上的显示尺寸。background_line_style里的stroke_opacity控制网格线的透明度改成 0.1 会更淡改成 0.6 会更明显这个看个人偏好。add_coordinates()是给网格加上角度和半径标注方便看数值。如果不加就只有网格线视觉上会少很多信息。plot_polar_graph是PolarPlane自带的极坐标曲线绘制方法。第一个参数传入一个接受角度θ的函数返回半径r。我这里用的是lambda theta: 1 np.cos(theta)就是r 1 cosθ。theta_range通过三元组定义了角度的起始值、结束值和采样间隔。间隔设成 0.01 时采样点足够密曲线会非常平滑设太大会出现明显的折线段。Create(curve)是一个经典动画效果会在画布上画出这条曲线看起来像是有人用笔把它描出来非常适合展示曲线。3.3 让动画活起来点沿曲线运动光画一条静态曲线还不够有表现力我们再加一个小圆点沿着曲线运动。代码继续扩展from manim import * import numpy as np class PolarHeartMovingDot(Scene): def construct(self): plane PolarPlane( radius_max3, size(6, 6), background_line_style{stroke_opacity: 0.3}, ).add_coordinates() self.add(plane) curve plane.plot_polar_graph( lambda theta: 1 np.cos(theta), theta_range[0, 2 * np.pi, 0.01], colorYELLOW, ) self.play(Create(curve), run_time2) dot Dot(colorRED) dot.move_to(plane.polar_to_point(1 np.cos(0), 0)) self.add(dot) self.play(MoveAlongPath(dot, curve), run_time4) self.wait(1)这里最关键的是plane.polar_to_point(r, theta)方法。它把极坐标中的(r, θ)转换成了 Manim 画布上的平面坐标。小圆点想从一个角度开始运动就要用这个方法算出起点位置。MoveAlongPath(dot, curve)让圆点沿曲线走一遍run_time4控制持续 4 秒。跑完你就会看到心形线被画出来的过程然后一个红点沿着曲线匀速走一圈数学公式里抽象的θ从 0 变到 2π 的过程就这样直观地展示出来了。一个小技巧如果觉得圆点走得不够顺滑可以把theta_range的采样间隔从 0.01 改小到 0.005曲线会更密点移动的路径也就更细腻。代价是渲染耗时稍微增加但对这类小动画影响不大。3.4 极坐标参数速查表参数/方法作用常用值radius_max极坐标网格最大半径根据函数值域设置size网格在画布上的显示尺寸(6, 6)background_line_style网格线样式{stroke_opacity: 0.3}add_coordinates()显示角度和半径标记无参数plot_polar_graph(func, theta_range)绘制极坐标曲线theta_range[0, 2*np.pi, 0.01]polar_to_point(r, theta)极坐标转画布坐标常用于定位点对象MoveAlongPath(obj, curve)让对象沿曲线运动run_time44. 进阶 XYZ三维坐标动画好不好做4.1 三维场景的基本结构ThreeDScene 与 ThreeDAxes极坐标画完接下来进入 XYZ 三维坐标。Manim 里做三维动画主要用两个东西ThreeDScene和ThreeDAxes。前者是场景基类后者是带 XYZ 三条轴的三维坐标系统。和二维的Scene相比ThreeDScene增加了一系列相机控制方法。默认视角是斜着看三维坐标角度可以通过set_camera_orientation调整。ThreeDAxes的用法和二维的Axes很接近直接指定 X、Y、Z 三个方向的范围就可以。比如axes ThreeDAxes( x_range[-3, 3], y_range[-3, 3], z_range[0, 13], ) self.add(axes)这段代码创建了一个 X 轴从 -3 到 3、Y 轴从 -3 到 3、Z 轴从 0 到 13 的三维坐标系。数字范围根据自己的函数值域来定不用强求完全对称。有一点要注意三维坐标系里曲线的可视化不太适合用Create的描画动画因为三维曲线的运动路径在动态视角下可能看不清楚。更常用的做法是先把曲线静止显示出来然后用相机旋转来创造动感。4.2 一条三维螺旋线的实现与原理解读三维螺旋线是 XYZ 动画里特别经典的一个例子。它既涉及参数曲线又涉及三维空间想象。我们可以用参数方程来表示x cos(t)y sin(t)z t。随着参数 t 增大点在 X-Y 平面上绕圆周运动同时 Z 方向不断升高形成盘旋上升的形状。from manim import * import numpy as np class ThreeDHelix(ThreeDScene): def construct(self): axes ThreeDAxes( x_range[-3, 3], y_range[-3, 3], z_range[0, 13], ) self.add(axes) self.set_camera_orientation(phi65 * DEGREES, theta30 * DEGREES) helix ParametricFunction( lambda t: np.array([np.cos(t), np.sin(t), t]), t_range[0, 4 * np.pi, 0.1], colorBLUE, ) self.play(Create(helix), run_time3) self.begin_ambient_camera_rotation(rate0.2) self.wait(3) self.stop_ambient_camera_rotation()ParametricFunction接收一个函数把参数 t 映射为空间坐标。这里我用np.array([np.cos(t), np.sin(t), t])生成了螺旋线坐标。t_range[0, 4 * np.pi, 0.1]表示参数从 0 到 4π步长 0.1。4π 约等于 12.57所以 Z 坐标最大值就是 12.57这也是为什么刚才z_range设到 13。begin_ambient_camera_rotation(rate0.2)是ThreeDScene的一个很方便的方法它会让相机自动绕 Z 轴缓慢旋转。这一个方法就能让整个三维场景活起来螺旋线的立体感马上出来。rate0.2表示旋转速度数值越大转得越快我一般用 0.1 到 0.3 之间太小没感觉太大容易看晕。4.3 相机控制phi、theta 与移动理解三维动画的控制核心是理解 phi 和 theta 这两个角度。phi是相机与 Z 轴的夹角也可以理解为从 Y-Z 平面里的倾斜角。phi90 * DEGREES时相机几乎在水平方向观察phi0时相机从正上方俯视。theta是绕 Z 轴旋转的方位角控制你从哪个方向看物体。theta0通常是从 X 轴方向看theta90 * DEGREES则是从 Y 轴方向看。实际使用时我比较习惯的初始值是phi60~70度theta20~40度这样既能看到 X-Y 平面的大致分布也能看到 Z 轴的起伏立体感最强。除了固定视角还可以用动画过渡视角self.play( self.camera.frame.animate.move_to([2, 3, 5]), run_time2 )这样可以在动画中途移动相机位置让观众的注意力跟着移动。不过新手阶段暂时用不上这么复杂的控制先掌握set_camera_orientation和begin_ambient_camera_rotation就够应付大部分场景了。4.4 浏览器端三维场景的性能保障浏览器端跑三维动画最担心的就是性能问题。Manim 的三维渲染依赖 WebGL如果你发现动画很卡先不要怀疑代码写得不对先检查下面几个点。第一个是硬件加速。Chrome 和 Edge 默认开启 WebGL 和 GPU 加速但有时候系统设置或浏览器插件会把它关掉。在浏览器地址栏输入chrome://gpuChrome或edge://gpuEdge可以看到 WebGL 相关的状态如果显示Disabled或Software only说明 GPU 加速没生效。第二个是场景复杂度。三维坐标系本身已经包含大量网格线如果还叠加多个曲线和文字标注浏览器端的绘制压力会很大。我通常会把background_line_style的透明度调低一点减少视觉负担或者减小坐标范围只保留数据密集的区域。第三个是渲染质量。如果你用的编辑器支持设置渲染质量参数可以先选择较低的分辨率来快速预览确定内容没问题再调高质量重新渲染。这个思路和本地 Manim 的-ql参数很类似只是入口不同。5. 常见问题与避坑手册5.1 曲线不出来只有坐标系这是新手最经常遇到的问题。坐标网格画出来了但曲线没有出现或者只出现一段。先检查theta_range的范围和步长。如果范围写成了[0, np.pi]那曲线就只画半圈。如果步长写得太大比如 1那采样点太少曲线可能看起来像一个折线甚至完全看不出形状。另外注意函数的值域是否超出radius_max。如果函数返回的 r 值大于radius_max超出网格范围的部分会截断或者不显示曲线看起来就像断了一截。这种情况要把radius_max调大或者把size调大。还有一个很隐蔽的原因self.add(plane)这句漏了。很多人写完plane PolarPlane(...)就直接去画曲线但忘了把 plane 加进场景里结果只看到一条孤零零的曲线飘在白色背景上。网格线有没有无所谓反正曲线在但如果你预期看到坐标系先确认这句没有漏。5.2 文字和公式显示空白在浏览器端跑 ManimText和MathTex是重灾区。MathTex类公式渲染依赖 LaTeX浏览器端不一定事先配好了对应的渲染依赖。常见的表现是代码执行不报错但文字区域是一块空白或者公式变成了一个方框图标。如果你遇到了这个情况我建议先在早期阶段减少对文本的依赖。几何曲线、坐标网格这些图形元素不受影响你可以先专心验证图形效果。等确认整个流程稳定以后再用本地环境或渲染服务处理带文本的精细版本。如果非要让文字在浏览器端显示试一下是不是字体缺失的问题。有些在线编辑器已经内置了常用字体有些没有。可以尝试换用基础英文单词测试能显示再排查中文问题如果中文显示不了大概率是字体文件没有随页面一起加载。5.3 动画卡顿、画面模糊、白屏白屏的问题首先要看是不是 WebGL 初始化失败。浏览器端 Manim 通常依赖 WebGL 核心能力和 GPU 加速如果这两个条件不满足场景画面就出不来。解决方法就是前面说的检查 GPU 状态、更新显卡驱动、换一个现代浏览器。我一直推荐优先用 Chrome 或 Edge 的最新稳定版它们对新特性的支持最稳。模糊问题多半是渲染分辨率太低。很多在线编辑器为了加载速度会把默认画布分辨率调低出来的视频在电脑全屏看当然会糊。在编辑器提供的输出设置里调高分辨率即可。卡顿问题可能的原因比较多除了场景复杂度和 WebGL 状态还可能是因为同时打开了太多其他标签页浏览器内存不够。把不用的标签页关掉给浏览器腾出资源通常能明显改善渲染速度。5.4 首次加载太慢怎么办如果你用的方案需要加载 Python 运行时第一次打开页面等上一两分钟是正常的。这个等待本质上是在下载一个完整的解释器环境几十到上百兆不等。等它加载完后续再打开同一页面会走浏览器缓存速度就会快很多。如果多次加载都慢可能是网络问题。可以换一个网络环境试试或者在浏览器设置里清理缓存之后重新加载。还有一个办法是尽量保持页面在后台不要频繁刷新这样运行时环境不会反复初始化。5.5 常见问题速查表现象可能原因对应处理曲线只显示一部分取值范围或值域超限调整theta_range和radius_max文字/公式空白缺字体或 LaTeX 渲染支持先去掉文本后续用本地环境处理画面白屏WebGL 未初始化检查 GPU 加速、换新浏览器画面模糊渲染分辨率太低调高输出分辨率动画卡顿场景太复杂或内存不足降低网格密度、关闭多余标签页首次加载慢Python 运行时尚未下载耐心等待后续走缓存6. 从跑通到跑好看的进阶路径6.1 一个组合玩法把极坐标心形线放进三维空间二维的极坐标和三维的 XYZ 并不是割裂的进阶玩法就是把它们结合起来。比如说我们在 XY 平面上画一条心形线然后让相机绕 Z 轴旋转从各个角度看这条平面曲线你会发现它在三维空间中的姿态变化非常有表现力。具体实现也不复杂。先把极坐标曲线转换到三维坐标直接保留 Z0然后设置三维场景相机旋转。代码可以这样写class PolarIn3D(ThreeDScene): def construct(self): axes ThreeDAxes( x_range[-3, 3], y_range[-3, 3], z_range[-1, 1], ) self.add(axes) self.set_camera_orientation(phi70 * DEGREES, theta30 * DEGREES) # 心形线的三维版本z 保持 0 curve ParametricFunction( lambda t: np.array([ (1 np.cos(t)) * np.cos(t), (1 np.cos(t)) * np.sin(t), 0 ]), t_range[0, 2 * np.pi, 0.01], colorYELLOW, ) self.play(Create(curve), run_time3) self.begin_ambient_camera_rotation(rate0.15) self.wait(3)这个动画给人的冲击感会比单纯的二维曲线大很多因为它让观众意识到原来这个平面图形放在三维空间里看只是某一种角度的投影旋转之后你会看到它真正的空间位置关系。6.2 视觉表现力的三个加分项跑通基础动画之后想让画面更好看我总结了三个见效最快的方向。第一个是颜色。Manim 自带了大量预置颜色比如BLUE、YELLOW、RED但你可以传入十六进制色值来定义更协调的配色。我习惯一个画面里最多用两三个主色避免花哨。第二个是动画节奏。run_time参数控制每一步动画的时长Create一条曲线、Write一行公式、Wait停顿这些时间配比决定观众的观看舒适度。我一般让最核心的动画占用 2 到 4 秒辅助动画 1 到 2 秒停顿 0.5 到 1 秒。第三个是坐标标注。给关键点加上数值标签给坐标轴加上名称让观众能看懂你画的到底是什么。二维极坐标里我会在曲线关键点标出角度和半径值三维场景里会在坐标轴末端加 XYZ 标签这些信息能极大提升教学效果。6.3 一些真实的使用经验根据我自己的体会浏览器端跑 Manim 最适合的还是做探索和验证。想快速确认一个数学函数的图像想看一条参数曲线的变形打开页面写几行代码、运行、在几秒内看到结果这个过程非常高效。它让我敢于尝试各种各样的函数表达式因为试错成本很低。但如果你需要制作一个正式发布的教学视频我仍然建议在最终渲染阶段使用本地环境因为浏览器端的渲染画质、分辨率、帧率控制还是有上限的。浏览器方案可以作为前期验证工具后期用本地环境做精细渲染两者配合使用效率最高。最后分享一个很实用的小技巧每次调试代码不要上来就把所有动画逻辑写完。先建一个最简场景确认坐标系正常、曲线能出来然后再逐步加入动画、文本、相机移动。这样每次只改一个变量出了错也容易定位。这个习惯救了我很多次也推荐给你。