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:
presentationProgress
, influenced by the
timing of the transition
presentationDirection
, either entering
or exiting
presentationDurationInFrames
(available from v4.0.153)
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 :StarPresentation ,props };};
custom-presentation.tsxtsx
import type {TransitionPresentation } from '@remotion/transitions';typeCustomPresentationProps = {width : number;height : number;};export constcustomPresentation = (props :CustomPresentationProps ,):TransitionPresentation <CustomPresentationProps > => {return {component :StarPresentation ,props };};
The component
is a React component which receives the following props:
children
: The markup to wrap around
presentationDirection
: Either
"entering"
or "exiting"
presentationProgress
: A number between
0
and 1
which represents the progress of the transition.
passedProps
: The custom props passed to the presentation
StarPresentation.tsxtsx
import type {TransitionPresentationComponentProps } from '@remotion/transitions';import {AbsoluteFill } from 'remotion';constStarPresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps }) => {return (<AbsoluteFill ><AbsoluteFill >{children }</AbsoluteFill ></AbsoluteFill >);};
StarPresentation.tsxtsx
import type {TransitionPresentationComponentProps } from '@remotion/transitions';import {AbsoluteFill } from 'remotion';constStarPresentation :React .FC <TransitionPresentationComponentProps <CustomPresentationProps >> = ({children ,presentationDirection ,presentationProgress ,passedProps }) => {return (<AbsoluteFill ><AbsoluteFill >{children }</AbsoluteFill ></AbsoluteFill >);};
Example
The following example implements a star mask transition:
passedProps
height
and width
, the inner radius of the star is calculated that will completely fill the canvas.
@remotion/shapes
, an SVG path is calculated, and grown from zero to the full size of the canvas.
presentationProgress
is used to interpolate the shape
size.
@remotion/paths
is used to center the star in the middle of the canvas.
clipPath
is used to clip the entering slide.
Inside the container, the children
get rendered.
presentationDirection
is set
to "exiting"
StarPresentation.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;};constStarPresentation :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 >);};
StarPresentation.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;};constStarPresentation :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.