Skip to content

Anim v0.1: Portable Animation Engine

Status: approved foundation plan

Summary

Build anim as a Rust library and headless CLI that compiles statically typed .anim programs into deterministic 2D/2.5D scenes, raster/vector frames, mixed audio, and AV1/Opus WebM.

The architecture separates language evaluation, scene representation, rendering, and media encoding so future codecs, renderers, abstractions, and browser runtimes do not alter DSL semantics.

Core Architecture and Language

  • Create a modular Cargo workspace for syntax/compiler, engine/scene/audio, CPU and GPU renderers, media codecs, and CLI. The compiler and engine core must build for wasm32-unknown-unknown without filesystem, threads, GPU, or codec dependencies.
  • Use a lossless CST followed by typed HIR and optimized evaluation IR. Keep a portable evaluator and allow host-only backends to compile supported monomorphic IR to machine code; constant-fold static work and memoize scene subtrees that do not depend on time or changed inputs.
  • Give .anim a Typst-inspired expression syntax with inferred static types, immutable values, functions, named arguments, modules, records, collections, generics, and dimensional units such as px, deg, s, ms, and fps.
  • Require an exported main: Composition. A composition defines exact dimensions, rational duration, rational frame rate/timebase, visual content, and an optional audio timeline.
  • Represent animated values as Signal<T>, a pure function of exact rational time. Provide tween, keyframes, easing, sequence, stagger, repeat, map, and signal-combination constructs. Properties accept constants or compatible signals.
  • Keep DSL evaluation referentially transparent. Do not expose mutable bindings, collections, objects, hidden random cursors, ambient inputs, or source-callable IO. Treat parameters, exact sample time, assets, imported data, seeds, and event streams as typed immutable inputs.
  • Represent sequential work as a deterministic pure Simulation<State, Input> fold/scan with a fixed rational tick, explicit seed, checkpoints, and replay rules. Use this for particles without exposing a mutable simulation object or making targeted frames depend on prior frame evaluation.
  • Resolve assets and other host operations through engine-managed typed requests/results, capability checks, resource limits, and structured errors. The compiler records their source-aware input dependencies; private caches and implementation mutation remain permitted when unobservable.
  • Make functions and immutable scene values the primary abstraction mechanism. Keep tracks, clips, transitions, layout helpers, and higher-level animation systems in standard-library modules rather than privileged syntax.
  • Emit source-spanned diagnostics for parsing, type/unit errors, dependency cycles, invalid frame conversions, incompatible path morphs, missing assets, and unsupported export features.

Scene, Rendering, and Media

  • Define a renderer-neutral retained scene IR containing groups, planar layers, paths, glyph runs, images, gradients, transforms, clips, masks, opacity, blend modes, filters, and cameras.
  • Support 2.5D through planar layers, 4×4 transforms, perspective projection, explicit depth/painter ordering, and camera transforms. Admit only bounded flat-color 2D deformation meshes under ADR 0028; exclude 3D/general meshes, lights, intersecting geometry, and general depth-buffer rendering.
  • Include rectangles, ellipses, Bézier paths, fills/strokes/dashes, path trim, compatible-contour morphing, text-on-path, images, masks, blur, shadows, color matrices, gradients, and deterministic particles.
  • Use linearized sRGB with premultiplied alpha as the sole working color space. The canonical CPU path uses controlled rounding/fixed-point coverage and compositing kernels so pinned builds produce identical pixels across supported architectures. Export 8-bit sRGB PNG and BT.709-tagged 8-bit video; defer wide gamut, HDR, and 10-bit output.
  • Build the CPU renderer as the reference implementation, using project-controlled deterministic raster/compositing kernels and font outlines rather than platform drawing APIs. Golden output from this backend defines correctness.
  • Build an optional wgpu/Vello-style GPU render graph for batching, path rendering, masks, filters, and compositing. GPU results use pixel-tolerance tests; an unsupported GPU operation falls back for the entire frame to CPU and is reported by inspect.
  • Shape and lay out text with the pure-Rust Fontations/HarfRust stack, Unicode bidi and line-breaking rules, variable-font axes, fallback chains, and text-on-path. Bundled fonts are preferred; system fonts are allowed for development but must be hash-pinned for locked renders.
  • Import PNG, JPEG, WebP, SVG, OpenType fonts, WAV, FLAC, MP3, Ogg/Vorbis, Ogg/Opus, JSON, and CSV. Defer video input.
  • Export:
    • Single PNG frames and numbered PNG sequences.
    • One SVG per sampled frame, with text outlined by default.
    • AV1/Opus WebM through streaming frame/audio sinks.
    • Raw premultiplied RGBA frames and 48 kHz PCM through the Rust API.
  • Make SVG export fail with source-linked diagnostics for unsupported subtrees. Permit fallback only through explicit rasterize(node, resolution:) or the equivalent CLI option.
  • Decode audio to a canonical 48 kHz timeline. Support offset, trim, gain automation, fades, mono/stereo conversion, pan, resampling, mixing, and muxing. Use deterministic fixed-point mixing with 64-bit accumulation; exclude synthesis and general DSP effects.
  • Isolate codecs behind internal traits. Use rav1e for AV1, ropus for fixed-point Opus, and a pure-Rust WebM muxer such as oxideav-mkv. Pin exact versions and validate their output independently because the container ecosystem is still young.
  • Stream evaluation → rendering → encoding with bounded, ordered frame queues. Parallelize independent frames and asset preparation without retaining the complete animation in memory. Permit bounded, discardable previous-frame caches and baseline/incremental kernel racing without making targeted frames depend on render history.

