Remotion 動画クリエイター
プログラムで動画を作成します - React コンポーネントを動画にレンダリングします。このスキルは、Skill Stack のビジュアルスタイルと、解説コンテンツ作成から得た教訓をエンコードしています。
目的
Skill Stack のコンセプトを説明する短尺動画コンテンツ(10~60秒)を、独特のリスグラフ風美的感覚で作成します。動画はコードであるため、バージョン管理され、再現可能で、無限に編集可能です。
このスキルを使用するタイミング
- Skill Stack のコンセプトを説明する解説動画の作成
- アニメーションソーシャルコンテンツの作成(縦型 9:16、正方形 1:1、横型 16:9)
- 技術的ワークフローや段階的開示の視覚化
- 正確なタイミングとタイポグラフィが重要な動画
次の場合は使用しません:
- 実写映像の編集(従来の動画ツールを使用)
- 複雑な3Dグラフィックス(Remotionは2Dに特化)
- 簡単な単発グラフィック(Figma や Canva を使用)
プロジェクトセットアップ
クイックスタート
# 新しい Remotion プロジェクトを作成
npx create-video@latest my-video
# 依存関係をインストール
cd my-video && npm install
# Google Fonts を追加
npm install @remotion/google-fonts
# スタジオを起動
npm run start # http://localhost:3000 が開きます
ファイル構成
my-video/
├── src/
│ ├── Root.tsx # コンポジション定義
│ ├── Main.tsx # メイン動画コンポーネント
│ └── components/ # 再利用可能な要素
├── package.json
├── remotion.config.ts
└── out/ # レンダリングされた動画
コンポジションのセットアップ (Root.tsx)
各動画に対して常に複数のアスペクト比を作成します:
import { Composition, Folder } from "remotion";
import { MyVideo } from "./MyVideo";
export const RemotionRoot = () => (
<>
<Folder name="MyVideo">
<Composition
id="MyVideo-Vertical"
component={MyVideo}
durationInFrames={600} // 30fpsで20秒
fps={30}
width={1080}
height={1920} // 9:16
/>
<Composition
id="MyVideo-Square"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1080}
height={1080} // 1:1
/>
<Composition
id="MyVideo-Landscape"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1920}
height={1080} // 16:9
/>
</Folder>
</>
);
ビジュアルスタイル: Skill Stack リスグラフ
カラーパレット
const C = {
paper: "#FAF8F5", // 暖かみのあるオフホワイトの背景
coral: "#D4694A", // アクセント、CTA、ハイライト
teal: "#1E4D4D", // ヘッダー、選択状態
ink: "#1C1C1C", // 本文
muted: "#666666", // セカンダリテキスト
dimmed: "#AAAAAA", // ターシャリ、無効
white: "#FFFFFF", // カード、コンテナ
};
タイポグラフィ
import { loadFont as loadInter } from "@remotion/google-fonts/Inter";
import { loadFont as loadPlayfair } from "@remotion/google-fonts/PlayfairDisplay";
import { loadFont as loadJetBrains } from "@remotion/google-fonts/JetBrainsMono";
// 本文、UIラベル
const { fontFamily: inter } = loadInter("normal", {
weights: ["400", "500", "600"],
subsets: ["latin"],
});
// 見出し、引用、感情的なテキスト
const { fontFamily: playfair } = loadPlayfair("normal", {
weights: ["400", "500", "600", "700"],
subsets: ["latin"],
});
// コード、技術コンテンツ、スキル名
const { fontFamily: mono } = loadJetBrains("normal", {
weights: ["400", "500"],
subsets: ["latin"],
});
フォントサイズガイドライン
動画における最小読み取り可能サイズ:
| 要素 | 正方形 (1080) | 縦型 (1080w) | 横型 (1920w) |
|---|---|---|---|
| 見出し | 64-84px | 64-84px | 72-96px |
| スキル名 | 36-40px | 36-40px | 40-48px |
| 本文 | 28-32px | 28-32px | 32-36px |
| ラベル | 24-28px | 24-28px | 28-32px |
| 注釈 | 22-24px | 22-24px | 24-28px |
重要な教訓: 思っているよりも常に大きく。動画は細部を圧縮します。
グレインオーバーレイ
const GrainOverlay: React.FC = () => {
const frame = useCurrentFrame();
return (
<AbsoluteFill
style={{
pointerEvents: "none",
opacity: 0.04,
mixBlendMode: "multiply",
}}
>
<svg width="100%" height="100%">
<defs>
<filter id="grain">
<feTurbulence
type="fractalNoise"
baseFrequency="0.8"
numOctaves="4"
seed={Math.floor(frame / 4)} // グレインをアニメーション
/>
</filter>
</defs>
<rect width="100%" height="100%" filter="url(#grain)" />
</svg>
</AbsoluteFill>
);
};
アニメーションパターン
コアツール
import {
useCurrentFrame,
useVideoConfig,
AbsoluteFill,
interpolate,
spring,
Sequence,
} from "remotion";
フェードイン/アウト
const fadeIn = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const fadeOut = interpolate(frame, [150, 180], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// シーンの不透明度を合成
<div style={{ opacity: fadeIn * fadeOut }}>
スプリングアニメーション
const { fps } = useVideoConfig();
// スムーズな出現
const entrance = spring({
frame: frame - 20, // 20フレーム遅延
fps,
config: { damping: 100 }, // スムーズ、跳ね返りなし
});
// バウンシーな選択
const selectPulse = spring({
frame: frame - 15,
fps,
config: { damping: 12, stiffness: 100 }, // 跳ね返りあり
});
// トランスフォームに適用
<div style={{
opacity: interpolate(entrance, [0, 1], [0, 1]),
transform: `translateY(${interpolate(entrance, [0, 1], [20, 0])}px)`,
}}>
タイプライターエフェクト
const ScenePrompt: React.FC<{ frame: number }> = ({ frame }) => {
const text = "ここにプロンプトテキスト";
const charsToShow = Math.floor(frame / 2); // 30fpsで15文字/秒
const visibleText = text.slice(0, charsToShow);
const isTyping = charsToShow < text.length;
const cursorBlink = Math.floor(frame / 18) % 2 === 0;
return (
<div>
"{visibleText}
{(isTyping || cursorBlink) && (
<span style={{
backgroundColor: C.coral,
marginLeft: 4,
opacity: cursorBlink ? 1 : 0,
}}>
{"\u00A0"}
</span>
)}
{!isTyping && '"'}
</div>
);
};
段階的リストアニメーション
const ITEMS = ["項目-1", "項目-2", "項目-3"];
{ITEMS.map((item, i) => {
const delay = i * 25; // 各項目間25フレーム
const s = spring({
frame: Math.max(0, frame - delay - 20),
fps,
config: { damping: 100 },
});
return (
<div
key={item}
style={{
opacity: interpolate(s, [0, 1], [0, 1]),
transform: `translateY(${interpolate(s, [0, 1], [20, 0])}px)`,
}}
>
{item}
</div>
);
})}
シーンタイミングガイドライン
時間計算
- 30 fps = 1秒あたり30フレーム
- 10秒 = 300フレーム
- 20秒 = 600フレーム
ペーシングの教訓
速すぎることが最大の間違いです。 視聴者には次の時間が必要です:
- シーンの変化に気づく
- テキストを読む
- 意味を理解する
- 次の変化に備える
最小シーン時間:
| シーンタイプ | 最小 | 快適 |
|---|---|---|
| タイプライターテキスト | 3-4秒 | 5-6秒 |
| リスト表示 | 4-5秒 | 6-8秒 |
| 選択/ハイライト | 3-4秒 | 5秒 |
| 技術図 | 4-5秒 | 6-8秒 |
| 決めゼリフ/CTA | 2-3秒 | 3-4秒 |
シーンオーバーラップパターン
シーンはハードカットではなく、クロスフェードする必要があります:
// 20秒動画(600フレーム)のシーンタイミング
{frame < 200 && <ScenePrompt frame={frame} />}
{frame >= 160 && frame < 340 && <SceneScan frame={frame - 160} />}
{frame >= 300 && frame < 460 && <SceneSelect frame={frame - 300} />}
{frame >= 420 && frame < 560 && <SceneLoad frame={frame - 420} />}
{frame >= 520 && <ScenePunchline frame={frame - 520} />}
40フレームのオーバーラップ(1.3秒)により、fadeIn/fadeOut補間と組み合わせることでスムーズなクロスフェードが生まれます。
ワークフロー
フェーズ1: ストーリーボード
コーディング前に以下を定義します:
- コアメッセージ - 視聴者が学ぶべきことは何か?
- シーン分割 - 4~6シーン、各シーンに1つのアイデア
- 合計時間 - ソーシャルでは10~20秒、解説では30~60秒
- テキスト内容 - 各シーンの正確な文言
フェーズ2: スキャフォールド
- 適切な時間でコンポジションを作成
- プレースホルダーコンテンツでシーンコンポーネントを構築
- 基本的なタイミングを設定(シーン範囲)
- すべてのシーンが表示されることをテスト
フェーズ3: スタイル
- カラーパレットとフォントを適用
- グレインオーバーレイを追加
- フォントサイズが読めることを確認
- スマートフォン(縦型)とデスクトップ(横型)でテスト
フェーズ4: アニメーション
- 各シーンにfadeIn/fadeOutを追加
- 出現にスプリングアニメーションを追加
- タイミングを微調整 - ほとんどの場合、遅くする必要がある
- フル再生を複数回テスト
フェーズ5: レンダリング
# 特定のコンポジションをレンダリング
npx remotion render MyVideo-Square out/square.mp4
# すべてのフォーマットをレンダリング
npx remotion render MyVideo-Vertical out/vertical.mp4
npx remotion render MyVideo-Square out/square.mp4
npx remotion render MyVideo-Landscape out/landscape.mp4
よくある間違い
❌ 中央揃えの問題
問題: コンテンツが左上隅に表示される。
修正: position: absolute ではなく、AbsoluteFillをフレックスボックスで使用します。
// ✅ 正しい
<AbsoluteFill style={{
justifyContent: "center",
alignItems: "center",
}}>
// ❌ 間違い
<div style={{ position: "absolute", left: "50%", top: "50%" }}>
❌ 小さすぎるフォント
問題: スタジオでは読めるが、スマートフォンでは読めない。
修正: 本文は最低28px、見出しは64px。
❌ 速すぎる
問題: テキストが消える前に読めない。
修正: 初期時間の見積もりを2倍にします。各シーンには最低4~8秒必要です。
❌ ハードカット
問題: シーン間の遷移がぎこちない。
修正: シーンを30~50フレーム重ね、fadeIn/fadeOutを使用します。
❌ アスペクト比のサポート欠如
問題: 動画がプラットフォームによって見た目が異なる。
修正: 最初から3つのコンポジション(縦型、正方形、横型)すべてを作成します。
キャプション統合
Remotionは優れたキャプションサポートを備えています。コスト別に3つのオプションがあります:
オプション1: ネイティブ Whisper(推奨 - 無料)
npm install @remotion/captions @remotion/install-whisper-cpp
npx @remotion/install-whisper-cpp --model large-v3-turbo
import { transcribe } from "@remotion/captions";
const result = await transcribe({
inputPath: "/path/to/audio.mp3",
model: "large-v3-turbo",
language: "en",
});
// result.captions = [{ text: "Hello", startTime: 0, endTime: 0.5 }, ...]
オプション2: ZapCap API($0.10/分)
ローカルモデルをセットアップせずにバッチ処理を行う場合。
オプション3: Submagic API($0.69/分)
プリスタイルの「バイラル」キャプションテンプレートですが、高価です。
完全なワークフロー詳細: references/caption-workflow.md を参照
コミュニティリソース
Discord
Remotion Discord - 6,000人以上のメンバー。 #help と #showcase チャンネルが活発。作成者(Jonny Burger)が直接応答します。
学習すべき主要テンプレート
| テンプレート | ユースケース | リンク |
|---|---|---|
| TikTok | 縦型ソーシャル動画 | remotion-dev/template-tiktok |
| Audiogram | ポッドキャストクリップ | remotion-dev/template-audiogram |
| GitHub Unwrapped | データ駆動型動画 | remotion-dev/github-unwrapped |
| claude-remotion-kickstart | AI支援ワークフロー | Claude + Remotion 用コミュニティスターター |
必須パッケージ
# キャプション
npm install @remotion/captions @remotion/install-whisper-cpp
# グラフィックス
npm install @remotion/skia # 2Dベクターグラフィックス
npm install @remotion/three # Three.jsによる3D
npm install @remotion/lottie # Lottieアニメーション
# レンダリング
npm install @remotion/lambda # AWSサーバーレスレンダリング
npm install @remotion/player # Webアプリへの埋め込み
完全なリソースリスト: references/community-resources.md を参照
バンドルリソース
references/what-is-a-skill.tsx- 「What Is A Skill」動画の完全なサンプルコンポーネントreferences/caption-workflow.md- 完全なキャプション統合ガイド(Whisper、ZapCap、Submagic)references/community-resources.md- テンプレート、パッケージ、学習パス
関連スキル
- video-caption-creation - レンダリングされた動画用のキャプションとハッシュタグ
- youtube-scriptwriting - 長尺解説動画のスクリプト用
- social-content-creation - 動画のコンセプトを静的投稿に転用
バージョン履歴
-
v1.1 (2026-01-22): キャプションとコミュニティ統合
@remotion/captionsによるネイティブ Whisper キャプションワークフローを追加- キャプションスタイルプリセット(ミニマル、ボールド、カラオケ、ブランド)を追加
- コミュニティリソース(Discord、テンプレート、パッケージ)を追加
- 新しいリファレンスファイル:
caption-workflow.md、community-resources.md - コスト比較: Whisper(無料) vs ZapCap($0.10/分) vs Submagic($0.69/分)
-
v1.0 (2026-01-21): 初期スキル作成
- リスグラフのビジュアルスタイル
- アニメーションパターン(スプリング、interpolate、タイプライター)
- タイミングガイドライン(「速すぎる」反復から学んだこと)
- シーンオーバーラップパターン
動画はコードです。バージョン管理し、繰り返し改良し、再利用可能なコンポーネントのライブラリを構築しましょう。