Custom presentations
This page describes how to create your own custom effect for <TransitionSeries>
.
Concept
A presentation is a higher order component which wraps around the entering slide as well as the exiting slide and which implements an effect based on three parameters:
1
The current presentationProgress
, influenced by the timing of the transition2
The presentationDirection
, either entering
or exiting
3
Additional developer-defined passedProps
Boilerplate
A custom presentation is a function which returns an object of type TransitionPresentation
.
It is an object with a React component (component
) and React props which are passed to the component as passedProps
.
custom-presentation.tsxtsx
import type {TransitionPresentation } from "@remotion/transitions";typeCustomPresentationProps = {width : number;height : number;};export constcustomPresentation = (props :CustomPresentationProps ,):TransitionPresentation <CustomPresentationProps > => {return {component :SlidePresentation ,props };};
custom-presentation.tsxtsx
import type {TransitionPresentation } from "@remotion/transitions";typeCustomPresentationProps = {width : number;height : number;};export constcustomPresentation = (props :CustomPresentationProps ,):TransitionPresentation <CustomPresentationProps > => {return {component :SlidePresentation ,props };};
The component
is a React component which receives the following props:
1
children
: The markup to wrap around2
presentationDirection
: Either "entering"
or "exiting"
3
presentationProgress
: A number between 0
and 1
which represents the progress of the transition.4
passedProps
: The custom props passed to the presentationSlidePresentation.tsxtsx
import type {TransitionPresentationComponentProps } from "@remotion/transitions";import {AbsoluteFill } from "remotion";constSlidePresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps ,}) => {return (<AbsoluteFill ><AbsoluteFill >{children }</AbsoluteFill ></AbsoluteFill >);};
SlidePresentation.tsxtsx
import type {TransitionPresentationComponentProps } from "@remotion/transitions";import {AbsoluteFill } from "remotion";constSlidePresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps ,}) => {return (<AbsoluteFill ><AbsoluteFill >{children }</AbsoluteFill ></AbsoluteFill >);};
Example
The following example implements a star mask transition:
1
Based on the passedProps
height
and width
, the inner radius of the star is calculated that will completely fill the canvas.2
Using @remotion/shapes
, an SVG path is calculated, and grown from zero to the full size of the canvas. 3
The presentationProgress
is used to interpolate the shape size. 4
@remotion/paths
is used to center the star in the middle of the canvas.5
A clipPath
is used to clip the entering slide. Inside the container, the children
get rendered.6
The effect is disabled if presentationDirection
is set to "exiting"
SlidePresentation.tsxtsx
import {getBoundingBox ,translatePath } from "@remotion/paths";import {makeStar } from "@remotion/shapes";import type {TransitionPresentationComponentProps } from "@remotion/transitions";importReact , {useMemo ,useState } from "react";import {AbsoluteFill ,random } from "remotion";export typeCustomPresentationProps = {width : number;height : number;};constSlidePresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps ,}) => {constfinishedRadius =Math .sqrt (passedProps .width ** 2 +passedProps .height ** 2) / 2;constinnerRadius =finishedRadius *presentationProgress ;constouterRadius =finishedRadius * 2 *presentationProgress ;const {path } =makeStar ({innerRadius ,outerRadius ,points : 5,});constboundingBox =getBoundingBox (path );consttranslatedPath =translatePath (path ,passedProps .width / 2 -boundingBox .width / 2,passedProps .height / 2 -boundingBox .height / 2,);const [clipId ] =useState (() =>String (random (null)));conststyle :React .CSSProperties =useMemo (() => {return {width : "100%",height : "100%",clipPath :presentationDirection === "exiting" ?undefined : `url(#${clipId })`,};}, [clipId ,presentationDirection ]);return (<AbsoluteFill ><AbsoluteFill style ={style }>{children }</AbsoluteFill >{presentationDirection === "exiting" ? null : (<AbsoluteFill ><svg ><defs ><clipPath id ={clipId }><path d ={translatedPath }fill ="black" /></clipPath ></defs ></svg ></AbsoluteFill >)}</AbsoluteFill >);};
SlidePresentation.tsxtsx
import {getBoundingBox ,translatePath } from "@remotion/paths";import {makeStar } from "@remotion/shapes";import type {TransitionPresentationComponentProps } from "@remotion/transitions";importReact , {useMemo ,useState } from "react";import {AbsoluteFill ,random } from "remotion";export typeCustomPresentationProps = {width : number;height : number;};constSlidePresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps ,}) => {constfinishedRadius =Math .sqrt (passedProps .width ** 2 +passedProps .height ** 2) / 2;constinnerRadius =finishedRadius *presentationProgress ;constouterRadius =finishedRadius * 2 *presentationProgress ;const {path } =makeStar ({innerRadius ,outerRadius ,points : 5,});constboundingBox =getBoundingBox (path );consttranslatedPath =translatePath (path ,passedProps .width / 2 -boundingBox .width / 2,passedProps .height / 2 -boundingBox .height / 2,);const [clipId ] =useState (() =>String (random (null)));conststyle :React .CSSProperties =useMemo (() => {return {width : "100%",height : "100%",clipPath :presentationDirection === "exiting" ?undefined : `url(#${clipId })`,};}, [clipId ,presentationDirection ]);return (<AbsoluteFill ><AbsoluteFill style ={style }>{children }</AbsoluteFill >{presentationDirection === "exiting" ? null : (<AbsoluteFill ><svg ><defs ><clipPath id ={clipId }><path d ={translatedPath }fill ="black" /></clipPath ></defs ></svg ></AbsoluteFill >)}</AbsoluteFill >);};
Example usage:
MyComp.tsxtsx
export constMyComp :React .FC = () => {const {width ,height } =useVideoConfig ();return (<TransitionSeries ><TransitionSeries .Sequence durationInFrames ={70}><Letter color ="orange">A</Letter ></TransitionSeries .Sequence ><TransitionSeries .Transition presentation ={customPresentation ({width ,height })}timing ={springTiming ({durationInFrames : 45,config : {damping : 200,},durationRestThreshold : 0.0001,})}/><TransitionSeries .Sequence durationInFrames ={60}><Letter color ="pink">B</Letter ></TransitionSeries .Sequence ></TransitionSeries >);};
MyComp.tsxtsx
export constMyComp :React .FC = () => {const {width ,height } =useVideoConfig ();return (<TransitionSeries ><TransitionSeries .Sequence durationInFrames ={70}><Letter color ="orange">A</Letter ></TransitionSeries .Sequence ><TransitionSeries .Transition presentation ={customPresentation ({width ,height })}timing ={springTiming ({durationInFrames : 45,config : {damping : 200,},durationRestThreshold : 0.0001,})}/><TransitionSeries .Sequence durationInFrames ={60}><Letter color ="pink">B</Letter ></TransitionSeries .Sequence ></TransitionSeries >);};
References
See the source code for already implemented presentations for a useful reference.