Learn Remotion: Create Animated Video with HTML, CSS & React

Share this article

Remotion: Create Animated Videos Using HTML, CSS and React

Creating a video with text, animations, colors, and shapes traditionally requires specialist software and potentially years of motion graphic training. What if you could use your existing toolset, training, and background in web development to do the same?

Remotion allows JavaScript developers to reuse the skills and knowledge they’ve built up to create complex animated videos using HTML, CSS, and React JS. If you can render text with React, animate a CSS style, or organize HTML content, you can now create and edit your own videos using solely code, with no video editing applications or software required.

In this article, I’ll go through the process of using Remotion and talk you through my discoveries as we go along.

You can find the complete code for this article on GitHub.

Remotion: What, and Why?

Remotion is a video creation toolkit for React created by Jonny Burger. This toolkit allows anyone with a basic understanding of React, HTML or CSS to create animated videos using code.

In the video creation space there’s currently a high barrier to entry due to the required software and training needed to use and master these tools. By utilizing JavaScript developers’ existing toolkits, this opens the video creation space to a wider user base. As videos become code, we can leverage existing patterns to allow for more effective video creation — such as automated generation based on parameters or build pipelines.

Getting Started

Thankfully, Remotion has a quick and easy setup process with a Yarn and npm starter kit. For this example, we’ll be sticking with npm as the build and run tool. Before we get started, you’ll need to have Node and npm installed. (For assistance, you can follow this guide to installing Node and npm.) Also check the Remotion installation guide if you’re on Linux, as you may need to install additional tools. After getting Node and npm set up, let’s create a new project by running this code:

npm init video

This will prompt you for a project name, which is also used as the directory name. In our case, it will be my-video. Once entered, we can move into the my-video directory and start the default video project by running the start script as follows:

cd my-video
npm start

After running the start command, the browser should automatically open. If not, open the browser and navigate to http://localhost:3000/. This feature allows you to watch and debug the video you’re creating. The player has controls that include a play button, which allows you to preview the video content. It may also be useful to start by looking at the code for the demo example, which Remotion provides as a guide for how to build your own video.

Hello, World!

We’re going to create our own video animating the text “Hello, World!”, to get to grips with the components and processes supplied in Remotion.

First of all, let’s delete the existing example code (everything in the src folder), as we want to start afresh. Then, let’s create a Demo directory under the src directory, which will hold and manage all our video work for this project. Inside the Demo directory, create a Demo.js file:

import {Composition, interpolate, Sequence, useCurrentFrame, useVideoConfig} from 'remotion';
import Title from './Title';
import Hello from './Hello';
import "./demo.css";

const Demo = () => {
  return (
  <div className="main-container">
    {/* TODO: add video content */}
  </div>
  );
};

export const DemoVideo = () => {
  return (
  <Composition
    id="Demo"
    component={Demo}
    durationInFrames={150}
    fps={30}
    width={1920}
    height={1080}
    defaultProps={{
      titleText: 'This is my first Remotion video',
      titleColor: 'blue',
    }}
    />
  )
}

The Demo file exports our video code. As you can see, we can create a Demo component that will hold all the visual elements in our video. We can then export a component that renders the Composition of our video. The Composition component allows us to define some basic properties such as the width and height of the video clip, the FPS (frames per second), and the feature that will be rendered. We also import some utils and hooks from Remotion and some additional components that we will create soon.

Currently our Demo component is empty, but let’s add some elements to our video:

const Demo = ({titleText, titleColor}) => {
  const frame = useCurrentFrame();
  const videoConfig = useVideoConfig();

  const totalOpacity = interpolate(
     frame,
     [videoConfig.durationInFrames - 25, videoConfig.durationInFrames - 15],
     [1, 0],
    {
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp',
    }
  );

  return (
    <div className="main-container">
      <div style={{opacity: totalOpacity}}>
        <Sequence from={0} durationInFrames={videoConfig.durationInFrames / 2}>
          <Hello/>
        </Sequence>
        <Sequence from={35} durationInFrames={Infinity}>
          <Title titleText={titleText} titleColor={titleColor} />
        </Sequence>
      </div>
    </div>
  );
};

We’ve added a lot to the file, so let’s break this all down.

