revideo

repository·main·Indexed 26 days ago

https://github.com/midrender/revideo

A rendering engine that allows developers to create videos using TypeScript. It enables describing scenes with shapes, text, and media, providing a headless API for programmatic video generation and a React player for browser-based previews. The engine includes a 2D scene system via makeScene2D and a variety of components such as Circle, Code, Curve, Grid, Icon, and Img.

Tokens
54K
Snippets
154
Records
285
Agent score
87%

What's inside revideo

  1. Overview of Revideo

    main

    Revideo is an open-source framework designed for programmatic video editing. It allows developers to create video templates using TypeScript and render them with dynamic inputs.

    Key features include:

    • Template Creation: Build video templates in TypeScript.
    • Dynamic Rendering: Use an API to render templates with varying data.
    • Web Player: Embed a player component into websites to allow users to preview videos before exporting them to MP4.

    Common use cases include automating video editing tasks or building web-based video editors.

  2. Understand the Revideo project structure

    main

    A default Revideo project initialized via npm init @revideo@latest follows a standard TypeScript structure. The key files are:

    • src/scenes/: Contains scene files (e.g., example.tsx) where video templates are defined.
    • src/project.ts: The main project configuration file defining scenes and variables.
    • src/render.ts: The entry point for programmatic video rendering.
    • vite.config.ts: Configuration for the Vite-based visual editor server.
    • public/: Directory for local assets (videos, images, etc.) accessible via absolute paths in scenes.
    • package.json, tsconfig.json, package-lock.json: Standard project dependency and configuration files.
    my-project/
    ├── package.json
    ├── package-lock.json
    ├── tsconfig.json
    ├── vite.config.ts
    ├── src/
    │   ├── project.ts
    │   ├── render.ts
    │   ├── project.meta
    │   └── scenes/
    │       └── example.tsx
    └── public/
        └── my-video.mp4
  3. Exclude nodes from layout using Groups

    main

    Nodes that do not extend the Layout class (such as a standard Node) are ignored by the layout engine. This allows you to group nodes to apply transformations or filters without affecting the Flexbox hierarchy of the layout root. From the perspective of the layout, only the direct Layout descendants are considered siblings.

    <Layout direction={'column'} width={960} gap={40} layout>
      <Node opacity={0.1}>
        <Rect height={240} fill={'#ff6470'} />
        <Rect height={240} fill={'#ff6470'} />
      </Node>
      <Rect height={240} fill={'#ff6470'} />
    </Layout>
  4. Upgrade scenes to plain modules in 0.10.x

    main

    In version 0.10.x, scenes are no longer imported using the ?scene query parameter. Instead, they are treated as plain modules. To upgrade:

    1. Add the JSX pragma /** @jsxImportSource @revideo/2d/lib */ to the top of your scene file.
    2. Provide a name as the first argument to makeScene2D().
    3. Import the scene in your project file without the ?scene suffix.
    // example.tsx (0.10.x)
    /** @jsxImportSource @revideo/2d/lib */
    import {makeScene2D} from '@revideo/2d';
    
    export default makeScene2D('example', function* (view) {
      // ...
    });
    
    // project.ts (0.10.x)
    import example from './example';
  5. Install and set up a new Revideo project

    main

    To use Revideo, ensure you have Node.js version 16 or greater installed.

    Linux Users: You must also install nscd for ffmpeg support:

    sudo apt-get install nscd

    To create a new project, run the following command and select the default project when prompted:

    npm init @revideo@latest

    After creation, navigate to the project directory and install dependencies:

    cd <project-path>
    npm install
    npm init @revideo@latest
    cd <project-path>
    npm install
  6. Understand Scene Hierarchy and JSX usage

    main

    Scenes in Revideo are organized as a tree hierarchy of nodes, starting from the view (the scene view) at the root. This structure is similar to the DOM.

    Revideo uses a custom JSX runtime to allow writing XML-like markup for node instantiation. Note that Revideo does not use React; there is no virtual DOM or reconciliation. JSX tags map directly to Node instances.

    Equivalent ways to add nodes:

    Using JSX:

    view.add(
      <>
        <Circle />
        <Layout>
          <Rect />
          <Txt>Hi</Txt>
        </Layout>
      </>
    );

    Using standard instantiation:

    view.add([
      new Circle({}),
      new Layout({
        children: [
          new Rect({}),
          new Txt({text: 'Hi'}),
        ],
      }),
    ]);
    view.add(
      <>
        <Circle />
        <Layout>
          <Rect />
          <Txt>Hi</Txt>
        </Layout>
      </>
    );
  7. Ensure consistent emoji rendering with custom fonts

    main

    Emojis can render inconsistently across different browser versions. To ensure consistent emoji rendering in Revideo, you should explicitly specify a font that supports your desired emoji variants.

    To use a specific emoji font (like Noto Color Emoji) alongside a standard text font (like Lexend), follow these steps:

    1. Import the fonts via CSS in your src/global.css file using @import.
    2. Import the global.css file into your src/project.ts.
    3. Set the fontFamily property on your <Txt/> nodes, listing the text font first followed by the emoji font as a fallback.
    /* src/global.css */
    @import url('https://fonts.googleapis.com/css2?family=Lexend:wght@600&family=Noto+Color+Emoji&display=swap');
    
    /* src/project.ts */
    import {makeProject} from '@revideo/core';
    import example from './scenes/example?scene';
    import './global.css';
    
    export default makeProject({
      scenes: [example],
    });
    
    /* src/scenes/example.tsx */
    import {Txt, makeScene2D} from '@revideo/2d';
    import {waitFor} from '@revideo/core';
    
    export default makeScene2D('scene', function* (view) {
      yield view.add(
        <Txt text={'Hello 🚀'} fontFamily={"Lexend, 'Noto Color Emoji'"} />,
      );
    
      yield* waitFor(1);
    });
  8. Optimize performance with Object Pooling in Spawners

    main

    Generating a large number of new nodes inside a spawner every time a dependency changes can cause performance issues. To mitigate this, use an object pool by pre-creating a set of nodes and then using a spawner to slice the pool based on the current state.

    const count = createSignal(10);
    
    // Pre-create a pool of nodes
    const pool = range(64).map(i => (
      <Circle x={i * 32} width={32} height={32} fill={'lightseagreen'} />
    ));
    
    const layout = createRef<Layout>();
    view.add(
      <Layout layout ref={layout}>
        {/* Use the spawner to select a subset of the pool */}
        {() => pool.slice(0, count())}
      </Layout>
    );
    const count = createSignal(10);
    
    const pool = range(64).map(i => (
      <Circle x={i * 32} width={32} height={32} fill={'lightseagreen'} />
    ));
    
    const layout = createRef<Layout>();
    view.add(
      <Layout layout ref={layout}>
        {() => pool.slice(0, count())}
      </Layout>
    );
  9. Render a video via the Render Endpoint

    main

    You can trigger a video render by sending a POST request to the Revideo render endpoint using a specific deployment ID.

    Endpoint URL Format: https://api.re.video/v1/render/{your-deployment-id}

    Authentication: Include your API key in the Authorization header.

    Request Body Parameters:

    • variables (any): An object containing the parameters for your video.
    • callbackUrl (string, optional): A URL to which the API will send a POST request once rendering is complete. If omitted, the HTTP request will remain open until rendering finishes.
    • settings (object, optional): Configuration for the render job.
      • workers (number): The number of workers to use for parallelizing the rendering job.
    curl -X POST \
      https://api.re.video/v1/render/{your-deployment-id} \
      -H 'Content-Type: application/json' \
      -H 'Authorization: <your-api-key>' \
      -d '{
        "variables": {
          "text": "Hello world",
          "color": "#FF0000"
        },
        "settings": {
          "workers": 5
        }
      }'
  10. Create custom language components using `withDefaults`

    main

    To avoid repeating highlighter configuration, you can create a custom component for a specific language using the withDefaults helper function. This allows you to extend the Code component with your own default properties, such as a specific highlighter.

    import {Code, LezerHighlighter, withDefaults} from '@revideo/2d';
    import {parser} from '@lezer/rust';
    
    const RustHighlighter = new LezerHighlighter(parser);
    
    export const RustCode = withDefaults(Code, {
      highlighter: RustHighlighter,
    });
    import {RustCode} from '../nodes/RustCode';
    
    // ...
    
    view.add(
      <RustCode
        code={`
    fn hello() {
      println!("Hello!");
    }
    `}
      />,
    );