コンテンツにスキップ

Architecture

目的: Manim 風の Python DSL や Mermaid / PlantUML 風のテキスト DSL から、動画フレームではなく Scene Graph / Timeline IR / Diff Stream を生成し、Web Runtime で再生・編集・プレビューできる仕組みを作る。


従来の Manim は、Python DSL から Cairo / OpenGL でフレームを描画し、最終的に MP4 を生成する。

Python DSL
→ Cairo / OpenGL Renderer
→ Frames
→ MP4

本プロジェクトでは、Manim を「Python で動画をレンダリングするツール」ではなく、Scene Graph の時間変化を生成するオーサリング環境として再定義する。

Python DSL / Text DSL
→ Scene Graph IR
→ Timeline / Animation IR
→ Diff Stream
→ Web Renderer

Python 側や Text DSL Compiler は描画を担当せず、意味を持つシーン構造と時間変化を生成する。


  • Manim 風 Python API を維持する
  • Mermaid / PlantUML のように、短いテキスト記述から Web 上で変換・再生できる入力方式を追加する
  • Scene, Mobject, Animation, Transform を Web 向け IR に変換する
  • 動画フレームではなく、Scene Graph と Timeline を出力する
  • Web 側で Canvas / SVG / WebGL / WebGPU による描画を行う
  • 差分更新による高速プレビューを可能にする
  • 将来的にインタラクティブ編集、AI 編集、Git 管理しやすい形式にする

初期段階では以下は目指さない。

  • Manim 完全互換
  • Cairo / OpenGL レンダリング
  • 高度な数式 morph
  • 複雑な path topology morph
  • MP4 レンダリングの完全代替

┌─────────────────────────────┐ ┌─────────────────────────────┐
│ Manim-like Python DSL │ │ Text DSL │
│ - Scene │ │ - Mermaid-like syntax │
│ - Mobject │ │ - PlantUML-like blocks │
│ - Animation │ │ - Browser compiler │
│ - Transform │ │ - Live preview │
└──────────────┬──────────────┘ └──────────────┬──────────────┘
└──────────────┬──────────────────┘
┌─────────────────────────────┐
│ Scene Graph IR │
│ - Node │
│ - Transform │
│ - Style │
│ - Geometry │
│ - Children │
└──────────────┬──────────────┘
┌─────────────────────────────┐
│ Timeline / Animation IR │
│ - create │
│ - delete │
│ - set │
│ - animate │
│ - group │
│ - ungroup │
└──────────────┬──────────────┘
┌─────────────────────────────┐
│ Diff Stream │
│ - seq │
│ - ops │
│ - patch updates │
└──────────────┬──────────────┘
┌─────────────────────────────┐
│ Web Runtime │
│ - Canvas / SVG / WebGL │
│ - interpolation │
│ - playback │
│ - hit testing │
│ - interaction │
└─────────────────────────────┘

Python DSL と Text DSL は競合するものではなく、同じ Scene Graph IR / Timeline IR にコンパイルされる複数の入力フロントエンドとして扱う。


Scene Graph は Scene を root とし、その下に Node を持つ木構造で表現する。

Scene
└─ Node
├─ id
├─ type
├─ transform
├─ style
├─ geometry
└─ children
{
"id": "circle1",
"type": "circle",
"transform": {
"x": 100,
"y": 80,
"scale": 1,
"rotation": 0,
"opacity": 1
},
"style": {
"fill": "#ffcc00",
"stroke": "#333333",
"strokeWidth": 2
},
"geometry": {
"r": 40
},
"children": []
}

現在の MVP では以下をサポートする。

type用途
group複数 Node のグループ
circle
rect矩形
line線分
pathSVG path 相当
text通常テキスト
mathLaTeX / KaTeX 数式

ManimScene Graph 版
MobjectNode
VMobjectPathNode
VGroupGroupNode
Tex / MathTexTextNode / MathNode
SceneScene Graph Root
AnimationTimeline Operation
TransformInterpolation Operation
self.add()create / graph insert
self.remove()delete
self.play()timeline operation generation
.animateproperty animation builder

既存 Manim ユーザーが大きな違和感なく使える API を目指す。

