Communitygithub.com

carissadarmafissaleha/remotion

Reactを使ったプログラムによる動画制作のための包括的なマスターガイド。Remotion 4.x、Spring物理演算、GSAP、Tailwind/CSS、CLIハードウェアアクセラレーションレンダリングを使用して、プロフェッショナルなモーショングラフィックス動画(16:9 解説動画、9:16 縦型ショート/TikTok/Reels)を設計、構築、アニメーション化、ナレーション/VOの同期、レンダリングします。ユーザーがRemotionベースの動画作成、MP4レンダリング、キネティックタイポグラフィ、シーン遷移(Series/TransitionSeries)、ボイスオーバー同期、またはレンダリングパフォーマンスの最適化を要求するたびにこのスキルを使用してください。

remotion とは?

このスキルは、Reactベースの動画フレームワーク「Remotion」を使用して、プログラムによる動画制作をマスターするための包括的なガイドです。開発者は、Reactコンポーネントを記述するように動画の各フレームを定義できるため、従来の動画編集ツールでは実現が難しい、精密で再現性の高いモーショングラフィックスやデータ駆動型動画を生成できます。このガイドでは、Root.tsxでのComposition設定、SequenceやSeriesを使ったタイムライン管理、spring()とinterpolate()による自然なアニメーション、キネティックタイポグラフィとボイスオーバーの同期、外部アセットの非同期読み込み(delayRender)、そしてCLIを使ったハードウェアアクセラレーションレンダリングのテクニックを網羅しています。対応プラットフォームはClaude Code, Cursor, Codexなどで、16:9の解説動画から9:16のTikTok/Reels用縦型動画まで、あらゆるフォーマットの動画制作を効率化します。

対応~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/carissadarmafissaleha/office-nara/tree/main/skills/remotion

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Remotion マスターガイド — React によるプログラム動画制作

Remotion を使用すると、純粋な React コードで映画のような動画を作成できます。各フレームは決定論的な状態 (frame) => UI として扱われ、途切れやフレームドロップのない完璧な 60 FPS の映像を生成します。


1. コンポジションアーキテクチャとルート設定

A. ルートエントリポイント (Root.tsx)

import { Composition } from 'remotion';
import { MainExplainer } from './compositions/MainExplainer';
import { VerticalShort } from './compositions/VerticalShort';

export const RemotionRoot: React.FC = () => {
  return (
    <>
      {/* 16:9 ランドスケープ シネマティック解説動画 */}
      <Composition
        id="MainExplainer-1080p"
        component={MainExplainer}
        durationInFrames={30 * 32} // 32秒 @ 30 FPS = 960フレーム
        fps={30}
        width={1920}
        height={1080}
        defaultProps={{
          title: '世界の氷河頂上融解の謎',
          author: 'NARA Studio',
          themeColor: '#f97316',
        }}
      />

      {/* 9:16 縦型 TikTok / Reels / Shorts */}
      <Composition
        id="VerticalShort-60fps"
        component={VerticalShort}
        durationInFrames={60 * 15} // 15秒 @ 60 FPS = 900フレーム
        fps={60}
        width={1080}
        height={1920}
      />
    </>
  );
};

B. フレームレートと尺のルール

  • 16:9 YouTube / 解説動画: 30 fps 推奨(レンダリング速度と動きの滑らかさのバランス)または 60 fps(超高精細キネティックタイポグラフィ)。
  • フレーム数計算: 常に durationInFrames = Math.round(seconds * fps) で計算してください。
  • ジッターゼロ: setInterval や setTimeout は使用せず、常に useCurrentFrame() と useVideoConfig() を使用してください。

2. レイアウトとタイムラインプリミティブ

AbsoluteFill

すべてのシーンレイヤーの基本です。自動的に position: absolute; inset: 0; width: 100%; height: 100%; となります。

import { AbsoluteFill } from 'remotion';

export const SceneBackground: React.FC = () => {
  return (
    <AbsoluteFill style={{ backgroundColor: '#090812', overflow: 'hidden' }}>
      {/* ビジュアルコンテンツ */}
    </AbsoluteFill>
  );
};

Sequence vs Series

  • Sequence: 要素を絶対時間に配置します(from と durationInFrames)。BGM、透かし、HUDオーバーレイ、重なり合う要素に最適です。
  • Series: シーンを自動的に順次配置するため、手動でフレームオフセットを計算する必要がありません。
import { Series, Sequence, Audio, staticFile } from 'remotion';

export const VideoStory: React.FC = () => {
  return (
    <AbsoluteFill>
      {/* 動画全体を通してのBGM */}
      <Audio src={staticFile('audio/ambient_score.mp3')} volume={0.35} />

      {/* 自動シーケンス */}
      <Series>
        <Series.Sequence durationInFrames={120}>
          <HookScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={180}>
          <ProblemScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={240}>
          <SolutionScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={150}>
          <CallToActionScene />
        </Series.Sequence>
      </Series>
    </AbsoluteFill>
  );
};

3. アニメーション物理演算: spring() と interpolate()

A. 自然なバネ運動 (spring())

spring() を使用して、現実的な物理運動を生成します(「PowerPoint感」を排除)。

import { spring, useCurrentFrame, useVideoConfig } from 'remotion';

const frame = useCurrentFrame();
const { fps } = useVideoConfig();

// 1. スナッピーポップ(テキスト/バッジが弾けるように出現)
const popScale = spring({
  frame,
  fps,
  config: { damping: 10, mass: 0.4, stiffness: 180 },
});

