Pre-1.0: the API is not stable yet and may change from version to version. Pin the exact version in your Cargo.toml and check the changelog before upgrading.

Migrating from Revideo

Revideo is a fork of Motion Canvas built for rendering from code: scenes with variables, a render function and a player. Its scenes port to oxframe the same way as Motion Canvas scenes; this page covers what Revideo adds on top.

Scenes: the Motion Canvas guide applies

A Revideo scene is a Motion Canvas generator with a name: makeScene2D('card', function* …). Nodes, signals, all, waitFor and the rest map as in Migrating from Motion Canvas: yield* becomes .await, refs become the handles view.add returns, and the scene's name is the name of the async fn.

What Revideo adds, in oxframe

Revideooxframe
useScene().variables.get('name', 'Ada')ordinary Rust: read the value from the environment or a file in the scene, or build the project in main from it
renderVideo({ projectFile, variables, settings })NAME=Grace oxframe render --out welcome.mp4; a loop in a shell script or CI renders one video per input
rendering in headless Chromiumno browser: oxframe draws frames itself, on the GPU or with --cpu
parallel rendering in workersoxframe render --jobs 8: 2-second segments in parallel, the same bytes as one job
<Audio>, <Video>sound(…).play(), Audio::track(…), Video (feature video)
the player for your own siteno published player package yet: share the rendered video or a playground link

The same scene in both

A welcome title with a name passed in from outside, rendered to a file.

Revideo

// src/scenes/card.tsx
import {Txt, makeScene2D} from '@revideo/2d';
import {createRef, useScene, waitFor} from '@revideo/core';

export default makeScene2D('card', function* (view) {
  const name = useScene().variables.get('name', 'Ada');
  const title = createRef<Txt>();
  view.add(<Txt ref={title} text={() => `Welcome, ${name()}`} fontSize={96} fill={'white'} opacity={0} />);
  yield* title().opacity(1, 0.5);
  yield* waitFor(1.5);
});

// render.ts
import {renderVideo} from '@revideo/renderer';

await renderVideo({
  projectFile: './src/project.ts',
  variables: {name: 'Grace'},
  settings: {outFile: 'welcome.mp4'},
});

oxframe open it in the playground

use oxframe::prelude::*;

#[oxframe::scene]
pub async fn card(view: View) {
    // Revideo's variables: here the environment (or a file you read).
    let name = std::env::var("NAME").unwrap_or_else(|_| "Ada".into());
    let title = view.add(Txt::new().text(format!("Welcome, {name}")).display().opacity(0.0));
    title.opacity().to(1.0, 0.5).await;
    wait_for(1.5).await;
}

pub fn project() -> Project {
    Project::new("welcome").scene(card())
}
  • The variable becomes std::env::var("NAME") with a default, so the scene still runs when nothing is passed — in the editor and in the playground too.
  • renderVideo becomes the CLI: NAME=Grace oxframe render --out welcome.mp4.

Porting a project

  1. Port the scenes as in the Motion Canvas guide.
  2. Move each variable into Rust: the environment for one value, a JSON or CSV file for many (read it with std::fs and serde).
  3. Replace the render script with oxframe render in CI; --cpu runs on any runner.
  4. Run oxframe check for each input you render.

With an agent: the motion-canvas-to-oxframe skill covers Revideo scenes as well; install it with npx skills add oxygenframe/oxframe-sdk.

Edit this page on GitHub