class Demo(Scene):
def construct(self):
c = Circle(id="c1", r=40)
self.add(c)
self.play(
c.animate.move_to(300, 100),
run_time=2
)

このコードは MP4 をレンダリングせず、以下を生成する。

  • Scene Graph
  • Timeline IR
  • 必要に応じた Diff Stream

Mermaid や PlantUML のように、ブラウザ上で短いテキストを編集し、その場で .fluxion.json に変換して再生できる入力方式も提供する。

scene width=1280 height=720 fps=60
circle c1 r=40 at 220,360 fill="#38bdf8"
text title "Fluxion" at 640,120 size=48 fill="#e2e8f0"
at 0s:
show c1
show title
animate c1.x from 220 to 640 duration=2s easing=smooth
animate c1.opacity from 1 to 0.35 start=2s duration=1s

この DSL は以下のように処理する。

Text DSL
→ Parser
→ AST
→ Scene Graph IR / Timeline IR
→ .fluxion.json
→ Web Runtime

Python DSL と違い、Text DSL は以下の用途に向く。

  • Web 上でのライブ編集
  • 教材・ドキュメントへの埋め込み
  • Git diff しやすい短い宣言的記述
  • AI が直接生成・編集しやすいソース形式
  • Mermaid / PlantUML と同じような「貼り付けて再生」ワークフロー

Text DSL は Python DSL の完全な置き換えではなく、宣言的に書きやすい範囲へ絞る。

項目方針
入力形式.fluxion または fenced code block
実行場所ブラウザ内 compiler を優先
出力.fluxion.json と同じ IR
構文shape 定義、style、timeline、animate を中心にする
拡張include, component は後段で検討
安全性任意コード実行を避けるため Python 実行は不要

Web Runtime には Text DSL の変換レイヤーを追加する。

Editor textarea / Markdown fenced block
→ Text DSL Compiler
→ validation
→ .fluxion.json
→ SVG / Canvas / WebGL Runtime
→ playback

構文エラーは .fluxion.json の生成前に検出し、行番号・列番号・期待される token を返す。生成後は既存の JSON schema で検証する。

複雑な生成ロジック、ループ、外部データ読み込み、プログラム的な配置は Python DSL が担当する。短い説明アニメーション、図解、教材、ドキュメント埋め込みは Text DSL が担当する。

必要であれば、将来的に Python DSL から Text DSL を出力する、または Text DSL から Python DSL の雛形を生成する相互変換も検討できる。現在の MVP では、Python DSL と Text DSL の両方が同じ IR を出力するところまでを対象にする。


動画全体をフレーム列ではなく、時間付きイベント列として表す。

[
{
"t": 0.0,
"op": "create",
"id": "circle1",
"type": "circle"
},
{
"t": 0.0,
"op": "set",
"id": "circle1",
"path": "transform.x",
"value": 0
},
{
"t": 1.0,
"op": "animate",
"id": "circle1",
"path": "transform.x",
"from": 0,
"to": 200,
"duration": 2.0,
"easing": "smooth"
}
]

MVP では以下だけを必須とする。

op説明
createNode を作成
deleteNode を削除
setNode の property を即時変更
animateproperty を時間補間

group / ungroup は後段で検討する。MVP の schema と runtime は create, delete, set, animate を扱う。


リアルタイムプレビューでは Scene Graph 全体を毎回送らず、変更分だけを送る。

{
"seq": 42,
"ops": [
{
"op": "set",
"id": "circle1",
"path": "transform.x",
"value": 120
}
]
}
  • ホットリロード
  • 即時プレビュー
  • WebSocket による同期
  • エディタ連携
  • AI 編集後の差分適用
  • 将来的な共同編集

Python 側や Text DSL Compiler は描画しない。Web Runtime が描画と再生を担当する。

Python
- DSL
- Scene Graph 生成
- Timeline 生成
- Diff 生成
Text DSL Compiler
- parse
- AST 生成
- Scene Graph 生成
- Timeline 生成
Web Runtime
- Text DSL editor / preview
- Canvas / SVG / WebGL / WebGPU 描画
- Timeline 再生
- easing 補間
- transform 解決
- hit test
- interaction

