【React】【TypeScript】Remotionで「Hello, World」が飛び出す動画を作ってみた

2023/12/10に公開

まえがき

ライブラリRemotionを使って「Hello, World」が徐々に表示される動画と飛び出す動画を作ります。
動画でも解説しているので、当記事と一緒にご覧ください。

https://youtu.be/O6aVAIa9Mf8

Remotionとは

Remotionとはプログラミングで動画を作れるライブラリです。

https://www.remotion.dev/

基本はReactベースでTypeScriptを使います。
また、他にもたくさんのテンプレートが用意されています。

https://www.remotion.dev/templates

TypeScriptではなく、JavaScriptでも使えます。
Reactのフレームワークである、Next JS App Routerも使えます。

プロジェクトを新規作成

まずはVS Codeを開いて、ターミナルを呼び出します。
プロジェクトを作成する任意の場所に移動します。
私はデスクトップ上のディレクトリProjectの中にディレクトリRemotionProjectを作成しています。
コマンドcd desktop/project/remotionproject/を実行して移動します。

cd desktop/project/remotionproject/

プロジェクトを作成するディレクトリに移動したら、ターミナルでコマンドnpm init videoを実行します。

npm init video

まずはプロジェクト名を質問されます。
ここではremotion-str-anima-ytとします。
ちなみにremotion-str-anima-ytは自由に決めていただいて結構です。

次はテンプレートを選択するように指示されます。ここでは、上から4番目のBlankを選択します。

ディレクトリremotion-str-anima-ytが作成されて、その中にプロジェクトが作成されます。
最後にVS Codeでプロジェクトを開くかどうか質問されるので、yを入力します。
新たにVS Codeが立ち上がるので、元のウィンドウは消します。
新たにが立ち上がったVS Codeでターミナルを開きます。
README.mdが開いているので閉じておきます。

文字列が徐々に現れるアニメーションを作成

最初は文字列が徐々に現れるアニメーションを作成します。

FadeIn.tsx

srcディレクトリにファイルFadeIn.tsxを作成します。
ファイルFadeIn.tsxを開いてrafcと入力すると候補が出てくるのでrafcを選択します。
すると、コードが自動補完されます。
これは、拡張機能、ES7+ React/Redux/React-Native snippetsを導入すると使えるようになります。
ぜひ、オススメします。

https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets

FadeIn.tsx
import React from 'react'

export const FadeIn = () => {
  return (
    <div>FadeIn</div>
  )
}

コードを以下のように編集します。

FadeIn.tsx
import { AbsoluteFill, useCurrentFrame } from "remotion";

export const FadeIn = () => {
  const frame = useCurrentFrame();
  const opacity = Math.min(1, frame / 60);
  return (
    <AbsoluteFill
      style={{
        justifyContent: "center",
        alignItems: "center",
        backgroundColor: "white",
        fontSize: 80,
      }}
    >
      <div style={{ opacity }}>Hello, World</div>
    </AbsoluteFill>
  );
};

returnの前にconst frame = useCurrentFrame();を追記します。
前回も説明しましたが、useCurrentFrame()はRemotionのフックで動画のフレーム数を取得します。
そして、変数frameに代入しています。
次はconst opacity = Math.min(1, frame / 60);を追記します。
これはopacityという変数に文字列の透明度の値を取得しています。
JavaScriptのMath.min関数は与えられた数値の中でもっとも小さい値を返します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/min

具体的にはframe / 601の間で小さい方の値をopacityとして選択します。
frame / 601より大きくなるときは1を使用します。
それ以外の場合はframe / 60の値をopacityとして使用します。
returnの中のdivタグをAbsoluteFillに変更します。
コンポーネントAbsoluteFillの解説は前回の動画ライブラリRemotionで動画を作成(PART1)をご覧ください。

https://zenn.dev/arafipro/articles/2023-10-23-remotion-beginner-yt#composition.tsx

次にAbsoluteFill内にdivタグを追記します。
divタグにstyleを当てていきます。
要素はopacityだけです。
最後にdivタグ内にHello, Worldを入力します。

Root.tsx

Root.tsx
import { Composition } from "remotion";
import { FadeIn } from "./FadeIn";

export const RemotionRoot: React.FC = () => {
  return (
    <>
      <Composition
        id="FadeIn"
        component={FadeIn}
        durationInFrames={60}
        fps={30}
        width={1280}
        height={720}
      />
    </>
  );
};