Firstly in our render section, we can see from the file that we can now return a div with opacity styles, allowing us to fade elements in and out at the start and end of the video. For the opacity value, we use a Remotion helper. The interpolate function allows you to better define animations and map the animation values to the current frame and the video duration. In this example, we pass in the current frame. The function will get called on each frame generated. The input range is calculated from the duration of the video and the output value ranges from 0 to 1, as this is the range for the opacity CSS value. As the Demo component is re-rendered for each frame, the interpolate function is called each time and will return the appropriate opacity value.

Next, we can begin rendering different visual elements on the video screen. In this example, we want the text “Hello, World!” to fade into view then disappear and the text “This is my first Remotion video” to then appear afterwards. To do so, we can render multiple Sequence components.

A Sequence component is another Remotion feature that allows us to define how and when a component renders in a video and for how long. This is great for building complex videos where you want to add timed or layered elements, such as this example. Each Sequence will also show in the browser player and be titled based on the child component name. This allows you to monitor the video you’re generating and the effects you’re adding to it in real time.

Remotion also provides some useful React hooks, and in this example we make use of the useCurrentFrame and useVideoConfig hooks. useCurrentFrame will return the current frame that the video is on, which is useful for animations and implementing actions based on where the current position of the video playback is. useVideoConfig will return an object with different values, such as:

  • width: the width of the video — useful for positioning elements in the video
  • height: the height of the video — useful for positioning elements in the video
  • FPS: frames per second — which can be used to determine the speed of animation or element movement
  • durationInFrames: the total length of the video in frames — which can be used to calculate animations or times for Sequence show and hide.

In our case, as mentioned, firstly we want our Hello component, the text “Hello, World!”, to appear at the start of the video and remain on screen for half of the time. We do this by using the videoConfig.duration value, which we’ve calculated from the useVideoConfigHook.

For the second Sequence, we want our Title component text, “This is my first Remotion video”, to appear after 35 frames and stay on screen for the full duration of the video. To achieve this, for From we enter 35, and for durationInFrames we enter Infinity.

To style our demo component, we can use CSS along with inline styles. When using CSS, we want to apply styles to the whole video, so let’s create a demo.css file that will hold any styles that cover the whole video area. In our example, we want to make the background white and align out items with Flexbox:

.main-container {
    flex: 1;
    background-color: white;
}

Now let’s delve deeper into these elements we’re rendering.

Rendering React Components in an Animation

The Hello component is going to be a basic React component that renders an H1 tag with some inline styles applied and the text “Hello, World!” This is the simplest form of a component we can render. For simplicity’s sake, we can use inline styles. But because this is React, you could also import styles from a CSS file and use a class name, styled-components, CSS modules, or any styling pattern you’re already familiar with as an alternative. Let’s create the Hello component. Inside the Demo folder, create a new file Hello.js:

const Hello = () => {
  return (
    <h1
      style={{
        fontFamily: 'SF Pro Text, Helvetica, Arial',
        fontWeight: 'bold',
        fontSize: 100,
        textAlign: 'center',
        position: 'absolute',
        bottom: 500,
        width: '100%'
      }}
    >
      Hello, World!
    </h1>
  );
};

export default Hello;

Now, let’s take a look at a more complex example. In the Demo folder, create a new file called Title.js and add in the component code below:

import {spring, useCurrentFrame, useVideoConfig} from 'remotion';

const Title = ({titleText, titleColor, bottom}) => {
  const videoConfig = useVideoConfig();
  const frame = useCurrentFrame();
  const text = titleText.split(' ').map((t) => ` ${t} `);
  return (
    <h1
      style={{
        fontFamily: 'SF Pro Text, Helvetica, Arial',
        fontWeight: 'bold',
        fontSize: 100,
        textAlign: 'center',
        position: 'absolute',
        bottom: bottom || 160,
        width: '100%',
      }}
    >
      {text.map((t, i) => {
        return (
          <span
            key={t}
            style={{
              color: titleColor,
              marginLeft: 10,
              marginRight: 10,
              transform: `scale(${spring({
                fps: videoConfig.fps,
                frame: frame - i * 5,
                config: {
                  damping: 100,
                  stiffness: 200,
                  mass: 0.5,
                },
              })})`,
              display: 'inline-block',
            }}
          >
            {t}
          </span>
        );
      })}
    </h1>
  );
};

export default Title;

We have a lot going on here, so again let’s break down what’s going on.

