remotion Documentation

Make videos programmatically with React

65,487 stars TypeScript TypeScript 1 file · ~45,766 tokens #javascript#react#video
RAW Doc

Technical Documentation: remotion-dev/remotion

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (README.md)




Video tools for the agent era.

Video Creation

  • Make videos agentically: Turn your idea into a video using your coding agent.
  • Make videos interactively: Edit and animate using drag and drop.
  • Make videos programmatically: Connect to data, and manage complexity with code.

React Code is the source of truth. Switch your workflow at any point.

Video Automation

  • Design systems: Create a library of animated assets for your organization.
  • Batch rendering: Render millions of videos on your own infrastructure.
  • Applications: Publish a simple tool or a complex video editor.

Get started

If you already have Node.JS installed, type

console
npx create-video@latest

to get started. Otherwise, read the installation page in the documentation.

Discover Remotion

Remotion is extensively documented over more than 1000 pages.

Documentation

Documentation: remotion.dev/docs
API Reference: remotion.dev/api

License

Be aware of that Remotion has a special license and requires obtaining a company license in some cases. Read the LICENSE page for more information.

Contributing

Please read CONTRIBUTING.md to learn about contributing to this project.


Packages Docs README (`packages/docs/README.md`)

@remotion/docs

Usage

This is an internal package and has no documentation.


Packages Docs Docs Getting Started (`packages/docs/docs/getting-started.mdx`)


image: /generated/articles-docs-getting-started.png id: getting-started title: Creating a new project sidebar_label: Installation slug: / crumb: "Let's begin!"

import {CreateWithChatGPTButton} from '../components/CreateWithChatGPTButton';

Using ChatGPT

If you have the ChatGPT desktop app, it can create a complete Remotion project that you can edit, run, and render locally using the Remotion plugin.

Coding Agent Prompt

Paste into a coding agent, such as Claude Code, Codex or OpenCode:

Ensure Node.js is installed.
Install Remotion Skills: npx -y skills@latest add remotion-dev/skills -g -y
Then use them to create a video.

From the command line

sh
npx create-video@latest --yes --blank my-video
cd my-video
npx remotion skills add
npm run dev

Creates a video in the my-video directory using the blank template and Agent Skills, without TailwindCSS.

Planning to prompt a video using a coding agent?
Click here for more detailed beginner instructions.

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Templates

Choose the template that is most suitable for you.
For your first project, we recommend the Hello World template.

Wizard

Customize the creation of a Remotion project by selecting a package manager, a template and whether to install Agent Skills.

<Tabs
defaultValue="npm"
values={[
{ label: 'npm', value: 'npm', },
{ label: 'bun', value: 'bun', },
{ label: 'pnpm', value: 'pnpm', },
{ label: 'yarn', value: 'yarn', },
{ label: 'nub', value: 'nub', },
]
}>

bash title="use npm as the package manager"
npx create-video@latest
bash title="use pnpm as the package manager"
pnpm create video
bash title="use yarn as the package manager"
yarn create video
bash title="use nub as the package manager"
nubx create-video@latest
bash title="use bun as the package manager and runtime"
bun create video

:::note
Bun as a runtime is mostly supported. Read more here.
:::

After the project has been scaffolded, start the local development server:

<Tabs
defaultValue="npm"
values={[
{ label: 'Regular templates', value: 'npm', },
{ label: 'Next.js + React Router 7', value: 'pnpm', },
]
}>

After the project has been scaffolded, we recommend to open the project in your text editor and starting the Remotion Studio:

bash
npm run dev

After the project has been scaffolded, we recommend to open the project in your text editor and starting the app:

bash
npm run dev

To start the Remotion Studio:

bash
npm run remotion

ESLint

Remotion templates include a recommended ESLint configuration. See @remotion/eslint-config to choose the config for your ESLint version or to add it to another project.

System requirements

To use Remotion, you need at least Node or Bun .
🍎 macOS 15 (Sequoia) or later is required. Older versions are not supported.
🐧 Linux distros need at least version 2.35 of Libc.
They also need to install some additional packages.
Alpine Linux and nixOS are unsupported.

Installation in existing projects

Want to install Remotion in an existing project? Go here instead: Installation in existing projects


Packages Docs Elements Template Index (`packages/docs/elements-template/index.mdx`)


title: Element title image: /elements/category-element-title-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {ElementComponent} from './element';

export const elementDefinition = {
category: 'category',
component: ElementComponent,
contributors: [],
dependencies: [],
displayName: 'Element title',
durationInFrames: 120,
elementHeight: null,
elementWidth: null,
fps: 30,
height: 1080,
posterFrame: 60,
preview: {
posterUrl: '/elements/category-element-title-preview.png',
videoUrl: '/elements/category-element-title-preview.mp4',
},
safeArea: 0,
slug: 'category/element-title',
installationMode: 'component-owned-sequence',
width: 1920,
};

Element title


Packages Docs Elements Index (`packages/docs/elements/index.mdx`)


title: Remotion Elements sidebar_label: Overview hide_table_of_contents: true pagination_next: null pagination_prev: null

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Remotion Elements

Drop-in video building blocks. Make it yours, interactively or with an agent.

Browse the catalog here or directly inside Remotion Studio.

More Elements

Add third-party Element Libraries to browse and install Elements from other creators in Studio.

Have an Element idea? Contribute.


Packages Docs Docs Ai Index (`packages/docs/docs/ai/index.mdx`)


image: /generated/articles-docs-ai-index.png crumb: 'Artificial Intelligence' title: Building with Remotion and AI

import {TableOfContents} from './TableOfContents';

Here are a few ways you can use AI in your Remotion workflow today:

Tella for boosting the development of @remotion/media-parser with $10.000!

License

Remotion License


Packages Docs Docs Media Utils Index (`packages/docs/docs/media-utils/index.mdx`)


image: /generated/articles-docs-media-utils-index.png title: "@remotion/media-utils"

import {TableOfContents} from './table-of-contents';

A package providing utility functions for getting information about video and audio, and for visualizing audio.

Except for useAudioData(), all functions can also be used outside of Remotion.

Functions

Record webcam and display as separate streams. Up to 4 sources can be recorded at the same time! Ensure you are in the center of the video and you are not too close to the microphone.

Different platforms require different formats

Each platform has its own conventions for how videos should look.

WIP
Twitter, LinkedIn
text
1:1
  Muted by default
  Captions burned in | **YouTube**
  16:9
  Audio by default
  
    Captions as .srt file{" "}
  
  Endcard with related videos | TikTok, Reels, Shorts{" "}
    
      [planned](#tiktok-format)
    
  
  9:16
  Safe space at bottom required
  Word-by-word captions |

The goal of the Recorder: Edit once and feel native on each platform.

This has a measurable impact on the performance of your post: For example, a 1:1 video on X results in 30-35% higher video views and a 80-100% higher engagement rate.

Captions are essential

Generate captions locally using Whisper.cpp. The Recorder will automatically install it for you.
AI will make mistakes - so we make it easy to correct them.

Captions have word-level timings Orphan words are avoided by balancing the text layout Use backticks to highlight technical terms
Fix captions quickly by clicking on a word Write a JavaScript function to fix common misspellings Captions are stored as editable JSON

Agnostic endcards

Your viewer watched the entire video! Now don't make them forget about you.

| If you post on Twitter, the call-to-action is "Follow" and your other platforms
are linked. | If you post on YouTube, the call to action is "Subscribe" and cutouts for related
videos are made. |

| --- | --- |

The endcard is written with React and CSS, so can be easily customized.

Customization

Having access to the entire source code, you can use CSS to customize the look of the Recorder.

Look of the built-in light theme Look of the built-in dark theme Use CSS to make it your own!

The Recorder is built with TypeScript and React, and you can fully customize it's behavior.
It's a hackable video editor.

Silence removal

Automatically remove the silence at the start and end of your take.

Music

Add background music to your video and automatically fade between the different sections.
Three exclusive tracks are included that you may use for your video.

Layouting

Whether you only record your facecam, or also your display, the Recorder always finds the ideal layout - even if you mix landscape and portrait videos.

Transitions

Enable clean transitions between scenes - no matter if you change the layout during the video.

Chapters

Mark a scene as the beginning of a new chapter and automatically generate animated chapters.

B-Roll

Add images and videos on top of your facecam or display while your voiceover is playing to give the video more depth.

Exporting

Export your video with much control over the encoding options.
Render a video with a single click on a button, the CLI, Node.JS APIs, GitHub Actions, or even on AWS Lambda!

See also


1) 9:16 format is not yet implemented.


