Scenes are coroutines
An animation is an async fn; every .await is a frame boundary. all, sequence, spawn and wait_until compose timing.
Motion Canvas’ model — animations as coroutines, frames as await points — with Rust’s
speed and a live editor.
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();
} An animation is an async fn; every .await is a frame boundary. all, sequence, spawn and wait_until compose timing.
Fixed dt, a single-threaded executor and seeded randomness: the same code renders byte-identical frames anywhere.
Markers, eases and tunables live in meta.json. Drag them in the editor; the code keeps only defaults.
oxframe dev rebuilds on save and reconnects the editor in about a second; scrubbing re-simulates without rendering.
vello on wgpu for speed, tiny-skia as a byte-exact reference and for CI without a GPU.
mp4, webm with alpha, ProRes 4444 or PNG sequences through ffmpeg, with your soundtrack muxed in.