name: transitions description: Scene transitions and overlays for Remotion using TransitionSeries. metadata:
<TransitionSeries> arranges scenes and supports two ways to enhance the cut point between them:
<TransitionSeries.Transition>) — crossfade, slide, wipe, etc. between two scenes. Shortens the timeline because both scenes play simultaneously during the transition.<TransitionSeries.Overlay>) — render an effect (e.g. a light leak) on top of the cut point without shortening the timeline.Children are absolutely positioned.
npx remotion add @remotion/transitions
import { TransitionSeries, linearTiming } from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneA />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={fade()}
timing={linearTiming({ durationInFrames: 15 })}
/>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneB />
</TransitionSeries.Sequence>
</TransitionSeries>;
Any React component can be used as an overlay. For a ready-made effect, see the light-leaks rule.
import { TransitionSeries } from "@remotion/transitions";
import { LightLeak } from "@remotion/light-leaks";
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneA />
</TransitionSeries.Sequence>
<TransitionSeries.Overlay durationInFrames={20}>
<LightLeak />
</TransitionSeries.Overlay>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneB />
</TransitionSeries.Sequence>
</TransitionSeries>;
Transitions and overlays can coexist in the same <TransitionSeries>, but an overlay cannot be adjacent to a transition or another overlay.
import { TransitionSeries, linearTiming } from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
import { LightLeak } from "@remotion/light-leaks";
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneA />
</TransitionSeries.Sequence>
<TransitionSeries.Overlay durationInFrames={30}>
<LightLeak />
</TransitionSeries.Overlay>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneB />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={fade()}
timing={linearTiming({ durationInFrames: 15 })}
/>
<TransitionSeries.Sequence durationInFrames={60}>
<SceneC />
</TransitionSeries.Sequence>
</TransitionSeries>;
<TransitionSeries.Transition> requires:
presentation — the visual effect (e.g. fade(), slide(), wipe()).timing — controls speed and easing (e.g. linearTiming(), springTiming()).<TransitionSeries.Overlay> accepts:
durationInFrames — how long the overlay is visible (positive integer).offset? — shifts the overlay relative to the cut point center. Positive = later, negative = earlier. Default: 0.Import transitions from their respective modules:
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
import { wipe } from "@remotion/transitions/wipe";
import { flip } from "@remotion/transitions/flip";
import { clockWipe } from "@remotion/transitions/clock-wipe";
import { slide } from "@remotion/transitions/slide";
<TransitionSeries.Transition
presentation={slide({ direction: "from-left" })}
timing={linearTiming({ durationInFrames: 20 })}
/>;
Directions: "from-left", "from-right", "from-top", "from-bottom"
import { linearTiming, springTiming } from "@remotion/transitions";
// Linear timing - constant speed
linearTiming({ durationInFrames: 20 });
// Spring timing - organic motion
springTiming({ config: { damping: 200 }, durationInFrames: 25 });
Transitions overlap adjacent scenes, so the total composition length is shorter than the sum of all sequence durations. Overlays do not affect the total duration.
For example, with two 60-frame sequences and a 15-frame transition:
60 + 60 = 120 frames60 + 60 - 15 = 105 framesAdding an overlay between two other sequences does not change the total.
Use the getDurationInFrames() method on the timing object:
import { linearTiming, springTiming } from "@remotion/transitions";
const linearDuration = linearTiming({
durationInFrames: 20,
}).getDurationInFrames({ fps: 30 });
// Returns 20
const springDuration = springTiming({
config: { damping: 200 },
}).getDurationInFrames({ fps: 30 });
// Returns calculated duration based on spring physics
For springTiming without an explicit durationInFrames, the duration depends on fps because it calculates when the spring animation settles.
import { linearTiming } from "@remotion/transitions";
const scene1Duration = 60;
const scene2Duration = 60;
const scene3Duration = 60;
const timing1 = linearTiming({ durationInFrames: 15 });
const timing2 = linearTiming({ durationInFrames: 20 });
const transition1Duration = timing1.getDurationInFrames({ fps: 30 });
const transition2Duration = timing2.getDurationInFrames({ fps: 30 });
const totalDuration =
scene1Duration +
scene2Duration +
scene3Duration -
transition1Duration -
transition2Duration;
// 60 + 60 + 60 - 15 - 20 = 145 frames