这是什么

DynMath 让你用几乎原版的 Manim Python 代码编写数学动画,并在动画里加入方便演示和讲解的交互控件(滑块、开关、可编辑数字 / 矩阵 / 表格)。

和以往的做法(先离线渲染成视频,或在浏览器中运行完整 Python 环境)不同,这里的动画通过轻量级库直接在浏览器里即时渲染:改完代码点一下运行,马上就能看到修改后的结果, 体积和性能相比于传统方案都有显著提升。可以直接到游乐场里体验。

代码与原版 Manim 的写法基本一致,numpy 也几乎支持。 暂不支持完整的 3D 渲染、文件读写,以及除 manim / numpy 之外的标准库 import。

快捷键与操作

运行⌘/Ctrl + Enter(编辑器 / 游乐场内),或点「运行」按钮
保存⌘/Ctrl + S(游乐场里是打开「发布到我的课件」弹窗)
下一步空格:交互场景在 blueprint 与 construct 之间推进
重来r:交互场景回到从头;展示页里非交互场景播放结束后会自动从头重播
操作控件拖动滑块、点击开关、点击数字后直接输入(Enter 提交,Esc 取消)

在输入文字 / 编辑数字时,播放类快捷键不会触发,避免冲突。

制作流程:「我的课件」点「+ 新建课件」,在左侧列表里新建 / 改名 / 排序 / 删除每一页;右侧写代码、运行、保存。在「设置」里选择可见性(未发布 / 私有发布,凭链接访问 / 发布到主页)并设置访问地址 /p/xxx。 展示页无需登录即可打开;别人点「我也想做这个动画」会进入游乐场,改完可发布到自己的课件。

交互控件

把 Scene 换成 InteractiveScene,并在 blueprint() 里创建控件。控件本身就是普通的 mobject,可以 self.add(...)、参与动画、被读取。要在 construct() 里用到的对象,记得在 blueprint() 里存到 self 上(如 self.circle = circle)。

  • blueprint():动画播放前的静置阶段,每一帧都会重跑所有 add_reaction 回调。适合放控件和「随控件实时变化」的图形。
  • construct():点「下一步」后进入。这里 add_reaction 不再生效,改用普通的 add_updater。
  • 两个方法都可以留空其一。想「只有交互、没有后续动画」,就只写 blueprint。

目前一共有 7 种控件:Slider、PathSlider、Switch、InputDecimalNumber、InputInteger、InputDecimalMatrix、 InputDecimalTable。它们都是 mobject,用 get_value() 读值。

多阶段:set_storyboard

默认情况下,一个 InteractiveScene 只有一组 blueprint / construct。如果需要「交互 → 讲解 → 再交互 → 再讲解」的多段流程,就在 setup() 里用 self.set_storyboard(...) 规划整个流程。

  • 每个元素是一个 (blueprint, construct) 二元组;某一半填 None 表示跳过该阶段(例如只要交互、不要动画)。
  • 按「下一步」(空格)依次推进:一个阶段的 blueprint 结束后进入它的 construct,再进入下一组的 blueprint。
  • 调用之后 blueprint() / construct() 不再被隐式执行,只按表里的顺序走;set_script 是它的别名。
  • 控件只在 blueprint 阶段可拖动 / 点击,construct 播放动画期间指针事件被忽略。

Slider(滑块)

一条轨道 + 一个圆点。拖动时 get_value() 返回 value_range 区间内的浮点数(左闭右闭)。

参数默认说明
start / end[-1,0,0] / [1,0,0]轨道两端(世界坐标,可用 axes.c2p)
value_range(0, 1)值域闭区间
init_valuevalue_range[0]初始值
color / stroke_widthYELLOW / 6颜色与轨道线宽
track_opacity / knob_opacity1 / 1轨道 / 滑块透明度,设 0 即隐藏

