Creating Videos Using React.js and Remotion

Banner for a MediaJam post

Eugene Musebe

Introduction

Videos enable us to establish authority and a more personal feel to your message. It enables us to connect with the emotional levels of our audience. React is a great JavaScript library for describing User Interfaces that change over time. To create video content programmatically with React.js

We are going to use an amazing tool called Remotion.

Let’s explore how we can achieve this.

Github

Check out this GitHub Repository for the complete source code.

Codesandbox

The final project can be viewed on Codesandbox.

You can find the complete source code on my Github repository.

Pre-requisites

Below are some requirements you are to meet to follow along with this article:

  • Basic knowledge of JavaScript
  • Basic knowledge of React.js

Setting Up the Sample Project

In your preferred directory, create a new remotion project using yarn create video

You might want to choose the recommended template but for the purposes of this choose a blank template. Run yarn start This will start the local dev server running. You will see a window like this. img.png On the left we have a sidebar showing all the compositions for our project which allows you to isolate and inspect each scene in the video. Each composition is a renderable component. Composition is made up of sequences which tell the video which frames to display the content in. The entry point of a remotion project is the index.tsx here we call the function registerRoot(RemotionVideo); which is in the Video.tsx

Introduction

Open the Video.tsx file. This file contains the RemotionVideo component. You can think of this component as your entire video.

1export const RemotionVideo: React.FC = () => {
2 return (
3 <>
4 <Composition
5 id="Empty"
6 component={MyComposition}
7 durationInFrames={450}
8 fps={30}
9 width={1280}
10 height={720}
11 />
12 </>
13 );
14};

A video is basically made up of one or more compositions. within the composition, we define video properties as the durationInFrames which is the number of frames which the video will take, fps which is the number of frames per second, width and height of the video in pixels.

When we talk of frames you can think of it as a still image at a given point in the video.

The id identifies the composition in the video player and references the component that contains the UI that you want to show. The width and height properties are used to change the resolution of the video e.g., to change the resolution to a portrait

1width={1080}
2 height={1920}

The actual length of the video in seconds is based on the fps. durationInFrames / fps = length(s) This implies that for this demo our video is 15 seconds long 450 / 30 = 15.

Customizing the Video

We are going to create new Main component just below the RemotionVideo component.

1const Main = () => {
2 return <h1>Welcome to Cloudinary!</h1>
3}

To view this on your browser you will have to change the value of the id from id="Empty" to id=" Main" also the component value to component={Main} When you change the id value you will also have to change the package.json file

1"build": "remotion render src/index.tsx Empty out/video.mp4"

to have the value of the id

1"build": "remotion render src/index.tsx Main out/video.mp4"

Once you open the video player you will see the video with the text Welcome to Cloudinary. To modify the css styling of your video programmatically use inline CSS.

1const Main = () => {
2 return (
3 <div style={{backgroundColor: 'white', flexGrow: 1}}>
4 <h1
5 style={{
6 position: 'absolute',
7 top: '50%',
8 width: '100%',
9 textAlign: 'center',
10 fontSize: '5rem',
11 }}
12 >Welcome to Cloudinary!</h1>
13 </div>
14 );
15};

We can have three components for this particular video the Title, SubTitle and the Image then call them inside the Main component.

1const Title = () => {
2 return(
3 <h1
4 style={{
5 position: 'absolute',
6 top: '50%',
7 width: '100%',
8 textAlign: 'center',
9 fontSize: '5rem',
10 }}
11 >Welcome to Cloudinary!</h1>
12 );
13}
14const SubTitle = () => {
15 return(
16 <h3
17 style={{
18 position: 'absolute',
19 top: '60%',
20 width: '100%',
21 textAlign: 'center',
22 fontSize: '3rem',
23 }}
24 >Transform images and videos to load faster with no visual degradation, automatically generate image and video variants, and deliver high quality responsive experiences to increase conversions.</h3>
25 );
26}

To add images and render them we have to use Img tag which shoud be imported from Remotion.

1import {Composition, Img} from 'remotion';
2import cloudinary from './cloudinary.png';

We can then create the Image Component

1const Image = () => {
2 return(
3 <Img
4 src={cloudinary} alt='cloudinary'
5 style={{
6 display: 'block',
7 marginLeft: 'auto',
8 marginRight: 'auto',
9 width: '30%',
10 height: '50%',
11 }}
12 />
13 );
14}
15const Main = () => {
16 return (
17 <div style={{backgroundColor: 'white', flexGrow: 1}}>
18 <Title />
19 <Image />
20 <SubTitle />
21 </div>
22 );
23};