Packages Docs Docs Rive Index (`packages/docs/docs/rive/index.mdx`)


image: /generated/articles-docs-rive-index.png sidebar_label: Overview title: "@remotion/rive" crumb: Integrations

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import {TableOfContents} from './table-of-contents';

This package provides a component for rendering Rive animations in Remotion.

Installation

Install @remotion/rive

<Tabs defaultValue="npm" values={[
{ label: 'npm', value: 'npm', },
{ label: 'yarn', value: 'yarn', },
{ label: 'pnpm', value: 'pnpm', },
]
}>

bash
npm i @remotion/rive
bash
yarn add @remotion/rive
bash
pnpm i @remotion/rive

API

License

Remotion License


Packages Docs Docs Rough Notation Index (`packages/docs/docs/rough-notation/index.mdx`)


image: /generated/articles-docs-rough-notation-index.png id: rough-notation-api slug: /rough-notation/api title: '@remotion/rough-notation'

@remotion/rough-notation

Animated marker highlights, circles, boxes, underlines and other hand-drawn text annotations for Remotion videos.

import {TableOfContents} from './table-of-contents';

APIs

Common props

Every component wraps the text or element passed as children and accepts these props:

`children`

The text or element to annotate.

`style?`

CSS styles applied to the tracked content. Text and font styles can also be edited in Remotion Studio.

`progress`

Controls how much of the annotation is drawn. Use a value between 0 and 1.

`disabled?`

Set to true to temporarily hide the annotation while keeping the component and its other props in place. Default: false.

`seed?`

Controls the generated shape. Change the integer on every frame to animate the shape. Default: 1.

`color?`

The annotation color. Default: currentColor.

`roughness?`

Controls how rough the annotation looks. The default is 3 for <Highlight> and 1.5 for the other components.

`maxRandomnessOffset?`

Controls how far points may be randomly offset from their ideal position. Default: 5.

`bowing?`

Controls how much straight lines bow. Default: 1.

`disableMultiStroke?`

Set to true to prevent Rough.js from drawing multiple strokes for a line. Default: false.

`preserveVertices?`

Preserves vertices when roughening a shape. Default: false.

The components are interactive in Remotion Studio and support editable text and font controls.

Inherited props

Every annotation component inherits from, durationInFrames, trimBefore, playbackRate, freeze, hidden, name and showInTimeline from <Sequence>.

From , it also inherits premountFor, postmountFor, styleWhilePremounted and styleWhilePostmounted from <Sequence>.

License

MIT


Packages Docs Docs Rounded Text Box Index (`packages/docs/docs/rounded-text-box/index.mdx`)


image: /generated/articles-docs-rounded-text-box-index.png title: '@remotion/rounded-text-box'

@remotion/rounded-text-box

Create a TikTok-like multiline text box SVG path with rounded corners.

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {TableOfContents} from './table-of-contents';

<Tabs
defaultValue="npm"
values={[
{ label: 'npm', value: 'npm', },
{ label: 'pnpm', value: 'pnpm', },
{ label: 'yarn', value: 'yarn', },
]
}>

bash
npm i @remotion/rounded-text-box
bash
pnpm i @remotion/rounded-text-box
bash
yarn add @remotion/rounded-text-box

Functions

License

MIT


Packages Docs Docs Sdk Get Canvas Sequence Reorder Insertion Index (`packages/docs/docs/sdk/get-canvas-sequence-reorder-insertion-index.mdx`)


image: /generated/articles-docs-sdk-get-canvas-sequence-reorder-insertion-index.png title: getCanvasSequenceReorderInsertionIndex() crumb: '@remotion/sdk'

getCanvasSequenceReorderInsertionIndex()

Calculates where a dragged group lands after removing its selected siblings. Returns null for a drop on the selection, a negative or duplicate source index, or a move that leaves a contiguous group in place.

ts twoslash title="get-insertion-index.ts"
import {getCanvasSequenceReorderInsertionIndex} from '@remotion/sdk';

const insertionIndex = getCanvasSequenceReorderInsertionIndex({
  sourceIndexes: [0, 2],
  targetIndex: 4,
  position: 'before',
});

// 2: after removing indexes 0 and 2, insert before the original index 4.
console.log(insertionIndex);

Indexes must describe siblings in the same order. This helper does not check whether the JSX nodes are direct siblings; reorderNodes() validates that against source code.

Options

sourceIndexes

The indexes of the selected siblings to move.

targetIndex

The index of the drop target in the original sibling list.

position

Either 'before' or 'after' the target.

Return value

The insertion index in the sibling list after the selected items are removed, or null for an invalid or unchanged move.

Compatibility

See also


Packages Docs Docs Sdk Index (`packages/docs/docs/sdk/index.mdx`)


image: /generated/articles-docs-sdk-index.png sidebar_label: Overview title: '@remotion/sdk' crumb: '@remotion/sdk'

@remotion/sdk

Build a composition preview and layer list for a Remotion authoring interface. The package combines `` playback with registered sequence data, selection, and synchronized hover.

:::warning

Experimental API: This package is not stable. Its public API may change without a major version bump.

:::

Installation

Install @remotion/player as well. Keep the Remotion packages on the same version.

Basic example

Pass the same controller to <Canvas> and your layer list. showOutlines enables hover and selection on the composition.

text
/* Detailed source-code truncated for AI context efficiency. */

The timeline contains registered <Sequence> and other sequence tracks from the mounted composition. The Canvas does not edit source files or provide timeline controls; your interface owns those actions.

For a timeline reorder gesture, getCanvasSequenceReorderSelection() chooses the dragged sequence group. getCanvasSequenceReorderInsertionIndex() identifies valid drop positions. Persist the result with reorderNodes().

Selection identity

The built-in getCanvasSequenceNodePathInfo() uses a source identity when available. Otherwise it falls back to a mounted sequence ID, which can change after a remount.

If your editor has the source code, register the source node of each sequence with setSequenceNodePaths(). For projects compiled with @remotion/browser-bundler, getCanvasSequenceSourceLocation() returns the file and position of each sequence's JSX element, which getNodes() maps to a node path. Alternatively, pass a custom resolveSequenceNodePathInfo to <Canvas> and use the same resolver for layer items. Return null for tracks that should not be selectable.

An outline requires a registered DOM element. A <Sequence layout="none"> has no outline of its own.

Editing

The Canvas exposes the controls of each mounted element: its interactivity schema and current prop values. Use them to build an inspector, and write changes to the source with @remotion/codemods.

While a value is being dragged, controller.overrides previews it on the canvas immediately. Persist the final value when the gesture ends, then clear the override.

Pass onSequencePropsChange to <Canvas> to let users move elements by dragging their outlines or pressing the arrow keys. The Canvas previews the movement itself and reports the final style.translate values to the callback. With getSequencePropStatuses, it respects how the source is written: computed values cannot be moved and keyframed values receive a keyframe.

Keyframes

Props animated with interpolate() are reported as keyframed by getNodeProps(). The package converts between the frame clock of the interpolation and the composition timeline, so a timeline can show and edit those keyframes like the Remotion Studio does.

getCanvasKeyframes() places the keyframes of a prop on the timeline. getCanvasKeyframeToggle() describes a keyframe button at the playhead and returns the change that adds or removes a keyframe there, while getCanvasPropValueAtFrame() reads the animated value for an inspector. startCanvasKeyframeDrag() moves keyframes with the pointer, previewing the result through controller.overrides. Every edit is a CanvasKeyframeChange whose operation you pass to updateNodeKeyframes().

