Code Scenes

Code scenes are the heart of Program. They're React components that render animated, interactive, data-driven visuals using Remotion.


What makes code scenes powerful

Unlike traditional video editing where you're limited to existing assets, code scenes let you create anything you can imagine. Animate text character by character. Visualize live data. Generate graphics procedurally. If you can code it in React, you can render it as video.

Anatomy of a code scene

Every code scene is a React component that exports a default function:

import { AbsoluteFill, useCurrentFrame, interpolate } from "remotion";

export default function MyScene() {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 30], [0, 1]);

  return (
    <AbsoluteFill style={{ backgroundColor: "#1a1a1a" }}>
      <h1 style={{ color: "white", opacity }}>
        Hello, video
      </h1>
    </AbsoluteFill>
  );
}
Key parts:
  • AbsoluteFill: a full-screen container that fills the video frame
  • useCurrentFrame(): returns the current frame number (0 to duration in frames)
  • interpolate(): maps frame numbers to visual values (opacity, position, scale)

Adding code scenes

Via AI

Describe what you want and the AI writes the component:

Add a scene with the text "Welcome" that fades in over 2 seconds

The AI creates the React code, adds the scene to your composition, and you see it render immediately.

Via CLI

Use the addScene tool with your component code:

program tool exec addScene \
  --title "Intro" \
  --duration 5 \
  --code 'export default function Intro() {
    return (
      <AbsoluteFill style={{ backgroundColor: "#000" }}>
        <h1 style={{ color: "white" }}>Welcome</h1>
      </AbsoluteFill>
    );
  }'

For more complex scenes, you can pass the code from a file:

program tool exec addScene \
  --title "Intro" \
  --duration 5 \
  --code "$(cat intro-scene.tsx)"

In the editor

Click "New Layer" in the timeline to create a blank scene. Select it and switch to code view to write your component directly. Changes save automatically and the preview updates in real-time.

Available APIs

Code scenes have access to Remotion's full API and more:

Remotion core

APIPurpose
useCurrentFrame()Current frame number
useVideoConfig()FPS, dimensions, total duration
interpolate()Smooth value transitions
spring()Physics-based animations
EasingEasing functions (ease-in, ease-out, etc.)
SequenceTime-offset nested content
SeriesSequential content blocks

Media

APIPurpose
OffthreadVideoEfficient video embedding
AudioAudio playback
ImgImage display
IFrameEmbed external content

Utilities

APIPurpose
staticFile()Reference static assets
prefetch()Preload assets
delayRender() / continueRender()Async loading

React hooks

Standard React hooks work in code scenes: useState, useEffect, useMemo, useCallback, useRef, and more.

Animation basics

Animations in Remotion are declarative. Instead of timelines and keyframes, you calculate visual values from the current frame.

Interpolation

interpolate() maps an input range to an output range:
const frame = useCurrentFrame();

// Fade in over first 30 frames
const opacity = interpolate(frame, [0, 30], [0, 1]);

// Slide in from left
const translateX = interpolate(frame, [0, 60], [-100, 0]);

Add easing for natural motion:

import { Easing } from "remotion";

const scale = interpolate(
  frame,
  [0, 30],
  [0.5, 1],
  { easing: Easing.out(Easing.ease) }
);

Springs

For physics-based motion that feels organic:

import { spring, useVideoConfig } from "remotion";

const { fps } = useVideoConfig();
const scale = spring({
  frame,
  fps,
  config: { damping: 10, mass: 0.5 }
});

Springs naturally settle into their final value with bounce and overshoot.

Sequences

Break your scene into timed segments:

import { Sequence, AbsoluteFill } from "remotion";

export default function MultiPartScene() {
  return (
    <AbsoluteFill>
      <Sequence from={0} durationInFrames={60}>
        <TitleSection />
      </Sequence>
      <Sequence from={60} durationInFrames={90}>
        <ContentSection />
      </Sequence>
    </AbsoluteFill>
  );
}

Each Sequence resets useCurrentFrame() to 0 for its children.

Multi-file components

Code scenes can span multiple files. Create utility functions, shared styles, or sub-components:

index.tsx        # Main component (entry point)
animations.ts    # Reusable animation functions
Logo.tsx         # Sub-component
constants.ts     # Shared values

Import between files with relative paths:

import { fadeIn } from "./animations";
import { Logo } from "./Logo";

External dependencies

Use npm packages directly in your code:

import { motion } from "framer-motion";
import confetti from "canvas-confetti";

Packages are loaded from CDN at render time. Most popular libraries work out of the box.

Styling

Multiple styling approaches work:

Inline styles (most common):
<div style={{ backgroundColor: "blue", padding: 20 }} />
Tailwind CSS (available in code scenes):
<div className="bg-blue-500 p-5 rounded-lg" />
CSS imports (for fonts):
// At the top of your component
// @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');

Props and customization

Make scenes reusable by accepting props:

interface Props {
  title: string;
  color?: string;
  animate?: boolean;
}

export default function TitleScene({
  title,
  color = "white",
  animate = true
}: Props) {
  const frame = useCurrentFrame();
  const opacity = animate
    ? interpolate(frame, [0, 30], [0, 1])
    : 1;

  return (
    <AbsoluteFill>
      <h1 style={{ color, opacity }}>{title}</h1>
    </AbsoluteFill>
  );
}

Props are passed when the scene is added to a composition.

Performance tips

Memoize expensive calculations:
const processedData = useMemo(() => {
  return heavyComputation(rawData);
}, [rawData]);
Avoid re-renders: Code scenes re-render every frame. Keep render logic fast. Preload assets: Use prefetch() for videos and images to avoid playback stutter. Use OffthreadVideo: For embedded videos, OffthreadVideo renders off the main thread.

Error handling

Code scenes are wrapped in an error boundary. If your code throws:

1. The error is caught and logged 2. A fallback is shown in the preview 3. Fix the code and the preview recovers automatically

Check the browser console for detailed error messages.

Common patterns

Typewriter effect

const frame = useCurrentFrame();
const text = "Hello, world";
const charsToShow = Math.floor(frame / 3);
const displayText = text.slice(0, charsToShow);

Staggered list items

{items.map((item, index) => {
  const delay = index * 10;
  const opacity = interpolate(
    frame,
    [delay, delay + 20],
    [0, 1],
    { extrapolateLeft: "clamp" }
  );
  return <li style={{ opacity }}>{item}</li>;
})}

Looping animations

const progress = (frame % 60) / 60; // 0 to 1 every 60 frames
const rotation = progress * 360;

For embedding existing video content, see Video Scenes.