Remotion: Make a video of the original Kanto pokemon *from code* Part 2

Remotion: Make a video of the original Kanto pokemon *from code* Part 2

So now, let's hop into Composition.tsx.

Composition.tsx

First, let's make a div and display hello in it to test if it is working!

image.png

export const MyComposition = () => {
    return <div>hello</div>;
};

Now, let's make the background black and make the width of the div 100%

export const MyComposition = () => {
    return <div style={{background: 'black', width: '100%'}}>hello</div>;
};

If you remember, we changed the color and font for the h1 last time. Let's put the hello in h1.

image.png

Data fetching

Docs: remotion.dev/docs/data-fetching

Here's an example from the docs:

import { useEffect, useCallback, useState } from "react";
import { continueRender, delayRender } from "remotion";

export const MyVideo = () => {
  const [data, setData] = useState(null);
  const [handle] = useState(() => delayRender());

  const fetchData = useCallback(async () => {
    const response = await fetch("http://example.com/api");
    const json = await response.json();
    setData(json);

    continueRender(handle);
  }, [handle]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return (
    <div>
      {data ? (
        <div>This video has data from an API! {JSON.stringify(data)}</div>
      ) : null}
    </div>
  );
};

Now what should we do? Let's create a function, and get the data of the first 151 Pokemon from PokeApi.

Let's import:

import {useEffect, useCallback, useState} from 'react';
import {continueRender, delayRender} from 'remotion';
const [data, setData] = useState < any[] > ([]);
const [handle] = useState(() => delayRender());
const fetchData = useCallback(
    async (num: number) => {
            const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${num}`);
            const json = await response.json();
            let arr = data;
            arr.push({
                json: json,
                num: num
            });
            setData(arr);

            continueRender(handle);
        },
        [handle]
);
useEffect(() => {
    for (let index = 0; index < 151; index++) {
        fetchData(index + 1);
    }
}, [fetchData]);

So here, we are getting the data, but also giving it a num property, so that it stays in the same order.

Now, let's show data in the code.

<h1>{JSON.stringify(data)}</h1>

image.png

Images

Now, let's display images. For testing, I'll show an image for every Pokemon first.

{
    data
        .sort((a, b) => (a.num > b.num ? 1 : b.num > a.num ? -1 : 0))
        .map((e) => {
            return <img src = {
                e.json.sprites.front_default
            }
            />;
        })
}

image.png

Now how to show a pokemon for 1 second 🤔.

Showing Pokemons once in a time

First, we need the current frame. For that, we have useCurrentFrame() in Remotion.

const frame = useCurrentFrame();

Also, let's import the Img tag so that it updates on its own.

So the current Pokemon data should be data.sort((a, b) => (a.num > b.num ? 1 : b.num > a.num ? -1 : 0))[Math.floor(frame / 20) ] right? Because our video is in 20fps. So the image should be:

<Img
src = {
    data.sort((a, b) =>
        a.num > b.num ? 1 : b.num > a.num ? -1 : 0
    )[Math.floor(frame / 20)]?.json?.sprites?.front_default
}
/>

Use optional chaining so that it doesn't give an error in the starting when the data hasn't loaded

But instead, let's use an SVG. You can find it like this: ?.json?.sprites?.other.dream_world?.front_default

Now you'll see something like this:

image.png

We're getting something cool now! Now let's also make an h1 and change its text to the Pokemon name.

<h1>
        {
            data.sort((a, b) => (a.num > b.num ? 1 : b.num > a.num ? -1 : 0))[
                Math.floor(frame / 20)
            ]?.json?.name
        }
            </h1>

Hope you like it so far! See you in Part 3, the last part!


Code till now

Video.tsx

import {Composition} from 'remotion';
import {MyComposition} from './Composition';

export const RemotionVideo: React.FC = () => {
    return (
        <>
            <Composition
                id="Empty"
                component={MyComposition}
                durationInFrames={3020}
                fps={20}
                width={1920}
                height={1080}
            />
        </>
    );
};

Composition.tsx

import './font.css';
import {useEffect, useCallback, useState} from 'react';
import {continueRender, delayRender, Img, useCurrentFrame} from 'remotion';
export const MyComposition = () => {
    const frame = useCurrentFrame();
    const [data, setData] = useState<any[]>([]);
    const [handle] = useState(() => delayRender());
    const fetchData = useCallback(
        async (num: number) => {
            const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${num}`);
            const json = await response.json();
            let arr = data;
            arr.push({
                json: json,
                num: num,
            });
            setData(arr);

            continueRender(handle);
        },
        [handle]
    );
    useEffect(() => {
        for (let index = 0; index < 151; index++) {
            fetchData(index + 1);
        }
    }, [fetchData]);
    return (
        <div style={{background: 'black', width: '100%'}}>
            <Img
                src={
                    data.sort((a, b) => (a.num > b.num ? 1 : b.num > a.num ? -1 : 0))[
                        Math.floor(frame / 20)
                    ]?.json?.sprites?.other?.dream_world?.front_default
                }
            />
            <h1>
                {
                    data.sort((a, b) => (a.num > b.num ? 1 : b.num > a.num ? -1 : 0))[
                        Math.floor(frame / 20)
                    ]?.json?.name
                }
            </h1>
        </div>
    );
}

font.css

@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
h1 {
    font-family: 'Press Start 2P';
    color: white;
}

Did you find this article valuable?

Support Raghav Singh Gulia's Blog by becoming a sponsor. Any amount is appreciated!