🗂️ Overview — when to use image templates
Image and media templates solve a very common problem: you have photos or static assets and need to bring them to life in a video. Choosing the right template depends on how many items you have, if you want focus on one element or an ensemble narrative, and whether the content is comparative or sequential.
🎯 Quick decision map
- •Too many photos with equal weight →
gallery-gridormasonry-gallery - •One featured photo at a time →
image-carouselorimage-zoom-reveal - •Before and after →
image-comparison-slider - •Nostalgic aesthetic / frame →
polaroid-frameorphoto-stack - •Two subjects at once →
split-screen - •Main content + context →
picture-in-picture
💡 File tip
All templates use staticFile() from Remotion for referencing local assets. Put your images in public/ at the project root and use staticFile("foto.jpg") — Remotion resolves the path in both Studio and the final render.
📐 gallery-grid — 2×3 grid with stagger
O gallery-grid arranges up to six images in a 2×3 grid where each card enters with a progressively longer delay (stagger). The result is that "cascade reveal" effect that adds rhythm without requiring any manual keyframes.
⚙️ How stagger works
Each item gets a delay proportional to its index. The spring starts earlier for the first item and later for the last, creating an entrance wave.
- •Item 0 starts at frame 0; item 5 starts at frame 25 (delay = index × 5).
- •
spring({ frame: Math.max(frame - delay, 0), fps })— the trick ofMath.maxprevents negative frames. - •The spring responds with 0→1; multiply by scale or opacity freely.
import { spring, useCurrentFrame, useVideoConfig } from "remotion"; // dentro do .map((item, i) => ...) const delay = i * 5; const s = spring({ frame: Math.max(frame - delay, 0), fps, config: { damping: 12, stiffness: 100 }, }); const scale = 0.8 + s * 0.2;
✓ What to DO
- ✓Use images with the same aspect ratio to keep the grid uniform.
- ✓Adjust the delay per item to control the wave speed.
- ✓Combine with captions that enter alongside each card.
✗ What NOT to do
- ✗Set the delay too high (>10/item) — the last card may never appear in the video.
- ✗Mix image aspect ratios without
objectFit: "cover". - ✗Use more than 9 items without adjusting the grid layout.
🎠 image-carousel — horizontal slide with centered focus
O image-carousel features slides in a horizontal row where only the centered item is at scale 1.0 — adjacent items progressively shrink. The frame determines where we are in the cycle, creating a continuous, smooth transition.
💡 The secret to central focus
The position of each slide is calculated as offset = índice - progress. When offset = 0, the item is exactly in the center and reaches maximum scale. The function interpolate(|offset|, [0,1,2], [1,0.75,0.55]) applies the gradual reduction to neighboring items.
const cycleLength = fps * 2; const progress = (frame % (cycleLength * slides.length)) / cycleLength; slides.map((slide, i) => { const offset = i - progress; const translateX = offset * 280; const scale = interpolate( Math.abs(offset), [0, 1, 2], [1, 0.75, 0.55], { extrapolateRight: "clamp" } ); });
Adjust the cycle speed
Change fps * 2 to fps * 3 for slower slides, or fps * 1 for faster scrolling. Each cycle corresponds to the time a slide stays in the center.
Control the spacing between slides
The value 280 in translateX = offset * 280 sets the distance between centers. Reduce it for more overlapping slides; increase it for more spaced-out slides.
Add z-index based on the offset
The center slide should sit above the side slides. Use zIndex: Math.round(10 - Math.abs(offset) * 3) for automatic stacking.
↔️ image-comparison-slider — before and after
O image-comparison-slider splits the screen vertically with a divider that moves over time, revealing the “after” image from bottom to top while the “before” image remains visible on the left. It’s the ideal template for showing edits, product transformations, or design comparisons.
🔀 Clip-path technique
The "after" image is overlaid with position: absolute and a clipPath that limits the visible area to a fraction of the total width. The frame controls this fraction via interpolate:
const clipWidth = interpolate(frame, [0, durationInFrames], [0, 100], { extrapolateRight: "clamp" }); // style da imagem "depois": clipPath: `inset(0 ${100 - clipWidth}% 0 0)`
✓ What to DO
- ✓Use images that are exactly the same size for perfect alignment.
- ✓Add a vertical divider as a visual indicator.
- ✓Combine with “Before” / “After” text that fades out during the reveal.
✗ What NOT to do
- ✗Images with different aspect ratios — the clip is off-center.
- ✗Reveal too quickly — it loses the impact of the comparison.
- ✗Apply to subjective comparisons without textual context.
🔍 image-zoom-reveal — zoom-out with focus
O image-zoom-reveal starts with the image highly zoomed in and progressively pulls back to its normal scale, creating a cinematic "pull back" effect. It feels like revealing the context around the initial detail.
💡 Why start enlarged
Starting with a detail grabs attention immediately — the viewer doesn’t know what they’re looking at. The gradual pullback builds tension, and the reveal of the full object makes an impact. Use long durations (fps × 3 or more) to maximize the dramatic effect.
const { fps, durationInFrames } = useVideoConfig(); const s = spring({ frame, fps, config: { damping: 20, stiffness: 30 } }); // começa em 2.5×, chega a 1.0× const scale = interpolate(s, [0, 1], [2.5, 1.0]); const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
🃏 masonry-gallery — Pinterest-style with spring
O masonry-gallery distributes blocks of varying heights across three columns, mimicking a Pinterest-style layout. Each block has its own spring delay, creating a sequence of pop-ins that feels deep and organic.
🏗️ Three-column architecture
The blocks are grouped by column before rendering. Each column is a flex-direction: column with gap. The blocks have different percentage heights to create the characteristic irregular masonry look.
// Blocos com delay e altura variável por coluna const blocks = [ { col: 0, height: "45%", delay: 0 }, { col: 1, height: "55%", delay: 3 }, { col: 2, height: "40%", delay: 5 }, ];
✓ What to DO
- ✓Distribute blocks of very different heights across columns for an organic effect.
- ✓Stagger the delays so each column feels independent.
- ✓Use gradients instead of images for quick prototypes.
✗ What NOT to do
- ✗Use the same height for every block—you lose the masonry effect.
- ✗Set all delays to the same value — it looks like an ordinary grid.
- ✗Exceeding 3 columns without adjusting the parent container.
📚 Complete Library — all 9 templates
Quick reference for all templates in this category. Each row includes the name, the file in templates/, a descriptive line and the main hook used.
📌 Module summary
Math.max(frame - delay, 0) creates a wave of reveals without manual keyframes.offset = índice - progress positions each slide relative to the center.clipPath: inset() progressively reveals the image "afterward".Next module:
2.5 — Backgrounds: nine animated background templates to set the context for any scene.