For now, everything we need for this video is set, but we need to do some animation to make create our video cool and interesting.

Animation

To make up our entire video clip we are going to use Sequences, these are small individual sections in finite time that make up our entire video. We then specify the time we from which we want a component to show using from={0} This means it will start to show at the start(0 seconds). You can also specify the time you want the component to disappear using the durationInFrames={60} attribute.

1<div style={{backgroundColor: 'white', flexGrow: 1}}>
2 <Sequence from={0}>
3 <Image />
4 </Sequence>
5 <Sequence from={60}>
6 <Title />
7 </Sequence>
8 <Sequence from={120}>
9 <SubTitle />
10 </Sequence>
11</div>

Adding Audio for our Video

We can simply add videos using the <Audio /> tag in Remotion. Let's add a Voice component to render the voice.

1import {Composition, Img, Audio} from 'remotion';
2import voice from './voice.mp3';
3// rest of the code
4const AudVoice = () => {
5 return (
6 <Audio src={voice} startFrom={0} endAt={30*15}/>
7 );
8};
9// other code

Remotion provides a variety of different hooks which enable us to provide data about the video.

useVideoConfig() hook enables us grab data about the fps, duration in frames, width, and height. We can use this to calculate values for animating our frames.

useCurrentFrame() hook gives us the current frame and the timeline. These frames will be re-rendered for each time in the video.

For now your video player is playing well but we now need to use the data about the video in place of the natural numbers 0, 60 and 90. Import useVideo from remotion.

1const Main = () => {
2 const {fps, durationInFrames} = useVideoConfig();
3 return (
4 <div style={{backgroundColor: 'white', flexGrow: 1}}>
5 <Sequence from={fps*0.3} durationInFrames={durationInFrames}>
6 <Image />
7 </Sequence>
8 <Sequence from={fps} durationInFrames={durationInFrames}>
9 <AudVoice />
10 </Sequence>
11 <Sequence from={fps} durationInFrames={durationInFrames}>
12 <Title />
13 </Sequence>
14 <Sequence from={fps*2} durationInFrames={durationInFrames}>
15 <Subtitle />
16 </Sequence>
17 </div>
18 );
19}

Fade-In effect on the SubTitle

Let's make our animation more captivating with a fade in effect. Here we'll use the useCurrentFrame() hook as shown.

1const SubTitle = () => {
2 const frame = useCurrentFrame();
3 const opacity = frame > 30 ? 1 : frame / 30;
4 return(
5 <h3
6 style={{
7 position: 'absolute',
8 top: '60%',
9 width: '100%',
10 textAlign: 'center',
11 fontSize: '3rem',
12 opacity
13 }}
14 >Transform images and videos to load faster with no visual degradation, automatically generate image and video variants, and deliver high quality responsive experiences to increase conversions.</h3>
15 );
16}

useCurrentFrame brings back the current frame which is SubTitle in the context of the sequence.

1const frame = useCurrentFrame();

We want the opacity to be zero at the start then as time goes it becomes one. If the frame is greater than 30 then return the opacity as 1. Otherwise, have the opacity as frame/30

1const opacity = frame > 30 ? 1 : frame / 30;

Bounce effect on the Image

1const Image = () => {
2 const frame = useCurrentFrame();
3 const {fps} = useVideoConfig();
4 const translate = spring({frame, fps, to: 100})
5 return(
6 <Img
7 src={cloudinary} alt='cloudinary'
8 style={{
9 display: 'block',
10 marginLeft: 'auto',
11 marginRight: 'auto',
12 width: '30%',
13 height: '50%',
14 transform: `translateY(${translate}px)`
15 }}
16 />
17 );
18}

The spring function makes our component bounce from a point to a point. We'll get the fps from the hook as shown. The function takes the frame and fps so that it knows how fast to go, from and to tell you how much range you want the outputs to be, and from has a default value of zero.

Building our Project

To build our project run yarn build or npm run build on your terminal. This has a dependency on ffmpeg, the terminal will give you instructions on how to configure it on your machine.

Once done you will find the video inside the out folder of your project.

Click this link to see the end video.

Conclusion

Great! In this article, we managed to create a 15-second video without using any video editing tools just React. It's amazing how we can create videos using react, right?

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.