【React】【TypeScript】Remotionで「Hello, World」が飛び出す動画を作ってみた
まえがき
ライブラリRemotionを使って「Hello, World」が徐々に表示される動画と飛び出す動画を作ります。
動画でも解説しているので、当記事と一緒にご覧ください。
Remotionとは
Remotionとはプログラミングで動画を作れるライブラリです。
基本はReactベースでTypeScriptを使います。
また、他にもたくさんのテンプレートが用意されています。
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を導入すると使えるようになります。
ぜひ、オススメします。
import React from 'react'
export const FadeIn = () => {
return (
<div>FadeIn</div>
)
}
コードを以下のように編集します。
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関数は与えられた数値の中でもっとも小さい値を返します。
具体的にはframe / 60と1の間で小さい方の値をopacityとして選択します。
frame / 60が1より大きくなるときは1を使用します。
それ以外の場合はframe / 60の値をopacityとして使用します。
returnの中のdivタグをAbsoluteFillに変更します。
コンポーネントAbsoluteFillの解説は前回の動画ライブラリRemotionで動画を作成(PART1)をご覧ください。
次にAbsoluteFill内にdivタグを追記します。
divタグにstyleを当てていきます。
要素はopacityだけです。
最後にdivタグ内にHello, Worldを入力します。
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)で詳しく解説しています。
プレビューを確認
コマンドnpm startを実行してプレビューを確認します。

文字列が飛び出すアニメーションを作成
次に文字列が飛び出すアニメーションを作成します。
ScaleText.tsx
srcディレクトリにファイルScaleText.tsxを作成します。
ファイルScaleText.tsxを開いてrafcと入力すると候補が出てくるのでrafcを選択します。
すると、コードが自動補完されます。
import React from 'react'
export const ScaleText = () => {
return (
<div>ScaleText</div>
)
}
コードを以下のように編集します。
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
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で公開しています。
参考にしてください。
Discussion