/remotion-best-practices
このスキルは、Remotion コンポジション — アニメーションデモ動画、プロダクトウォークスルー、ハッカソン提出物、ナレーション付きプレゼンテーションなど、npx remotion render で MP4 にレンダリングされるもの — を作成する際はいつでも使用してください。
このスキルは、2 つの知識レイヤーを束ねています。
- Remotion の基礎 — Remotion チームが
github.com/remotion-dev/skillsで管理する上流のルールファイル(コンポジション、アニメーション、フォント、オーディオ、トランジション、FFmpeg、キャプションなど)。 - デモ動画作成クラフトレール — vskill / Skill Studio ハッカソンデモの長い反復サイクルから得られた教訓。これらのルールを破ると、「プロダクトウォークスルー」ではなく「スライドショー」になってしまいます。
作成を開始する前に、両方のレイヤーを読んでください。
範囲と適用性
以下のレイヤー 2 クラフトレールは、vskill / Skill Studio ハッカソンデモ(Anthropic / Claude Code "Built with Opus" ハッカソン、2026 年 4 月)という特定のプロジェクトから導出されました。 これらは、そのプロダクトのルックアンドフィール — パンくずヘッダー、サイドバーツリー、ダークな verified-skill.com ページ(モノフォント使用)、ターミナルシーン、「Inter は AI スラップ、特徴的なセリフが優秀さ」という論旨 — を反映しています。
これらのルールを無関係なデモにそのまま適用しないでください。 コンシューマーモバイル、金融ダッシュボード、ゲーム、B2B SaaS ピッチには、それぞれ独自のビジュアルランゲージ、ペーシング、視聴者の期待があります。「保存してから公開」フロー、
verified-skill.com/queueページ、または PROJECT/PERSONAL/PLUGINS カウントのある Studio サイドバーは、コンテンツ であり、クラフト ではありません。このレイヤーを、基本となるテクニックのリファレンスとして使用してください: カメラズームパターン、カーソルターゲティングの規律、コンテンツにフィットしたハイライト四角形、インプレース状態遷移、音声/script.ts の結合、レンダリング + オーディオブーストパイプライン — これらは一般化可能です。正確な定数(1.72 倍ズーム、x=1488 ボタン中心、v1.0.0 → v1.0.1 バージョンピル、「Tier-1 パターン · Tier-2 LLM · ソケット」クレジット)は Skill Studio 固有のものです — 翻訳し、コピーしないでください。
レイヤー 1 — Remotion の基礎
上流の remotion-best-practices スキル(https://github.com/remotion-dev/skills/blob/HEAD/skills/remotion/SKILL.md)を反映しています。
新しいプロジェクトのセットアップ
空のフォルダーまたは既存の Remotion プロジェクトがないワークスペースでは、以下を使用してスキャフォールディングします。
npx create-video@latest --yes --blank --no-tailwind my-video
プレビューの開始
Remotion Studio を起動して動画をプレビューします。Studio の HMR はファイル変更時にライブリロードされます — 別の preview_start メカニズムは必要なく、Bash run_in_background が編集間で起動状態を維持する適切な方法です。
npx remotion studio --port=3030
レンダリング
# エントリーポイントは registerRoot() を呼び出すファイルである必要があります(通常は src/remotion/index.ts)
npx remotion render src/remotion/index.ts <CompositionId> out/video.mp4 --concurrency=8 --log=info
よくある落とし穴:
Root.tsxをエントリとして渡すとエラー:"this file does not contain registerRoot"。index.tsを使用してください。TransitionSeriesは直接の子要素に対してプロパティイントロスペクションを行います。子要素を<React.Fragment>でラップしないでください。<TransitionSeries.Sequence>と<TransitionSeries.Transition>要素のフラットな配列を返すflatMapを使用してください。interpolate(frame, [a, b], …)はa < bが厳密に必要です。定数からbを導出する場合は、シーンバジェット設計時にチェックしてください — Remotion は最初に評価されたフレームで "inputRange must be strictly monotonically increasing" をスローし、コンポジション全体の読み込みに失敗します。
1 フレームレンダリングチェック
npx remotion still <composition-id> --scale=0.25 --frame=30
上流ルールファイルでカバーされるトピック
(上流スキルリポジトリからオンデマンドでロード — github.com/remotion-dev/skills/tree/HEAD/skills/remotion/rules/)
compositions.md— コンポジション、スチル、フォルダー、デフォルトプロパティ、動的メタデータの定義animations.md—interpolate、spring、イージング、フレームベースの計算transitions.md—@remotion/transitions(フェード、スライド、ワイプ)、TransitionSeries内での連鎖方法assets.md—staticFile()、Img、Audio、Video、フォント読み込みfonts.md—@remotion/google-fontsとローカルフォント登録audio.md— インポート、トリミング、音量、速度、ピッチcaptions.md、subtitles.md— キャプショントラックと同期ffmpeg.md— FFmpeg サブプロセスによるトリミング、結合、オーディオ操作silence-detection.md、extract-frames.md、get-audio-duration.md、get-video-duration.md— Mediabunny ユーティリティcharts.md、gifs.md、light-leaks.md、3d.md— 特殊なレンダリングレシピ
レイヤー 2 — デモ動画作成クラフトレール
これらのルールは、長い反復サイクルを経て獲得されたものです。これらをオプションの仕上げではなく、デフォルトとして扱ってください — これらのほとんどは、「これ、変だよ、直して」というフィードバックから生まれ、解決に複数回のラウンドを要しました。
A. 参照の忠実度
A1. 常に実際の参照を取得する
ユーザーが「この YouTube 動画の 2:43 のようにして」と言ったら、フレームを抽出して研究してください。記憶から近似しないでください。
SOURCE="/Users/antonabyzov/Movies/.../Source.mov"
DEST_DIR=".specweave/.../assets/keyframes"
for t in 102 105 108 110 112; do
ffmpeg -y -ss "$t" -i "$SOURCE" -frames:v 1 -q:v 2 "$DEST_DIR/at-${t}s.jpg" -loglevel error
done
次に、各 JPG を Read し、画面上にあるもの — タイポグラフィ、正確なボタンラベル、バッジの色、サイドバーツリーのレイアウト、検索入力の配置、カウント値(例:PROJECT (1)、PERSONAL (0 of 12)、PLUGINS (0 of 50)、AVAILABLE (62)) — からデザインしてください。
A2. 実際のロゴとアイコンを使用し、近似値を使用しない
- ベルバッジ
skill-studio-logo.png— すべての Studio シーンに<Img src={staticFile("...")} />としてコピーしてください。✷グリフをレンダリングしてロゴと呼んではいけません。 - プロバイダーアイコン — Claude、Anthropic、OpenAI、OpenRouter、Ollama、LM Studio の実際の SVG/PNG を取得してください(例:
lobehub/static-pngから)。絵文字で代用しないでください。 - マスコット — 形状を正確に合わせるために、スタイル付き div で描画してください。Claude Code のマスコットは、ピーチ色 (
#e08160) のボディに 2 つの四角い目、体の中央に 2 つの側面ハンドナブ、そして下に 2 対の脚 (▪ ▪ ▪ ▪) があります。アスキーアートではありません。 - アプリウィンドウのクローム — 「Chrome ブラウザ」でウェブサイトを表示する場合、実際の Chrome ブラウザフレーム(角丸、信号機ドット、‹ › ↻ ナビゲーション、実際の URL が表示されたロック付き URL バー(
localhost:3000/hero、余分なスペースや中点なし))をレンダリングしてください。
A3. YouTube 参照レイアウトにピクセル単位で合わせる
想像だけでシーンを再設計する前に、参照フレーム内の表示要素をリストアップし、それぞれを出力と照合してください。
- バナーテキスト — 正確な文言(
Submit skills for verification、Submit a Skillではない) - タブの順序 —
Overview · Edit · Tests · Run · Trigger · Versions - トラストバッジ —
T1 UNSCANNED、Security-Scanned —、Trusted Publisher - フィルター入力 — サイドバーの
AVAILABLEの上に常に配置 - カウント — スライド間で一貫性を保つ(すべての場所で
PERSONAL (0 of 12)、あるスライドで(11)、別のスライドで(0 of 12)にしない) - ヘッダー右側のコントロール(この順序):
🔍 Find skills [⌘K]·+ New Skill·● Model selector·🔔 bell
B. カメラズーム
B1. カメラズームはキャンバス全体に対して行い、セクション単位で拡大しない
クローム内の単一パネルをスケーリングしないでください。クローム全体(トップバー + ボディ) を transform div でラップし、それをスケーリングおよび翻訳してください。
<div
style={{
width: "100%",
height: "100%",
transform: `translate(${cameraTx}px, ${cameraTy}px) scale(${cameraScale})`,
transformOrigin: "50% 50%",
willChange: "transform",
}}
>
{/* トップバー + ボディ */}
</div>
カーソル + クリックリップル SVG はこのラッパーの内側に配置し、クロームと一緒にスケーリングされ、ターゲットに固定されたままになるようにします。
B2. クリックしてからズームする
視聴者は、クリックターゲットをコンテキスト内で見てから、結果を見るためにズームインされる必要があります。順序:
フレーム 130 カーソルがボタンに近づく
フレーム 174 クリックリップル
フレーム 184 ボタンに "Running…" が表示される
フレーム 188 カメラズームイン開始 (1.0 → 1.55+、約 30 フレーム)
フレーム 220+ ズーム保持 — パスカスケード / 結果 / スクロールアップ表示がここで発生
最初にズームしてからクリックすると、プレゼンテーションのスライドのように感じられます。最初にクリックしてからズームすると、ユーザーがアクションを実行し、カメラがそれに追従したように感じられます。
B3. 実際にクロームをキャンバス外に押し出すスケールを選ぶ
控えめな 1.1 倍ではほとんど何も変わりません。「トップバーがキャンバスの上部から消える」ようにするには、焦点をキャンバスの中心に持ってくる翻訳と組み合わせて、≥ 1.5 倍が必要です。ターゲット ≥ (キャンバスの高さの半分) / (焦点からトップバーまでの距離) を計算します — y=540 の行と 64 ピクセルのトップバーの場合、≥ ~1.5 倍になります。「ビューポートを埋める」ためのデフォルトとして 1.55–1.85 倍 を使用してください。
C. カーソルクリックターゲット
C1. 実際の要素にヒットさせる
カーソルが間違ったボタン(モデルセレクターピルの代わりに + New Skill)に着地すると、視聴者はデモが壊れていると思ってしまいます。毎回レイアウトからターゲットを再導出してください — ピクセル値を推測しないでください。
padding: "0 22px" を持つフレックス右揃えコントロールストリップの場合:
// 右端 → 22 パッド → ベル (32) → 14 → モデル (~290) → 14 → New Skill (~120) → 14 → Find skills (~150)
NEW_SKILL_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 60 // = 1488 (ボタン中心)
FIND_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 120 - 14 - 75 // = 1339
定数を取得したら、カーソル接近補間とカーソル離脱補間の両方でそれを使用して、クリックリップルがピルに正確に着地し、その右 200 ピクセルに着地しないようにします。
C2. カーソルが近づくにつれてターゲットを強調表示する
共有ヘッダーコンポーネント(例:StudioHeader の findActive、newSkillActive)に *Active プロパティを追加し、カーソルシーンが接近 + クリックウィンドウの間それをオンに切り替えます。ボタンは次のようになります。
- 1.08 倍のスケール
box-shadow: 0 0 0 4px rgba(99,102,241,0.30)によるソフトなインディゴまたはパープルのリングtransition: all 0.15s ease
D. ハイライトと四角形
D1. ハイライト四角形はコンテンツ幅に合わせ、行全体にしない
ユーザーが 2 行のターミナル行の周りに赤い四角形を希望する場合、親のフレックスカラムをラップしないでください — それは行全体に広がります。以下を使用してください。
<div
style={{
display: "inline-flex",
flexDirection: "column",
alignSelf: "flex-start",
width: "fit-content",
border: "2px solid #dc2626",
borderRadius: 6,
padding: "10px 16px",
backgroundColor: "transparent",
}}
>
{/* 2 行、それ以上でもそれ以下でもない */}
</div>
四角形の外側にあるべきもの(例:3 行目の "Generating component…")は、子要素ではなく、兄弟要素である必要があります。
D2. 注釈:楕円よりも四角形を優先する
行の周りの手描き風の四角形のストロークは、「キャンバス上の蛍光ペン」として読まれ、これはほとんどのユーザーが「これをハイライトして」と言う意味です。楕円は装飾的に感じられることがあります。
<svg viewBox="0 0 1000 100" preserveAspectRatio="none">
<rect
x="6" y="6" width="988" height="88" rx="6" ry="6"
fill="none"
stroke="#ea580c"
strokeWidth="3.6"
strokeDasharray="2160"
strokeDashoffset={2160 * (1 - progress)}
/>
</svg>
D3. 「これが新しいもの」にはオレンジ(#ea580c)を、「これがバグです」には赤(#dc2626)を使用する
同じデモで両方を使用できます。混在させないでください。
E. プロダクトクロームのレイアウトパターン
E1. Studio ヘッダーは単一の共有コンポーネントにする
1 つの StudioHeader.tsx を使用し、以下の標準レイアウトで、すべての Studio シーンから呼び出します。
- 左側:ロゴ画像(40 × 40 PNG)+ "Skill Studio" ワードマーク + パンくず
[Authoring|Available] / [scope] / [folder] / [skill] - 右側:🔍 Find skills
[⌘K]· ✦ + New Skill · ● Model selector · 🔔 Bell
breadcrumb、bellBadge、findActive、newSkillActive をプロパティとして渡します。すべてのシーンのヘッダーはピクセル単位で安定します。
E2. サイドバーには AVAILABLE の上に常にフィルター入力がある
すべての Studio サイドバー — Browse、Update、AuthorEvals、ConsumeInstall、AuthorEditAndPublish — は、AVAILABLE ツリーの上に同じ Filter skills… 入力を取得します。ユーザーが既に検索しているスライドでは、コンテキスト内のクエリ(frontend-design)を事前に入力します。
E3. サイドバーの幅とタイポグラフィ
- 幅:400 px(または深くネストされたツリーがあるスライドでは 460 px)
- 外側のパディング:24–30 px
- グループヘッダー(
AVAILABLE、AUTHORING):18–19 pt、文字間隔 1.6、ウェイト 700 - サブヘッダー(
SKILLS、.CLAUDE):15–16 pt、文字間隔 1.4 - 行テキスト:17–19 pt
- バージョンピル:13–14 pt モノフォント、1 px ボーダー、パディング 3/10
- 垂直ギャップ:セクション間 12–14 px、セクションヘッダーの上 22–36 px
細くて密集したサイドバーは設定パネルのように感じられます。広くて開放的ないサイドバーは、実際のプロダクト UI のように感じられます。
F. インプレース状態遷移
F1. 1 つの画面のように感じられるべきシーン間でスライド左遷移を使用しない
「「インストール」をクリック → ツリーが新しいスキルで更新される」が 1 つの連続した操作として読まれるべき場合:
- 次のシーンで
transitionType: nullを設定するか、2 つのシーンを 1 つにマージする - シーン間でクロームを同一に保つ
- 変化する要素(カウンターフリップ、シェブロン回転、行のスライドイン)をアニメーション化する — 全面フェードは行わない
F2. 新しいアイテムを強く強調表示する
ピーチ色の背景 + 2 px のソリッドオレンジリング + ドロップシャドウ + ✓ Just installed コールアウトピルは、「これがインストールされたばかりです」に適切な強度です。微妙な背景の色合いはデフォルト状態として読まれ、視聴者は気づきません。
backgroundColor: "#fff5ee",
boxShadow: `0 0 0 2px ${ORANGE}, 0 8px 22px rgba(234,88,12,0.22)`,
F3. カウンターフリップ:パルスハロー + シェブロン回転
カウントが変化したとき(PROJECT (0) → (1)):
- シェブロンを回転させる
▸ → ▼(200 ms のトランジション) - カウントの背後に短いオレンジのハローをレンダリング:18 フレームかけて不透明度
0.45 → 0、スケール0.4 → 2.2 - 新しい子行を
translateY: -12 → 0で 24 フレームかけてスライドイン
G. エディター / SKILL.md 編集パターン
G1. 必須フィールドは削除せず、置き換える
スキルには常に description が必要です。説明をアップグレードするには:プリミティブな行を赤で取り消し線にし、新しい説明をスライドインさせます...
このセクションは、指定された長さに収めるために短縮されました。