
In a recent article, we looked at how easy it is to clone your voice using Elevenlabs and Node.js, so this time we thought we’d take a look at how to create videos programmatically, too. In a future article, we’ll piece it all together and combine multiple programmatically-generated videos with a voiceover, as well as a few custom animations, but for now let’s take a look at how to get started.
For this, we’re going to use Remotion, a library that lets you build videos as React components (with props making it easy to pass in dynamic data, and hooks great for handling complex state), preview in a light UI - called Remotion Studio - and then render out from there, too (or the CLI).
Set up the project
To get started, create a directory, initialise it and install Remotion alongside React and TypeScript, for type safety. Note that we install the core remotion library, along with @remotion/cli so we can run preview and render later on:
mkdir remotion-demo && cd remotion-demo
npm init -y
npm install remotion @remotion/cli react react-dom
npm install -D typescript @types/react @types/react-dom
Let’s run npx tsc --init to create a tsconfig.json file, so we get auto-complete, type-checking and the other benefits of Typescript.
Create your first composition
Every Remotion project starts from a “Root” file that registers one or more Compositions, which are React components that include props like width, height, frame rate, and duration in frames.
So, in src/index.ts, we import registerRoot, and pass it our ./Root path imported as Root.
import {registerRoot} from 'remotion';
import {Root} from './Root';
registerRoot(Root);
Next, in src/Root.tsx, where the composition is registered, we create a <Composition>, and pass in those props we mentioned:
import React from 'react';
import {Composition} from 'remotion';
import {Shapes} from './Shapes';
export const Root: React.FC = () => {
return (
<Composition
id="Shapes"
component={Shapes}
width={1280}
height={720}
fps={30}
durationInFrames={150}
/>
);
};
Here, we’re making a 5 second-long video, with 30 frames per-second, so 150 frames in total. You’ll notice we’re passing in a <Shapes> component, which doesn’t actually exist yet, so let’s create it now.
Build the Shapes component
In src/Shapes.tsx, we’ll place three different animating shapes that we’ll create in a moment, and stagger them with <Sequence> so they appear one after another instead, using the from keyword to say the frame position we want each respective animation to start from:
import {AbsoluteFill, Sequence} from 'remotion';
export const Shapes: React.FC = () => {
return (
<AbsoluteFill style={{backgroundColor: '#15161D'}}>
<Sequence from={0}><FadeCircle /></Sequence>
<Sequence from={30}><SlideSquare /></Sequence>
<Sequence from={60}><RotateTriangle /></Sequence>
</AbsoluteFill>
);
};
As a little tip, if you find frames a little confusing and would rather work in seconds, just pass in the number of seconds multiplied by the frame rate, for example for={4*30} will start the animation from the 4-second mark.
Animate something on screen
Now let’s create our animating shapes. For this example, we’re going to create the <FadeCircle> component, create an opacity variable where we animate opacity from 0 to 1 across the first 30 frames. Then, with extrapolateRight: 'clamp' we stop our animation when it gets to 1 and holds it there. The opacity const then gets passed in as the style for our <div>:
const FadeCircle: React.FC = () => {
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 30], [0, 1], {extrapolateRight: 'clamp'});
return <div style={{width: 150, height: 150, borderRadius: '50%', backgroundColor: '#4C6EF5', opacity}} />;
};
Now we won’t dig into the code for other two, but you can see how they animate down below, with interpolate driving a different CSS property over a frame range, so the concept stays the same.
Preview and Render
Finally, if we’re using the CLI, let’s add a script to our package.json’s scripts, to make it easy to switch between Remotion studio, and rendering from the command line (which also skips over needing to select output options like you do in the UI):
{
"scripts": {
"start": "remotion studio",
"render": "remotion render src/index.ts Shapes out/video.mp4"
}
}
If you want to take a look at a live and scrubbable preview - with hot load - lets run npm run start, and when we’re done let’s run npm run render to output our chosen file.
We really enjoyed working with Remotion, and we’re pretty sure any React developers are going to find this incredibly easy to pick up, too.
We hope you enjoyed this article, and be sure to let us know what you think on socials!