Skip to content
Back to skills

Remotion Video

ASecurity

This skill should be used when the user asks to "make a video with Remotion", "create a programmatic/data-driven video in React", "render an MP4/GIF from code", "animate with useCurrentFrame/interpolate/spring", "sync video to audio/beats", or "render a templated video per record headlessly". Covers building React compositions and rendering them via CLI or @remotion/renderer.

  • 24 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added August 31, 2026
designgobashreactnodespringcode-reviewapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned August 31, 2026

npx -y skills add iart-ai/motion-design-skills --skill remotion-video --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Remotion Video?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Remotion Video
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/iart-ai-remotion-video/badge)](https://www.skillsdirectory.com/skills/iart-ai-remotion-video)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: remotion-video
description: This skill should be used when the user asks to "make a video with Remotion", "create a programmatic/data-driven video in React", "render an MP4/GIF from code", "animate with useCurrentFrame/interpolate/spring", "sync video to audio/beats", or "render a templated video per record headlessly". Covers building React compositions and rendering them via CLI or @remotion/renderer.
version: 0.1.0
---

# Remotion (Programmatic Video)

Build real MP4/GIF/WebM videos in React. Every frame is a pure function of `useCurrentFrame()`, so output is deterministic, scrubbable, diffable, and renderable in CI. The code-first alternative to After Effects for templated and data-driven motion graphics.

## When to use

- Render MP4/GIF/WebM from code (social clips, title cards, explainers).
- Templated/data-driven videos: one composition, many outputs from props (per-user, per-record, per-row of a CSV/DB).
- Motion graphics that must be versioned, code-reviewed, and rendered in CI without a GUI.
- Programmatic audio sync, charts that animate from data, or embedding shaders/Three.js into video.

## Core techniques

### Frame-driven animation

Animation is derived from the current frame, never from `setState` or `requestAnimationFrame`. `interpolate` maps an input range to an output range; `spring` produces physically natural motion.

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

export const Title = () => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();

  // Fade in over frames 0-30, then stay (clamp prevents over/undershoot).
  const opacity = interpolate(frame, [0, 30], [0, 1], {
    extrapolateLeft: 'clamp',
    extrapolateRight: 'clamp',
  });

  // Spring entrance; divide by spring duration is unnecessary — drive transforms directly.
  const scale = spring({frame, fps, config: {damping: 200, mass: 1, stiffness: 100}});

  return <h1 style={{opacity, transform: `scale(${scale})`}}>Hello</h1>;
};
```

Always clamp `interpolate` unless an intentional overshoot is desired — by default it extrapolates linearly past the range, which produces opacity > 1 or negative values.

### Scheduling: Sequence and Series

`<Sequence>` shifts time: children see `frame` reset to 0 at the sequence's `from`. Use it to place clips on a timeline. `<Series>` lays out back-to-back segments without manual offset math.

```jsx
import {Sequence, Series, AbsoluteFill} from 'remotion';

export const Timeline = () => (
  <AbsoluteFill style={{backgroundColor: 'black'}}>
    <Sequence from={0} durationInFrames={60}><Intro /></Sequence>
    <Sequence from={60} durationInFrames={90}><Body /></Sequence>

    {/* Series auto-sequences; offset overlaps the previous segment for crossfades */}
    <Series>
      <Series.Sequence durationInFrames={60}><ShotA /></Series.Sequence>
      <Series.Sequence durationInFrames={60} offset={-15}><ShotB /></Series.Sequence>
    </Series>
  </AbsoluteFill>
);
```

### Composition registration + parametric props

The `<Composition>` declares id, size, fps, duration, and `defaultProps`. A zod schema makes props type-safe and editable in the Studio sidebar.

```jsx
import {Composition} from 'remotion';
import {z} from 'zod';

export const schema = z.object({
  title: z.string(),
  accent: z.string(),
  fps: z.number().default(30),
});

export const Root = () => (
  <Composition
    id="Promo"
    component={Promo}
    durationInFrames={150}
    fps={30}
    width={1080}
    height={1920}
    schema={schema}
    defaultProps={{title: 'Launch', accent: '#5b8cff', fps: 30}}
  />
);
```

To make duration data-dependent, use `calculateMetadata` on the Composition to compute `durationInFrames` from props (e.g. number of rows × frames per row) before render.

### Audio and beat sync

```jsx
import {Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';

const BEATS_SEC = [0.5, 1.0, 1.5, 2.0]; // detected offline
export const Music = ({children}) => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig();
  const t = frame / fps;
  const onBeat = BEATS_SEC.some((b) => Math.abs(t - b) < 1 / fps);
  return (
    <>
      <Audio src={staticFile('track.mp3')} />
      <div style={{transform: `scale(${onBeat ? 1.06 : 1})`}}>{children}</div>
    </>
  );
};
```

Detect beats offline (e.g. with `web-audio-beat-detector` or aubio) and bake the timestamps into props — never analyze audio at render time, since headless rendering has no realtime audio clock.

### Rendering

Preview in the browser-based Studio; render headlessly via CLI or the programmatic API.

```bash
npx remotion studio                                  # interactive preview
npx remotion render Promo out/promo.mp4 \
  --props='{"title":"Launch","accent":"#f43"}'        # pass parametric props
