Why I made this video with code
Today's video is made different. I threw away all my fancy editing tools like Adobe Premiere and After Effects and instead did all the editing with JavaScript code thanks to a tool called Remotion, which allows you to create video content programmatically with React.
When you think about it, a video is just a function of images over time. Every second we might render 60 still images, or frames, each one changing slightly to create an animation. React is a great tool for describing UIs that change over time, so why not use it to describe video content as well?
That's the idea behind Remotion, which opens the door for web developers to storify their data. For example, you might use a weather API to fetch the local weather forecast, then use Remotion to animate a video out of that data. If it's raining, show some raindrops; if it's cloudy, make some clouds float by; and if there's a tornado, show the entire town being destroyed.
By the end of this tutorial you'll know how to create your own custom data-driven videos from scratch using nothing but JavaScript and Remotion.
Getting started: project and shout-outs
If you're new here, like and subscribe and check out the full source code on GitHub. Before we jump into the code for this project, I want to give a huge shout out to William Candione. He put together the code for this video and has an awesome YouTube channel that you should definitely be subscribed to. And respect to Johnny Burger, the creator of Remotion.
This tutorial is unlike anything else out there, and by the end of it you'll be able to add video editor to your resume and you might be surprised at how easy it really is to create videos with React once you understand the fundamentals of video animation.
Initializing Remotion and the video component
If you go to GitHub and clone the project, it'll pull up a browser window that allows you to scrub through the entire timeline of the intro that you just watched, and you can modify it using HTML, CSS, and JavaScript. What I'm going to show you in this video is how to recreate the weather scene from scratch. To follow along and create your own video right now, run npm init video from the terminal to initialize Remotion. It provides a variety of different templates to start with. My goal is to show you the basic step by step, so I'm going to choose a blank TypeScript template.
The first place we'll go is the video.tsx file, which contains a Remotion video component. Think of this component as your entire video. Now a video is made up of one or more compositions. Remotion allows you to visualize these compositions in the browser by running npm start. You'll notice in the full project that we have a bunch of different compositions here on the sidebar. These are like their own little mini videos that allow you to isolate and inspect each scene in the video.
Composition props: id, resolution, and duration
Back in the code you'll notice a composition has a variety of different props. It has an id to identify it in the video player, but more importantly it references a React component that contains the actual UI that you want to show.
Before we get to that point though, we'll need to determine the resolution for the video, which I'm setting to 1080 by 1920 to give us a portrait, and also the duration. The duration is the number of frames that will be rendered for the scene. A frame is basically just a still image at a given point in the video. Now the actual length in seconds will be based on the frames per second. If we do 120 frames at 30 fps, that will give us a video length of 4 seconds.
Building the composition UI and simple animations
Now let's go ahead and shift our attention over to the composition file. This is where we'll define the actual graphics for our video. Inside the component we have a div with the text of "Hello, world." Now we can style it with CSS using inline styles here. Using inline styles allows us to modify them programmatically. If you open the video player you should see a 4 second long scene that says "Hello, world." That's pretty cool, but also extremely boring. How do we make the video do something cool?
Remotion provides a variety of different hooks to provide data about the video. With useVideoConfig we can grab data about the fps, duration, and resolution and we can use that data to calculate values for our animations or, as I'm doing here, display it directly in the video content. But more importantly for animation, the useCurrentFrame hook will give us the current frame in the timeline. Remember, this React component will be re-rendered for each frame in the video. We can use the current frame to calculate a slight difference between each frame to create an animation. Here's an example of how you might create a fade animation: let's define a variable for opacity as the current frame divided by the total duration in frames. That'll give us an opacity that starts at 0 and gradually increases to 1 over the duration of the video. Now we can use it as the opacity value in the CSS and the end result is a linear fade-in animation when we preview it in the browser.
Integrating and animating SVG graphics
Remotion has a bunch of other powerful features baked into it. What I want to do next is integrate an SVG graphic into the composition. I'm creating a new component that will be a map of France, and in the JSX I'm simply pasting an SVG graphic that I found on the internet. The cool thing about SVG is that we can use and modify its source code directly inside our JavaScript. Unlike a PNG or JPEG file, you can find the SVG code on GitHub or experiment with one of your own SVG graphics.
Now to make our lives easier, Remotion provides a bunch of different helper components and functions, one of which is AbsoluteFill. This component will absolutely position the child so you don't have to manually configure all the CSS properties. Now I am going to add some additional alignment and padding to position it right in the center, and then we can simply import this component into our composition and declare it there. That graphic should now appear in the video.
Animating raindrops with interpolate and spring
Let's take things a step further and do some actual SVG animation. You'll notice in the full demo that a bunch of raindrops randomly animate in from top to bottom. This effect is accomplished with a single raindrop SVG. First, create a new component called Raindrop. Inside of it I'm adding an SVG graphic of a single raindrop to the JSX. The SVG will have a variety of dynamic styles. We can use transform to give each raindrop a slightly different size, but more importantly we'll animate the absolute position of it like left and top to move it from top to bottom.
The real question here is where do these values come from? Some of them will come in from the parent via props like the delay, x position, and size. We will randomize these values in the next step. The tricky part is making a raindrop go from top to bottom. For that we'll need to interpolate the top position. That sounds like it might require some fancy math. Luckily Remotion has our back here with an interpolate helper function. In our case we provide it with the frame minus the delay, then an input range and output range. The output range is the actual top position, which will start off the screen at 0.2 on the y-axis and then animate to the bottom off the screen at 1.1 on the y-axis. That'll get the job done, but we can make our animation even more realistic by making it kind of bouncy and gooey because Remotion also has a primitive called spring to add spring physics to your animations.
To use it, we'll create a variable called drop that calls the spring function. It takes the frames per second as well as the frame minus delay as arguments, and you can customize the springiness with damping and stiffness. Using that as the interpolate input will give us a more interesting effect that takes care of one raindrop.
Scaling up: thousands of raindrops and rendering output
Now the question becomes how do we randomly animate hundreds or millions of raindrops at the same time? To handle that we'll create another component called Rain. Inside of it we'll start by defining a variable called drops that contains 300 true values in it. Each value represents one raindrop. What we want to do is randomize the x position, delay, and size of each raindrop. Let's map each value in the array to an object of those values.
Once again Remotion helps us out here by providing a random helper that can generate random values with a seed, which means you'll get the same random value given the same seed. That takes care of the randomization. One extra step we'll want to take here is to wrap this function in useMemo with React and pass it an empty array as the dependency because we only want to run this function once when that component is first initialized. Remember it will re-render for every frame in the video and we don't need to recalculate on every frame.
Now in the JSX we'll use the AbsoluteFill component and then map over the raindrop array to display each individual raindrop and pass it the required props, and that's all it takes to make it rain. Take the Rain component and declare it in our composition and then preview it in the browser; that should give you an end result that looks something like this.
In the full demo we have additional weather animations like clouds and tornadoes and they're rendered conditionally based on actual weather data that comes from an API. But now let's render it to a real MP4 video that we can upload to TikTok or YouTube. You'll first need to have FFmpeg installed on your system. From there, if you go into the package.json file you'll notice a build script. It contains the input and output files as well as the id of your composition. You'll want to make sure that matches whatever composition id you've chosen. Now go ahead and run npm run build from the terminal and it will render out your code to the out directory as an MP4 file. Congratulations, you just made a video with React.
What I find so cool about this is that it provides a really nice way to generate videos programmatically based on some kind of underlying data source. My plan is to connect it to GPT-3 along with the Giphy SDK to automatically write, produce, and edit all my future YouTube videos. I'm going to go ahead and wrap things up there and give Remotion a star on GitHub and let's see if we can get them past 10k. Thanks for watching and I will see you in the next one.