← Blog

Why your Remotion scene transitions look broken

A fade() between two Remotion scenes leaves both of them on screen at full opacity. Here is why, and the one-line fix.

You wire up <TransitionSeries>, drop a fade() between two scenes, render — and for half a second in the middle, both scenes are on screen at once. Two headlines stacked on the same pixels, unreadable.

It is not a bug in your components, and it is not a timing problem. It is what fade() does.

The exiting scene never fades out

Here is the presentation, from @remotion/transitions:

opacity: isEntering
  ? presentationProgress
  : passedProps.shouldFadeOutExitingScene
    ? 1 - presentationProgress
    : 1,

Read the last branch. When the scene is exiting and you have not passed shouldFadeOutExitingScene, its opacity is 1 — for the entire transition. The arriving scene ramps 0 → 1 on top of a scene that is still fully painted.

So an 18-frame transition means 18 frames where both scenes are inked. If both put something in the middle of the frame — and almost every scene does — you get a double exposure.

Settling earlier does not help

The instinct is to make the outgoing scene finish sooner, so it is "done" before the overlap. That fixes nothing. A finished scene is exactly as opaque as an unfinished one. The problem is not that it is still moving; it is that it is still there.

shouldFadeOutExitingScene: true does not rescue it either. Now both scenes sit at 50% through the middle of the transition — two ghost headlines instead of two solid ones.

Transparency makes it worse

If your scene components render transparent — which is the right default, so the composition owns the background — then every compositing presentation has the same flaw:

PresentationSafe between two centred scenes?
fade()No — exiting scene stays at full opacity
none()No — both stacked, entering one on top
wipe(), iris(), clockWipe()No — the exiting scene shows through the revealed region
slide(), flip()Yes — the scenes are moved apart

A wipe looks like it should work, because it has a hard edge. But it clips the entering scene; it does not remove the exiting one. Wherever the entering scene is transparent, the old one is still visible underneath.

The fix

Use a presentation that moves the scenes apart rather than blending them. Then every pixel belongs to exactly one scene, no matter what either one paints:

import { springTiming, TransitionSeries } from "@remotion/transitions";
import { slide } from "@remotion/transitions/slide";

const beat = {
  presentation: slide({ direction: "from-right" }),
  timing: springTiming({ durationInFrames: 18, config: { damping: 200 } }),
};

<TransitionSeries>
  <TransitionSeries.Sequence durationInFrames={110}>
    <SceneOne />
  </TransitionSeries.Sequence>
  <TransitionSeries.Transition {...beat} />
  <TransitionSeries.Sequence durationInFrames={130}>
    <SceneTwo />
  </TransitionSeries.Sequence>
</TransitionSeries>;

Two details worth keeping:

damping: 200. The default spring overshoots. On a scale or an opacity that reads as bounce; on a full-frame slide it throws the whole scene past centre and drags it back. Critically damping it removes the wobble without making the move feel slow.

direction: "from-right". Remotion's default is from-left, which brings the new scene in from the left and pushes the old one right — the direction a "back" gesture moves. from-right reads as forward.

When a fade is still right

A crossfade is not always wrong. It is right when the outgoing scene is empty by the time the transition starts — a scene that has already animated its own content away, or a full-bleed background with nothing to read. That is a real shot, and it is the only case where the overlap costs you nothing.

Everywhere else, slide.

FAQ

Why do both scenes show during a Remotion fade transition?

fade() only fades the entering scene in. The exiting scene stays at full opacity for the whole transition unless you pass shouldFadeOutExitingScene, so both are visible at once.

Which Remotion transition works between two scenes with centred content?

slide() or flip(). They move the scenes apart, so every pixel belongs to one scene. fade(), none(), wipe(), iris() and clockWipe() composite the scenes and let the old one show through.

When is a fade transition in Remotion still the right choice?

When the outgoing scene is already empty by the time the transition starts, such as a scene that has animated its content away or a plain background.