Between two keyframes, getCanvasKeyframeEasingSegments() describes the segments a timeline can draw and select, and getCanvasKeyframeEasingChange() sets the easing of one, with canvasKeyframeEasingPresets for a picker. getCanvasKeyframeSettings() and getCanvasKeyframeSettingsChange() read and write the extrapolation, output mode and posterize of the interpolation. getCanvasKeyframeChangeOverride() turns any change into an override, so the canvas shows it before the source is updated.

APIs

import {TableOfContents} from './table-of-contents';

License

Remotion License


Packages Docs Docs Sfx Index (`packages/docs/docs/sfx/index.mdx`)


image: /generated/articles-docs-sfx-index.png crumb: API title: '@remotion/sfx'

@remotion/sfx

Sound effect URLs for general use.
Available as a package or from loading through a URL directly.
Normalized volume for the peak to be at -3dB.
All files can be used without attribution, but the attribution is available on the detail page of a sound.

import {TableOfContents} from './table-of-contents';

Exports

License

NPM package: MIT
See license of each sound effect by clicking on it.


Packages Docs Docs Shapes Index (`packages/docs/docs/shapes/index.mdx`)


image: /generated/articles-docs-shapes-index.png title: "@remotion/shapes" crumb: "SVG component library"

import {TableOfContents} from './table-of-contents';

A package providing utility functions for generate SVG shapes.

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

<Tabs
defaultValue="npm"
values={[
{ label: 'npm', value: 'npm', },
{ label: 'pnpm', value: 'pnpm', },
{ label: 'yarn', value: 'yarn', },
]
}>

bash
npm i @remotion/shapes
bash
pnpm i @remotion/shapes
bash
yarn add @remotion/shapes

Functions

License

MIT


Packages Docs Docs Starburst Index (`packages/docs/docs/starburst/index.mdx`)


image: /generated/articles-docs-starburst-index.png id: starburst-api slug: /starburst/api title: '@remotion/starburst' crumb: API

~~@remotion/starburst~~

:::info Deprecated
@remotion/starburst is deprecated and will no longer be published starting with Remotion 5.0. Migrate to starburst() from @remotion/effects/starburst. The <Starburst> component will not be moved to @remotion/effects.
:::

Starburst ray effect for Remotion videos.

import {TableOfContents} from './table-of-contents';

APIs

License

Remotion License


Packages Docs Docs Studio Protocol Index (`packages/docs/docs/studio-protocol/index.mdx`)


image: /generated/articles-docs-studio-protocol-index.png title: 'Remotion Studio Protocol' crumb: '@remotion/studio-protocol'

@remotion/studio-protocol

With this package, you can create payloads for passing content to Remotion Studio.

Capabilities

Installing Remotion Elements

Websites can provide Elements to a Studio either using drag-and-drop or using an installation dialog.

1 Create an Element payload with createElementPayload().
2 Put it on a drag event with setStudioDragData(), or send a signal to a Studio using installInStudio().

Method Benefits Tradeoffs
Drag-and-drop The user chooses the exact Studio tab, timeline position, and canvas position. Studio labels the source as unverified.
Installation dialog The requesting website is shown. Remotion attempts to bring the Studio to the foreground. The most recently focused tab is selected, or the sole writable tab if none has been focused.

Adding an Element Library

Using addElementLibraryToStudio() you can request to add an Element Library to the Studio.

Previewing Elements

Using buildOpenInRemotionNewUrl(), you can open your Element in remotion.dev/new.

APIs

import {TableOfContents} from './table-of-contents';

Security

Learn about the confirmation and origin policy.

License

Remotion License

See also


Packages Docs Docs Tailwind V4 Overview (`packages/docs/docs/tailwind-v4/overview.mdx`)


image: /generated/articles-docs-tailwind-v4-overview.png id: overview sidebar_label: Overview title: '@remotion/tailwind-v4'

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {ExperimentalBadge} from '../../components/Experimental';
import {TableOfContents} from './TableOfContents';

This package provides utilities useful for integrating TailwindCSS v4 with Remotion, as documented on our TailwindCSS page.

Installation

Install @remotion/tailwind-v4 as well as TailwindCSS dependencies.

Override the bundler config by using enableTailwind().

ts twoslash title="remotion.config.ts"
import {Config} from '@remotion/cli/config';
import {enableTailwind} from '@remotion/tailwind-v4';

Config.overrideBundlerConfig((currentConfiguration) => {
  return enableTailwind(currentConfiguration);
});

Then follow the remaining set up steps from the TailwindCSS page.

APIs


Packages Docs Docs Tailwind Overview (`packages/docs/docs/tailwind/overview.mdx`)


image: /generated/articles-docs-tailwind-overview.png id: tailwind sidebar_label: Overview title: '@remotion/tailwind'

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {ExperimentalBadge} from '../../components/Experimental';
import {TableOfContents} from './TableOfContents';

:::note
This is documentation for enabling Tailwind v3.
For the Tailwind v4 version of this site, see the Tailwind v4 documentation.
:::

This package provides utilities useful for integrating TailwindCSS with Remotion, as documented on our TailwindCSS page.

Installation

Install @remotion/tailwind as well as TailwindCSS dependencies.

Override the bundler config by using enableTailwind().

ts twoslash title="remotion.config.ts"
import {Config} from '@remotion/cli/config';
import {enableTailwind} from '@remotion/tailwind';

Config.overrideBundlerConfig((currentConfiguration) => {
  return enableTailwind(currentConfiguration);
});

Then follow the remaining set up steps from the TailwindCSS page.

APIs


Packages Docs Docs Timeline Index (`packages/docs/docs/timeline/index.mdx`)


image: /generated/articles-docs-timeline-index.png title: Remotion Timeline

import {TableOfContents} from './TableOfContents';

<Timeline>

A paid customizable timeline component that integrates seamlessly with Remotion Player.
It's perfect for builders who need a layer-based editing interface for their video editing app.

You can buy the timeline component on remotion.pro.

Key Features

Interface:

  • Multiple track support with drag-and-drop functionality (between and within tracks)
  • Timeline item selection and manipulation
  • Keyboard shortcuts for common actions
  • CanvasComposition for rendering the timeline state in the Remotion Player
  • Zoomable timeline and <ZoomSlider> component to control the zoom level

Customization:

  • Theming with variables (Tailwind CSS V4 and V3)
  • Extensible state management

License

The source code of the Remotion Timeline is governed by the Remotion License and its own specific license.

  • Remotion, as an underlying technology of the Remotion Timeline, is free to use for individuals and small companies. If you fall into this category, you can buy the Remotion Timeline as a one-time purchase. If you are a larger company, you must subscribe to the Company License. Read the Terms & Conditions.

  • The Remotion Timeline License can be seen in the Remotion Store Page as well as accessible through the dedicated GitHub repository after purchase.


Packages Docs Docs Transitions Index (`packages/docs/docs/transitions/index.mdx`)


image: /generated/articles-docs-transitions-index.png sidebar_label: Overview title: '@remotion/transitions'

@remotion/transitions

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {TableOfContents} from './table-of-contents';

This package provides the `` component for transitioning between two scenes as well as timing presets.

Installation

API

License

Remotion License

See also


Packages Docs Docs Vercel Index (`packages/docs/docs/vercel/index.mdx`)


id: vercel-api slug: /vercel/api title: '@remotion/vercel' crumb: 'API'

import {TableOfContents} from './table-of-contents';

@remotion/vercel

:::warning
Experimental package: We reserve the right to make breaking changes in order to correct bad design decisions until this notice is gone.
:::

Render Remotion videos on Vercel Sandbox.
This package requires @vercel/sandbox as a peer dependency.

APIs

License

Remotion License


Packages Docs Docs Video Matting Index (`packages/docs/docs/video-matting/index.mdx`)


image: /generated/articles-docs-video-matting-index.png title: '@remotion/video-matting' crumb: 'Separate a video into layers'