Remotion has first-class support for TypeScript. This is not required, but it can make the development process better, as you’ll get more detailed autocomplete suggestions in your IDE. However, to make this example more beginner friendly, we’ll just use normal JavaScript.

Our component takes in two props — titleText and titleColor — which will be used later in our render method. This shows that, using React, we can still pass props around the application, therefore making our video elements reusable and dynamic. You may have noticed that, in our Demo component, we passed props in from the Composition component. This shows the power of React in action. We can pass in props from the very top of the React application, making the video responsive, and meaning you could change one block of text to make a new video or to change the whole video context.

After we’ve accessed our props in the Title component, we call the Remotion hooks again to get the videoConfig and frame data. The Title component then breaks the text prop passed and renders it one word at a time using a combination of a map and CSS transform. Here we have the opportunity to use another built-in helper function. Spring takes in values to help generate a smooth output for the animation value. We pass the main video config’s FPS to control the speed of the animation. The frame value controls when the animation starts, and finally we pass in additional configuration options to control the smoothness of the animation.

After we have all our video components created and ready to go, we need to finally create an index.js file in the root of the src folder and add the following content:

import {registerRoot} from 'remotion';
import { DemoVideo } from './Demo/Demo';

registerRoot(DemoVideo);

The index file imports the registerRoot function from Remotion, which allows us to render the video content. Think of this as the ReactDOM render function but for Remotion. Then we pass our DemoVideo component to registerRoot, which will visualize the rendered video in either development or build modes.

We’re now importing the Demo video that will get rendered by Remotion.

Now that we have all of these features combined, we have a fully animated video that provides one example of the different components and helper functions supplied by Remotion.

We can run the video from the root of the project with the following command:

./node_modules/.bin/remotion preview src/index.js

Or, you can update the start script in the package.json file:

- "start": "remotion preview src/index.tsx",
+ "start": "remotion preview src/index.js",

Then run the animation using npm start.

Building the StarWars Animation

Now we have a basic understanding of Remotion and the different components on offer, we can challenge ourselves and have a little bit more fun. Let’s build our own version of the iconic Star Wars title intro screen. We want to be able to render a sparkly star background with bright yellow text that scrolls up the screen. We can use the knowledge we have from our “Hello, World!” example as a starting off point.

Let’s start by creating the files we need. In the src folder, create a starWarsIndex.js file and a StarWars folder. In the StarWars folder, create a further four files: starWars.js, starWars.css, starsBackground.js, starsBackground.css.

When you’re done, the src folder should look like this:

.
├── Demo
│   └── Files from "Hello, World!" demo
├── index.js
├── StarWars
│   ├── starsBackground.css
│   ├── starsBackground.js
│   ├── starWars.css
│   └── starWars.js
└── starWarsIndex.js

Creating the Scrolling Text

First, we start with a StarWarsVideo component, which will render a Composition component to define the video properties. As the scrolling text is longer, we define a higher durationInFrames number.

Add the following to src/starWarsIndex.js:

import {registerRoot, Composition, Sequence} from 'remotion';
import {useEffect, useState} from 'react'
import { LoremIpsum } from 'lorem-ipsum';

import Stars from './StarWars/starsBackground';
import StarWars from './StarWars/starWars';

const StarWarsVideo = () => {
  const [textBlocks, setTextBlocks] = useState([]);
    
  useEffect(() => {
   setTextBlocks([
    lorem.generateSentences(5),
    lorem.generateSentences(5),
    lorem.generateSentences(5),
   ])
  }, [])
  return (
    <>
      <Composition
        id='star-wars'
        component={Video}
        durationInFrames={580}
        fps={30}
        width={1920}
        height={1080}
        defaultProps={{ textBlocks }}
        />
    </>
  );
};


registerRoot(StarWarsVideo);

We also need to define some React state. In this Star Wars example, we’re going to make use of React state and props to generate random text each time we reload the video. Using the lorem-ipsum npm module we can make the text responsive and different every time it’s generated.

Let’s install the module:

npm i lorem-ipsum

Then, in the same file add:

// import statements

const lorem = new LoremIpsum({
  sentencesPerParagraph: {
    max: 8,
    min: 4
  },
  wordsPerSentence: {
    max: 16,
    min: 4
  }
});