Public Interfaces and Workflow

  • Expose Rust types including Engine, CompiledProject, RenderSession, RenderRequest, Composition, Scene, AudioTimeline, Time, Duration, FrameRate, FrameIndex, Frame, and Diagnostic.
  • Provide:
    • Engine::compile(ProjectInput, CompileOptions) -> CompiledProject.
    • Composition discovery and typed parameter inspection.
    • Targeted frame evaluation and rendering.
    • Streaming range rendering into image, audio, or media sinks.
    • Experimental AssetProvider, Renderer, ImageEncoder, VideoEncoder, and Muxer traits.
  • Treat all Rust and DSL interfaces as versioned experimental 0.x APIs. Store a language/IR version in compiled artifacts and provide migration diagnostics after intentional breaks.
  • CLI commands:
    • anim check <input> for compilation and capability validation.
    • anim inspect <input> [--json] for compositions, parameters, assets, timing, backend support, and cache dependencies.
    • anim render -i <input> -o <output> with --frame, half-open --range, --backend cpu|gpu, --reproducible, --locked, quality, seed, and worker controls.
    • anim watch <input> to invalidate affected modules/assets and rerender a selected frame or range.
    • anim lock <input> to hash transitive sources, assets, fonts, and dependencies.
    • anim init for an optional project manifest and starter composition.
  • Support standalone .anim files using their containing directory as the local read root. An optional anim.toml defines entrypoint, defaults, asset roots, font aliases, path or pinned-Git dependencies, and capabilities. anim.lock records revisions and content hashes.
  • Provide no ambient clock, environment, subprocess, or network access to DSL programs. Locked mode rejects undeclared files, unpinned system fonts, changed hashes, floating dependency revisions, and missing lock entries.
  • Keep host effects outside ordinary DSL evaluation. Module/asset resolution, decoding, rendering, encoding, output writes, progress, and cancellation run through explicit engine phases; equivalent immutable inputs must produce equivalent compiled and rendered values regardless of evaluation history.
  • Keep implementation source, tests, generated browser/runtime bundles, and native binaries proprietary. License authored documentation and examples under MIT through explicit nested license boundaries.

Delivery Sequence

  1. Establish workspace boundaries, core value/time types, diagnostic conventions, manifest/lock formats, conformance fixtures, and codec/rendering feasibility spikes.
  2. Implement parser, type checker, module graph, typed optimized evaluation IR, portable evaluation, measured host-native acceleration, standard animation primitives, check, and inspect.
  3. Implement scene IR, typography, assets, deterministic CPU rendering, PNG/SVG export, targeted rendering, and golden examples.
  4. Implement exact audio timelines, decoding/mixing, AV1/Opus encoding, WebM muxing, streaming scheduling, and reproducible media mode.
  5. Implement the GPU backend, incremental watch workflow, cache instrumentation, benchmarks, documentation, language reference, and cross-platform release packaging.

Release v0.1 only when one representative project with Unicode title animation, SVG artwork, path motion, masks/effects, deterministic particles, imported data, and synchronized mixed audio renders successfully to PNG sequence, SVG frames, and browser-playable WebM.

Test and Acceptance Plan

  • Parser/type-system snapshots, malformed-input recovery, unit checking, module cycles, exact rational timing, non-integer rates such as 24000/1001, and zero-drift frame/sample conversion.
  • Cross-platform canonical pixel and PCM goldens on Linux, macOS, and Windows, including x86-64 and ARM64. --reproducible also pins encoder configuration, threading, timestamps, metadata ordering, and CPU feature paths.
  • Typography fixtures for Arabic, Indic scripts, CJK, mixed bidi text, combining marks, emoji fallback, variable fonts, line wrapping, and text-on-path.
  • Scene tests for clipping, masks, blend modes, perspective projection, filter boundaries, path morph validation, transparency, particles, and SVG unsupported-feature failures.
  • Independent WebM validation and playback tests in Chromium and Firefox, plus AV1/Opus decode comparisons, duration checks, A/V synchronization, odd dimensions, empty audio, and partial final frames.
  • Capability tests proving undeclared reads, network, environment, clock, and lockfile drift are rejected.
  • Incremental tests proving changes invalidate only dependent modules, signals, assets, and frames.
  • Performance gates on a documented reference machine:
    • Warm check or targeted-frame rebuild under 200 ms for the standard 50-module/1,000-node project.
    • GPU rendering at 1080p60 for the standard 10,000-path/1,000-glyph scene without heavy filters.
    • At least 70% parallel efficiency from one to eight CPU workers on the independent-frame benchmark.
    • Default in-flight memory bounded to twice the configured worker count.
  • Fuzz the parser, evaluator, path handling, font ingestion, image/audio decoders, and container writer; run sanitizers/Miri where supported.

Assumptions and Deferred Work

  • “Pure Rust codecs” means the canonical/reproducible media backend has no FFmpeg runtime, subprocesses, or C codec linkage; an explicitly requested, non-reproducible CLI export may use a locally installed FFmpeg as decided in ADR 0027. Optional architecture-specific assembly inside pinned Rust crates may be disabled by reproducible mode.
  • Browser v1 means browser-compatible output and a WASM-ready core, not an in-browser renderer or preview application.
  • Deferred beyond v0.1: H.264/MP4, video input, HDR/wide gamut, native 3D, interactive editor/player, remote package registry, network data sources, WASM/native plugin ABI, shader DSL, and full audio DSP.

Anim 0.1 preview · Documentation and examples are MIT licensed · Runtime binaries are proprietary