@remotion/video-matting

Separate a video into opaque base and transparent foreground layers, locally in the browser or Node.js using WebGPU.

import {TableOfContents} from './table-of-contents';

Installation

Studio

Remotion Studio offers Remove background for a selected video. It replaces the video's source with a transparent WebM. Duplicate the layer first if you want to keep the original alongside it.

For programmatic base and foreground outputs, see separateVideoLayers().

Model hosting

We noticed that hosting the models on R2 leads to faster downloading than through Hugging Face directly.
We mirrored the models to remotion.media, keeping them byte-identical.
We also notified Hugging Face and they are investigating the issue. We may migrate back to the official hosting in the future.

APIs

Requirements

A GPU is needed for this.
Use canUseVideoMatting() to check whether your system can use video matting.

The browser must also be able to decode the input video and encode VP9 with alpha through WebCodecs.
separateVideoLayers() checks these media capabilities for the selected input.

License

The package is MIT licensed.
Models retain the licenses listed under getAvailableModels().


Packages Docs Docs Videos Index (`packages/docs/docs/videos/index.mdx`)


image: /generated/articles-docs-videos-index.png title: Embedding videos into Remotion sidebar_label: Adding a video crumb: 'How To'

You can embed existing videos into Remotion by using the <Video> from @remotion/media component.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';

export const MyComp: React.FC = () => {
  return <Video src="https://remotion.media/BigBuckBunny.mp4" />;
};

Using a local file

Put a file into the public folder and reference it using staticFile().

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} />;
};

Trimming

By using the trimBefore prop, you can remove the first few seconds of the video.

In the example below, the first two seconds of the video are skipped (assuming a composition FPS of 30).

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} trimBefore={60} />;
};

Use durationInFrames to select how many source frames should play.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} trimBefore={60} durationInFrames={60} />;
};

Delaying

Use the from prop to delay the appearance of a video.
In the example below, the video will start playing at frame 60.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video from={60} src={staticFile('video.mp4')} />;
};

Size and Position

You can size and position the video using CSS.
You'll find the properties width, height, position, left, top, right, bottom, margin, aspectRatio and objectFit useful.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return (
    <Video
      src={staticFile('video.mp4')}
      style={{
        width: 640,
        height: 360,
        position: 'absolute',
        top: 100,
        left: 100,
      }}
    />
  );
};

Volume

You can set the volume of the video using the volume prop.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} volume={0.5} />;
};

You can also mute a video using the muted prop.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} muted />;
};

See Using Audio for more ways you can control volume.

Speed

You can use the playbackRate prop to change the speed of the video.

tsx twoslash
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} playbackRate={2} />;
};

This only works if the speed is constant. See also: Changing the speed of a video over time.

Looping

Use the loop prop to restart the video when it reaches the end.

tsx twoslash title="looping a video"
import React from 'react';
import {Video} from '@remotion/media';
import {staticFile} from 'remotion';

export const MyComp: React.FC = () => {
  return <Video src={staticFile('video.mp4')} loop />;
};

To learn how looping interacts with trimBefore and durationInFrames, see Timing and trimming.

GIFs

See: Using GIFs

See also


Packages Docs Docs Web Renderer Index (`packages/docs/docs/web-renderer/index.mdx`)


image: /generated/articles-docs-web-renderer-index.png sidebar_label: Overview title: '@remotion/web-renderer' crumb: API

This package allows you to render videos and stills directly in the browser, without requiring server-side infrastructure.

The API is stable from .

Key differences from server-side rendering

Unlike server-side rendering with @remotion/renderer, client-side rendering:

  • Runs in the browser instead of Node.js
  • Encodes with WebCodecs using Mediabunny instead of FFmpeg
  • Limited to a subset of tags and CSS properties - see limitations
  • No bundling step - takes components and video config directly

Installation

API

import {TableOfContents} from './TableOfContents';

See also


Packages Docs Docs Webcodecs Index (`packages/docs/docs/webcodecs/index.mdx`)


image: /generated/articles-docs-webcodecs-index.png sidebar_label: Overview title: '@remotion/webcodecs'

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {TableOfContents, WebCodecsGuide} from './TableOfContents';

@remotion/webcodecs

:::warning
We are phasing out Remotion WebCodecs and are moving to Mediabunny!
:::

This package provides APIs for converting videos in the browser.
It leverages @remotion/media-parser to parse the video and audio data, and then uses the WebCodecs API to encode the video.

import {LicenseDisclaimer} from './LicenseDisclaimer';
import {UnstableDisclaimer} from './UnstableDisclaimer';

What can you do with this package?

In browsers that implement WebCodecs, you can use this package to:

Is it fast?

Unlike solutions which leverage WebAssembly, WebCodecs have full access to GPU acceleration.
You can expect vastly faster processing than with online converters or WebAssembly-based processing.

See a comparison here.

💼 License Disclaimer

🚧 Unstable API Warning

Installation

Guide

APIs

The following APIs are available:


Packages Docs Docs Whisper Web Index (`packages/docs/docs/whisper-web/index.mdx`)


image: /generated/articles-docs-whisper-web-index.png title: '@remotion/whisper-web' crumb: 'Transcribe audio in browser'

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

~~@remotion/whisper-web~~

:::info Deprecated
@remotion/whisper-web is deprecated and will no longer be published starting with Remotion 5.0. Migrate to @remotion/whisper-webgpu, which uses WebGPU and does not require cross-origin isolation. Existing 4.x versions remain available.
:::

Similar to @remotion/install-whisper-cpp but for the browser. Allows you to transcribe audio locally in the browser, with the help of WASM.

import {TableOfContents} from './whisper-web';

Installation

Required configuration

@remotion/whisper-web uses a WebAssembly (WASM) backend that requires SharedArrayBuffer support. To enable this functionality, you need to configure cross-origin isolation headers in your application. This is a security requirement for using SharedArrayBuffer in modern browsers.

See: Important Considerations

Vite

To use @remotion/whisper-web with Vite, you need to make two important changes:

  1. Exclude the package from Vite's dependency optimization to prevent known issues
  2. Configure the required security headers for SharedArrayBuffer support
tsx title="vite.config.ts"
import {defineConfig} from 'vite';

export default defineConfig({
  optimizeDeps: {
    // turn off dependency optimization: https://github.com/vitejs/vite/issues/11672#issuecomment-1397855641
    exclude: ['@remotion/whisper-web'],
  },
  // required by SharedArrayBuffer
  server: {
    headers: {
      'Cross-Origin-Embedder-Policy': 'require-corp',
      'Cross-Origin-Opener-Policy': 'same-origin',
    },
  },
  // ...
});

Example usage

tsx twoslash title="transcribing with @remotion/whisper-web"
import {transcribe, canUseWhisperWeb, resampleTo16Khz, downloadWhisperModel} from '@remotion/whisper-web';

const file = new File([], 'audio.wav');
const modelToUse = 'tiny.en';

const {supported, detailedReason} = await canUseWhisperWeb(modelToUse);
if (!supported) {
  throw new Error(`Whisper Web is not supported in this environment: ${detailedReason}`);
}

console.log('Downloading model...');
await downloadWhisperModel({
  model: modelToUse,
  onProgress: ({progress}) => console.log(`Downloading model (${Math.round(progress * 100)}%)...`),
});

console.log('Resampling audio...');
const channelWaveform = await resampleTo16Khz({
  file,
  onProgress: (p) => console.log(`Resampling audio (${Math.round(p * 100)}%)...`),
});

console.log('Transcribing...');
const {transcription} = await transcribe({
  channelWaveform,
  model: modelToUse,
  onProgress: (p) => console.log(`Transcribing (${Math.round(p * 100)}%)...`),
});

console.log(transcription.map((t) => t.text).join(' '));

Functions

License

MIT


Packages Docs Docs Whisper Webgpu Index (`packages/docs/docs/whisper-webgpu/index.mdx`)


