Procedural animation in Rust

Motion Canvas’ model — animations as coroutines, frames as await points — with Rust’s speed and a live editor.

Open the playground Get started See the showcase

use oxframe::prelude::*;

#[oxframe::scene]
async fn intro(view: View) {
    let square = view.add(Rect::new().size(200.0).x(-300.0).fill(color!("#e13238")));
    all((
        square.x().to(300.0, 1.0),
        square.radius().to(100.0, 1.0),
    ))
    .await;
}

fn main() {
    Project::new("intro").scene(intro()).main();
}

Scenes are coroutines

An animation is an async fn; every .await is a frame boundary. all, sequence, spawn and wait_until compose timing.

Deterministic

Fixed dt, a single-threaded executor and seeded randomness: the same code renders byte-identical frames anywhere.

Edit timing without recompiling

Markers, eases and tunables live in meta.json. Drag them in the editor; the code keeps only defaults.

Fast preview

oxframe dev rebuilds on save and reconnects the editor in about a second; scrubbing re-simulates without rendering.

GPU and CPU renderers

vello on wgpu for speed, tiny-skia as a byte-exact reference and for CI without a GPU.

Video out

mp4, webm with alpha, ProRes 4444 or PNG sequences through ffmpeg, with your soundtrack muxed in.