const Video = ({ textBlocks }) => {
  return (
   <div>
    <Sequence from={0} durationInFrames={Infinity}>
     <Stars/>
    </Sequence>
    <Sequence from={0} durationInFrames={Infinity}>
     <StarWars
      textBlocks={textBlocks}
     />
    </Sequence>
   </div>
  )
}

const StarWarsVideo = () => { ... };

registerRoot(StarWarsVideo);

For the Sequence components, we can layer up two main components for the video. The Stars component will render the starry background, and the StarWars component will render the scrolling yellow text. The star background is using standard CSS animation and transforms to display stars. The StarWars component is where we start getting back into Remotion-based animations. We can use the Spring helper function to control the top position, rotate, and translate CSS transform properties to animate the scrolling of the text based on the current time in the video.

Add the following to src/starWars.js:

import React from 'react';
import './starWars.css';
import {spring, useCurrentFrame} from 'remotion';

const StarWars = ({ textBlocks }) => {
  const frame = useCurrentFrame()
  const fps = 6000;

  const top = spring({
    frame,
    from: 0,
    to: -6000,
    fps,
  })

  const rotate = spring({
    frame,
    from: 20,
    to: 25,
    fps,
  })

  const translateZ = spring({
    frame,
    from: 0,
    to: -2500,
    fps,
  })

  return (
    <>
      <div className="fade"/>

      <section className="star-wars">
        <div
          className="crawl"
          style={{
            top: `${top}px`,
            transform: `rotateX(${rotate}deg) translateZ(${translateZ}px)`
          }}
        >

          <div className="title">
            <p>Episode IV</p>
            <h1>A New Hope</h1>
          </div>
          {
            textBlocks.map((block, index) => {
              return (
                <p key={index}>{block}</p>
              )
            })
          }
        </div>
      </section>
    </>
  )
}

export default StarWars;

Note that we’re rendering out the textBlocks prop, which will be our random text each time we generate the video.

All that remains now is to create the Stars component. Add the following to src/starsBackground.js:

import React from 'react';
import './starsBackground.css';

const Stars = () => {
  return (
    <>
      <div id='stars'/>
      <div id='stars2'/>
      <div id='stars3'/>
    </>
  );
}

export default Stars;

Also add the following styles to src/starsWars.css:

.fade {
  position: relative;
  width: 100%;
  min-height: 60vh;
  top: -25px;
  z-index: 1;
}

.star-wars {
  display: flex;
  justify-content: center;
  position: relative;
  height: 800px;
  color: #feda4a;
  font-family: 'Pathway Gothic One', sans-serif;
  font-size: 500%;
  font-weight: 600;
  letter-spacing: 6px;
  line-height: 150%;
  perspective: 400px;
  text-align: justify;
}

.crawl {
  position: relative;
  top: 9999px;
  transform-origin: 50% 100%;
}

.crawl > .title {
  font-size: 90%;
  text-align: center;
}

.crawl > .title h1 {
  margin: 0 0 100px;
  text-transform: uppercase;
}

The src/starsBackground.css is too large to list here. Please grab its contents from the GitHub repo and add it to your own project.

This will result in a fully functional Stars Wars intro video, created using only code, and no video editing software.

The last step to get the StarWars example running is to add the following script to the package.json file:

"start:starwars": "remotion preview src/starWarsIndex.js",

And there we have it — a StarWars intro, fully coded in React.

If you want to insert the actual StarWars text, grab it from here and alter the useEffect method call in src/starWarsIndex.js:

useEffect(() => {
 setTextBlocks([
-  lorem.generateSentences(5),
-  lorem.generateSentences(5),
-  lorem.generateSentences(5),
+  "It is a period of civil war. Rebel spaceships...",
+  "Pursued by the Empire’s sinister agents..."
 ])
}, [])

Awesome!

Conclusion

We’ve made two examples showcasing the power of Remotion, each of varying complexity. However, this is just scratching the surface of how capable Remotion is. Below are some of the other features that Remotion provides that we didn’t cover.

Don’t forget, all of the code is available on GitHub.

Data Fetching

To add a reactive element to your videos, you can fetch data to help populate the content at build time. Remotion provides hooks to handle the fetching of data, such as continueRender. delayRender can also be used in circumstances to pause the rendering of the video content until the data has been fetched. These features could be used to generate videos based on data imputed into a database. Or they can pull data from the server — for example, creating an intro video for a blog post and pulling the blog’s title and hero image from a server.