image: /generated/articles-docs-whisper-webgpu-index.png title: '@remotion/whisper-webgpu' crumb: 'Transcribe audio locally'

@remotion/whisper-webgpu

Transcribe audio locally in the browser or Node.js using timestamped Whisper models and WebGPU through Transformers.js, and convert the result to @remotion/captions.

import {TableOfContents} from './table-of-contents';

Installation

Example

ts twoslash title="transcribe.ts"
import {clearStaleModels, downloadWhisperModel, resampleTo16Khz, toCaptions, transcribe} from '@remotion/whisper-webgpu';

export const transcribeFile = async (file: File) => {
  await clearStaleModels();
  await downloadWhisperModel({model: 'small.en'});

  const channelWaveform = await resampleTo16Khz({file});
  const transcription = await transcribe({
    channelWaveform,
    model: 'small.en',
    language: 'en',
  });

  const {captions} = toCaptions({whisperWebGpuOutput: transcription});
  return captions;
};

Model hosting

We noticed that hosting the models on R2 leads to faster downloading than through Hugging Face directly.
We mirrored the models to remotion.media, keeping them byte-identical.
We also notified Hugging Face and they are investigating the issue. We may migrate back to the official hosting in the future.

On the server

See @remotion/whisper-webgpu in Node.js for a complete Node.js example.

APIs

Requirements

You obviously need a GPU.
Use canUseWhisperWebGpu() to determine if it is supported.

License

MIT


Packages Docs Docs Zod Types Index (`packages/docs/docs/zod-types/index.mdx`)


image: /generated/articles-docs-zod-types-index.png sidebar_label: Overview title: '@remotion/zod-types' crumb: Schema

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import {ZodTypesTableOfContents} from './TableOfContents';

Includes utility types and Remotion-specific types for Zod.

:::note
Since Remotion v4.0.426, @remotion/zod-types is based on Zod v4.
If you want, you can now upgrade to Zod v4.
If you want to stay on Zod 3.22.3 as previously required by Remotion, use @remotion/zod-types-v3 instead of @remotion/zod-types.
:::

Installation

API

License

Remotion License


Packages Docs Elements Audio Index (`packages/docs/elements/audio/index.mdx`)


title: Audio

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Audio


Packages Docs Elements Backgrounds Index (`packages/docs/elements/backgrounds/index.mdx`)


title: Backgrounds

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Backgrounds


Packages Docs Elements Captions Index (`packages/docs/elements/captions/index.mdx`)


title: Captions

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Captions

How to use

Transcribing in the Studio

1 Select a video or audio.
2 Click Generate captions in the inspector.
3 Keep the default Basic Captions style, or select a caption Element in the Styles tab.
4 Click Generate captions to transcribe and insert captions using the chosen style.

Style selection is available from . Basic Captions works without loading the Element library.

Importing captions into Studio

1 Install an Element from below.
2 Select its caption layer in Studio.
3 In the Captions inspector, click Import and choose a file.

Supported formats:

  • Remotion Caption[] JSON
  • SRT
  • ElevenLabs Speech-to-Text or segmented JSON
  • OpenAI Whisper JSON transcript (verbose mode must be on)

Packages Docs Elements Commerce Index (`packages/docs/elements/commerce/index.mdx`)


title: Effects

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Effects


Packages Docs Elements Data Index (`packages/docs/elements/data/index.mdx`)


title: Charts & Data

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Charts & Data


Packages Docs Elements Layouts Index (`packages/docs/elements/layouts/index.mdx`)


title: Layouts

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Layouts


Packages Docs Elements Maps Index (`packages/docs/elements/maps/index.mdx`)


title: Maps

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Maps


Packages Docs Elements Overlays Index (`packages/docs/elements/overlays/index.mdx`)


title: Overlays

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Overlays


Packages Docs Elements Storytelling Index (`packages/docs/elements/storytelling/index.mdx`)


title: Storytelling

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Storytelling


Packages Docs Elements Text Index (`packages/docs/elements/text/index.mdx`)


title: Text Effects

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

Text Effects


Packages Docs Elements Youtube Index (`packages/docs/elements/youtube/index.mdx`)


title: YouTube

import {ElementLibrary} from '@site/src/components/Elements/ElementLibrary';

YouTube


Packages Docs Docs Cli Browser Index (`packages/docs/docs/cli/browser/index.mdx`)


image: /generated/articles-docs-cli-browser-index.png title: npx remotion browser crumb: '@remotion/cli' sidebar_label: 'browser'

import {TableOfContents} from './table-of-contents';

npx remotion browser

Commands for managing the browser used by Remotion.

Commands

See also


Packages Docs Docs Lambda Without Iam Index (`packages/docs/docs/lambda/without-iam/index.mdx`)


image: /generated/articles-docs-lambda-without-iam-index.png title: Using Lambda with IAM roles sidebar_label: 'With IAM Roles' crumb: 'Lambda without IAM'

import {UserPolicy} from '../../../components/lambda/user-permissions.tsx';

As documented on the Permissions page, the default way of using Remotion Lambda involves creating a Remotion user and assign it policies.

These policies give permission to Lambda to render a video with renderMediaOnLambda(). These credentials are considered long-term which is less secure and are disallowed in some companies.

Additionally, there might be requirements to execute renderMediaOnLambda() on services such as Lambda, EC2, and other computing services where the use of long-term credentials is not an option.

AWS offers the concept of IAM Roles as a solution to the problem above. When a role is assigned to an AWS service, AWS gives any elevated privileges based on the attached policies and the role is empowered to execute activities such as putting a file to an S3 bucket.

The role is given temporary AWS credentials such as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN to generate the video. This approach enhances security as there are no long-term credentials lingering around and the need to keep track of their rotation is eliminated.

The steps below provide authorization for the Lambda function to execute renderMediaOnLambda() without permission issues.

Prerequisites

  1. A deployed Lambda function running on AWS. An example using CDK is available here. It gives you an idea how to call renderMediaOnLambda() inside another Lambda function. The function is triggered by API Gateway. The example assumes that you have knowledge of using CDK, a write up is also available.
  2. An execution role that is assigned to the Lambda function.
  3. A user policy with the necessary user permissions.

Setup

1. Create role policy

  • Go to the IAM policies section in the AWS Management Console

  • Click on "Create policy"

  • Click on JSON

  • Copy the JSON policy template below:

    Show full role permissions JSON file for latest Remotion Lambda version

  • Click next. On the tags page, you don't need to fill in anything. Click next again.

  • Give the policy the name remotion-executionrole-policy. The other fields can be left as they are.

2. Assign the policy to the Lambda execution role

  • Go to the AWS Management Console
    • Navigate to Lambda (change to your function region)
    • Select Functions
    • Select your Lambda function
    • Select the "Configuration" tab
    • Select the "Permissions" tab
    • Click the role under Execution role
    • When redirected, click "Permissions" tab
    • Click on Add permissions
    • Attach policy
    • Find the policy, i.e. remotion-executionrole-policy
    • Select the policy
    • Click the Attach policies button.

With the assignment of the policy to the Lambda execution role, it is now empowered to execute the renderMediaOnLambda() API without permission issues.

In the background, when the Lambda function is executed, it is provided with environment variables such as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN that has temporary permission to AWS resources that renderMediaOnLambda() requires to render the video. The elevated powers come from the policy statements in remotion-executionrole-policy.

:::note
This procedure can be also applied to other AWS compute services such as EC2, Fargate etc..
:::

Render into a different bucket

Optionally, if you want to move the video to another S3 bucket after it is rendered, the Lambda function also needs permission to do so. The process is similar to the previous steps, but you will need to create a new policy statement that defines the bucket that Lambda needs to transfer the rendered video to.

Example

Use the outName property to select a different bucket. See: Custom output destination

ts twoslash title="my-function.ts"
import {renderMediaOnLambda} from '@remotion/lambda/client';

