remotion
remotion copied to clipboard
Chained sequences with transitions
Would be interesting to have a built-in wat to chain sequences + transitions like the video below:
https://user-images.githubusercontent.com/3165839/158035225-ff1eb6bd-45fe-4180-a324-d5b8331dfd71.mov
Here is the code that I used for it:
Scene.tsx
import React, {useMemo} from 'react';
import {interpolate, Sequence, AbsoluteFill, useCurrentFrame} from 'remotion';
type SceneProps = {
from: number;
durationInFrames: number;
transitionDurationInFrames: number;
interpolateRange?: Array<number>;
styles?:
| React.CSSProperties
| ((interpolateValue: number) => React.CSSProperties);
};
export const Scene: React.FC<SceneProps> = ({
from,
durationInFrames,
transitionDurationInFrames,
interpolateRange = [0, 1],
styles,
children,
}) => {
const frame = useCurrentFrame();
const interpolateValue = interpolate(
frame,
[from, from + transitionDurationInFrames],
interpolateRange,
{extrapolateRight: 'clamp'}
);
const stylesValue: React.CSSProperties | undefined = useMemo(() => {
if (typeof styles === 'function') {
return styles(interpolateValue);
}
return styles;
}, [interpolateValue]);
return (
<Sequence from={from} durationInFrames={durationInFrames}>
<AbsoluteFill style={stylesValue}>{children}</AbsoluteFill>
</Sequence>
);
};
export const useTransitionSequence = ({
sceneDuration,
transitionDuration,
scenes,
}: {
sceneDuration: number;
transitionDuration: number;
scenes: Array<
Pick<SceneProps, 'interpolateRange' | 'styles'> & {children: JSX.Element}
>;
}) => {
const render = () =>
scenes.map((scene, index) => {
const isFirst = index === 0;
const isLast = index === scenes.length - 1;
const overlaps = isFirst || isLast ? 1 : 2;
const durationInFrames = sceneDuration + overlaps * transitionDuration;
return (
<Scene
key={index}
{...scene}
from={
index * sceneDuration +
(!isFirst ? (index - 1) * transitionDuration : 0)
}
durationInFrames={durationInFrames}
transitionDurationInFrames={transitionDuration}
/>
);
});
return {
render,
};
};
export const measureTransitionSequence = ({
numberOfScenes,
sceneDuration,
transitionDuration,
}: {
numberOfScenes: number;
sceneDuration: number;
transitionDuration: number;
}) => {
const overlaps = numberOfScenes - 1;
return numberOfScenes * sceneDuration + overlaps * transitionDuration;
};
Usage
import React from 'react';
import {useVideoConfig, AbsoluteFill} from 'remotion';
import {useTransitionSequence} from '../Scene';
const secondsTo = (value: number) => (seconds: number) => {
return Math.round(seconds * value);
};
export const MyVideo: React.FC = () => {
const videoConfig = useVideoConfig();
const secondsToFrame = secondsTo(videoConfig.fps);
const sequence = useTransitionSequence({
sceneDuration: secondsToFrame(1),
transitionDuration: secondsToFrame(0.5),
scenes: [
{styles: {backgroundColor: 'red'}, children: <>Hi world!</>},
{
interpolateRange: [1, 0],
styles: (interpolateValue) => ({
backgroundColor: 'blue',
transform: `translateX(${interpolateValue * 100}%)`,
}),
children: <>Hi text!</>,
},
{
interpolateRange: [1, 0],
styles: (interpolateValue) => ({
backgroundColor: 'yellow',
transform: `translateY(${interpolateValue * 100}%)`,
}),
children: <>Hi text!</>,
},
{
interpolateRange: [1, 0],
styles: (interpolateValue) => ({
backgroundColor: 'green',
transform: `translateX(${interpolateValue * 100}%)`,
}),
children: <>Hi text!</>,
},
],
});
return <AbsoluteFill>{sequence.render()}</AbsoluteFill>;
};
Good idea! We still want to provide first-party transition support. Do you think it can be treater together with #35 or is it a different idea?
Started working on it: https://github.com/remotion-dev/remotion/pull/1057
@BrunoQuaresma Have you had a look at https://github.com/marcusstenbeck/remotion-transition-series?
fyi, I'm the author