ファイルComposition.tsxは不要なので削除しておきます。
ファイルRoot.tsxを開いて、Compositionの引数をMyCompositionからFadeInに変更します。
idの引数もMyCompからFadeInに変更します。
残りの値をそのままでいいです。
コンポーネントCompositionの解説はライブラリRemotionで動画を作成(PART1)で詳しく解説しています。

https://zenn.dev/arafipro/articles/2023-10-23-remotion-beginner-yt#root.tsx

プレビューを確認

コマンドnpm startを実行してプレビューを確認します。

文字列が飛び出すアニメーションを作成

次に文字列が飛び出すアニメーションを作成します。

ScaleText.tsx

srcディレクトリにファイルScaleText.tsxを作成します。
ファイルScaleText.tsxを開いてrafcと入力すると候補が出てくるのでrafcを選択します。
すると、コードが自動補完されます。

ScaleText.tsx
import React from 'react'

export const ScaleText = () => {
  return (
    <div>ScaleText</div>
  )
}

コードを以下のように編集します。

ScaleText.tsx
import {
  AbsoluteFill,
  spring,
  useCurrentFrame,
  useVideoConfig,
} from "remotion";

export const ScaleText = () => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  const scale = spring({ fps, frame });
  return (
    <AbsoluteFill
      style={{
        flex: 1,
        backgroundColor: "white",
        justifyContent: "center",
        alignItems: "center",
        fontSize: "7rem",
      }}
    >
      <div style={{ transform: `scale(${scale})` }}>Hello, World</div>
    </AbsoluteFill>
  );
};

まずはreturnの前にconst frame = useCurrentFrame();を追記します。
するとuseCurrentFillが自動でインポートされます。
次にconst { fps } = useVideoConfig();を追記します。
useVideoConfigが自動でインポートされます。
useVideoConfigはRemotionライブラリのフックで、動画の設定情報を取得するために使用されます。
このフックを使用することで動画のフレームレート(fps)などの設定を取得できます。
上記のコードではuseVideoConfigから取得した動画のフレームレートを変数fpsに代入しています。
これにより、動画のフレームレートを使用してアニメーションを制御できます。
最後にconst scale = spring({ fps, frame });を追記します。
springが自動でインポートされます。
spring関数は指定されたフレームレートとフレーム数に基づいてスケール値を計算します。
Reactのインポートは不要なので削除します。

returnの中のdivタグの開始タグと終了タグをAbsoluteFillに変更します。
AbsoluteFillタグにstyleを当てていきます。
style内の説明は割愛します。
AbsoluteFillタグ内のScaleTextを消してdivタグを追加します。
divタグにstyleを当てていきます。
要素はtransform: `${scale(${scale})}`です。
transformプロパティにscale()関数を適用して文字列を拡大縮小しています。
最後にdivタグ内にHello, Worldを入力します。

Root.tsx

Root.tsx
  import { Composition } from "remotion";
  import { FadeIn } from "./FadeIn";
+ import { ScaleText } from "./ScaleText";
  
  export const RemotionRoot: React.FC = () => {
    return (
      <>
+       <Composition
+         id="ScaleText"
+         component={ScaleText}
+         durationInFrames={60}
+         fps={30}
+         width={1280}
+         height={720}
+       />
        <Composition
          id="FadeIn"
          component={FadeIn}
          durationInFrames={60}
          fps={30}
          width={1280}
          height={720}
        />
      </>
    );
  };

ファイルRoot.tsxを開きます。
元々あるCompositionをコピペして新たにCompositionを追加します。
引数idと引数componentの値をScaleTextに変更します。
名前 'ScaleText' が見つかりません。とエラーが表示されます。

カーソルを合わせるとダイアログが表示されます。

Command + . でクイックフィックスを使います。

選択肢の2番目にインポートの追加が表示されるので選択して追加します。
残りの値をそのままでいいです。

プレビューを確認

コマンドnpm startを実行してプレビューを確認します。

あとがき

今回は徐々にHello, Worldが表示される動画とHello, Worldが飛び出すような動画を作成しました。
プロジェクトのソースコードをGitHubで公開しています。
参考にしてください。

https://github.com/arafipro/remotion-str-anima-yt

GitHubで編集を提案

Discussion