Parameterized Rendering

From the examples we used earlier, we could control the flow of props getting passed into video elements. This allows the videos to be responsive. However, this requires code changes each time. With parameterized rendering, you can pass the data in as part of the build command. This means that you could, as part of a CI/CD flow, generate videos depending on passed-in data — for example, auto-generating onboarding videos with the person’s name and title passed in as props.

Asset Imports

You don’t need to create elements only using CSS. You can also import other assets such as images, existing videos, and audio files into your project.

There are many more additional features, and new features are being released regularly in Remotion. Remotion is a fully developed project and is making big steps in the JavaScript-based video space. This is a very powerful tool with a realm of possibilities yet to uncover.

If you’ve used Remotion to build something cool, let me know on Twitter.

Frequently Asked Questions (FAQs) about Creating Animated Videos Using HTML, CSS, and React

How Can I Create Animated Videos Using HTML, CSS, and React?

Creating animated videos using HTML, CSS, and React involves a few steps. First, you need to have a basic understanding of these three technologies. HTML (HyperText Markup Language) is the standard markup language for creating web pages. CSS (Cascading Style Sheets) is a style sheet language used for describing the look and formatting of a document written in HTML. React is a JavaScript library for building user interfaces. Once you have a grasp of these, you can use libraries like Remotion to create your animations. Remotion is a suite of libraries building a fundament for creating videos programmatically using React.

What is Remotion and How Does it Work?

Remotion is a powerful library that allows developers to create videos programmatically using React. It leverages the power of React and JavaScript to allow for the creation of complex animations and transitions. With Remotion, you can create components that represent frames in your video, and then animate those frames using standard React state and props.

Can I Use Remotion for Commercial Projects?

Yes, you can use Remotion for commercial projects. It is an open-source library, which means it is free to use and modify. However, it’s always a good idea to check the specific licensing terms of any open-source library before using it in a commercial project.

How Can I Convert HTML5 Animations to Video?

Converting HTML5 animations to video can be done using various tools and libraries. One such tool is Remotion. It allows you to create videos programmatically using React. You can create your animation using HTML, CSS, and React, and then use Remotion to render that animation as a video.

What are the Best Practices for Creating Animated Videos with HTML, CSS, and React?

When creating animated videos with HTML, CSS, and React, it’s important to keep a few best practices in mind. First, always plan your animation before you start coding. This will help you understand the flow and sequence of the animation. Second, keep your animations simple. Complex animations can be difficult to understand and can distract from the message you’re trying to convey. Finally, test your animations thoroughly to ensure they work as expected across different browsers and devices.

Can I Add Audio to My Animated Videos Created with Remotion?

Yes, you can add audio to your animated videos created with Remotion. Remotion supports the use of audio files, allowing you to sync your animations with sound for a more engaging viewer experience.

How Can I Optimize My Animated Videos for Better Performance?

Optimizing your animated videos for better performance can involve several strategies. These include minimizing the use of complex animations, optimizing your code for performance, and using efficient rendering techniques. Additionally, using tools like Remotion can help you create more efficient animations by allowing you to create videos programmatically.

What are the Limitations of Creating Animated Videos with HTML, CSS, and React?

While creating animated videos with HTML, CSS, and React offers many benefits, there are also some limitations. These include browser compatibility issues, performance limitations, and the need for a good understanding of these technologies. However, libraries like Remotion can help overcome some of these limitations by providing a powerful and efficient way to create videos programmatically.

Can I Use Other JavaScript Libraries Alongside Remotion?

Yes, you can use other JavaScript libraries alongside Remotion. Remotion is built to work with React, but it doesn’t prevent you from using other JavaScript libraries in your project. This allows you to leverage the strengths of different libraries to create more complex and engaging animations.

How Can I Learn More About Creating Animated Videos with HTML, CSS, and React?

There are many resources available to learn more about creating animated videos with HTML, CSS, and React. These include online tutorials, documentation, and community forums. Additionally, the Remotion documentation is a great resource for learning more about how to use this powerful library to create animated videos.

Chris LaughlinChris Laughlin
View Author

Application developer based in Belfast, Northern Ireland. Focused on front end development especially JavaScript. Been working in software development since 2010 and still learning and sharing everyday.

HTML5 videoReactRemotionvideovideo animation
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week