npx remotion render Promo out.gif --codec=gif         # GIF output
```

For batch/data-driven pipelines, render in Node with `@remotion/renderer` (bundle once, render many) — see the reference file.

## Deliver & verify (rendered stills → MP4)

> **Packaged helper** (`scripts/`): tile your stills with `scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png`, then assert the encode with `scripts/probe-mp4.sh out.mp4 [WxH] [fps]`. See `scripts/README.md`.

Remotion is frame-deterministic by construction — every frame is a pure function of `useCurrentFrame()`, so you can render any exact frame headlessly with **no seek harness** (this is the heavy-tier counterpart to a web scene's `?t=N`). Use this tier when the output must be an MP4/GIF, must carry exact numbers/text, or batches from data; for a lightweight web animation, deliver standalone HTML instead.

**Output contract:**
- A Remotion project with the composition registered (`<Composition>` + zod `schema` + `defaultProps`), all motion frame-driven (no timers / `Date.now()` / `Math.random()`).
- Deliverable = the rendered `out/*.mp4` (plus the project, so the user can re-render with new props/data).
- Duration data-dependent? compute it in `calculateMetadata`, not by hand.

**Verify loop — render stills → inspect → encode.** Render single frames first (cheap, no video encode), inspect them, and encode the full video only once the frames are right.

```bash
# 1. Frame-exact stills at start / mid / end (PNG, headless, fast)
npx remotion still Promo out/f-start.png --frame=0
npx remotion still Promo out/f-mid.png   --frame=75
npx remotion still Promo out/f-end.png   --frame=149   # last frame = durationInFrames - 1
#    render with the SAME props you'll ship, not just defaultProps:
#    npx remotion still Promo out/f-mid.png --frame=75 --props='{"title":"Launch"}'

# 2. Inspect each PNG — fidelity (matches brief; numbers/text correct) AND
#    artifacts (text overflow, off-canvas, clipped safe-area, missing font, wrong data binding).

# 3. Only after the stills check out, encode the video:
npx remotion render Promo out/promo.mp4 --props='{"title":"Launch"}'
```

- Use `npx remotion compositions` to read each composition's `durationInFrames`/`fps` and pick the end frame.
- **Data-driven / batch**: verify ONE representative props set via stills *before* batch-rendering all rows — catch a layout bug once instead of N times.
- **README demo GIF for free**: `npx remotion render Promo out/demo.gif --codec=gif` produces the first-screen proof clip (Direction D).

**Before you finish:**
1. `npx remotion still` renders cleanly at frame 0, mid, and last — no errors, no missing assets/fonts.
2. Numbers/text are exact and inside safe areas at every checked frame.
3. Frame-driven only — no `Date.now()` / `Math.random()` / timers (determinism holds in CI).
4. Props are zod-typed; the **shipped** props render correctly (not just `defaultProps`).
5. Full MP4 encoded and plays; (optional) GIF rendered for the README.

## Quick reference

| Need | Use |
|---|---|
| Map time → value | `interpolate(frame, [a,b], [x,y], {extrapolateRight:'clamp'})` |
| Natural easing | `spring({frame, fps, config})` |
| Place a clip at t | `<Sequence from durationInFrames>` |
| Back-to-back shots | `<Series>` |
| Audio | `<Audio src={staticFile(...)} />` |
| Frame ↔ seconds | `frame / fps` |
| Loop a value | `frame % period` then interpolate |
| Editable props | zod `schema` on `<Composition>` |
| CI render | `npx remotion render` or `@remotion/renderer` |

## Gotchas

- Never use `Math.random()`, `Date.now()`, or animation timers — they break determinism. Use `random(seed)` from Remotion for stable per-frame randomness.
- Load fonts and assets via `staticFile()` and wait with `delayRender`/`continueRender`, or fonts pop in mid-render.
- Default `interpolate` extrapolates — clamp it.
- `useCurrentFrame` inside a `<Sequence>` is local (starts at 0); use `useVideoConfig().durationInFrames` for absolute timing.

## Reference files

- `references/api-and-patterns.md` — `interpolate` options and `Easing`, spring config recipes, Sequence/Series scheduling, `<Audio>` + beat-sync, parametric `defaultProps` with zod + `calculateMetadata`, CLI flags, programmatic `@remotion/renderer` batch rendering, and embedding GLSL shaders / Three.js (`@remotion/three`).

Files in this skill

  • SKILL.md9 KB
  • references/api-and-patterns.md7.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.