MVP では実装容易性を優先し、以下の順で検討する。

  1. SVG
  2. Canvas 2D
  3. WebGL
  4. WebGPU

初期は SVG が適している。

理由:

  • Scene Graph との相性が良い
  • DOM inspection がしやすい
  • テキスト / 数式との統合が簡単
  • デバッグしやすい

MVP Runtime は seek ごとに Scene Graph を再構築し、指定時刻までの Timeline IR を適用する。

  • create operation を含む document は空の graph から開始する
  • create operation を含まない document は nodes を初期 graph として扱う
  • 同じ時刻の operation は createsetanimatedelete の順に適用する
  • duration <= 0 の animation は即時に final value を適用する
  • 非数値 value は補間せず、完了時に to value へ切り替える

ブラウザ editor は Text DSL を live compile し、Preview, Play / Stop / Reset, scrubber, generated JSON preview を提供する。


方式メリットデメリット
MathTex → SVG path見た目が安定morph や編集が難しい
MathTex → MathML意味を保持しやすい表示互換性に注意
MathTex → KaTeX HTML/SVGWeb プレビューが速いManim 完全互換ではない

MVP では KaTeX を推奨する。

{
"id": "eq1",
"type": "math",
"latex": "e^{i\\pi}+1=0",
"renderer": "katex",
"transform": {
"x": 100,
"y": 100,
"scale": 1,
"rotation": 0,
"opacity": 1
}
}

Manim の Transform(a, b) は、Scene Graph 版では「Node A から Node B への意味的・幾何的補間」として扱う。

circle = Circle(id="shape")
square = Square()
self.play(Transform(circle, square))

IR 例:

[
{
"op": "create",
"id": "shape",
"type": "circle",
"geometry": {
"r": 40
}
},
{
"op": "animate",
"id": "shape",
"path": "geometry",
"from": {
"type": "circle",
"r": 40
},
"to": {
"type": "rect",
"w": 80,
"h": 80
},
"duration": 1.0,
"easing": "smooth"
}
]
Phase対応内容
Phase 1translate, scale, rotate, opacity
Phase 2basic geometry morph
Phase 3SVG path morph
Phase 4text / math morph
Phase 5topology-aware morph

初期 MVP では Phase 1 までで十分。


.fluxion.json
{
"version": "0.1",
"width": 1280,
"height": 720,
"fps": 60,
"nodes": [
{
"id": "c1",
"type": "circle",
"transform": {
"x": 0,
"y": 0,
"scale": 1,
"rotation": 0,
"opacity": 1
},
"style": {
"fill": "#ffffff",
"stroke": "#000000",
"strokeWidth": 2
},
"geometry": {
"r": 40
},
"children": []
}
],
"timeline": [
{
"t": 0.0,
"op": "animate",
"id": "c1",
"path": "transform",
"from": {
"x": 0,
"y": 0
},
"to": {
"x": 300,
"y": 100
},
"duration": 2.0,
"easing": "easeInOut"
}
]
}

MVP で実装するもの:

  • Scene
  • Node
  • Mobject
  • Circle
  • Rectangle
  • Line
  • Text
  • Math
  • Group
  • Animation
  • .animate
  • Scene.add()
  • Scene.remove()
  • Scene.play()
  • JSON export

MVP で実装するもの:

  • .fluxion.json loader
  • SVG renderer
  • timeline player
  • create
  • delete
  • set
  • animate
  • transform interpolation
  • opacity interpolation
  • basic easing

現在使えるもの:

  • Text DSL parser
  • AST to .fluxion.json compiler
  • browser editor
  • line / column error reporting

将来構想として扱うもの:

  • JSON schema validation の compiler 内統合強化
  • fenced code block embedding

初期構成案は以下。

