Your first video

Write a composition in one TSX file, look at three of its frames, and render it to an MP4.

View as Markdown

After this page you will have written a three-second vertical video in TypeScript and React, looked at its frames, and rendered it to an MP4. You need raea installed (Install raea) and nothing else: no project template, no npm install and no browser.

1. Write the composition

Make a folder and save this as hello.tsx in it:

hello.tsx
// check: frames 0,30,89
import { AbsoluteFill, Composition, Sequence, interpolate, registerRoot, useCurrentFrame } from "raea";

// One card: its text fades in over the first 12 frames of its Sequence.
function Card({ text }: { text: string }) {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 12], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ background: "#000", color: "#fff", justifyContent: "center", alignItems: "center", fontSize: 120 }}>
      <span style={{ opacity }}>{text}</span>
    </AbsoluteFill>
  );
}

// Three seconds at 30 fps, vertical: "Hello" for the first half, "world" for the second.
registerRoot(() => (
  <Composition
    id="hello"
    width={1080}
    height={1920}
    fps={30}
    durationInFrames={90}
    component={() => (
      <>
        <Sequence from={0} durationInFrames={45}>
          <Card text="Hello" />
        </Sequence>
        <Sequence from={45} durationInFrames={45}>
          <Card text="world" />
        </Sequence>
      </>
    )}
  />
));

What each part does:

  • registerRoot tells raea what the file contains. Here it is one Composition: 1080 by 1920 pixels, 30 frames a second, 90 frames long.
  • Sequence places its children on the timeline. Inside a Sequence, useCurrentFrame() counts from the Sequence's own start, so each Card fades in from its own frame 0.
  • interpolate(frame, [0, 12], [0, 1], ...) maps frames 0 to 12 onto an opacity of 0 to 1. The clamp options hold the value at 0 before frame 0 and at 1 after frame 12.

2. Look at three frames

Render the frames you care about as PNGs before you render the whole video:

Terminal
raea render hello.tsx --at 0,30,89 -o frames/

This writes frames/frame-00000.png, frame-00001.png and frame-00002.png: the first frame (nothing visible yet), frame 30 ("Hello" fully in) and the last frame ("world"). Open them and check that the text fits and nothing overlaps.

3. Check the text in a second

Terminal
raea check hello.tsx --quick

The quick check renders three stills and measures their text: clipped words, cramped lines, text outside the safe areas and text too small to read. It takes about a second, so run it after every save.

4. Render the video

Terminal
raea render hello.tsx -o hello.mp4

The MP4 is H.264 with the picture in yuv420p. On a Mac it is encoded by VideoToolbox; on Linux and Windows by openh264.

What to try next

  • Change fontSize, save, and run step 2 again. Every frame is computed from the code, so the same file always renders the same pixels.
  • Make the cards spring in instead of fading: see Compositions and frames.
  • Put footage under the cards and cue them on what is said: see Captions and cues on words.
  • Make a landscape version: add a second Composition with id="hello-wide", width={1920} and height={1080}, and render it with raea render hello.tsx --composition hello-wide -o hello-wide.mp4.