Animora Architecture — Overview & System Design
1. Vision & Philosophy
Animora is a high-level, declarative animation framework built on top of Manim (Community Edition). Its purpose is to democratize the creation of high-quality educational, technical, mathematical, and algorithmic visualizations.
The Seaborn Analogy
In the scientific Python ecosystem, Matplotlib provides pixel-level and primitive-level control for rendering plots, but building complex statistical visualizations directly with Matplotlib is verbose and error-prone. Seaborn sits on top of Matplotlib: it understands domain concepts like datasets, distributions, regressions, and hue groupings, letting users describe what statistical relationship to visualize while delegating low-level rendering to Matplotlib.
Animora adopts an identical philosophy for technical animation:
| Dimension | Low-Level Engine (Manim) | High-Level Abstraction (Animora) |
|---|---|---|
| Core Abstraction | Mobject, VMobject, VectorField |
Component, Scene, Layout, Theme |
| Mental Model | Geometric coordinates & manual transforms | Semantic data structures & declarative operations |
| Target Task | Animating circles, arrows, and parametric curves | Visualizing BFS traversal on a Graph or sorting an Array |
| API Style | Imperative animation orchestration | High-level declarative intent + semantic action methods |
| Escape Hatch | N/A (it is the foundation) | First-class .manim_object property on every component |
2. Layered Architecture
Animora is structured into four distinct, strictly ordered architectural layers:
graph TD
User["User Script / Application / CLI"] --> L1["Layer 1: Public Semantic API<br/>(Components, Semantic Animations, Themes)"]
L1 --> L2["Layer 2: Layout & Composition Engine<br/>(animora.layout: Linear, Grid, Tree, Graph, Circular)"]
L2 --> L3["Layer 3: Core Abstraction Layer<br/>(animora.core: Base Component, Scene, Animation Bridge, Theme Engine)"]
L3 --> L4["Layer 4: Rendering & Math Engine<br/>(Manim Community Edition, NumPy, NetworkX)"]
classDef layer fill:#1e293b,stroke:#38bdf8,stroke-width:2px,color:#f8fafc;
classDef user fill:#0f172a,stroke:#a855f7,stroke-width:2px,color:#f8fafc;
class User user;
class L1,L2,L3,L4 layer;
Layer Breakdown
Layer 1: Public Semantic API (animora.components, animora.animations, animora.theme)
- Responsibility: Provides high-level, domain-specific visualization constructs.
- Key Concepts:
- Primitives:
Text,Shape,Arrow,Connector,Group,Panel. - Data Visualizations:
BarChart,LineChart,ScatterPlot,Histogram,Table. - Data Structures:
Array,LinkedList,Stack,Queue,Heap,Tree,BinarySearchTree,Graph,HashTable. - High-level operations:
graph.bfs(start="A"),array.swap(i, j),tree.insert(value). - Constraint: Must never interact directly with private Manim internals; all rendering passes through Layer 3 abstractions.
Layer 2: Layout & Composition Engine (animora.layout)
- Responsibility: Pure coordinate and spatial geometry calculation decoupled from visual rendering.
- Key Concepts:
HorizontalLayout,VerticalLayout,GridLayout,TreeLayout,GraphLayout,CircularLayout,FlowLayout. - Constraint: Layout algorithms compute spatial offsets, bounding boxes, and target transformations. They operate on abstract component bounding dimensions and node-edge topologies without instantiating Manim mobjects.
Layer 3: Core Abstraction Layer (animora.core)
- Responsibility: The foundational bridge linking Animora’s declarative world to Manim's imperative rendering pipeline.
- Key Concepts:
Component: Lifecycle, hierarchy, properties, bounds, and the.manim_objectescape hatch.Scene: ManimScenesubclass with automated camera management, layout anchoring, and component registration.Animation: Bridge between Animora semantic operations and ManimAnimation/Transforminstances.Config&Registry: Global runtime settings and plugin dispatch.
Layer 4: Rendering & Math Engine (External)
- Responsibility: Frame rasterization, vector rendering, ffmpeg video export, and matrix math.
- Dependencies:
manim(Community Edition),numpy,networkx.
3. Component vs. Layout Boundary Resolution
The Architectural Question
Should a Component know how to lay out its own children internally, or should layout logic live exclusively in a separate animora.layout engine that components consume?
The Decision: Decoupled Pure Layout Engine
Animora adopts a strict separation between Components (Visual Representation & Hierarchy) and Layouts (Pure Geometric Solvers).
- Components define WHAT: A
Componentmaintains its state, visual elements, child relationships, and exposes its measured dimensions (width,height,depth,center). - Layouts compute WHERE: A
Layoutclass takes a collection of components (or a graph topology) and solves for their 2D/3D coordinate transformations. - Application: When a compound component (like
TreeorArray) positions its sub-elements, it delegates spatial calculation to an explicit layout strategy (e.g.ReingoldTilfordTreeLayoutorFlexLinearLayout).
Rationale and Justification
- Reusability: The same
TreeLayoutalgorithm can layout aBinarySearchTreecomponent, an AST visualizer, or a flowchart without duplicating positioning logic. - Testability: Layout algorithms are pure mathematical functions operating on bounding boxes and adjacency lists. They can be 100% unit-tested with lightweight mock geometry without initializing Manim rendering contexts or OpenGL/cairo backends.
- Extensibility: Users and plugin authors can implement custom layouts (e.g., custom force-directed or physics-based positioning) and apply them to any existing Animora components without subclassing the components.
Rejected Alternative: Component-Embedded Layouts
- Why Rejected: Embedding layout calculations inside component classes leads to bloated base classes, code duplication across components (e.g. linear positioning repeated in
Array,Stack, andQueue), and makes it impossible to swap layout algorithms dynamically at runtime.
4. Execution Flow: From Script to Rendered Frame
sequenceDiagram
autonumber
actor User as User Script
participant Comp as Animora Component (e.g. Graph)
participant Layout as animora.layout Engine
participant Core as animora.core (Component / Scene Bridge)
participant Manim as Manim Engine
User->>Comp: Graph(vertices, edges, layout="circular")
Comp->>Layout: CircularLayout.solve(nodes, edges, bounds)
Layout-->>Comp: CoordinateMap {node: (x, y, z)}
Comp->>Core: Build component tree & bind layout coordinates
Core->>Manim: Construct underlying VMobjects (Dots, Lines, Labels)
User->>Comp: graph.bfs(start="A")
Comp->>Core: Generate semantic step sequence
Core->>Manim: Map to Manim Animations (FadeToColor, Indicate, Transform)
Core->>Manim: scene.play(*animations)
5. Architectural Principles
- Declarative First, Imperative When Needed: High-level semantic calls (
array.sort(),graph.dijkstra()) produce clean, timed animation sequences automatically, but every step is customizable. - Zero-Magic Escape Hatch: Animora never hides Manim. Every component exposes its underlying Manim object directly via
.manim_object, allowing seamless mixing of Animora components with native Manim animations. - Stateless Layout Solvers: Layout calculations do not mutate global scene state. They take bounding geometries and graph topologies as input and return coordinate mappings.
- Theme Driven Design: Visual styling (colors, strokes, typography, timing) is abstracted into design tokens via
animora.theme, ensuring consistent, publication-ready aesthetics by default.
6. Consistency Self-Check
This architecture specification has been validated across all five Phase 0 documents:
- Layer Names: Layer 1 (Public Semantic API), Layer 2 (Layout & Composition Engine), Layer 3 (Core Abstraction Layer), Layer 4 (Rendering & Math Engine).
- Module Names:
animora.core,animora.components,animora.layout,animora.theme,animora.animations,animora.cli. - Base Class & Escape Hatch:
Component,.manim_object. - Target Python Floor: Python
>= 3.10. - Target Manim Range:
manim >= 0.18.0, < 1.0.0.