@remotion/player でReactアプリにインタラクティブ動画を埋め込む
@remotion/player でReactアプリにインタラクティブ動画を埋め込む
Remotionで制作したコンポジションを動画ファイルとして書き出す前に、Reactアプリの中でそのままインタラクティブに再生できることを知っていますか。シークバーを操作したり、プログラムから再生・停止を制御したり、ユーザーが入力したデータをリアルタイムで反映させたりできます。これを実現するのが @remotion/player パッケージです。
サービス紹介ページに動画テンプレートをライブ表示したい、SaaSのダッシュボードでユーザーが動画をダウンロードする前にプレビューを確認できるようにしたい、社内ツールでデータ駆動アニメーションをスクラブ操作で確認したい——こうしたニーズに <Player> コンポーネントはぴったりです。
この記事では、インストールから全プロップの解説、playerRefによる外部制御、商用利用に必要な acknowledgeRemotionLicense、Next.jsとReact標準環境での埋め込みパターンまでを体系的に説明します。
なぜ <video> タグではなく @remotion/player を使うのか
レンダリング済みの .mp4 ファイルを <video> タグで埋め込む場合、そのファイルは静的です。ユーザー入力やライブデータに基づく動的な動画の場合、データが変わるたびにファイルを再レンダリングする必要があり、時間とサーバーリソースが掛かります。
@remotion/player はコンポジションをブラウザ内でReactとして描画します。動画はリアルタイムで生きています。プロップを変えれば、アニメーションが即座に更新されます。これが特に効果的な用途は次のとおりです。
- インタラクティブプレビュー — サーバーレンダリングの前にカスタマイズ済み動画をユーザーに確認させる
- テンプレートショーケース — ランディングページに動画ファイルなしでアニメーションデモを埋め込む
- ダッシュボードウィジェット — ライブデータと連動するデータビジュアライゼーションアニメーションを表示する
- 学習ツール — アニメーション解説をスクラブ操作で確認させる
インストール
@remotion/player はコアの remotion ライブラリとは別パッケージです。既存のRemotionプロジェクトに追加インストールします。
npm install @remotion/player
@remotion/core を別途インストールする必要はありません。コアフックやユーティリティは remotion パッケージに含まれています。
基本的な使い方
<Player> コンポーネントは、既存のRemotionコンポジションコンポーネントをプロップとして受け取り、操作可能なプレイヤーとして描画します。
import { Player } from '@remotion/player';
import { MyComposition } from './MyComposition';
export const VideoPreview: React.FC = () => {
return (
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '100%' }}
/>
);
};
このコードだけで再生・一時停止ボタンとシークバーを持つインタラクティブプレイヤーが表示されます。追加の設定は不要です。
必須プロップ
component
型: React.FC<Props>
描画するRemotionコンポジションコンポーネントです。Root.tsx の <Composition> に渡すコンポーネントと同じものを指定します。コンポーネントは inputProps をReactプロップとして受け取ります。
durationInFrames
型: number
アニメーションの総フレーム数です。描画するコンポジションの長さと一致させてください。
<Player durationInFrames={90} ... />
// 30fps で 90フレーム = 3秒
fps
型: number
フレームレートです。コンポジション内部で useVideoConfig() が返す fps と必ず一致させてください。不一致があるとアニメーション速度がずれます。
compositionWidth と compositionHeight
型: number
コンポジションキャンバスの内部的な幅と高さ(ピクセル)です。アスペクト比とコンポジション内の座標空間を定義します。ブラウザ上の表示サイズとは独立しており、表示サイズは style プロップで制御します。
<Player
compositionWidth={1920}
compositionHeight={1080}
style={{ width: '854px' }} // 視覚的には 854×480 で表示
...
/>
主なオプションプロップ
inputProps
コンポジションコンポーネントに直接渡すプロップです。ユーザー名、カスタムカラー、ライブメトリクスなど動的なデータをアニメーションに注入するために使います。
<Player
component={SalesCard}
inputProps={{
revenue: 128500,
period: 'Q2 2026',
}}
durationInFrames={120}
fps={30}
compositionWidth={1280}
compositionHeight={720}
/>
inputProps はReactのstateに接続でき、stateが変わるとアニメーションが即座に更新されます。
controls
型: boolean(デフォルト: false)
true にすると、プレイヤーの下に再生・一時停止ボタンとシークバーが表示されます。
autoPlay
型: boolean(デフォルト: false)
マウント時に自動再生を開始します。loop と組み合わせると継続的に再生します。
loop
型: boolean(デフォルト: false)
再生が終わると最初から繰り返します。
style
型: React.CSSProperties
プレイヤーの外側コンテナに適用するCSSスタイルです。compositionWidth/compositionHeight の内部座標に影響せず、表示サイズのみを制御します。
playerRef でプログラムから再生を制御する
ref プロップを使うと、コンポーネント外部からプレイヤーの再生APIに命令的にアクセスできます。
import { Player, PlayerRef } from '@remotion/player';
import { useRef } from 'react';
import { MyComposition } from './MyComposition';
export const ControlledPlayer: React.FC = () => {
const playerRef = useRef<PlayerRef>(null);
return (
<>
<Player
ref={playerRef}
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
/>
<div style={{ marginTop: 12, display: 'flex', gap: 8 }}>
<button onClick={() => playerRef.current?.play()}>再生</button>
<button onClick={() => playerRef.current?.pause()}>一時停止</button>
<button onClick={() => playerRef.current?.seekTo(75)}>中間にジャンプ</button>
</div>
</>
);
};
PlayerRef で使えるメソッド
| メソッド | 説明 |
|---|---|
play() | 再生を開始する |
pause() | 一時停止する |
toggle() | 再生・一時停止を切り替える |
seekTo(frame) | 指定フレームにシークする |
getCurrentFrame() | 現在のフレーム番号を返す |
isPlaying() | 再生中かどうかを返す |
mute() | ミュートにする |
unmute() | ミュートを解除する |
setVolume(volume) | 音量を設定する(0〜1) |
getVolume() | 現在の音量を返す |
isMuted() | ミュート中かどうかを返す |
プレイヤーのイベントを購読する
再生状態の変化に反応するためのイベントハンドラプロップも用意されています。
<Player
ref={playerRef}
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
onPlay={() => console.log('再生開始')}
onPause={() => console.log('一時停止')}
onEnded={() => console.log('再生終了')}
onFrameUpdate={(e) => console.log('現在フレーム:', e.detail.frame)}
/>
onFrameUpdate はフレームごとに発火します。カスタムプログレスバーを現在の再生位置と同期させるときに便利です。
acknowledgeRemotionLicense プロップ
商用アプリケーションで @remotion/player を使用する場合、Remotionはライセンスへの同意を求めます。このプロップを渡さないと、非開発環境でウォーターマークや警告が表示されます。
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
acknowledgeRemotionLicense
/>
acknowledgeRemotionLicense(値なし)は acknowledgeRemotionLicense={true} と同等です。Remotionのライセンスモデルでは、個人開発者やオープンソースプロジェクトは無償で使用できますが、商用利用には有償ライセンスが必要です。このプロップを渡すことで、remotion.dev/license の利用規約を確認し同意したことを示します。
Next.jsへの埋め込み
@remotion/player はクライアントサイドコンポーネントです。Next.jsのどちらのルーターを使っていても、ブラウザ環境でのみ描画されるよう設定する必要があります。
App Router(Next.js 13以降)
<Player> をインポートするファイルに "use client" ディレクティブを追加します。
'use client';
import { Player } from '@remotion/player';
import { MyComposition } from '@/remotion/MyComposition';
export const VideoEmbed: React.FC = () => {
return (
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
controls
acknowledgeRemotionLicense
style={{ width: '100%', borderRadius: '12px' }}
/>
);
};
このクライアントコンポーネントは、サーバーコンポーネントのページから通常通りインポートできます。
Pages Router
next/dynamic と ssr: false を使い、サーバーサイドレンダリングを防ぎます。
import dynamic from 'next/dynamic';
const VideoEmbed = dynamic(
() => import('../components/VideoEmbed'),
{ ssr: false }
);
export default function Page() {
return <VideoEmbed />;
}
レスポンシブ対応
プレイヤーの視覚的なサイズは CSS で制御します。compositionWidth/compositionHeight は内部キャンバスの定義であり、style プロップが DOM 上の表示サイズを決めます。
コンテナいっぱいに広がるレスポンシブプレイヤー:
<Player
component={MyComposition}
durationInFrames={150}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
style={{
width: '100%',
aspectRatio: '16 / 9',
}}
controls
acknowledgeRemotionLicense
/>
プレイヤーはアスペクト比を維持しながらコンポジションキャンバスをコンテナにフィットさせるため、画面サイズに関係なく常にレイアウトが正しく見えます。
inputProps でライブデータを接続する
ユーザーがフォームに入力したら即座に動画プレビューに反映させる、というパターンはSaaSツールで非常によく使われます。
'use client';
import { Player } from '@remotion/player';
import { useState } from 'react';
import { PersonalizedCard } from '@/remotion/PersonalizedCard';
export const PersonalizationPreview: React.FC = () => {
const [name, setName] = useState('あなたの名前');
const [color, setColor] = useState('#3b82f6');
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="名前を入力"
style={{ display: 'block', marginBottom: 8, padding: '6px 10px', width: '100%' }}
/>
<input
type="color"
value={color}
onChange={(e) => setColor(e.target.value)}
style={{ marginBottom: 12 }}
/>
<Player
component={PersonalizedCard}
durationInFrames={90}
fps={30}
compositionWidth={1280}
compositionHeight={720}
inputProps={{ name, accentColor: color }}
controls
autoPlay
loop
acknowledgeRemotionLicense
style={{ width: '100%' }}
/>
</div>
);
};
名前フィールドへの入力ごとにアニメーションが即座に更新されます。サーバーへのレンダリングジョブ送信も、待ち時間も不要です。
よくある落とし穴
App Routerで "use client" を忘れる
<Player> をサーバーコンポーネントに直接インポートすると、Next.jsがハイドレーションエラーを投げます。プレイヤーを含むファイルには必ず "use client" を追加してください。
fps と durationInFrames の不一致
<Player> に渡す fps がコンポジション内部の useVideoConfig() の値と異なると、Remotion Studioでは正常に見えていてもプレイヤー上でアニメーション速度がずれます。fps は一か所で定義し、<Composition> と <Player> の両方に渡す習慣をつけましょう。
本番環境での acknowledgeRemotionLicense の未設定
本番商用アプリでこのプロップを省略するとウォーターマークが表示されます。開発の早い段階から追加しておき、本番リリース時に慌てないようにしましょう。
よくある質問(FAQ)
Q: @remotion/player を使うためにRemotionのStudioサーバーが必要ですか?
不要です。@remotion/player は独立したReactコンポーネントです。Remotionの開発サーバーやStudioに依存しません。@remotion/player パッケージをインストールしてインポートするだけで動作します。
Q: 同じページに複数のプレイヤーを表示できますか?
できます。<Player> インスタンスはそれぞれ独立しています。各インスタンスが独自のアニメーションループを実行するため、多数のプレイヤーを同時に再生すると低スペックデバイスでパフォーマンスに影響が出る場合があります。
Q: ViteなどNext.js以外のバンドラーでも使えますか?
使えます。@remotion/player は標準的なReactパッケージです。Vite、Webpack、Parcelなど、Reactをサポートする任意のバンドラーで動作します。"use client" ディレクティブはNext.js App Routerに特有の設定です。
Q: モバイルで自動再生が機能しない場合はどうすればいいですか?
ブラウザの自動再生ポリシーにより、音声付きメディアのモバイル自動再生はブロックされます。コンポジションに音声がある場合は autoPlay={false} にして controls を表示し、ユーザーが手動で再生を開始できるようにしてください。無音のコンポジションはモバイルでも自動再生が機能する傾向があります。
Q: durationInFrames にコンポジションの実際の長さより大きい値を渡すとどうなりますか?
プレイヤーはコンポジションの自然な終了を超えて再生しようとし、最後のフレームがフリーズした状態が続きます。durationInFrames は常にコンポジションの実際の長さと一致させてください。
Q: <Composition> ラッパーなしでも @remotion/player は使えますか?
使えます。<Player> の component プロップは生のReactコンポーネントを直接受け取ります。Root.tsx や <Composition> の登録は不要で、プレイヤーが必要なコンテキストを内部でセットアップします。
Q: ライセンスについて、個人の趣味プロジェクトでも acknowledgeRemotionLicense が必要ですか?
商用目的でない個人プロジェクトや、Remotionのライセンス条件を満たすオープンソースプロジェクトでは不要です。ただし、プロップを追加しておく習慣は推奨されます。公式のライセンスページで条件の詳細を確認してください。
まとめ
@remotion/player はプログラマブル動画制作とインタラクティブなWebアプリケーションを橋渡しするコンポーネントです。要点をまとめます。
@remotion/playerはベースのremotionパッケージとは別にインストールする- 必須プロップは
component、durationInFrames、fps、compositionWidth、compositionHeightの5つ inputPropsで動的データを注入する——アニメーションはリアクティブに更新されるplayerRefでコンポーネント外部から命令的に再生を制御する- 商用アプリでは必ず
acknowledgeRemotionLicenseを追加する - Next.js App Routerでは、プレイヤーを含むファイルに
"use client"を付ける
本番品質のRemotionテンプレートは RenderComp で公開中 →
RenderCompライブラリのすべてのテンプレートは、適切に構造化されたRemotionコンポジションとして提供されており、<Player> 埋め込みにそのまま利用できます。サイト上でライブプレビューを確認し、プロップをカスタマイズして、Reactアプリに直接統合してください。