fluxion/
python/
fluxion/
__init__.py
scene.py
node.py
mobject.py
animation.py
timeline.py
export.py
primitives/
circle.py
rectangle.py
line.py
text.py
math.py
web/
package.json
src/
index.ts
runtime/
sceneGraph.ts
timeline.ts
diff.ts
player.ts
renderers/
svgRenderer.ts
dsl/
parser.ts
compiler.ts
diagnostics.ts
easing.ts
schemas/
fluxion.schema.json
docs/
architecture.md
protocol.md
mvp.md
examples/
simple_circle.py
simple_circle.fluxion
simple_circle.fluxion.json

  • .fluxion.json の schema を定義
  • Node schema を定義
  • Timeline operation schema を定義
  • easing 名を定義
  • Scene
  • Node
  • Circle
  • Rectangle
  • Line
  • Text
  • Scene.add()
  • Scene.play()
  • .animate
  • JSON export
  • JSON load
  • SVG node creation
  • timeline playback
  • transform update
  • opacity update
  • Python 側 diff emission
  • WebSocket or local dev server
  • Web Runtime に patch apply 機構を追加
  • .fluxion 構文の最小仕様
  • browser parser / compiler
  • editor から .fluxion.json への変換
  • 変換結果を既存 Web Runtime で再生
  • Markdown fenced block からの埋め込み再生
  • Math node
  • KaTeX integration
  • LaTeX string preservation
  • shape transform
  • path morph
  • text morph
  • math morph

16.1 ピクセルではなく意味を保存する

Section titled “16.1 ピクセルではなく意味を保存する”

MP4 は各フレームのピクセル列である。

Fluxion では次を保存する。

  • 円がある
  • 線がある
  • 数式がある
  • 円が右に移動する
  • この Node はこの Group に属する
  • この property は 2 秒かけて変化する

これにより以下が可能になる。

  • 即時プレビュー
  • 差分更新
  • Web 再生
  • インタラクティブ操作
  • AI による編集
  • Git 管理
  • semantic diff

16.2 入力 DSL と Renderer を分離する

Section titled “16.2 入力 DSL と Renderer を分離する”

Python DSL と Text DSL は IR の生成に専念する。Renderer は Web 側に置く。

この分離により、将来的に複数の入力 DSL と複数 renderer を持てる。

Python DSL ─┐
Text DSL ─┼─ Same IR
GUI Editor ─┘
├─ SVG Renderer
├─ Canvas Renderer
├─ WebGL Renderer
├─ WebGPU Renderer
└─ Export Renderer

最初に作るべきものは Manim 互換 renderer ではない。

最初に作るべきものは以下。

Manim-like Python DSL / Text DSL
→ Scene Graph JSON
→ Web playback

本アプリケーション名は Fluxion とする。

理由:

  • 短い
  • .fluxion.json と相性が良い
  • Manim 風の作り心地を持ちながら、独立プロジェクト名として使いやすい

この設計の核心は以下の 4 点。

  1. Mobject や Text DSL の shape 宣言を Node 化する
  2. AnimationTimeline 化する
  3. play() を Timeline / Diff 生成にする
  4. Renderer を Web 側に分離する

現在の MVP は次の経路を対象にする。

Manim-like Python DSL / Text DSL
→ Scene Graph JSON
→ SVG Web Runtime

これにより、従来の Manim よりも以下の用途に強いシステムになる。

  • 高速プレビュー
  • Web ネイティブ再生
  • 差分更新
  • 編集可能なアニメーション
  • インタラクティブ教材
  • AI による構造編集
  • Git 管理可能な animation source

FluxionDocument includes a root camera state: camera: { x, y, scale, rotation }. The default { x: 0, y: 0, scale: 1, rotation: 0 } maps scene origin (0,0) to the viewport center. Timeline operations address the camera with id: "camera" and paths such as camera.x or camera.scale.

The SVG renderer creates a root <g> for all scene nodes and applies camera before node transforms:

Screen = Camera * ParentNode * ChildNode * Geometry
Camera = translate(centerX + camera.x, centerY + camera.y) rotate(camera.rotation) scale(camera.scale) translate(-focusX, -focusY)
Node = translate(node.x, node.y) rotate(node.rotation) scale(node.scale)

For mode=center, focusX=0 and focusY=0; target modes use the target coordinate as focus. This makes camera pan scene-level while zoom / rotation pivot around the scene origin at the viewport center, and each node’s transform remains local and composes under the camera.