🎥

ReactとRemotionで動画を作ってみた!

2023/05/15に公開

¡Hola! こんにちは!テラーノベルのオスカルです。最近Webの開発をしてます。日本語はまだまだ勉強してますので、応援してください! 🙏

今回、Reactで動画制作ができるRemotionというライブラリを触ってみて、思ったより楽しかったので絶対紹介したいと思いました。

セットアップのインストール

Node >= 14FFmpegは必要です。そこから、プロジェクトを作りましょう:

yarn create video

↑を実行するとテンプレートがいくつ出てきて選べます:

今回は僕はBlankを選びます。するといろんなファイルを作ってくれます。みてみよう!

これだけ?なるほど! じゃ、簡単そうなので一つずつ確認しましょう:

Index.ts

このファイルはエントリーポイントだけです。RootはインポートしてregisterRootします、ここから始めると言っているようなものです!

Root.tsx

Reactコードですね!。ここはCompositionというコンポーネントがいくつ追加できます。各Compositionの定義は動画の設定です: フレーム数、FPS、サイズなど。また、component={MyComposition}という記述がありますが、これは動画内で表示される内容がMyCompositionコンポーネントによって制御されていることを意味します。

MyComposition.tsx

ここには、アニメーションを作成するためのコンポーネントです。他のエレメントとスタイルを追加することができます。

何も入っていないので、ちょっとコードを追加しましょう!

export const MyComposition = () => {
    return (
        <div
            style={{
                width: '100%',
                height: '100%',
                backgroundColor: '#f2511b',
                color: '#fff',
                textAlign: 'center',
                alignItems: 'center',
                justifyContent: 'center',
                fontSize: '5rem',
                fontFamily: 'Arial',
            }}
        >
            <h1>Teller Novel</h1>
        </div>
    );
};

h1タイトルを含むスタイル付きのdivレイヤーを追加しましたね。次はプレビュー機能を確認しましょう:

プレビュー

もしターミナルでエントリポイントファイルへのパスを指定してこのコマンドを実行すれば、本当に素晴らしいUIが表示されます!

npx remotion preview src/index.ts

サーバーが起動し、ブラウザで以下のような画面が表示されるはずです。

#1- Root.tsxで設定した動画 (いくつあったらここに出てきます)
#2- MyCompのプレビュー
#3- タイムラインです

現在、コンテンツは静的な状態ですので、アニメーションを追加しましょう!

useCurrentFrame フック

Root.tsxを見たら、MyComp動画はこの設定でした:

durationInFrames={60}

この動画には60フレームがあります。useCurrentFrameというフックがあり、現在のフレーム番号を取得できます。その値は0から59まで変化します。フレーム番号を知っていれば、要素のアニメーションに使用することができます!

まず最初に、フックをインポートし、フレームを取得し、Teller Novelのタイトルのすぐ後に表示させましょう:

import { useCurrentFrame } from "remotion";

export const MyComposition = () => {
  const frame = useCurrentFrame();

  return (
    <div
      style={....}
     >
       <h1>Teller Novel {frame}</h1>
     </div>
  )
};

保存とプレビュー画面を開いて、プレイをしたら:

ちゃんと変更してますね!、じゃ、frameを使ってh1にCSSでアニメーションを追加していきます:

<h1 style={{
 transform: `translateY(${frame * 2}px)`,
}}>
  Teller Novel
</h1>

結果は:

もっとCSSを弄ったら:

<h1
  style={{
    display: 'inline-block',
    padding: '10px',
    border: `${frame / 20}px solid white`,
    borderRadius: `${frame / 5}px`,
    boxShadow: `11px 10px ${frame * 2}px 0px rgba(0,0,0,0.75)`,
    transform: `translateY(${frame * 5}px) 
    translateX(-${frame}px) 
    rotate(${frame / 2}deg) 
    scale(${frame / 30})`,
  }}>
    Teller Novel
</h1>

ここまでできました!

useVideoConfigフックもありますよ、fpsheightdurationInFramesなども取れますので、細かくまでコンポーネントは調整できます!

Springで物理アニメーション計算

