# Remotion User Guide

Remotion lets you create **real MP4 videos using React**. You write components with JSX, animate them as a function of the current frame, preview everything live in a browser-based Studio, and render the result to a video file — locally, on a server, or in the cloud. If you can build a web page, you can build a video.

This guide is written for the people who *use* Remotion: motion designers, developers, and teams who want to generate videos programmatically. It covers installation, every core building block, the Studio, rendering, embedding videos in your own app, and the large ecosystem of helper packages. Architecture, deployment internals, and operational concerns live in the companion **Admin Guide**.

> [!NOTE]
> Remotion is React **19**-ready and ships as the `remotion` package (currently `4.0.472`) plus a family of `@remotion/*` packages. Everything in this guide is derived directly from the source code of those packages.

---

## Table of Contents

1. [What Remotion Is](#1-what-remotion-is)
2. [Quick Start](#2-quick-start)
3. [Installation & Requirements](#3-installation--requirements)
4. [Core Concepts](#4-core-concepts)
5. [Defining Compositions](#5-defining-compositions)
6. [Animating](#6-animating)
7. [Sequencing & Timing](#7-sequencing--timing)
8. [Working with Media](#8-working-with-media)
9. [Loading Data & Asynchronous Work](#9-loading-data--asynchronous-work)
10. [The Remotion Studio](#10-the-remotion-studio)
11. [Rendering Videos](#11-rendering-videos)
12. [Embedding Videos with the Player](#12-embedding-videos-with-the-player)
13. [The Package Ecosystem](#13-the-package-ecosystem)
14. [Cloud & Server Rendering](#14-cloud--server-rendering)
15. [Common Workflows](#15-common-workflows)
16. [Troubleshooting](#16-troubleshooting)
17. [FAQ](#17-faq)
18. [Licensing](#18-licensing)
19. [Command & Reference Tables](#19-command--reference-tables)

---

## 1. What Remotion Is

Remotion turns React into a video engine. The mental model is simple:

- A video is a sequence of **frames**.
- At any moment, the **current frame** is just a number.
- Your React component renders what the video should look like *at that frame*.
- To play or render, Remotion advances the frame number and captures each frame.

Because every frame is a pure function of its frame number, your animations are **deterministic**: the same frame always produces the same pixels, whether you preview it, render it locally, or render it across a thousand cloud workers.

```text
frame 0    frame 15    frame 30    frame 45
  │           │           │           │
  ▼           ▼           ▼           ▼
[render]   [render]    [render]    [render]   →  stitched into video.mp4
```

You get the full power of the web platform — CSS, SVG, Canvas, WebGL, fonts, the DOM — plus React's component model for composition and reuse.

> [!TIP]
> If you are new, the fastest way to understand Remotion is to scaffold a project (next section), open the Studio, and scrub the timeline while watching the code update.

---

## 2. Quick Start

The fastest path from nothing to a playing video is the project scaffolder.

=== "npm"

    ```bash
    npx create-video@latest
    ```

=== "pnpm"

    ```bash
    pnpm create video
    ```

=== "yarn"

    ```bash
    yarn create video
    ```

=== "bun"

    ```bash
    bun create video
    ```

This launches an interactive wizard that lets you pick a template (Hello World, blank, audiogram, TikTok-style captions, Next.js, Remotion Recorder, and more), then installs dependencies.

Once it finishes:

```bash
cd my-video
npx remotion studio
```

```text
Server ready - Local: http://localhost:3000
```

The **Studio** opens in your browser. You'll see a sidebar of compositions, a live preview, and a timeline you can scrub. Edit a file in `src/`, save, and the preview hot-reloads.

To render the default composition to a file:

```bash
npx remotion render
```

```text
 + Bundled  100%
 + Rendered 100%  out/HelloWorld.mp4
```

That's the whole loop: **scaffold → studio → edit → render**.

---

## 3. Installation & Requirements

### Adding Remotion to an existing project

Remotion is a set of npm packages. The core package is `remotion`; you almost always also want the CLI:

```bash
npm i remotion @remotion/cli
```

To render programmatically (instead of the CLI), add the renderer and bundler:

```bash
npm i @remotion/renderer @remotion/bundler
```

> [!IMPORTANT]
> All `remotion` and `@remotion/*` packages **must be on the exact same version**. Mixing versions causes hard-to-debug errors. When installing, pin exact versions (remove the `^`), e.g. `npm i remotion --save-exact`. Remotion warns at runtime if it detects multiple versions.

### Peer dependencies

The `remotion` package declares React as a peer dependency:

| Peer | Required version |
|------|------------------|
| `react` | `>=16.8.0` (React 19 supported and recommended) |
| `react-dom` | `>=16.8.0` |

### System requirements

| Requirement | Detail |
|-------------|--------|
| Node.js | Node 18+ (or Bun). The Studio and renderer run on Node/Bun. |
| Chrome/Chromium | Used for rendering. Remotion **downloads its own** Chrome Headless Shell automatically — you don't need a system Chrome. |
| FFmpeg | **Bundled** with `@remotion/renderer`. You do **not** install FFmpeg separately. |
| OS | macOS, Windows, and Linux are supported. On Linux, some shared libraries may be needed for headless Chrome (see the Admin Guide). |
| Disk | Renders write frames to a temp directory before stitching; ensure free space for long videos. |

> [!NOTE]
> Because Chrome and FFmpeg are managed by Remotion itself, a fresh `npm i` is usually all you need on a developer machine. Server and Docker setups have additional library requirements covered in the Admin Guide.

### Project anatomy

A typical Remotion project looks like this:

```text
my-video/
├── package.json
├── remotion.config.ts      # Studio/render configuration (Config.* calls)
├── public/                 # Static assets — referenced via staticFile()
└── src/
    ├── index.ts            # Calls registerRoot(RemotionRoot)
    ├── Root.tsx            # Lists your <Composition>s
    └── MyComp.tsx          # An actual video component
```

The **entry point** (`src/index.ts`) registers the root component:

```tsx
import {registerRoot} from 'remotion';
import {RemotionRoot} from './Root';

registerRoot(RemotionRoot);
```

---

## 4. Core Concepts

Before building, internalize these five ideas. Everything else composes from them.

### Frames and FPS

A composition has a frame rate (`fps`) and a length (`durationInFrames`). A 5-second video at 30 fps is `durationInFrames={150}`. You convert between seconds and frames yourself: `seconds * fps`.

### `useCurrentFrame()`

The single most important hook. It returns the frame currently being displayed or rendered, starting at `0`.

```tsx
import {useCurrentFrame} from 'remotion';

const frame = useCurrentFrame(); // 0, 1, 2, ...
```

Every animation derives from this number.

> [!IMPORTANT]
> Do **not** use `setInterval`, `requestAnimationFrame`, CSS animations/transitions, or `Date.now()` to animate in Remotion. Those are wall-clock based and are not deterministic across frames — they will not render correctly. Drive *all* motion from `useCurrentFrame()`.

### `useVideoConfig()`

Returns the metadata of the composition you're inside:

```tsx
import {useVideoConfig} from 'remotion';

const {width, height, fps, durationInFrames} = useVideoConfig();
```

### Compositions

A `<Composition>` registers a renderable video: an id, dimensions, fps, duration, and the component to render. Compositions appear in the Studio sidebar and are the targets you render from the CLI.

### The Root

`registerRoot()` tells Remotion which component lists your compositions. That component returns one or more `<Composition>` (and optionally `<Folder>`) elements.

```tsx
import {Composition} from 'remotion';
import {MyComp} from './MyComp';

export const RemotionRoot = () => {
  return (
    <Composition
      id="MyComp"
      component={MyComp}
      durationInFrames={150}
      fps={30}
      width={1920}
      height={1080}
    />
  );
};
```

---

## 5. Defining Compositions

### `<Composition>`

Registers a video so it shows in the Studio and can be rendered.

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `id` | `string` | Yes | URL-safe unique identifier; the render target and Studio entry name. |
| `component` | component | Yes* | The React component to render. |
| `lazyComponent` | `() => Promise<{default}>` | Yes* | Lazy alternative to `component` (code-splitting). |
| `durationInFrames` | `number` | Yes** | Length of the video in frames. |
| `fps` | `number` | Yes** | Frames per second. |
| `width` | `number` | Yes** | Pixel width. |
| `height` | `number` | Yes** | Pixel height. |
| `defaultProps` | object | No | Default props passed to the component (editable in the Studio). |
| `schema` | Zod object | No | A Zod schema used to validate and edit props visually in the Studio. |
| `calculateMetadata` | function | No | Compute dimensions/fps/duration/props at runtime (e.g. from a video file or API). |

\* Provide exactly one of `component` or `lazyComponent`.
\** Required unless a `calculateMetadata` function supplies them.

```tsx
<Composition
  id="Promo"
  component={Promo}
  durationInFrames={300}
  fps={30}
  width={1080}
  height={1080}
  defaultProps={{title: 'Hello'}}
/>
```

> [!TIP]
> `id` must be URL-safe — it becomes part of routes and output filenames. Stick to letters, numbers, and dashes.

### `calculateMetadata` — dynamic durations

Often the duration depends on data: the length of an audio file, a fetched dataset, or props. `calculateMetadata` runs before rendering and can return any of `durationInFrames`, `fps`, `width`, `height`, `props`, and default render settings.

```tsx
import type {CalculateMetadataFunction} from 'remotion';

const calc: CalculateMetadataFunction<{src: string}> = async ({props}) => {
  const durationInSeconds = await fetchAudioDuration(props.src);
  return {
    durationInFrames: Math.floor(durationInSeconds * 30),
    fps: 30,
  };
};

<Composition id="Audiogram" component={Audiogram} schema={mySchema}
  width={1080} height={1080} calculateMetadata={calc} defaultProps={{src: ''}} />
```

The function receives `{defaultProps, props, abortSignal, compositionId, isRendering}` and may return its result synchronously or as a Promise. It can also override default render settings: `defaultCodec`, `defaultOutName`, `defaultVideoImageFormat`, `defaultPixelFormat`, `defaultProResProfile`, and `defaultSampleRate`.

### `<Still>`

For single-image outputs (thumbnails, social cards, OG images), use `<Still>`. It's like `<Composition>` but has no `fps` or `durationInFrames` — a still is one frame.

```tsx
import {Still} from 'remotion';

<Still id="Thumbnail" component={Thumbnail} width={1200} height={630}
  defaultProps={{title: 'Launch day'}} />
```

### `<Folder>`

Groups compositions in the Studio sidebar for organization. It has no effect on rendering.

```tsx
import {Folder} from 'remotion';

<Folder name="Marketing">
  <Composition id="Promo" {/* ... */} />
  <Composition id="Teaser" {/* ... */} />
</Folder>
```

### Type-safe, editable props with Zod

Pass a Zod `schema` and Remotion renders an editable form for `defaultProps` in the Studio, validates input props, and infers your component's prop types.

```tsx
import {z} from 'zod';

const promoSchema = z.object({
  title: z.string(),
  accentColor: z.string(),
});

export const RemotionRoot = () => (
  <Composition
    id="Promo"
    component={Promo}
    schema={promoSchema}
    defaultProps={{title: 'Hello', accentColor: '#0b84f3'}}
    durationInFrames={150} fps={30} width={1920} height={1080}
  />
);
```

---

## 6. Animating

Animation in Remotion is "given the current frame, compute a value." Two functions do most of the work: `interpolate` and `spring`.

### `interpolate()`

Maps an input range to an output range — the workhorse for fades, moves, and scales.

```tsx
import {interpolate, useCurrentFrame} from 'remotion';

const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 30], [0, 1]);
```

Signature:

```ts
interpolate(input, inputRange, outputRange, options?)
```

| Option | Type | Default | Meaning |
|--------|------|---------|---------|
| `easing` | easing fn **or array of fns** | linear | Curve applied between keyframes. As an array, one entry per segment (`inputRange.length - 1`). |
| `extrapolateLeft` | `'extend' \| 'clamp' \| 'identity' \| 'wrap'` | `'extend'` | Behavior for inputs below the range. |
| `extrapolateRight` | same | `'extend'` | Behavior for inputs above the range. |
| `posterize` | `number` | — | Snap the input to steps of this size (choppy/stop-motion look). |

By default values **extend** past the range. To hold the start/end values, clamp:

```tsx
const opacity = interpolate(frame, [0, 30], [0, 1], {
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp',
});
```

> [!WARNING]
> `inputRange` must be **strictly monotonically increasing**. `interpolate(frame, [0, 30, 30], ...)` throws `inputRange must be strictly monotonically increasing`. `inputRange` and `outputRange` must also have the **same length**.

#### Multi-segment interpolation

Chain keyframes by passing more than two points (fade in, hold, fade out):

```tsx
const opacity = interpolate(frame, [0, 20, 130, 150], [0, 1, 1, 0]);
```

#### String and tuple output ranges

`interpolate` can animate CSS strings (`scale`, `translate`, `rotate`) and numeric tuples directly:

```tsx
// Animate a CSS transform value
const transform = interpolate(frame, [0, 30], ['translateY(0px)', 'translateY(100px)']);
// ⚠ Strings must be the same kind/units across the range.

// Animate a tuple (e.g. an [r, g, b] color)
const rgb = interpolate(frame, [0, 30], [[255, 0, 0], [0, 0, 255]]);
```

### `Easing`

The `Easing` module provides curves to pass to `interpolate`'s `easing` option.

```tsx
import {interpolate, Easing} from 'remotion';

const x = interpolate(frame, [0, 30], [0, 200], {
  easing: Easing.bezier(0.25, 0.1, 0.25, 1),
  extrapolateRight: 'clamp',
});
```

| Easing | Description |
|--------|-------------|
| `Easing.linear` | No easing. |
| `Easing.ease` | Default browser-style ease. |
| `Easing.quad`, `Easing.cubic` | Power curves. |
| `Easing.poly(n)` | Generic power curve of degree `n`. |
| `Easing.sin`, `Easing.circle`, `Easing.exp` | Trigonometric/exponential curves. |
| `Easing.elastic(bounciness)` | Springy overshoot. |
| `Easing.back(s)` | Slight backward anticipation. |
| `Easing.bounce` | Bouncing ball. |
| `Easing.bezier(x1,y1,x2,y2)` | Cubic Bézier (CSS-style). |
| `Easing.step0`, `Easing.step1` | Step functions. |
| `Easing.in(fn)`, `Easing.out(fn)`, `Easing.inOut(fn)` | Modifiers that flip/mirror a curve. |

### `spring()`

Physics-based animation that feels natural. Always pass `frame` and `fps`.

```tsx
import {spring, useCurrentFrame, useVideoConfig} from 'remotion';

const frame = useCurrentFrame();
const {fps} = useVideoConfig();

const scale = spring({frame, fps, config: {damping: 200}});
```

| Parameter | Type | Default | Meaning |
|-----------|------|---------|---------|
| `frame` | `number` | — | The current frame (required). |
| `fps` | `number` | — | Frames per second (required). |
| `config.damping` | `number` | `10` | Higher = less oscillation. Must be `> 0`. |
| `config.mass` | `number` | `1` | Heavier = slower. |
| `config.stiffness` | `number` | `100` | Higher = snappier. |
| `config.overshootClamping` | `boolean` | `false` | Prevent overshooting past `to`. |
| `from` | `number` | `0` | Start value. |
| `to` | `number` | `1` | End value. |
| `durationInFrames` | `number` | — | Stretch/squash the spring to a fixed length. |
| `delay` | `number` | `0` | Delay the animation by N frames. |
| `reverse` | `boolean` | `false` | Play the spring backwards. |

> [!TIP]
> A spring returns ~0 → ~1 by default. Combine it with `interpolate` to map that progress onto any range, or pass `from`/`to` directly. `measureSpring()` (also exported) tells you a spring's natural duration in frames.

### `interpolateColors()`

Interpolates between colors (hex, `rgb`, `rgba`, `hsl`):

```tsx
import {interpolateColors, useCurrentFrame} from 'remotion';

const color = interpolateColors(useCurrentFrame(), [0, 30], ['#ff0000', '#0000ff']);
```

### `random()`

`Math.random()` is **not** allowed — it differs every call and breaks deterministic rendering. Use Remotion's seeded `random()` instead.

```tsx
import {random} from 'remotion';

const jitter = random('particle-3') * 10; // same seed → same value, every render
```

Pass a string or number seed and you always get the same pseudo-random value in `[0, 1)`. Passing `null` falls back to true randomness (rarely what you want).

> [!CAUTION]
> Calling `random(null)` (or `Math.random()`) inside a component makes renders non-reproducible and can cause flicker between frames during multi-threaded rendering. Always seed.

---

## 7. Sequencing & Timing

### `<Sequence>`

Time-shifts its children: they see frame `0` when the sequence starts, and only appear during their window.

```tsx
import {Sequence} from 'remotion';

<Sequence from={30} durationInFrames={60}>
  <Title />
</Sequence>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `from` | `number` | `0` | Frame at which children start (can be negative). |
| `durationInFrames` | `number` | `Infinity` | How long children are mounted. Must be positive. |
| `name` | `string` | — | Label shown on the Studio timeline. |
| `layout` | `'absolute-fill' \| 'none'` | `'absolute-fill'` | Whether to wrap children in an absolutely positioned div. |
| `premountFor` | `number` | — | Mount (hidden) N frames early so assets/data are ready. |
| `postmountFor` | `number` | — | Keep mounted (hidden) N frames after it ends. |
| `style` | CSS | — | Applied to the wrapper (only when `layout="absolute-fill"`). |
| `showInTimeline` | `boolean` | `true` | Whether to display this sequence on the timeline. |

Inside a sequence, `useCurrentFrame()` returns the *local* frame (0-based from `from`):

```tsx
const Title = () => {
  const frame = useCurrentFrame(); // 0 when the parent <Sequence from={30}> begins
  // ...
};
```

> [!NOTE]
> `premountFor` is invaluable when a child does data fetching or media loading — it renders the child invisibly ahead of time so it's "warm" when it becomes visible. `layout="none"` is for when you don't want the wrapping div (e.g. wrapping a `<tr>` or text).

### `<Series>`

Plays children one after another, auto-computing each one's `from` from the previous durations. No manual offset math.

```tsx
import {Series} from 'remotion';

<Series>
  <Series.Sequence durationInFrames={40}><Intro /></Series.Sequence>
  <Series.Sequence durationInFrames={60}><Body /></Series.Sequence>
  <Series.Sequence durationInFrames={40} offset={-10}><Outro /></Series.Sequence>
</Series>
```

`<Series.Sequence>` props: `durationInFrames` (required), `offset` (shift relative to the previous clip — negative overlaps), plus `layout`, `name`, and `style`.

### `<Loop>`

Repeats its children.

```tsx
import {Loop} from 'remotion';

<Loop durationInFrames={30} times={4}>
  <Pulse />
</Loop>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `durationInFrames` | `number` | — | Length of one iteration. |
| `times` | `number` | `Infinity` | How many times to loop (integer ≥ 0). |
| `layout` | `'absolute-fill' \| 'none'` | `'absolute-fill'` | Wrapper behavior. |

Remotion automatically caps `times` so the loop never exceeds the composition's duration.

### `<Freeze>`

Freezes its children at a specific frame.

```tsx
import {Freeze} from 'remotion';

<Freeze frame={60}>
  <Animation />
</Freeze>
```

It also accepts an `active` boolean to toggle freezing on and off.

---

## 8. Working with Media

### Layout: `<AbsoluteFill>`

A div that fills its parent absolutely (top/left/right/bottom = 0, flex column). The standard way to stack full-screen layers.

```tsx
import {AbsoluteFill} from 'remotion';

<AbsoluteFill style={{backgroundColor: 'black', justifyContent: 'center'}}>
  <Title />
</AbsoluteFill>
```

### Images: `<Img>`

Like `<img>`, but Remotion waits for it to load before capturing the frame (no half-loaded images in your render).

```tsx
import {Img, staticFile} from 'remotion';

<Img src={staticFile('logo.png')} />
```

### Static files: `staticFile()`

References a file in your project's `public/` folder. **Never** build asset paths by hand.

```tsx
staticFile('images/logo.png'); // → /images/logo.png (correctly encoded)
```

> [!CAUTION]
> `staticFile()` rejects remote URLs, relative paths (`./`, `..`), absolute filesystem paths, and a leading `public/`. For remote assets, pass the URL directly to `src` without wrapping it. Since Remotion 4, `staticFile()` performs URL encoding for you — don't pre-encode.

### Audio: `<Audio>`

Plays audio in preview and includes it in the render.

```tsx
import {Audio, staticFile} from 'remotion';

<Audio src={staticFile('music.mp3')} volume={0.5} />
```

Key props: `volume` (number **or** a function `(frame) => number` for fades), `trimBefore` / `trimAfter` (trim the clip in frames), `playbackRate`, `muted`, `toneFrequency`, and `loopVolumeCurveBehavior`.

```tsx
// Fade the music in over the first 30 frames
<Audio src={staticFile('music.mp3')}
  volume={(f) => interpolate(f, [0, 30], [0, 1], {extrapolateRight: 'clamp'})} />
```

### Video: `<OffthreadVideo>` and `<Video>`

For embedding video, `<OffthreadVideo>` is the recommended component for **rendering** — it extracts exact frames off the main thread for frame-accurate, reliable output. `<Video>` (HTML5) is also available.

```tsx
import {OffthreadVideo, staticFile} from 'remotion';

<OffthreadVideo src={staticFile('clip.mp4')} />
```

| Prop | Type | Description |
|------|------|-------------|
| `src` | `string` | Required. Local (via `staticFile`) or remote URL. |
| `trimBefore` | `number` | Trim N frames from the start. *(replaces the deprecated `startFrom`)* |
| `trimAfter` | `number` | Trim to end at frame N. *(replaces the deprecated `endAt`)* |
| `volume` | number \| function | Volume, optionally animated per frame. |
| `playbackRate` | `number` | Speed multiplier. |
| `muted` | `boolean` | Mute audio. |
| `transparent` | `boolean` | Render with alpha (e.g. WebM/ProRes pipelines). |
| `toneMapped` | `boolean` | Apply tone mapping for HDR sources. |
| `toneFrequency` | `number` | Pitch correction factor. |
| `playbackRate` | `number` | Speed up / slow down. |
| `audioStreamIndex` | `number` | Choose which audio track to use. |
| `onVideoFrame` | function | Callback per frame (e.g. to draw to a canvas). |
| `delayRenderTimeoutInMilliseconds` / `delayRenderRetries` | `number` | Tune the per-frame fetch timeout/retries. |

> [!IMPORTANT]
> `startFrom`/`endAt` were renamed to `trimBefore`/`trimAfter`. The old names still work but are deprecated — prefer the new ones in new code.

### Animated images & GIFs

- `<AnimatedImage>` (core) plays animated AVIF/WebP/APNG.
- `<Gif>` from `@remotion/gif` plays GIFs frame-accurately (see the ecosystem section).

### `<IFrame>`

Like `<iframe>`, but participates in Remotion's load-waiting so the render doesn't capture a blank frame.

---

## 9. Loading Data & Asynchronous Work

Rendering is frame-by-frame and synchronous by nature, so Remotion needs to know when your async work (data fetch, font load, image decode) is done. That's what `delayRender` / `continueRender` do.

### `delayRender()` and `continueRender()`

Call `delayRender()` to tell Remotion "don't capture this frame yet," do your async work, then call `continueRender(handle)`.

```tsx
import {delayRender, continueRender, useCurrentFrame} from 'remotion';
import {useEffect, useState} from 'react';

const Data = () => {
  const [data, setData] = useState(null);
  const [handle] = useState(() => delayRender('Fetching data'));

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then((res) => res.json())
      .then((json) => {
        setData(json);
        continueRender(handle);
      });
  }, [handle]);

  return data ? <Chart data={data} /> : null;
};
```

| `delayRender` option | Type | Default | Meaning |
|----------------------|------|---------|---------|
| `timeoutInMilliseconds` | `number` | `30000` | How long to wait before failing the frame. |
| `retries` | `number` | `0` | Retry the frame on timeout. |

> [!WARNING]
> If a `delayRender()` handle is never cleared, the render fails with: *"A delayRender() … was called but not cleared after 30000ms."* Every `delayRender()` must be matched by a `continueRender()` (or `cancelRender()`). Pass a descriptive label so timeouts point you to the culprit.

### `cancelRender()`

Abort the entire render with a clear error (e.g. when a fetch fails irrecoverably):

```tsx
import {cancelRender} from 'remotion';

fetch(url).catch((err) => cancelRender(err));
```

### `prefetch()`

Preloads a remote asset (audio/video/image) and returns `{free, waitUntilDone}`. Useful in the Player to fetch media before playback so it doesn't stutter.

### Fonts

Use `@remotion/google-fonts` for Google Fonts or `@remotion/fonts`' `loadFont()` for local fonts — both integrate with the load-waiting system so text is ready before capture (see the ecosystem section).

---

## 10. The Remotion Studio

The Studio is a local web app for previewing and configuring your videos. Start it with:

```bash
npx remotion studio
# or specify an entry point:
npx remotion studio src/index.ts
```

```text
Server ready - Local: http://localhost:3000
```

What you get:

- **Composition list** — every `<Composition>`/`<Still>`, organized by `<Folder>`.
- **Live preview** — hot-reloads on save.
- **Timeline** — scrub frames; sequences, audio, and video show as tracks.
- **Props editor** — if a composition has a Zod `schema`, edit `defaultProps` with a visual form and validation.
- **Render button** — render directly from the UI, with a queue.
- **Visual editing helpers** — rulers, guides, keyboard shortcuts.

> [!TIP]
> The `preview` command is an alias for `studio`. Common flags include `--port` to set the port and `--props` to pass input props.

Studio behavior is configured in `remotion.config.ts` via `Config.*` (covered in the Admin Guide), for example `Config.setStudioPort(3001)` or `Config.setKeyboardShortcutsEnabled(false)`.

---

## 11. Rendering Videos

### Render a video

```bash
npx remotion render <entry-point?> <composition-id?> <output?>
```

Examples:

```bash
npx remotion render                       # render the only/default composition
npx remotion render MyComp                # render a specific composition
npx remotion render MyComp out/video.mp4  # custom output path
```

```text
 + Bundled  100%
 + Rendered 150/150
 + out/video.mp4 (2.1 MB)
```

### Render a still image

```bash
npx remotion still MyStill out/thumb.png --frame=30
```

### List compositions

```bash
npx remotion compositions
```

```text
The following compositions are available:
  Promo
  Teaser
  Thumbnail
```

### Common render flags

These map directly to the configuration options; pass them on the CLI or set them in `remotion.config.ts`.

| Flag | Purpose |
|------|---------|
| `--props='{"k":"v"}'` or `--props=props.json` | Input props for the composition. |
| `--codec=h264\|h265\|vp8\|vp9\|prores\|gif` | Output codec. |
| `--image-format=jpeg\|png` | Frame image format (png for transparency). |
| `--jpeg-quality=80` | JPEG frame quality (0–100). |
| `--crf=<n>` | Quality/Constant Rate Factor (codec-dependent). |
| `--scale=2` | Scale output dimensions by a factor. |
| `--frames=0-30` or `--frames=30` | Render a frame range or single frame. |
| `--concurrency=<n>` | Parallel rendering tabs (default: half your CPU threads). |
| `--muted` | Drop the audio track. |
| `--pixel-format=yuva420p` | Pixel format (e.g. for transparency). |
| `--every-nth-frame=2` | For GIFs: pick every Nth frame. |
| `--log=verbose` | Verbose logging (browser logs, IO). |
| `--gl=angle\|swangle\|egl\|...` | OpenGL backend for Chrome. |
| `--scale`, `--width`/`--height` overrides | Dimension overrides. |

> [!NOTE]
> Transparency: render with `--codec=vp8`/`vp9` (WebM) or `prores` and `--image-format=png` / `--pixel-format=yuva420p`. See the Admin Guide's encoding section for the full matrix.

### Programmatic rendering (Node SSR)

For build pipelines and servers, render in code with `@remotion/bundler` + `@remotion/renderer`:

```ts
import {bundle} from '@remotion/bundler';
import {selectComposition, renderMedia} from '@remotion/renderer';

const serveUrl = await bundle({entryPoint: './src/index.ts'});

const composition = await selectComposition({
  serveUrl,
  id: 'MyComp',
  inputProps: {title: 'Hello'},
});

await renderMedia({
  serveUrl,
  composition,
  codec: 'h264',
  outputLocation: 'out/video.mp4',
  inputProps: {title: 'Hello'},
});
```

Key functions: `bundle()`, `getCompositions()` / `selectComposition()`, `renderMedia()`, `renderStill()`, `renderFrames()`, `stitchFramesToVideo()`, `ensureBrowser()`, and `makeCancelSignal()`. Full option references are in the Admin Guide.

---

## 12. Embedding Videos with the Player

`@remotion/player` lets you embed an interactive Remotion video inside any React app — no rendering, it plays your composition live in the browser.

```bash
npm i @remotion/player
```

```tsx
import {Player} from '@remotion/player';
import {MyComp} from './MyComp';

export const App = () => (
  <Player
    component={MyComp}
    durationInFrames={150}
    compositionWidth={1920}
    compositionHeight={1080}
    fps={30}
    controls
    style={{width: '100%'}}
    inputProps={{title: 'Hello'}}
  />
);
```

Selected `<Player>` props:

| Prop | Type | Description |
|------|------|-------------|
| `component` / `lazyComponent` | component | The composition to play. |
| `durationInFrames`, `fps`, `compositionWidth`, `compositionHeight` | `number` | Video metadata (required). |
| `inputProps` | object | Props for your component. |
| `controls` | `boolean` | Show the built-in control bar. |
| `autoPlay` | `boolean` | Start playing on mount. |
| `loop` | `boolean` | Loop playback. |
| `clickToPlay`, `doubleClickToFullscreen`, `spaceKeyToPlayOrPause` | `boolean` | Interaction toggles. |
| `allowFullscreen` | `boolean` | Enable fullscreen. |
| `showVolumeControls` | `boolean` | Show volume UI. |
| `playbackRate` | `number` | Speed. |
| `initialFrame` | `number` | Frame to start at. |
| `inFrame` / `outFrame` | `number \| null` | Limit playback to a sub-range. |
| `renderLoading`, `renderPoster` | functions | Custom loading/poster UI. |
| `showPosterWhenPaused` / `...WhenEnded` / `...WhenBuffering` | `boolean` | When to show the poster. |
| `renderPlayPauseButton`, `renderFullscreenButton`, `renderMuteButton`, `renderVolumeSlider`, `renderCustomControls` | functions | Fully custom controls. |
| `numberOfSharedAudioTags` | `number` | Audio tag pool for autoplay reliability. |
| `schema` | Zod | Validate `inputProps`. |
| `acknowledgeRemotionLicense` | `boolean` | Acknowledge the license (suppresses the console notice). |

Control the Player imperatively with a ref and the `useCurrentPlayerFrame` / `usePlayer` helpers, and listen to events (`play`, `pause`, `seeked`, `ended`, etc.) via `addEventListener` on the ref.

`<Thumbnail>` is a sibling component that renders a single frame as a poster image.

> [!TIP]
> The Player's `component` takes your composition component directly — **not** a `<Composition>`. Do not mount `<Composition>` inside a Player; Remotion throws an explicit error if you do.

---

## 13. The Package Ecosystem

Remotion ships dozens of `@remotion/*` packages. Install only what you use; each is versioned in lockstep with `remotion`. Here are the ones you'll reach for most.

### Animation & transitions

**`@remotion/transitions`** — animate *between* scenes with `<TransitionSeries>`.

```tsx
import {TransitionSeries, linearTiming, springTiming} from '@remotion/transitions';
import {fade} from '@remotion/transitions/fade';
import {slide} from '@remotion/transitions/slide';

<TransitionSeries>
  <TransitionSeries.Sequence durationInFrames={60}><A /></TransitionSeries.Sequence>
  <TransitionSeries.Transition presentation={fade()} timing={linearTiming({durationInFrames: 30})} />
  <TransitionSeries.Sequence durationInFrames={60}><B /></TransitionSeries.Sequence>
</TransitionSeries>
```

Built-in presentations include: `fade`, `slide`, `wipe`, `flip`, `clockWipe`, `iris`, `none`, `crossZoom`, `dreamyZoom`, `filmBurn`, `linearBlur`, `zoomBlur`, `book-flip`, `crosswarp`, `dissolve`, `ripple`, `swap`, `zoom-in-out`. Timing functions: `linearTiming`, `springTiming`. Hook: `useTransitionProgress`.

**`@remotion/animation-utils`** — helpers like `makeTransform` and style interpolation for building CSS `transform` strings cleanly.

### Graphics & drawing

| Package | What it gives you |
|---------|-------------------|
| `@remotion/shapes` | Components `<Rect>`, `<Circle>`, `<Ellipse>`, `<Triangle>`, `<Star>`, `<Polygon>`, `<Pie>`, `<Heart>`, `<Arrow>` + `make*` functions returning raw path data. |
| `@remotion/paths` | SVG path math: `getLength`, `getPointAtLength`, `getTangentAtLength`, `evolvePath`, `interpolatePath`, `warpPath`, `translatePath`, `scalePath`, `reversePath`, `getBoundingBox`, `getSubpaths`, and more. |
| `@remotion/noise` | `noise2D`, `noise3D`, `noise4D` simplex noise for organic motion. |
| `@remotion/svg-3d-engine` | Project and extrude SVG paths in 3D. |
| `@remotion/effects` | Visual effects like `rings` and `zigzag`. |
| `@remotion/motion-blur` | `<CameraMotionBlur>` and `<Trail>` for motion-blur/echo effects. |
| `@remotion/rounded-text-box`, `@remotion/starburst`, `@remotion/light-leaks`, `@remotion/animated-emoji` | Specialized visual building blocks. |

### Rendering engines for other tech

| Package | Use |
|---------|-----|
| `@remotion/three` | `<ThreeCanvas>` — render react-three-fiber / Three.js scenes. |
| `@remotion/skia` | `<SkiaCanvas>` — React Native Skia drawing. |
| `@remotion/lottie` | `<Lottie>` + `getLottieMetadata` — play Lottie animations frame-accurately. |
| `@remotion/gif` | `<Gif>`, `getGifDurationInSeconds`, `preloadGif` — frame-accurate GIFs. |
| `@remotion/rive` | Render Rive animations. |

### Audio, captions & media analysis

| Package | Use |
|---------|-----|
| `@remotion/media-utils` | `getAudioData`, `useAudioData`, `visualizeAudio` (waveform/spectrum for audiograms), `getVideoMetadata`, `getImageDimensions`, `createSmoothSvgPath`. |
| `@remotion/captions` | `Caption` type, `parseSrt`, `serializeSrt` for subtitles. |
| `@remotion/install-whisper-cpp`, `@remotion/openai-whisper`, `@remotion/elevenlabs` | Generate captions / speech via Whisper and ElevenLabs. |
| `@remotion/media-parser` | `parseMedia` / `downloadAndParseMedia` — pure-JS media metadata + frame parsing. |
| `@remotion/webcodecs` | `convertMedia`, encoders/decoders — in-browser media conversion via WebCodecs. |
| `@remotion/media` | New `experimental_Audio` / `experimental_Video` components (next-gen media pipeline). |

### Fonts & assets

| Package | Use |
|---------|-----|
| `@remotion/google-fonts` | `getAvailableFonts` and per-font `loadFont()` — load Google Fonts with load-waiting built in. |
| `@remotion/fonts` | `loadFont()` for local font files. |
| `@remotion/preload` | `preloadAudio`, `preloadVideo`, `preloadImage`, `preloadFont`, `resolveRedirect` — warm up remote assets for the Player. |
| `@remotion/layout-utils` | `measureText`, `fitText`, `fillTextBox` — size text precisely (auto-fit headlines). |

### Tooling

`@remotion/tailwind` / `@remotion/tailwind-v4` (Tailwind support), `@remotion/enable-scss` (SCSS), `@remotion/eslint-plugin` and `@remotion/eslint-config` (linting), `@remotion/zod-types` (extra Zod types like color pickers in the Studio), `@remotion/mcp` and `@remotion/skills` (AI/agent integration).

---

## 14. Cloud & Server Rendering

For scale, render in the cloud. These are summarized here for users; full setup is in the Admin Guide.

### AWS Lambda — `@remotion/lambda`

Render thousands of videos in parallel, each across many Lambda invocations.

```ts
import {renderMediaOnLambda, getRenderProgress} from '@remotion/lambda/client';

const {renderId, bucketName} = await renderMediaOnLambda({
  region: 'us-east-1',
  functionName: 'remotion-render-...',
  serveUrl: 'https://...your-deployed-site...',
  composition: 'MyComp',
  codec: 'h264',
  inputProps: {title: 'Hello'},
});

const progress = await getRenderProgress({renderId, bucketName, functionName, region});
```

You first deploy a Lambda function (`deployFunction`) and a bundled site (`deploySite`), then render against them. Output lands in S3. The same flags you use locally (codec, crf, scale, frame range, etc.) are accepted as input fields.

### Google Cloud Run — `@remotion/cloudrun`

The GCP equivalent: deploy a Cloud Run service and a site, then render. Note: the Cloud Run integration is offered as an alpha by the Remotion team.

### Self-hosted / containers

You can also run the Node SSR APIs (Section 11) on your own server or in Docker. The Admin Guide covers Dockerfiles and the required system libraries.

---

## 15. Common Workflows

### A typical title animation

```tsx
import {AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig} from 'remotion';

export const Title: React.FC<{text: string}> = ({text}) => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();

  const enter = spring({frame, fps, config: {damping: 200}});
  const opacity = interpolate(frame, [0, 20], [0, 1], {extrapolateRight: 'clamp'});

  return (
    <AbsoluteFill style={{justifyContent: 'center', alignItems: 'center'}}>
      <h1 style={{opacity, transform: `scale(${enter})`}}>{text}</h1>
    </AbsoluteFill>
  );
};
```

### An audiogram (waveform synced to audio)

1. Load the audio with `useAudioData` from `@remotion/media-utils`.
2. Use `visualizeAudio` to get amplitude bands for the current frame.
3. Render bars/shapes from those bands.
4. Add `<Audio src={...} />` so the sound is in the output.
5. Use `calculateMetadata` to set `durationInFrames` from the audio length.

The `audiogram` starter template wires all of this up — scaffold it with `npx create-video@latest`.

### Captioned vertical video (TikTok style)

1. Generate captions with `@remotion/install-whisper-cpp` (or import an `.srt` and `parseSrt`).
2. Render words/segments timed with `<Sequence>` based on caption timestamps.
3. Use `<OffthreadVideo>` for the background clip.

The `tiktok` template demonstrates the full pipeline.

### Data-driven videos at scale

1. Build one parameterized composition with a Zod `schema`.
2. Render once per dataset by passing different `--props` (CLI) or `inputProps` (Lambda/SSR).
3. Use `calculateMetadata` to adapt duration/size per dataset.

---

## 16. Troubleshooting

### Error: `A delayRender() "<label>" was called but not cleared after 30000ms`

**Cause:** An async task started with `delayRender()` never called `continueRender()` (the promise rejected, a condition was never met, or the work genuinely takes longer than the timeout).
**Solution:** Ensure every `delayRender()` is matched by a `continueRender(handle)` on every code path, including errors. For genuinely slow work, raise the timeout: `delayRender('label', {timeoutInMilliseconds: 60000})` or `Config.setDelayRenderTimeoutInMilliseconds(60000)`.
**Prevention:** Always pass a descriptive label; the timeout message includes it and the call stack.

### Error: `inputRange must be strictly monotonically increasing but got [...]`

**Cause:** An `interpolate()` `inputRange` has equal or decreasing values.
**Solution:** Make every value strictly larger than the last (e.g. `[0, 30, 60]`, never `[0, 30, 30]`).
**Prevention:** When generating keyframes dynamically, sort and de-duplicate them.

### Error: `inputRange (n) and outputRange (m) must have the same length`

**Cause:** Mismatched array lengths passed to `interpolate()`.
**Solution:** Provide one output value per input keyframe.

### Error: `staticFile() does not support remote URLs` / `relative paths` / `absolute paths`

**Cause:** Passing a URL, `./`/`..` path, OS path, or a `public/`-prefixed path to `staticFile()`.
**Solution:** For remote assets, pass the URL straight to `src`. For local files, pass the path **inside** `public/` without the `public/` prefix, e.g. `staticFile('img/logo.png')`.

### Error: `Spring damping must be greater than 0`

**Cause:** `spring({config: {damping: 0}})`.
**Solution:** Use a positive damping value (default is `10`).

### `<Composition> mounted inside another composition` / `inside the component passed to <Player>`

**Cause:** A `<Composition>` was placed inside another composition's component tree or passed as the Player's `component`.
**Solution:** `<Composition>` belongs only in the Root component. The Player takes your composition component directly, not `<Composition>`.

### Animations work in preview but not in the render

**Cause:** Using wall-clock animation (CSS transitions/animations, `requestAnimationFrame`, `setInterval`, `Date.now()`) or unseeded `Math.random()`.
**Solution:** Drive every animated value from `useCurrentFrame()` and use seeded `random()`.

### Video frames look wrong, duplicated, or stuttery in the render

**Cause:** Using `<Video>` (HTML5) for rendering, or a non-monotonic source.
**Solution:** Use `<OffthreadVideo>` for rendering; tune `delayRenderTimeoutInMilliseconds`/`delayRenderRetries` for slow remote sources.

### Render is very slow

**Cause:** Low concurrency, heavy per-frame work, or large uncached assets.
**Solution:** Increase `--concurrency`, use `premountFor` on data-heavy sequences, prefetch remote media, and consider GPU/hardware acceleration (Admin Guide).

### "Multiple versions of Remotion" warning

**Cause:** `remotion` / `@remotion/*` packages on different versions.
**Solution:** Align *all* of them to the exact same version (`--save-exact`).

---

## 17. FAQ

**Q: Do I need to know video editing or FFmpeg?**
No. You write React. FFmpeg is bundled and used internally; you rarely touch it.

**Q: Do I have to install FFmpeg or Chrome?**
No. `@remotion/renderer` bundles FFmpeg and downloads its own Chrome Headless Shell automatically.

**Q: What video formats can I export?**
H.264 (default), H.265, VP8, VP9 (WebM), ProRes, GIF, image sequences (PNG/JPEG), and audio-only outputs.

**Q: How do I make a transparent video?**
Render with a codec/pixel format that supports alpha (WebM VP8/VP9 or ProRes) and PNG frames / `yuva420p`. See the Admin Guide's encoding section.

**Q: How do I change the video's duration based on data?**
Use `calculateMetadata` on the `<Composition>` to compute `durationInFrames` at render time.

**Q: How do I pass data into a video?**
`defaultProps` on the composition, plus `--props` on the CLI or `inputProps` in SSR/Lambda. Validate with a Zod `schema`.

**Q: Can I show a Remotion video in my web app without rendering?**
Yes — use `@remotion/player`.

**Q: Why is my random animation flickering between frames?**
You're using `Math.random()` / `random(null)`. Use a seeded `random('some-seed')` so each element is stable across frames.

**Q: Can I use Tailwind / SCSS / TypeScript?**
Yes — `@remotion/tailwind`(/`-v4`), `@remotion/enable-scss`, and TypeScript work out of the box.

**Q: How do I render lots of videos cheaply and fast?**
Render on AWS Lambda (`@remotion/lambda`) or Google Cloud Run (`@remotion/cloudrun`), parameterizing each render with different input props.

**Q: Is Remotion free?**
Free for individuals, small for-profit companies (up to 3 employees), and non-profits. Larger for-profit organizations need a company license — see below.

---

## 18. Licensing

Remotion's source is publicly available, but it is **not** a standard open-source MIT project — it uses a two-tier license (`SEE LICENSE IN LICENSE.md`).

| Tier | Who | Cost |
|------|-----|------|
| **Free License** | Individuals; for-profit organizations with **up to 3 employees**; non-profit / not-for-profit organizations; anyone evaluating Remotion before commercial use. | Free, including commercial video creation. |
| **Company License** | For-profit organizations above the free-tier size. | Paid (via remotion.pro). |

**Allowed under the free license:** using Remotion (commercially or non-commercially) to create videos and images, and modifying the source for your own use or to contribute fixes back.

**Not allowed:** copying or modifying Remotion to sell, rent, license, or sublicense your own derivative of Remotion.

> [!IMPORTANT]
> If your company needs a paid license, obtain a key from remotion.pro and set it with `Config.setPublicLicenseKey('...')` (or `'free-license'` if you qualify for the free tier). The `@remotion/licensing` package and the Player's `acknowledgeRemotionLicense` prop relate to this system. This guide summarizes the terms; the authoritative text is in the project's `LICENSE.md`, and the license changes slightly in Remotion 5.0.

---

## 19. Command & Reference Tables

### CLI commands

Run any command with `npx remotion <command>`. Add `--help` for full flags.

| Command | Purpose |
|---------|---------|
| `studio` (alias `preview`) | Start the Remotion Studio. |
| `render` | Render a composition to a video/audio/image-sequence. |
| `still` | Render a single still image. |
| `compositions` | List compositions in a project. |
| `bundle` | Create a deployable bundle of your project. |
| `lambda` | AWS Lambda subcommands (deploy functions/sites, render, etc.). |
| `cloudrun` | Google Cloud Run subcommands. |
| `benchmark` | Benchmark render performance across concurrency settings. |
| `browser` | Manage the Chrome Headless Shell (e.g. ensure/download). |
| `gpu` | Report GPU / OpenGL backend info. |
| `ffmpeg` / `ffprobe` | Run the bundled FFmpeg / FFprobe. |
| `upgrade` | Upgrade all Remotion packages together. |
| `versions` | Show installed Remotion versions and check alignment. |
| `add` | Add a Remotion package to your project. |
| `skills` | AI agent skills integration. |
| `help` | Show CLI help. |

### Core `remotion` exports (most-used)

| Category | Exports |
|----------|---------|
| Registration | `registerRoot`, `Composition`, `Still`, `Folder` |
| Hooks | `useCurrentFrame`, `useVideoConfig`, `useBufferState`, `useCurrentScale` |
| Animation | `interpolate`, `interpolateColors`, `spring`, `measureSpring`, `Easing`, `random` |
| Layout | `AbsoluteFill` |
| Timing | `Sequence`, `Series`, `Loop`, `Freeze` |
| Media | `Audio`, `Video`, `OffthreadVideo`, `Img`, `IFrame`, `AnimatedImage`, `staticFile` |
| Async | `delayRender`, `continueRender`, `cancelRender`, `prefetch` |
| Data | `getInputProps`, `getStaticFiles`, `watchStaticFile` |

### Environment variables you may use

Variables prefixed `REMOTION_` are exposed to your bundle. Common ones include `REMOTION_AWS_ACCESS_KEY_ID` / `REMOTION_AWS_SECRET_ACCESS_KEY` (Lambda credentials), `REMOTION_GCP_*` (Cloud Run), and a custom `.env` location via `Config.setDotEnvLocation()`. The full operational variable list is in the Admin Guide.

---

_Generated June 2026 from remotion-dev/remotion at 26d3e03. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