const {bucketName, renderId} = await renderMediaOnLambda({
  region: 'us-east-1',
  functionName: 'remotion-render-bds9aab',
  composition: 'MyVideo',
  serveUrl: 'https://remotionlambda-qg35eyp1s1.s3.eu-central-1.amazonaws.com/sites/bf2jrbfkw',
  codec: 'h264',
  privacy: 'no-acl',
  outName: {
    key: 'my-output',
    bucketName: 'output-bucket',
  },
});

In the example above, renderMediaOnLambda() is configured to output the rendered video to the output-bucket bucket. The following steps grant the Remotion Lambda execution role access to this bucket.

Steps

  • Again we assign the policy to the Lambda execution role. Go to the AWS Management Console and:
    • Navigate to Lambda (change to your function region)
    • Functions
    • Select your Lambda function
    • Configuration tab
    • Permissions tab
    • Click the role under Execution role
    • When redirected, click Permissions tab
    • Click on Add permissions
    • Click "Create inline policy"
    • Click the "JSON" tab

Add the policy below to grant s3:PutObject on the destination bucket's objects. This is the minimum destination policy for the example above with Remotion 4.0.535 or later. See write-only AWS S3 buckets.

json title="destination bucket policy"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:PutObject"],
      "Resource": ["arn:aws:s3:::{bucketname}/*"],
      "Effect": "Allow"
    }
  ]
}
  • Replace {bucketname} with the name of the bucket where you want to move the rendered video to.
  • Click on Review policy
  • Click Save changes

The Lambda function can now move the rendered video to the other bucket when the render process is completed.

Optionally grant s3:GetObject on arn:aws:s3:::{bucketname}/* and s3:ListBucket on arn:aws:s3:::{bucketname} to detect existing output before rendering and recover completion if the final progress update is missing. For compatibility with earlier Remotion versions, grant both permissions.

If you set privacy to "public" or "private" instead of "no-acl", also grant s3:PutObjectAcl on arn:aws:s3:::{bucketname}/*.

See also


Packages Docs Docs Player Drag And Drop Index (`packages/docs/docs/player/drag-and-drop/index.mdx`)


image: /generated/articles-docs-player-drag-and-drop-index.png sidebar_label: 'Drag & Drop' title: 'Drag & Drop in the Remotion Player' crumb: '@remotion/player' no_ai: true

import {DragAndDropDemo} from './Demo';

The Remotion Player supports reacting to mouse events allowing for building interactions on the canvas.
Try to drag and resize the elements below.

General considerations

Pointer events work mostly just like in regular React.

Disable the controls prop to disable any obstructing elements. You can render Playback controls outside of the Player.

The Player might have CSS scale() applied to it.
If you measure elements, you need to divide by the scale obtained by useCurrentScale().

You can pass state update functions via inputProps to the Player.
Alternatively, wrapping the Player in React Context also works.

Example

twoslash include item
export type Item = {
	id: number;
	durationInFrames: number;
	from: number;
	height: number;
	left: number;
	top: number;
	width: number;
	color: string;
	isDragging: boolean;
};
text
/* Detailed source-code truncated for AI context efficiency. */
twoslash include layer
import React, {useMemo} from 'react';
import {Interactive} from 'remotion';
import type {Item} from './item';

export const Layer: React.FC<{
  item: Item;
}> = ({item}) => {
  const style: React.CSSProperties = useMemo(() => {
    return {
      backgroundColor: item.color,
      position: 'absolute',
      left: item.left,
      top: item.top,
      width: item.width,
      height: item.height,
    };
  }, [item.color, item.height, item.left, item.top, item.width]);

  return (
    <Interactive.Div
      from={item.from}
      durationInFrames={item.durationInFrames}
      style={style}
    />
  );
};
text
/* Detailed source-code truncated for AI context efficiency. */
twoslash include sortedoutlines
import React from 'react';
import {SelectionOutline} from './SelectionOutline';
import type {Item} from './item';

const displaySelectedItemOnTop = (
  items: Item[],
  selectedItem: number | null,
): Item[] => {
  const selectedItems = items.filter((item) => item.id === selectedItem);
  const unselectedItems = items.filter((item) => item.id !== selectedItem);

  return [...unselectedItems, ...selectedItems];
};

export const SortedOutlines: React.FC<{
  items: Item[];
  selectedItem: number | null;
  changeItem: (itemId: number, updater: (item: Item) => Item) => void;
  setSelectedItem: React.Dispatch<React.SetStateAction<number | null>>;
}> = ({items, selectedItem, changeItem, setSelectedItem}) => {
  const itemsToDisplay = React.useMemo(
    () => displaySelectedItemOnTop(items, selectedItem),
    [items, selectedItem],
  );

  const isDragging = React.useMemo(
    () => items.some((item) => item.isDragging),
    [items],
  );

  return itemsToDisplay.map((item) => {
    return (
      <SelectionOutline
        key={item.id}
        changeItem={changeItem}
        item={item}
        setSelectedItem={setSelectedItem}
        selectedItem={selectedItem}
        isDragging={isDragging}
      />
    );
  });
};
twoslash include main
import React, {useCallback} from 'react';
import {AbsoluteFill} from 'remotion';
import type {Item} from './item';
import {Layer} from './Layer';
import {SortedOutlines} from './SortedOutlines';

export type MainProps = {
  readonly items: Item[];
  readonly setSelectedItem: React.Dispatch<React.SetStateAction<number | null>>;
  readonly selectedItem: number | null;
  readonly changeItem: (itemId: number, updater: (item: Item) => Item) => void;
};

const outer: React.CSSProperties = {
  backgroundColor: '#eee',
};

const layerContainer: React.CSSProperties = {
  overflow: 'hidden',
};

export const Main: React.FC<MainProps> = ({
  items,
  setSelectedItem,
  selectedItem,
  changeItem,
}) => {
  const onPointerDown = useCallback(
    (e: React.PointerEvent) => {
      if (e.button !== 0) {
        return;
      }

      setSelectedItem(null);
    },
    [setSelectedItem],
  );

  return (
    <AbsoluteFill style={outer} onPointerDown={onPointerDown}>
      <AbsoluteFill style={layerContainer}>
        {items.map((item) => {
          return <Layer key={item.id} item={item} />;
        })}
      </AbsoluteFill>
      <SortedOutlines
        selectedItem={selectedItem}
        items={items}
        setSelectedItem={setSelectedItem}
        changeItem={changeItem}
      />
    </AbsoluteFill>
  );
};
text
/* Detailed source-code truncated for AI context efficiency. */

Let's build the demo above.

The following features have been defined as goals:

  • Ability to freely position and resizing the squares with the mouse.
  • One item can be selected at a time. Clicking on an empty space will deselect the item.
  • Items can not overflow the container, however the blue outlines can overflow the container.

1 Data structure

Create a TypeScript type that describes the shape of your item.

In this example we store an identifier id, start and end frame from and
durationInFrames, the position left, top, width and height, a
background color as well as a boolean isDragging to fine-tune the behavior while dragging.

tsx twoslash title="item.ts"
// @filename: item.ts
// ---cut---
// @include: item

If you like to support different types of items (solid, video, image),
see here.

2 Item rendering

Declare a React component that renders the item.

tsx twoslash title="layer.tsx"
// @filename: item.ts
// @include: item
// @filename: Layer.tsx
// ---cut---
// @include: Layer

By passing from and durationInFrames to Interactive.Div, the item is only displayed from from until from + durationInFrames.

Interactive.Div renders the draggable `` directly, without an additional layout wrapper.

3 Outline rendering

Create a React component that renders an outline when an item isselected or hovered.

tsx twoslash title="selectionoutline.tsx"
// @filename: ResizeHandle.tsx
// @include: ResizeHandle
// @filename: item.ts
// @include: item
// @filename: SelectionOutline.tsx
// ---cut---
// @include: SelectionOutline
tsx twoslash title="resizehandle.tsx"
// @filename: item.ts
// @include: item
// @filename: ResizeHandle.tsx
// ---cut---
// @include: ResizeHandle

Z-indexing: These elements will later in this tutorial be rendered on top of all layers so that they are able to accept mouse events.
Clicking on one of these elements will select the underlying item.