Spring は、フレームとFPSに基づいてバウンスする値を計算するためのライブラリです。

追加が非常に簡単なので、試してみましょう!

Springアニメーションに必要なFPSを取得するために、useVideoConfigを使用していることに注意してください。

先のh1transform css部分はspringに変更します:

import {useCurrentFrame} from 'remotion';
import {useVideoConfig} from 'remotion'; // <-- ここ!
import {spring} from 'remotion'; // <-- ここ!

export const MyComposition = () => {
  const frame = useCurrentFrame();
  const {fps} = useVideoConfig(); // <-- ここ!

  return (
    <div style=[..]>
      <h1
        style={{
	  display: 'inline-block',
	  padding: '10px',
	  border: `${frame / 20}px solid white`,
	  borderRadius: `${frame / 5}px`,
	  boxShadow: `11px 10px ${frame * 2}px 0px rgba(0,0,0,0.75)`,
	  transform: `scale(${spring({fps, frame})})`, // <-- ここ!
	}}
      >
	Teller Novel
      </h1>
    </div>
  );
};

動画を見ると、タイトルのサイズアニメーションは素敵な加速度で行われます:

画像の使用

アセットはpublicフォルダに配置されます。
その後、ImgstaticFileコンポーネントを使ってそれらをインポートすることができます。Teller Novelのタイトルにテノちゃん入れましょう!

import {Img, staticFile, useCurrentFrame} from 'remotion'; // <-- ここ
import {useVideoConfig} from 'remotion';
import {spring} from 'remotion';

export const MyComposition = () => {
 [..]
  return (
    <div style=[..]>
	<h1 style=[..]>
	  Teller Novel
	  <Img // <-- ここから
	    src={staticFile('tenno-white.png')}
	    style={{
	      transform: `rotate(${frame * 15}deg)`
	     }}
	   />
	</h1>
    </div>
  );
};

くるくるでちょっとかわいそうだけど、プレイしよう!!

お、忘れちゃったけど、いつでもこのコマンドを実行することでMP4ファイルも作成することができますよ!

npx remotion render MyComposition out.mp4 

画像の連続で行われる伝統的なアニメーション

もし各フレームごとに異なる画像を用意し、動的に読み込むようにすれば、簡単に伝統的なアニメーションを作成することもできます!

ここから:




(cat1.png - cat5.png ですね)

画像は5個だけあるので、CompositiondurationInFrames5にしよう (fps=10もいい気がします):

Root.tsx

<Composition
  id="MyComposition"
  component={MyComposition}
  durationInFrames={5}
  fps={10}
  width={1280}
  height={720}
/>

Composition.tsx

import {Img, staticFile, useCurrentFrame} from 'remotion';

export const MyComposition = () => {
  const frame = useCurrentFrame();
  return (
    <div style=[..]>
       <Img src={staticFile(`cat${frame + 1}.png`)} height="200" />
    </div>
  );
};

この簡単なコードで、美しいアニメーションを作成することができました!

他の興味深い機能

音声

mp3ファイルなどをpublicフォルダに入れたら<Audio>コンポーネントで動画に入れれますよ。frameもわかるので、アニメーションに効果音を追加することができますよね。

データの取得

Reactなので、fetchSWRフックを使ってAPIからデータを取れます。delayRenderあって、データあるまでレンダリングされないので、すごく便利です!
例えば:

import { continueRender, delayRender } from "remotion";
[..]

  const [handle] = useState(() => delayRender());
  const [data, setData] = useState(null);
  useEffect(() => {
   fetch('https://catfact.ninja/fact')
     .then((response) => response.json())
     .then((d) => {
       setData(d.fact);
       continueRender(handle);
     });
   }, [handle]);

これにより、例えば、各ユーザーに対して動的に個別のパーソナライズされたムービーを作成することができますよ!

終わりに

Remotionは非常に柔軟で強力なツールです! もっともっとできることあるので、docsを是非読んでみてください。ショーケースもあるので、なんかなんでもできそう気がします!

もし動画作ってみたらコメントで教えてください!🙏

¡Adios! Happy coding-filming! 🎥

テラーノベル テックブログ

Discussion