Appearance
Design and architecture
Conceptual guides to the design principles, mathematical foundations, and system boundaries behind Anim.
1. Referential Transparency & Continuous Time Signals
The Problem with Imperative Frame Loops
Traditional game and graphics engines drive animation using mutable state update loops:
state = update(state, delta_time)
render(state)This model suffers from fundamental flaws when applied to precise animation:
- Frame Rate Dependency: Variable step sizes ((\Delta t)) cause accumulated floating-point rounding error and physics divergence.
- Sequential Coupling: Frame (N) cannot be rendered without evaluating all frames (0 \dots N-1). Parallel rendering of frame ranges across multiple CPU cores becomes impossible or expensive.
- Non-Determinism: Ambient hardware clocks, floating-point non-associativity, and thread scheduling introduce variations across different machines.
The Anim Signal Paradigm
Anim eliminates frame loops by treating all animated values as referentially transparent continuous signals:
Signal<T> : Rational -> T
A signal is a pure mathematical function mapping continuous presentation time (t) (represented as an exact rational number) to a value of type (T).
┌───────────────────────┐
│ Presentation │
│ Time t ∈ Rational │
└───────────┬───────────┘
│
▼
┌─────────────────────────────────────┐
│ Signal<T> (Referentially Pure) │
└──────────────────┬──────────────────┘
│
▼
┌───────────────────────┐
│ Evaluated Scene IR │
└───────────────────────┘Properties of Anim Signals:
- Order-Independence: Frame 1,000 can be evaluated without evaluating frames 0 through 999.
- Parallelizable Evaluation: Independent frames can be scheduled in any order. Actual throughput still depends on the renderer, scene, and worker implementation.
- Referential Transparency: Identical supported source and exact input time produce the same evaluated scene value.
2. Deterministic CPU Rasterization & Color Space Math
Exact Cross-Platform Pixel Identity
A core contract of the native CPU renderer is canonical determinism: supported builds use the same controlled math and serialization path, with exact fixtures pinning the resulting PNG bytes. The browser Canvas 2D player is an interactive preview backend, not the canonical pixel contract.
To achieve this:
- Fixed-Point Rounding & Geometry Math: All spatial calculations use project-controlled fixed-point Q16 arithmetic rather than platform-dependent floating-point libraries.
- Linearized sRGB Color Space: Standard sRGB color values are non-linear (gamma-compressed). Blending non-linear colors produces dark fringes along anti-aliased edges. Anim decodes all color inputs to linearized sRGB prior to compositing:
[ C_{\text{linear}} = \begin{cases} \frac{C_{\text{srgb}}}{12.92} & \text{if } C_{\text{srgb}} \leq 0.04045 \ \left(\frac{C_{\text{srgb}} + 0.055}{1.055}\right)^{2.4} & \text{if } C_{\text{srgb}} > 0.04045 \end{cases} ]
- Premultiplied Alpha Compositing: Color channels are stored premultiplied by alpha ((r' = r \cdot a), (g' = g \cdot a), (b' = b \cdot a)). The classic Porter-Duff "Over" compositing operation is implemented as:
[ C_{\text{result}} = C_{\text{src}} + C_{\text{dst}} \cdot (1 - \alpha_{\text{src}}) ]
[ \alpha_{\text{result}} = \alpha_{\text{src}} + \alpha_{\text{dst}} \cdot (1 - \alpha_{\text{src}}) ]
This prevents hidden straight-alpha color from bleeding into partially transparent edges and gives stack a controlled, explicitly ordered compositing path.
3. Physics & Mathematics of 2D Mesh Deformation
Anim's 2D mesh deformation system (mesh2d and deform2d) provides deterministic mass-spring skeletal physics without mutable simulation loops.
The Physics Constraint Solver
When a mesh is deformed by bone target positions, vertex displacements are computed using an iterative constraint solver:
Rest Mesh Topology Skeleton Bone Targets
(x, y) (Root & Tips)
│ │
└───────────────┬────────────────┘
▼
┌──────────────────────────────────┐
│ Fixed-Tick Iterative Spring │
│ Solver (Edge, Area, Tether) │
└────────────────┬─────────────────┘
▼
Deformed Mesh Surface Points- Edge Stiffness: Maintains rest distance between connected vertex pairs.
- Area Stiffness: Preserves triangle area and prevents mesh inversion or self-folding.
- Tether Stiffness: Anchors vertices back to rest skeleton handles, preventing elastic runaway.
- Soft Damping: Dissipates kinetic energy over time.
Checkpointed Deterministic Replay
To maintain frame order-independence despite physics step accumulation, anim-deform uses a checkpointed deterministic replay buffer. State snapshots are stored every CHECKPOINT_INTERVAL (120 ticks). To sample frame (N), the engine restores the nearest preceding checkpoint and advances the solver deterministically to frame (N).
4. Zero-Drift Rational Timebases
The Precision Problem in Digital Video
Floating-point time accumulators (t += 1.0 / 60.0) accumulate floating-point drift over time. Furthermore, standard NTSC broadcast frame rates are non-integer fractions:
[ \text{FPS}_{\text{NTSC}} = \frac{24000}{1001} \approx 23.976023976... \text{ fps} ]
Representing frame duration as a 64-bit float causes timestamp drift over multi-minute animations, leading to audio sync loss and dropped frames.
Exact rational presentation time
Anim represents time with a normalized rational whose public numerator and denominator are signed 64-bit integers:
rust
pub struct Rational {
numerator: i64,
denominator: i64,
}- Frame Duration: (\Delta t = \frac{1}{\text{FPS}}).
- Exact Frame Timestamp: (t_n = n \times \Delta t = \frac{n \times 1001}{24000}\text{ seconds}).
Because all time arithmetic operates in exact rational space, zero microsecond drift occurs regardless of animation length.
5. System Architecture & Crate Layering
The Anim repository is organized into a modular Cargo workspace designed to keep platform-neutral domain semantics separate from host rendering, conversion, and CLI concerns.
┌─────────────────┐
│ anim-cli │
└────────┬────────┘
│
┌──────────────────────────┼──────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ anim-lang │ │ anim-lottie │ │ anim-svg │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└──────────────────────────┼──────────────────────────┘
│
▼
┌─────────────────┐
│ anim-render │
└────────┬────────┘
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ anim-deform │ │ anim-scene │
└───────┬───────┘ └───────┬───────┘
│ │
└──────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────┐
│ anim-core │
└─────────────────┘Core Workspace Packages:
anim-core: Platform-neutral primitives such as exact rational time, frame rate, dimensions, color, and fixed-point units.anim-scene: Renderer-neutral Retained Scene Graph IR (Nodes, Shapes, Transforms, Clips, Masks, Opacity).anim-lang: Lexer, Parser, CST/AST, Type Checker, and Evaluator for.animfiles.anim-render: Reference deterministic CPU rasterizer, RGBA compositing engine, and SVG exporter.anim-deform: Mass-spring 2D mesh deformation solver.anim-lottie: Converter from Lottie JSON documents to native.animAST.anim-cli: Headless CLI executable providingcheck,inspect,render, andimport-lottie.
6. Lottie Import Mapping Principles
The Lottie importer (anim-lottie) parses After Effects animation graphs and translates them directly into native Anim signal primitives.
| Lottie JSON Construct | Anim DSL Target Construct |
|---|---|
Shape Layer Rectangle ("ty": "rc") | rect(x, y, width, height, fill) |
Shape Layer Ellipse ("ty": "el") | ellipse(x, y, width, height, fill) |
| Linear Position Keyframes | tween(from, to, start, end) |
Bézier Keyframe Ease Handles ("o", "i") | tween(..., easing: cubic_bezier(x1, y1, x2, y2)) |
Pre-composition Layers ("ty": 0) | Sub-tree scoping & nested stack nodes |
Layer Alpha Matte ("tt": 1) | mask(mask, content) |
Opacity Property ("o") | opacity(value, scene) |
By mapping supported Lottie keyframe tracks into ordinary Anim signals, imported source uses the same exact timing, targeted evaluation, and canonical CPU rendering path as hand-authored source.