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.tsxtsximport type {TransitionPresentation } from '@remotion/transitions';typeCustomPresentationProps = {width : number;height : number;};export constcustomPresentation = (props :CustomPresentationProps ,):TransitionPresentation <CustomPresentationProps > => {return {component :StarPresentation ,props };};
custom-presentation.tsxtsximport 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.tsxtsximport 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.tsxtsximport 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.tsxtsximport {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.tsxtsximport {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.tsxtsxexport 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.tsxtsxexport 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.