Scaling: The `` has a CSS scale transform applied to it.
Since we consume the coordinates of the pointer events, we need to divide them by useCurrentScale() to get the correct position.

The thickness of the borders will also be affected by the scale, so we need to divide them by the scale too.

Pointer event handling: On any pointerdown event, we call e.stopPropagation() prevent the event from bubbling up.
Later, we will treat any event that bubbles up as an click on an empty space and deselect the item.

We also don't do any action if e.button !== 0. This prevents a bug where the item moves after a right click.

We add userSelect: 'none' to disable the native selection and drag behavior of the browser.

We also add touchAction: 'none' to disable scrolling the page on mobile while dragging.

We keep track if the item is being dragged by using the isDragging property and disable the hover effect while an item is being dragged.

4 Sorting outlines

Let's create a component that renders all outlines.
The item which gets rendered as last element will be on top of all other items.

The item that is selected should be rendered on top of all other items because it is the item that is responsive to mouse events.

We render the selected outlines last. This ensures that the resize handles are always on top.
This logic only applies to the outlines, not the actual layers.

tsx twoslash title="sortedoutlines.tsx"
// @filename: item.ts
// @include: item
// @filename: ResizeHandle.tsx
// @include: ResizeHandle
// @filename: SelectionOutline.tsx
// @include: SelectionOutline
// @filename: SortedOutlines.tsx
// ---cut---
// @include: SortedOutlines

5 Putting it together

Next, we create a main component that renders the items and the outlines.

tsx twoslash title="main.tsx"
// @filename: item.ts
// @include: item
// @filename: ResizeHandle.tsx
// @include: ResizeHandle
// @filename: SelectionOutline.tsx
// @include: SelectionOutline
// @filename: SortedOutlines.tsx
// @include: SortedOutlines
// @filename: Layer.tsx
// @include: Layer
// @filename: Main.tsx
// ---cut---
// @include: Main

Z-indexing: We render the layers first and then the outlines. This means the outlines get rendered on top the items.

Overflow behavior: Note that we apply a different overflow behavior to the layers and the outlines.
We hide the overflow of the layers, but show the overflow of the outlines.
This is a UI behavior that is similar to Figma frames.

Click handling: We also listen to pointerdown events on the canvas.
Any event that was not stopped using e.stopPropagation() before will be treated as a click on an empty space and results in deselecting the item.

6 Rendering the Player

We can now render the Main component that we created in the Remotion Player.

tsx twoslash title="demo.tsx"
// @filename: item.ts
// @include: item
// @filename: ResizeHandle.tsx
// @include: ResizeHandle
// @filename: SelectionOutline.tsx
// @include: SelectionOutline
// @filename: SortedOutlines.tsx
// @include: SortedOutlines
// @filename: Layer.tsx
// @include: Layer
// @filename: Main.tsx
// @include: Main
// @filename: Demo.tsx
// ---cut---
// @include: Demo

We omit the controls prop to disable the built-in controls.
You can add custom controls outside the Player.

We add the overflowVisible prop to make the outlines visible if they go outside the canvas.
Remember that we've hidden the overflow of the layers itself because it would also not be visible in the final video.

We've now implemented thoughtful drag and drop interactions!

See also


Packages Docs Docs Recorder Record Index (`packages/docs/docs/recorder/record/index.mdx`)


image: /generated/articles-docs-recorder-record-index.png title: Record using the interface sidebar_label: Using the interface crumb: Recorder

import {RecordingButton} from '../../../components/recorder/RecordButton';

The Recorder ships with its own recording interface.
From it, you can record a clip and add it as a scene to your project.

If you haven't done so, start the Remotion Recorder:

tsx
bun run dev

A Vite app will listen on http://localhost:4000.
Open this URL in the browser.
Give the page access to the webcam and microphone.

Select the composition

Recordings need to be stored in a subfolder of public named after the composition ID.
For example, if you want to record for the composition my-video, recordings will be stored under public/my-video.

In the top right corner, use the dropdown to "Create a new folder".
Use the ID of the composition you want to record for as the folder name.
The folder will be created and your subsequent recordings will be saved in this folder.

Select sources

In the top left panel, select your webcam and microphone.
In the top right panel, optionally select the screen you want to record.

You can record more sources, but out of the box, the Remotion Recorder does not do anything with them.

Before starting

Say "Test One Two Three" and ensure the volume meter is not going into the red zone.

Make sure you are centered in the video. You can enable the crop target overlay to see how the video will crop when miniaturized.

Prefer making short recordings. You're less likely to make a mistake and it's easy to stitch them together.

There is no countdown – The recording will start immediately.
However, the Recorder will later automatically trim away the silence in the beginning.

Take a deep breath and think of what you are about to say and show.

You're ready to record!

Start the recording

text
To start recording, press <kbd>R</kbd> or click{' '}
in the top left corner.

Once you are done with the scene, click

.

Selecting a take

After you have recorded a scene and you are happy with your take, click "Use this take".

The server will then do the following:

  • Convert the videos from WebM to MP4
  • Put them into your project under public/[composition-id].
  • Caption the files with Whisper.cpp

Discard a take

If you have taken a recording that you don't want to use, click "Discard and retake" to clear the existing recording from memory.

record.remotion.dev

You can also use the hosted version of the recoding interface at record.remotion.dev.

It will not allow you to select a save destination, but instead download the recordings to your Downloads folder.

They will have names like webcam171234567890.mp4 and display171234567890.mp4.

To copy the recordings to your Remotion project, first open copy.ts in your code editor. Set the prefix at the top of your file to the ID of the composition that you gave when you first created a new video.

ts title="copy.ts"
const prefix = '<id-of-your-composition>';

Then run the copy.ts script whenever you want to save a take and immediately generate captions:

bash
bun copy.ts
bun sub.ts

If you want to not use a take, just make another recording. The copy.ts script will only take the recordings with the latest timestamp.


Packages Docs Docs Transitions Presentations Index (`packages/docs/docs/transitions/presentations/index.mdx`)


image: /generated/articles-docs-transitions-presentations-index.png title: Presentations crumb: "@remotion/transitions"

A presentation together with a timing forms a transition.
Remotion provides certain presentations out of the box, but you can also create your own.

Table of contents

import { Presentations } from "../../../components/TableOfContents/transitions/presentations";


Packages Docs Docs Transitions Timings Index (`packages/docs/docs/transitions/timings/index.mdx`)


image: /generated/articles-docs-transitions-timings-index.png title: Timings crumb: "@remotion/transitions"

A timing together with a presentation forms a transition.
Remotion provides certain timings out of the box, but you can also create your own.

Available timings

import { Timings } from "../../../components/TableOfContents/transitions/timings";

Getting the duration of a timing

You can get the duration of a transition by calling getDurationInFrames() on the timing:

tsx twoslash title="assuming a framerate of 30fps"
import { springTiming } from "@remotion/transitions";

springTiming({ config: { damping: 200 } }).getDurationInFrames({ fps: 30 }); // 23

Packages Docs Elements Audio Mirrored Spectrum Index (`packages/docs/elements/audio/mirrored-spectrum/index.mdx`)


title: Mirrored Spectrum image: https://remotion.media/elements/audio-mirrored-spectrum-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Mirrored Spectrum

<ElementPage definition={getElementDefinition('audio/mirrored-spectrum')} sourceFile="./mirrored-spectrum.tsx" />


Packages Docs Elements Audio Oscilloscope Index (`packages/docs/elements/audio/oscilloscope/index.mdx`)


title: Oscilloscope image: https://remotion.media/elements/audio-oscilloscope-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Oscilloscope

<ElementPage definition={getElementDefinition('audio/oscilloscope')} sourceFile="./audio-oscilloscope.tsx" />


Packages Docs Elements Audio Waveform Progress Index (`packages/docs/elements/audio/waveform-progress/index.mdx`)


title: Voice Note image: https://remotion.media/elements/audio-waveform-progress-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Voice Note

