description: How to choreograph transitions BETWEEN scenes (and shots within a scene) in FlatRender Remotion templates — cut, dissolve, wipe, clip-path mask, morph, match-cut, shape transition, camera push, zoom/whip-blur — built from primitives. Use whenever a template has more than one scene/beat, when one element must hand off to the next, or when stitching multi-scene sequences so they feel seamless instead of slideshow-y. Read before sequencing scenes.
---
# Scene transitions for Remotion
A multi-scene template lives or dies on its *joins*. A hard slideshow of fades reads as "made in a tool"; a transition that carries motion, color, or a shape across the cut reads as "made by a studio". We have **no `@remotion/transitions` package** (not a dependency) and asset CDNs are geo-blocked — so every transition is built from primitives: `<Sequence>`, `interpolate`/`spring`, CSS `clipPath`/`maskImage`, blend modes, and (for 3D) a camera move driven by `useCurrentFrame()`. Everything is a pure function of `frame` — **never**`useFrame`, `Math.random`, `Date.now` (use `rand()` from `lib/anim.ts`).
## The one structural rule: overlap, don't abut
A clean transition needs scenes to **overlap** for the transition window (12–20f). Don't place `<Sequence>`s back-to-back — give the outgoing scene a tail and the incoming a head that share the window.
```tsx
import{Sequence,useVideoConfig}from"remotion";
const{fps}=useVideoConfig();
constsec=(s: number)=>Math.round(s*fps);// never hardcode 30
constT=sec(0.5);// transition window
// Scene A holds frames 0..120, Scene B starts at 120-T so they cross-fade
Inside each scene, derive a local progress from `useCurrentFrame()` (already 0-based inside a `Sequence`) for its *in* and *out* phases.
## Transition catalog — what to build, when, and how
| Transition | فارسی | Feel / when | Build (primitive) |
|---|---|---|---|
| **Cut** | برش | Hard, energetic, beat-synced, brutalist/anti-design | No overlap; `<Sequence>` ends, next begins. Snap a 1f flash or shake for punch. |
| **Match-cut** | برش تطبیقی | Storytelling, "made by a studio" | A shape/element at the SAME position+size in both scenes; cut while it's identical. |
| **Shape transition** | گذار شکلی | Brand mark grows into scene | A circle/blob scales up to fill frame (color = `accent`), then the new scene is revealed inside it. |
| **Camera push / dolly** | حرکت دوربین (۳بعدی) | Cinematic, 3D logo/product | Move the R3F camera `position.z` / target between two staged setups by `frame`. |
| **Zoom / whip blur** | زوم/تار حرکتی | Fast, hype, music, TikTok | Scale up + `filter: blur()` on out, scale-down + blur-out on in; peak blur ON the cut. |
<AbsoluteFillstyle={{clipPath:`circle(${r}% at 50% 50%)`}}><SceneB/></AbsoluteFill>
```
For a brand shape transition: render a full-frame circle filled with `colorSchema.accent` scaling up over Scene A, then swap to Scene B *masked by the same circle* — the brand color carries the cut.
Use `StudioEnv/StudioLights/StudioFloor/StudioEffects` from `lib/three-kit.tsx`; let DOF + bloom + vignette sell the move. Camera moves use `ease-in-out`/heavy spring; never linear (linear is only for continuous orbit/rotation).
## Match-cut & seamless choreography (the studio-grade joins)
The eye forgives a cut if **something continues across it**. Carry one of:
- **Position+scale** — a circle bottom-left in Scene A is a circle bottom-left, same size, in Scene B. Cut while identical. (Classic match-cut.)
- **Color** — Scene A ends on a full-frame `accent` wash; Scene B opens from that wash. Use `mixHex`/`hexToRgba` (`lib/anim.ts`) so it's palette-driven.
- **Motion vector** — text exits stage-left at speed `v`; the next element enters from stage-right at the same `v`. Momentum reads as continuity.
- **A mask** — the shape that wiped scene A out is the shape scene B wipes in with.
For a full template: write a **beat list first** (logo in → tagline → 3 features cascade → CTA → out), assign one transition per join, and make adjacent joins *differ* (don't dissolve every cut) but **rhyme** (reuse the brand shape/color). Vary cut length and build to the hero moment — pacing is a transition too.
## Timing & easing (the difference between pro and slideshow)
- **Window:** scene transition **12–20f**; whip/cut feels best at the short end, dissolve/camera at the long end.
- **Entrances ease-out** (`Easing.out(Easing.quint)` / `Easing.bezier(0.16,1,0.3,1)`); **exits ease-in and always SHARPER than the entrance** — scenes leave faster than they arrive.
- **A→B on-screen / camera = ease-in-out.** **Linear ONLY** for continuous rotation/marquee.
- Per-aspect: tighten the window on `isWide` (reads faster), loosen on `isTall`. Use the proposed `pick(wide,square,tall)` helper on `Layout` when it lands; until then branch on `isWide/isSquare/isTall`.
## Reusable transition components
Build these once in `lib/` and reuse across templates — each takes an `enter`/`exit` phase and a window:
```tsx
// CrossFade.tsx — wrap any scene; computes its own in/out from frame + duration
Make sibling wrappers `Wipe`, `CircleReveal`, `WhipZoom`, `ShapeWipe` with the same `(children, win, dir)` contract so a template can swap transitions by changing one wrapper. Keep the SFX hook in mind: a whoosh 2–3f before the cut + an impact ON it (`../remotion-sound-effects/SKILL.md`).