How to Use the Sequence Component for Layering Clips in Remotion
The <Sequence> component creates time-shifted, absolutely-positioned layers by wrapping each clip in an <AbsoluteFill> container that renders only during its specified frame range, enabling complex video compositions through simple JSX nesting.
The Sequence component from the remotion-dev/remotion repository is the fundamental building block for orchestrating multiple media elements in time. By assigning temporal offsets and durations to nested JSX elements, you can stack videos, images, and animations into sophisticated layered compositions without imperative timeline manipulation.
Understanding the Sequence Component Architecture
The layering capability relies on a context-based architecture that tracks temporal metadata across the component tree.
SequenceContext and Temporal Offsets
Each <Sequence> instantiates a SequenceContext ([packages/core/src/SequenceContext.tsx](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/SequenceContext.tsx)) that stores cumulatedFrom and relativeFrom values. These properties calculate the absolute frame position by accumulating offsets from parent sequences, allowing child components to determine their precise location on the global timeline.
SequenceManager Registration
When rendering in the Remotion Studio or during prerendering, each sequence registers itself with the SequenceManager ([packages/core/src/SequenceManager.tsx](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/SequenceManager.tsx)). This registration enables the timeline UI to visualize sequence boundaries and provides visibility toggling for debugging layered compositions.
Rendering Logic and AbsoluteFill
The core implementation in [packages/core/src/Sequence.tsx](https://github.com/remotion-dev/remotion/blob/main/packages/core/src/Sequence.tsx) uses useTimelinePosition to compute the absolute frame. It conditionally renders children based on the current frame, the sequence's from offset, and durationInFrames. When active, children are wrapped in <AbsoluteFill> by default, creating a CSS-stacking context that allows sequences to overlay one another.
Layering Mechanics with Sequence
Layering clips requires coordinating three primary properties: temporal offset, duration, and stacking order.
Time-Shifting with from and durationInFrames
The from prop defines the frame offset where a sequence begins on the global timeline. The durationInFrames prop controls how long the sequence remains mounted. By varying these values across multiple sequences, you create clips that appear and disappear at specific times.
import {Sequence} from 'remotion';
import {BackgroundVideo} from './BackgroundVideo';
import {ForegroundGraphic} from './ForegroundGraphic';
export const LayeredComposition = () => {
return (
<>
{/* Runs from frame 0 to 299 */}
<Sequence durationInFrames={300}>
<BackgroundVideo />
</Sequence>
{/* Appears at frame 60, runs for 60 frames */}
<Sequence from={60} durationInFrames={60}>
<ForegroundGraphic />
</Sequence>
</>
);
};
Stacking Order and Z-Index
By default, each sequence renders with layout="absolute-fill", which applies position: absolute; inset: 0 to a wrapper div. Later siblings in the JSX tree paint above earlier siblings, following standard CSS stacking context rules. This means the last <Sequence> in your component tree appears as the topmost layer.
Layout Options for Custom Positioning
While layout="absolute-fill" is optimal for full-screen layers, you can disable the automatic wrapper by setting layout="none". This is essential when nesting sequences inside custom canvases, such as Three.js scenes, or when you need precise control over positioning.
import {Sequence} from 'remotion';
import {ThreeCanvas} from './ThreeCanvas';
import {UIOverlay} from './UIOverlay';
export const CustomLayoutExample = () => {
return (
<>
{/* No wrapper div for the 3D scene */}
<Sequence layout="none">
<ThreeCanvas />
</Sequence>
{/* UI overlay with default absolute positioning */}
<Sequence from={30} layout="absolute-fill">
<UIOverlay />
</Sequence>
</>
);
};
Practical Examples for Layering Clips
Basic Three-Layer Composition
This example demonstrates a typical workflow: an intro clip, a main video, and a semi-transparent overlay that appears on top of the main content.
import {Sequence, AbsoluteFill} from 'remotion';
import {IntroAnimation} from './IntroAnimation';
import {MainContent} from './MainContent';
import {Watermark} from './Watermark';
export const MyVideo = () => {
return (
<>
{/* Layer 1: Intro (frames 0-29) */}
<Sequence durationInFrames={30}>
<IntroAnimation />
</Sequence>
{/* Layer 2: Main content (frames 30-89) */}
<Sequence from={30} durationInFrames={60}>
<MainContent />
</Sequence>
{/* Layer 3: Watermark overlay (frames 45-75) */}
<Sequence from={45} durationInFrames={30}>
<AbsoluteFill style={{backgroundColor: 'rgba(0,0,0,0.3)'}}>
<Watermark />
</AbsoluteFill>
</Sequence>
</>
);
};
Integrating with Three.js Using layout="none"
When combining Remotion with WebGL libraries, you must prevent the default absolute-fill wrapper from interfering with the canvas rendering context.
import {Sequence} from 'remotion';
import {ThreeScene} from './ThreeScene';
import {HtmlAnnotation} from './HtmlAnnotation';
export const ThreeCanvasExample = () => {
return (
<>
{/* 3D scene without wrapper div */}
<Sequence layout="none">
<ThreeScene />
</Sequence>
{/* HTML overlay positioned absolutely over the canvas */}
<Sequence from={60} layout="none">
<div style={{position: 'absolute', top: 20, left: 20, color: 'white'}}>
<HtmlAnnotation />
</div>
</Sequence>
</>
);
};
Preventing Flicker with Premounting
For components with expensive initialization (like video decoding or complex shaders), use premountFor and postmountFor to keep the layer rendered outside its visible range, ensuring smooth timeline scrubbing.
import {Sequence} from 'remotion';
import {HeavyVideoComponent} from './HeavyVideoComponent';
export const PremountExample = () => {
return (
<Sequence
from={100}
durationInFrames={200}
premountFor={30} // Render 30 frames before frame 100
postmountFor={30} // Keep rendered 30 frames after frame 300
>
<HeavyVideoComponent />
</Sequence>
);
};
Advanced Layering Techniques
Nested Sequences for Reusable Sub-Clips
Sequences can be nested to create modular, reusable components that carry their own internal timing. The SequenceContext automatically accumulates offsets, so a child sequence's from prop is relative to its parent's start frame.
import {Sequence} from 'remotion';
import {LowerThirds} from './LowerThirds';
// Reusable sub-clip that runs for 60 frames internally
const BrandedLowerThird = () => {
return (
<Sequence durationInFrames={60}>
<LowerThirds />
</Sequence>
);
};
// Parent composition places the sub-clip at frame 120
export const MainVideo = () => {
return (
<Sequence from={120}>
<BrandedLowerThird />
</Sequence>
);
};
Ref Handling for Dynamic Measurements
From version 3.2.13, you can attach a React ref to a sequence to access the underlying DOM node. This is useful for dynamically measuring layer dimensions or integrating with imperative animation libraries.
import {useRef} from 'react';
import {Sequence} from 'remotion';
export const MeasurableLayer = () => {
const sequenceRef = useRef<HTMLDivElement>(null);
return (
<Sequence ref={sequenceRef} from={50} durationInFrames={100}>
<div>Content to measure</div>
</Sequence>
);
};
Summary
- Temporal Control: Use the
fromanddurationInFramesprops to define when each layer appears and disappears on the global timeline. - Automatic Stacking: By default, each sequence wraps children in an
<AbsoluteFill>container, creating CSS stacking contexts where later siblings render above earlier ones. - Layout Flexibility: Set
layout="none"to disable the automatic wrapper when integrating with WebGL canvases or custom positioning systems. - Performance Optimization: Use
premountForandpostmountForto keep expensive components rendered outside their visible range, ensuring smooth timeline scrubbing. - Modularity: Nest sequences to create reusable sub-clips with internal timing that automatically accumulate offsets from parent sequences.
Frequently Asked Questions
How do I change the z-index of a sequence layer?
Remotion sequences rely on the standard CSS stacking order rather than explicit z-index values. By default, each sequence renders with layout="absolute-fill", which applies position: absolute; inset: 0 to a wrapper div. Later siblings in your JSX tree automatically appear above earlier siblings. To reorder layers, rearrange the sequence declarations in your component so that the desired topmost layer appears last.
Can I use sequences inside a Three.js or WebGL canvas?
Yes, but you must disable the default layout wrapper. Set layout="none" on the sequence to prevent it from rendering an <AbsoluteFill> div that would interfere with the WebGL rendering context. This allows you to nest Remotion sequences directly inside Three.js scenes or other canvas-based environments while still benefiting from temporal control via from and durationInFrames.
What is the difference between from and delay?
The from prop specifies the absolute frame offset on the global timeline where the sequence begins rendering. Internally, this value is stored as relativeFrom in the SequenceContext and accumulated into cumulatedFrom for nested sequences. While delay is not a standard prop on the Sequence component, you can achieve delayed starts by increasing the from value. The sequence will remain unmounted until the timeline reaches the specified frame, conserving React rendering cycles.
How do I prevent flickering when scrubbing past a sequence boundary?
Use the premountFor and postmountFor props available from Remotion v3.2.13 onwards. Set premountFor to a positive number of frames to keep the component rendered before its from offset, and postmountFor to maintain it after its durationInFrames ends. This ensures that expensive initialization—such as video decoding or shader compilation—completes before the layer becomes visible, eliminating flicker during timeline scrubbing or rapid frame seeking.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →