Skip to content
Mohammad Oumari
← All projects
buildingbuildingengines2026source · private

MotionForge

A Rust motion-graphics engine — declarative JSON in, rendered video out.

Role · Solo — pipeline, renderer, CLI

RustVellowgpuTaffyFFmpegJSON

Renderer

Vello / wgpu

Authoring

Declarative JSON

Output

PNG · MP4 · WebM · MOV

Demo

  • Title intro: keyframes, easing, masked reveals

  • Audio visualiser driven by a muxed audio track

  • Taffy-backed flex layout animating in place

MotionForge turns a declarative JSON document into rendered motion graphics. There is no timeline UI and no node editor — the document is the source of truth, which makes compositions diffable, reviewable, and generatable by a program or an agent.

The project began with a deliberate core reset, and that reset is still the design discipline: a feature lands only when it fits cleanly into the staged pipeline. Nothing gets bolted on sideways.

The pipeline

JSON document
  -> mf-parser      read source-shaped JSON into raw schema data
  -> mf-compiler    validate, normalize, expand generators, resolve references,
                    build the dependency graph, prepare typed property sources
  -> mf-eval        compute one concrete frame from frame-native context
  -> mf-layout      Taffy-backed block/flex plus absolute positioning
  -> mf-transform   anchor, position, scale, rotation, skew, perspective
  -> mf-resolver    convert to renderer-ready scene data
  -> mf-render-vello
  -> PNG / frame sequence / MP4 / transparent WebM + MOV

Each stage has a contract, and the contracts are the point. The renderer consumes resolved scene data only — it cannot reach back for the document, which is what keeps it swappable. Evaluation is frame-native, so any frame can be computed independently without simulating the ones before it.

What it renders today

  • Variables, layers, children, and style/transform/property namespaces.
  • Frame-native context: $frame, $time, $fps, $duration, $progress.
  • References, numeric expressions, keyframes, easing, and dependency-cycle detection.
  • Vector nodes — rect, ellipse, line, polygon, star, path — plus .svg import that expands into native vector paths, so imported artwork animates and takes effects like anything else.
  • group nodes with hierarchy, clipping, opacity, grouped effects, and blend modes.
  • Text, image, video, and shader render providers. Video supports constant-rate playback_rate and an animatable time_remap curve for speed ramps, freeze frames, and reverse.
  • audio timeline nodes with trim, volume, and pan, muxed into MP4.
  • Reusable prefab definitions with child time scopes and time remapping.
  • Vector masks — clip and alpha mattes — with invert, feathering, and reveal presets.
  • Scene transition nodes: fade, slide, wipe, iris, radial, and zoom.
  • Linear, radial, and conic gradient paints.

Assets resolve from local paths, http(s), or data: URIs — images, video, audio, fonts, and .cube LUTs — fetched and decoded once, then cached. Remote fetching goes through an injectable AssetFetcher so the library has no opinion about networking.