// 2. スムーズドリフト(カメラが滑らかに移動)
const smoothSlide = spring({
  frame,
  fps,
  config: { damping: 20, mass: 1.2, stiffness: 60 },
});

// 3. バウンシードロップ(アイコン/パーティクルがバウンドしながら落下)
const bounce = spring({
  frame: frame - 10, // 10フレーム遅延
  fps,
  config: { damping: 8, mass: 0.6, stiffness: 140 },
});

B. スムーズな値のマッピング (interpolate())

import { interpolate, Easing } from 'remotion';

// ベジェイージングによるアルファと回転のトランジション
const opacity = interpolate(frame, [0, 20], [0, 1], {
  extrapolateRight: 'clamp',
});

const rotateY = interpolate(frame, [0, 60], [-45, 0], {
  easing: Easing.bezier(0.16, 1, 0.3, 1),
  extrapolateRight: 'clamp',
});

4. キネティックタイポグラフィとボイスオーバー同期

A. 単語ごとの出現アニメーション

import React from 'react';
import { useCurrentFrame, useVideoConfig, spring, interpolate } from 'remotion';

interface KineticTextProps {
  sentence: string;
  startFrame?: number;
  wordDelay?: number;
}

export const KineticText: React.FC<KineticTextProps> = ({
  sentence,
  startFrame = 0,
  wordDelay = 4, // 単語間のフレーム間隔
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const words = sentence.split(' ');

  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', justifyContent: 'center' }}>
      {words.map((word, idx) => {
        const wordStart = startFrame + idx * wordDelay;
        const progress = spring({
          frame: frame - wordStart,
          fps,
          config: { damping: 12, mass: 0.4, stiffness: 160 },
        });

        const translateY = interpolate(progress, [0, 1], [40, 0]);
        const opacity = interpolate(progress, [0, 1], [0, 1]);

        return (
          <span
            key={idx}
            style={{
              display: 'inline-block',
              transform: `translateY(${translateY}px)`,
              opacity,
              fontSize: '48px',
              fontWeight: 800,
              color: idx === 0 ? '#f97316' : '#ffffff',
              letterSpacing: '-1px',
              fontFamily: "'JetBrains Mono', sans-serif",
            }}
          >
            {word}
          </span>
        );
      })}
    </div>
  );
};

B. ボイスオーバーと効果音の同期

  • オーディオファイルは public/audio/ フォルダに配置します。
  • staticFile('audio/file.mp3') を使用して参照します。
  • volume プロパティを使用して、フェードイン/フェードアウトトランジションを作成します。
<Audio
  src={staticFile('audio/naskah_vo.mp3')}
  volume={(f) =>
    interpolate(f, [0, 15, 880, 900], [0, 1, 1, 0], {
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp',
    })
  }
/>

5. 非同期アセットとプリロード (delayRender)

動画がカスタムフォント、外部画像、APIデータを読み込む場合、空のフレームをレンダリングしないように Remotion に通知する必要があります。

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

export const DynamicScene: React.FC = () => {
  const [handle] = useState(() => delayRender('フォントとアセットの読み込み'));

  useEffect(() => {
    document.fonts.ready.then(() => {
      continueRender(handle);
    });
  }, [handle]);

  return <AbsoluteFill>...</AbsoluteFill>;
};

6. NARA モーショングラフィックステンプレートとレシピ

8ステージのシネマティック公式(アンチPPT)

  1. シーン 1: コールドフック (00-03秒) → 謎めいたビジュアル + 大きなキネティックタイポグラフィ。
  2. シーン 2: 問題提起 (04-07秒) → 氷河崩壊のビジュアル / 燃えるような赤いグラフ。
  3. シーン 3: データ深掘り (08-12秒) → 統計数字がカウントアップ (Math.floor)。
  4. シーン 4: ダイナミックスケールシフト (13-16秒) → マクロからミクロへのスケール変化。
  5. シーン 5: 人間への影響 (17-20秒) → キャンバス上のキャラクターの反応。
  6. シーン 6: 解決策の提示 (21-25秒) → ビジュアルが明るい緑/オレンジに切り替わる。
  7. シーン 7: アクションステップ (26-29秒) → 3つのポイントが浮かぶ3Dカード。
  8. シーン 8: クライマックスとCTA (30-32秒) → スタジオロゴのパルス + ウィッシュサウンド効果。

7. CLIレンダリング実行とハードウェアアクセラレーション

A. 単一動画のレンダリング (1080p 60fps)

npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --gl=angle

B. 高並列処理による高速レンダリング

npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --concurrency=8 --gl=angle --jpeg-quality=90

C. 重要なレンダリングフラグ

  • --gl=angle: Windows で DirectX GPU アクセラレーションを使用(ソフトウェアラスタライザよりはるかに高速)。
  • --gl=swiftshader: コンテナ/CI 環境で GPU が利用できない場合のソフトウェアフォールバック。
  • --concurrency=N: 並列レンダリングに使用する CPU コア数。
  • --muted: ビジュアルのみ必要な場合、オーディオストリームなしでレンダリング。
  • --props='{"title":"新"}': コマンドラインから JSON で動的パラメータを渡す。

8. トラブルシューティングガイド

  1. 黒い画面 / 画像が表示されない: アセットが public/ フォルダにあり、staticFile('ファイル名') で呼び出されていることを確認してください。
  2. レンダリング中に動画が停止する: useMemo 内の無限ループや、delayRender を閉じていない React コンポーネントがないか確認してください。
  3. オーディオの同期がずれる: コンポジションの fps 値が、ボイスオーバーの秒数計算(seconds = frames / fps)と完全に一致していることを確認してください。

関連スキル