🎬 Sequence from= — the time offset
The prop from of the Sequence is simple and powerful: it specifies the frame where this block starts existing in the video. Before that frame, the child component simply isn’t rendered. Afterward, the local frame starts at zero—as if the clock reset for that element.
🎯 The central idea
Inside a Sequence, useCurrentFrame() returns 0 at the frame from, 1 on the frame from+1, and so on. This means animations inside Sequences are always relative to their start — not at the start of the video.
- •The child does not exist before frame
from— it isn't rendered or take up space. - •The local frame within the Sequence always starts at 0.
- •Combine with
durationInFramesalso limits the end of its existence.
import { Sequence, useCurrentFrame, spring, useVideoConfig } from "remotion"; export const StaggedEntry = () => { const { fps } = useVideoConfig(); return ( <> {/* Título aparece imediatamente */} <Sequence from={0}> <Title /> </Sequence> {/* Subtítulo entra 15 frames depois */} <Sequence from={15}> <Subtitle /> </Sequence> {/* Lista entra após 30 frames */} <Sequence from={30}> <ItemList /> </Sequence> </> ); };
💡 Practical tip
Drag the Remotion Studio timeline bar to frame 14 — the Subtitle doesn’t exist yet. Go to 15 — it appears. This direct visual control is the best way to calibrate your offsets.
🪜 Stagger with index * N
The stagger pattern is the most common in animated lists, menus, and grids: each item gets a from based on its index multiplied by a constant N. The result feels like a “cascade”—the elements enter one after another naturally.
✓ What to DO
- ✓Use
from={index * N}where N = 4 to 8 frames. - ✓Combine with a local spring() for each smooth entrance.
- ✓Use small N values for long lists (to avoid long waits).
✗ What NOT to do
- ✗N too large (>15) makes the list take too long to complete.
- ✗Stagger for items the viewer doesn't follow in order.
- ✗Forgetting to add the offset to
fromfrom the parent group.
const items = ["React", "Remotion", "TypeScript", "Vite"]; const STAGGER = 6; // frames entre cada entrada return ( <> {items.map((item, index) => ( <Sequence key={item} from={index * STAGGER}> <AnimatedItem text={item} /> </Sequence> ))} </> ); // Dentro de AnimatedItem: const frame = useCurrentFrame(); // começa em 0 para cada item const { fps } = useVideoConfig(); const scale = spring({ frame, fps, config: { damping: 14 } }); const opacity = interpolate(frame, [0, 8], [0, 1], { extrapolateRight: "clamp" });
🔗 Sync End with Start — Overlap
One of the most effective timing techniques is to make element B start while A is still exiting. This intentional overlap eliminates the “gap” of an empty screen and smoothly shifts the viewer’s attention from one element to another.
Calculate the from value for element A
Ex: TITLE_START = 0, TITLE_DUR = 60 (frames the title stays visible).
Define the desired overlap
Typically 8–12 frames. Too much overlap creates confusion; too little doesn’t feel smooth.
Derive B's from
LIST_START = TITLE_START + TITLE_DUR - OVERLAP — B starts before A ends.
Test in Studio
Drag the playhead through the overlap frames and check that neither element visually “competes” — one should dominate.
💡 Practical tip
If element A has an animated fade-out (opacity 1→0 in the last 10 frames), activate B exactly when A starts fading. The viewer perceives the transition without noticing the cut.
🧮 Named Constants — No Magic Numbers
Clean timing code declares all offsets as named constants at the top of the component. That way, when you need to adjust "the title takes a little longer," you only change TITLE_DUR — and all elements that depend on it recalculate automatically.
// ✅ Constantes no topo — fáceis de ajustar const TITLE_START = 0; const TITLE_DUR = 45; const OVERLAP = 10; const SUBTITLE_START = TITLE_START + TITLE_DUR - OVERLAP; // 35 const LIST_START = SUBTITLE_START + 30; // 65 // ❌ Magic numbers — impossível de manter // <Sequence from={35}> ← por que 35? ninguém sabe // <Sequence from={65}> ← muda TITLE_DUR e quebra
✓ Advantages of constants
- ✓Changing 1 number propagates to all dependents.
- ✓Self-documenting code: SUBTITLE_START speaks for itself.
- ✓Easy to extract into props and make the template configurable.
✗ The problem with magic numbers
- ✗Changing one duration means hunting down and calculating all the following ones.
- ✗
from={47}— impossible to know where it came from without debugging. - ✗Common bug: two elements that should stay in sync drift out of sync.
👁️ Avoid starting everything at frame 0
The most common mistake beginners make when combining elements is not using from= in any of them — the result: everything appears simultaneously on frame 0. For viewers, it’s like receiving a shout instead of an introduction.
⚠️ What happens without timing
- ✗Title, subtitle, icon, and list all animate together at frame 0 — visual congestion.
- ✗Each element's spring competes for attention at the same instant.
- ✗The visual hierarchy disappears—the viewer can't tell what's important.
✅ Priority rule
Sort elements by importance and define a from increasing for each:
- 1.Frame 0: the most important element (logo, main title).
- 2.Frame 10–15: supporting element (subtitle, description).
- 3.Frame 20+: secondary elements (list, icons, decoration).
⚡ Timing with spring inside Sequence
The Sequence + spring combination is the most natural starting pattern in Remotion. Since each Sequence's local frame starts at 0, the spring "starts fresh" for each element—regardless of when the Sequence was opened on the timeline.
const Item = ({ label }: { label: string }) => { const frame = useCurrentFrame(); // sempre 0 no primeiro frame do item const { fps } = useVideoConfig(); const progress = spring({ frame, fps, config: { damping: 12, stiffness: 120 }, }); return ( <div style={{ opacity: progress, transform: `translateY(${(1 - progress) * 20}px)`, }}> {label} </div> ); }; // No componente pai — stagger automático: {["A", "B", "C"].map((l, i) => ( <Sequence key={l} from={i * 5}> <Item label={l} /> </Sequence> ))}
💡 Why this is powerful
Each Item is completely independent — you can reorder the array, add or remove items, and the stagger recalculates automatically. No code depends on any element's absolute position on the timeline.
📌 Module summary
Next module:
3.2 — Layers & Visual Composition: stacked AbsoluteFill, layer order, and how to maintain legibility.