<ElementPage definition={getElementDefinition('audio/waveform-progress')} sourceFile="./audio-waveform-progress.tsx" />


Packages Docs Elements Backgrounds Liquid Contours Index (`packages/docs/elements/backgrounds/liquid-contours/index.mdx`)


title: Liquid Contours image: https://remotion.media/elements/backgrounds-liquid-contours-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Liquid Contours

<ElementPage definition={getElementDefinition('backgrounds/liquid-contours')} sourceFile="./liquid-contours.tsx" />


Packages Docs Elements Backgrounds Moving Waves Index (`packages/docs/elements/backgrounds/moving-waves/index.mdx`)


title: Moving Waves image: https://remotion.media/elements/backgrounds-moving-waves-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Moving Waves

<ElementPage definition={getElementDefinition('backgrounds/moving-waves')} sourceFile="./moving-waves.tsx" />


Packages Docs Elements Backgrounds Moving Zigzags Index (`packages/docs/elements/backgrounds/moving-zigzags/index.mdx`)


title: Moving Zigzags image: https://remotion.media/elements/backgrounds-moving-zigzags-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Moving Zigzags

<ElementPage definition={getElementDefinition('backgrounds/moving-zigzags')} sourceFile="./moving-zigzags.tsx" />


Packages Docs Elements Backgrounds Notebook Paper Index (`packages/docs/elements/backgrounds/notebook-paper/index.mdx`)


title: Notebook Paper image: https://remotion.media/elements/backgrounds-notebook-paper-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Notebook Paper

<ElementPage definition={getElementDefinition('backgrounds/notebook-paper')} sourceFile="./notebook-paper.tsx" />


Packages Docs Elements Backgrounds Paper Texture Index (`packages/docs/elements/backgrounds/paper-texture/index.mdx`)


title: Paper Texture image: https://remotion.media/elements/backgrounds-paper-texture-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Paper Texture

<ElementPage definition={getElementDefinition('backgrounds/paper-texture')} sourceFile="./paper-texture.tsx" />


Packages Docs Elements Backgrounds Rotating Starburst Index (`packages/docs/elements/backgrounds/rotating-starburst/index.mdx`)


title: Rotating Starburst image: https://remotion.media/elements/backgrounds-rotating-starburst-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Rotating Starburst

<ElementPage definition={getElementDefinition('backgrounds/rotating-starburst')} sourceFile="./rotating-starburst.tsx" />


Packages Docs Elements Captions Basic Captions Index (`packages/docs/elements/captions/basic-captions/index.mdx`)


title: Basic Captions sidebar_label: Basic image: https://remotion.media/elements/captions-basic-captions-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Basic Captions

<ElementPage definition={getElementDefinition('captions/basic-captions')} sourceFile="./basic-captions.tsx" />


Packages Docs Elements Captions Moving Pill Captions Index (`packages/docs/elements/captions/moving-pill-captions/index.mdx`)


title: Moving Pill Captions sidebar_label: Moving Pill image: https://remotion.media/elements/captions-moving-pill-captions-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Moving Pill Captions

<ElementPage definition={getElementDefinition('captions/moving-pill-captions')} sourceFile="./moving-pill-captions.tsx" />


Packages Docs Elements Captions Popping Word Captions Index (`packages/docs/elements/captions/popping-word-captions/index.mdx`)


title: Popping Word Captions sidebar_label: Popping Word image: https://remotion.media/elements/captions-popping-word-captions-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Popping Word Captions

<ElementPage definition={getElementDefinition('captions/popping-word-captions')} sourceFile="./popping-word-captions.tsx" />


Packages Docs Elements Captions Rounded Captions Index (`packages/docs/elements/captions/rounded-captions/index.mdx`)


title: Rounded Captions sidebar_label: Rounded image: https://remotion.media/elements/captions-rounded-captions-preview-694426c4-721c-484f-8a33-79f21d54da5d.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Rounded Captions

Based on the @remotion/rounded-text-box demo.

<ElementPage definition={getElementDefinition('captions/rounded-captions')} sourceFile="./rounded-captions.tsx" />


Packages Docs Elements Captions Word Highlight Captions Index (`packages/docs/elements/captions/word-highlight-captions/index.mdx`)


title: Word Highlight Captions sidebar_label: Word Highlight image: https://remotion.media/elements/captions-word-highlight-captions-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Word Highlight Captions

<ElementPage definition={getElementDefinition('captions/word-highlight-captions')} sourceFile="./word-highlight-captions.tsx" />


Packages Docs Elements Commerce Peel Index (`packages/docs/elements/commerce/peel/index.mdx`)


title: Peel image: https://remotion.media/elements/commerce-peel-preview-57fbe8da-01d3-405c-82f9-84707b1ce6fa.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Peel

<ElementPage definition={getElementDefinition('commerce/peel')} sourceFile="./peel.tsx" />


Packages Docs Elements Commerce Product Collection Index (`packages/docs/elements/commerce/product-collection/index.mdx`)


title: Rotating Cards image: https://remotion.media/elements/commerce-product-collection-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Rotating Cards

<ElementPage definition={getElementDefinition('commerce/product-collection')} sourceFile="./product-collection.tsx" />


Packages Docs Elements Commerce Product Discount Callout Index (`packages/docs/elements/commerce/product-discount-callout/index.mdx`)


title: Wiggling Callout image: https://remotion.media/elements/commerce-product-discount-callout-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Wiggling Callout

<ElementPage definition={getElementDefinition('commerce/product-discount-callout')} sourceFile="./product-discount-callout.tsx" />


Packages Docs Elements Commerce Shine Index (`packages/docs/elements/commerce/shine/index.mdx`)


title: Shine image: https://remotion.media/elements/commerce-shine-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Shine

<ElementPage definition={getElementDefinition('commerce/shine')} sourceFile="./shine.tsx" />


Packages Docs Elements Commerce Tear Index (`packages/docs/elements/commerce/tear/index.mdx`)


title: Tear apart image: https://remotion.media/elements/commerce-tear-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Tear apart

<ElementPage definition={getElementDefinition('commerce/tear')} sourceFile="./tear.tsx" />


Packages Docs Elements Data Horizontal Bar Chart Index (`packages/docs/elements/data/horizontal-bar-chart/index.mdx`)


title: Horizontal Bar Chart image: https://remotion.media/elements/data-horizontal-bar-chart-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Horizontal Bar Chart

<ElementPage definition={getElementDefinition('data/horizontal-bar-chart')} sourceFile="./horizontal-bar-chart.tsx" />


Packages Docs Elements Data Line Chart Index (`packages/docs/elements/data/line-chart/index.mdx`)


title: Line Chart image: https://remotion.media/elements/data-line-chart-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Line Chart

<ElementPage definition={getElementDefinition('data/line-chart')} sourceFile="./line-chart.tsx" />


Packages Docs Elements Data Number Counter Index (`packages/docs/elements/data/number-counter/index.mdx`)


title: Number Counter image: https://remotion.media/elements/data-number-counter-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Number Counter

<ElementPage definition={getElementDefinition('data/number-counter')} sourceFile="./number-counter.tsx" />


Packages Docs Elements Data Pie Chart Index (`packages/docs/elements/data/pie-chart/index.mdx`)


title: Pie Chart image: https://remotion.media/elements/data-pie-chart-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Pie Chart

<ElementPage definition={getElementDefinition('data/pie-chart')} sourceFile="./pie-chart.tsx" />


Packages Docs Elements Data Vertical Bar Chart Index (`packages/docs/elements/data/vertical-bar-chart/index.mdx`)


title: Vertical Bar Chart image: https://remotion.media/elements/data-vertical-bar-chart-preview.png

import {ElementPage} from '@site/src/components/Elements/ElementPage';
import {getElementDefinition} from '@site/src/components/Elements/element-utils';

Vertical Bar Chart

<ElementPage definition={getElementDefinition('data/vertical-bar-chart')} sourceFile="./vertical-bar-chart.tsx" />


--- METRICS ---