想让「真正的滑块」是别的图形(如三角形),用 slider.attach(mobj): 圆点会自动变透明,被附着的物体随 set_value 一起移动;slider.unattach() 解除。命中判定始终基于轨道线段,与透明度无关。

PathSlider(曲线滑块)

轨道可以是任意 VMobject(曲线、折线、VGroup 拼出的路径)。 其余行为与 Slider 相同:value_range 左端对应路径起点、 右端对应终点,按弧长比例映射;拖动只沿路径切线方向移动,不会跳到路径外。

参数默认说明
path(位置参数)必填轨道 VMobject,会被直接采用并上色
is_closedFalse路径是否首尾相接;为真时值按 value_range 长度循环
其余参数同 Slidervalue_range / init_value / color / stroke_width / track_opacity / knob_opacity / knob_radius / hit_radius

is_closed=True 时(如 Circle),set_value 对超出区间的值按区间长度取模,拖动越过接缝会从一端绕回另一端。attach / unattach 用法与 Slider 相同。

Switch(开关)

蓝白配色开关,点击切换布尔值。get_value() 返回 True / False。

参数默认说明
valueFalse初始状态(也可作为第一个位置参数)
width / height0.66 / 0.33尺寸
colorBLUE_E打开时的蓝色

set_value(False) 直接设置,toggle() 取反。

InputDecimalNumber(可编辑数字)

继承自 DecimalNumber,但可以点击并在原地输入,数字上方会出现 ^ 光标。get_value() 返回当前数值。

只接受数字、.、-;按 Enter 或点击别处提交,Esc 取消。参数与 DecimalNumber 相同,其中 group_with_commas 默认关闭。注意 num_decimal_places 会重新格式化数值,固定小数位或整数场景使用最自然。

InputInteger(可编辑整数)

用法与 InputDecimalNumber 相同,但小数位数固定为 0, 编辑时不接受小数点,get_value() 返回整数(四舍五入后截断)。

InputDecimalMatrix(可编辑矩阵)

与 DecimalMatrix 参数完全一致,区别是每个格子都是 InputDecimalNumber,可以单独点击编辑;编辑后矩阵自动重排 (列宽按各列最宽的格子、行高按各行最高的格子),括号跟着内容伸缩,中心保持不变。

  • A.get_entries() / A.mob_matrix[i][j] 返回格子, 可 get_value() / set_value(v)。
  • 格子的小数位等参数通过 element_to_mobject_config={"num_decimal_places": 1} 传入。
  • 编辑任一格会触发 A.relayout();也可手动调用。

InputDecimalTable(可编辑表格)

与 DecimalTable 参数完全一致,区别是每个数据格都是 InputDecimalNumber,编辑后自动重排并用新的行列位置重建表格线 (include_outer_lines 等行为不变),中心保持不变。

  • T.get_entries(pos) / T.get_entries_without_labels(pos) 读取表格内容,用法与 Table 一致。
  • 编辑触发 T.relayout(),会重建 T.horizontal_lines / T.vertical_lines。

示例

点每一段下面的「亲自试一试」,会在游乐场里打开并自动运行;改一改数字再运行即可。

基础交互:滑块 + 数字 + 开关

滑块改变圆的大小,输入框改变正方形宽度,开关切换颜色。

亲自试一试在游乐场里打开并运行

圆环滑块:用角度驱动向量

PathSlider 沿圆环滑动,右侧单位圆上实时画出对应角度的向量。

亲自试一试在游乐场里打开并运行

可编辑矩阵与行列式

点击矩阵的任意一格修改数值,下方的行列式实时更新。

亲自试一试在游乐场里打开并运行

可编辑表格与开关

点击表格单元格编辑,开关切换读数是求整表之和还是对角线之和。

亲自试一试在游乐场里打开并运行

多阶段:set_storyboard

先用滑块调圆,按「下一步」播放动画;再用输入框调正方形,再次「下一步」。

亲自试一试在游乐场里打开并运行