ccvideo — Claude風プロモーションビデオ
AnthropicのClaude製品紹介ビデオのビジュアル言語で、短尺プロモ動画(20~45秒、1920×1080 @ 30 fps)を制作します。暖かみのあるテラコッタキャンバス、macOSターミナルウィンドウでClaude Codeセッションを実行する様子、タイプライター調のテキスト表示、ロックされたフレーミング間の短いカメラプッシュ、セリフ体のタイトルカードが特徴です。
前提条件
- Remotionプロジェクトが存在すること。なければ、以下でスキャフォールド:
npx create-video@latest --yes --blank --no-tailwind .その後npm i。 - パッケージ(
npx remotion add <pkg>でバージョンを合わせてインストール):@remotion/google-fonts,@remotion/transitions,zod(zodは明示的に宣言 — ライブラリが直接インポートするため、推移的依存に頼らないこと)。 - コンポーネントライブラリが
src/ccvideo/に存在すること。なければ、このスキルのtemplates/ディレクトリから全ファイルをsrc/ccvideo/にコピー。これらのコンポーネントをゼロから書き直さないこと。 - キャプチャ/検証ツールがプロジェクトルートの
scripts/に存在すること。なければ、このスキルのscripts/ディレクトリ(scripts/lib/を含む)をそこにコピー。全スクリプトは実行ディレクトリからの相対でcaptures/を解決するため、常にプロジェクトルートから実行すること。
グラウンドトゥルース(絶対的なコンテンツルール)
ビデオの内容は、シーンコンポーネントに手書きで記述してはいけません。表示されるすべての事実 — 数値、パス、エンドポイント、コマンド出力、行数 — は、実際に実行されたもののキャプチャから取得する必要があります:
- 各ビデオには
captures/<name>/ディレクトリがあり、未加工のアーティファクト(APIレスポンス、抽出されたセッションイベント)と、それらから決定論的に構築されたprops.jsonを保持。props.jsonはコンポジションがレンダリングする単一の信頼源です。 - まずキャプチャする。 ビデオを作成する前に、実際の処理を実行:
node scripts/capture-xapi-cli.mjs— xapi CLI 経由のライブXデータ(npx xapi-to、キーは~/.xapi/config.json;.agents/skills/xapi/の xapi スキルに全機能のドキュメントあり)。node scripts/capture-x-user.mjs— 公式X API バリアント(X_BEARER_TOKENが必要;--sampleはraw-meta.jsonにsample: trueをマークしたプレースホルダーデータを書き込む — サンプルキャプチャは絶対に公開しない)。node scripts/transcript-to-props.mjs <session.jsonl> --prompt-match <str> --out captures/<name>— 実際のClaude Codeセッションターンを再生(トランスクリプトは~/.claude/projects/<project-slug>/*.jsonlに存在)。- 新しいデータソース? 同じパターンに従って新しいキャプチャスクリプトを作成:実際のデータを取得 → 未加工を保存 →
scripts/lib/の共有決定論的ビルダーでpropsを構築。
- 公開前に検証:
node scripts/verify-props.mjs captures/<name>は未加工アーティファクトからpropsを再構築し、手編集があれば失敗。props.jsonを編集するのではなく、再キャプチャして修正すること。 - 正直な再生境界:ペーシングはパフォーマンス(タイピング速度、スピナー時間)だが、機能は現実でなければならない — ビデオはキャプチャされた実行が実際に行ったことだけを表示してよい。これは外観にも及びます:セッションヘッダーの情報(Claude Code バージョン、cwd)はキャプチャから取得するか(
claude --version、実際のcwd)、ヘッダーは省略。スピナーのトークンカウンターは、キャプチャが実際のthinkingTokens値を提供する場合のみ表示(それ以外は秒のみ)。サンプルキャプチャはverify-propsで完全に失敗します(--allow-sampleはパイプラインテスト専用)。 - キャプチャはコミットしても安全であるよう目指しており、多層防御を備えています — ただし完全な保証ではありません:
transcript-to-propsはビデオが実際に使用する入力のみを保持(選択されたイベントの表示行+カウント、1つのトランケートされたコマンド出力、サマリーブレット行)、秘密っぽい文字列(APIキー、Bearerトークン、URLの認証情報、env/JSONのパスワードフィールド、秘密鍵)を削除し、通常パスとスラッグフラット化されたホームパスの両方を~に書き換え — これらすべてはpropsが構築される前に行われるため、props、ビデオ、アーカイブされた未加工データは同一の編集済みコンテンツを参照します。パターンリストは完全にはなり得ません:コミット前に必ずキャプチャをレビューし、編集警告は停止サインとして扱ってください。
ワークフロー
- まずキャプチャ(グラウンドトゥルース参照):実際の実行から
captures/<name>/props.jsonを生成。 - キャプチャからビートシートを作成。 プレゼンテーションテキスト(カードタイトル、思考ワード)はキャプチャスクリプトの定数/フラグに存在 — 1つのプロンプト、コードビート、実行出力、サマリーブレットを選択。クラシックな流れを目指す:コード → 作成 → 実行+出力 → サマリー。
- コンポーズ:
src/Root.tsxに<Composition>を登録。src/ccvideoのGroundedVideoを使用し、schema={groundedVideoSchema}、キャプチャのprops.jsonからインポートしたdefaultProps、groundedVideoDurationで持続時間を導出するcalculateMetadataを設定 — 持続時間はコンテンツに自動的に従います。標準の流れを超えたカスタムシーン作業:ライブラリのプリミティブで構築し、同じルールに従う。 - スチルで検証してから完了と宣言。ビートごとに1枚スチルをレンダリング:
npx remotion still <CompId> --frame=<n> --scale=0.5 out.pngで確認。ターミナルウィンドウで何もクリップされていないか([ccvideo]オーバーフロー警告が出たらビートをトリミング)、タイミングが急がず、色がパレットに合っているか確認。 node scripts/verify-props.mjs captures/<name>を実行し、npx remotion studio --no-openでプレビュー。最終レンダリングはnpx remotion render <CompId> out/<CompId>.mp4(--props=captures/<name>/props.jsonを追加してコードに触れずに別のキャプチャをレンダリング;--scale=2で公式デモのような4Kマスターに — コンポジションはコード上では1920×1080 @ 30 fpsのまま)。
2つのテーマ
プロダクトごとに選択。どちらもブランドのテラコッタ #D97656/#D97757 を共有:
- テラコッタ(デフォルト)— 暖かみのあるキャンバス、Claude Code REPLセッション。エージェント/AIワークフローストーリー向け。コンポーネント:
GroundedVideo/DataSession。 - ダーク(
antCLIデモ文法)— ほぼ黒のキャンバス#0B0B0B、暖色系黒のターミナル#181716(微妙なボーダーのみで区切る)、シェルプロンプト▶ ~/dir >(矢印#8B92C9、シェブロン#5FA97B)、クリーム色のセリフ体#D6D4CF。構造は章立て:ピクセルロゴワードマークカード → [章ごとに:インタースティシャルカード(モノキッカー+細い区切り線+セリフ体クレーム) → フレッシュシェルビート(実際のコマンドをタイプ、実際の出力がフェードイン、アイドルプロンプトが戻る)] → ワードマークアウトロ。CLI/開発ツールプロダクト向け。コンポーネント:DarkVideo/ShellBeat/InterstitialCard/WordmarkCard、theme.tsでdarkパレット、スキーマdarkVideoSchema(ライトテーマと同様にキャプチャから構築 — 例えばcapture-xapi-cli.mjsが書き込むprops-dark.json、verify-props.mjsで検証)。
ビジュアル(絶対的なスタイルルール)
- キャンバス
#CC7D5D、ターミナル#2B2C36、タイトルバー#3A3634。本文テキスト#E3E4EB、ディム#9899A1、コメント#6C6E6A、行番号#83848C。アクセント:ペリウィンクル#B8B9F2(パス、インラインコード、文字列)、ティール#85BEC5(キーワード)、ゴールド#F2C43D(ステータス矢印)。すべてsrc/ccvideo/theme.tsで定義 — インポートして使用、ハードコードしない。 - フォント:JetBrains Mono(ターミナル一切)、Source Serif 4(タイトルカード)。
theme.tsで@remotion/google-fonts経由でロード、Noto Sans SC は両スタックのCJKフォールバックとして既に追加 — 中国語プロンプトもそのままレンダリング可能。 - ターミナルウィンドウ 1560×950(セッション
header表示時は985)、14 px 角丸、深いソフトシャドウ、3つのトラフィックライト、タスクを反映したモノタイトルバーテキスト(例:dev — · Implement X — claude — 106×31)。 - Claude Code セッションは実際に見える必要あり:
>入力行の上に金色⏵⏵ auto mode on(shift+tab で切替)· esc で中断ステータスバー(両方常に表示、下部に固定);入力行のすぐ上の固定高さスロットに✻ Cogitating…スピナー;●ツール結果ブレット;番号付きコードブロックの末尾に… +N lines(ctrl+o で展開);太字What it doesサマリーと-ブレット。 - カメラ:ターミナルシーンでの持続的なズームやパンは禁止 — スローな分数スケーリングは小さなモノテキストを目に見えてドリフト・スイムさせる。許可されるカメラ動作は
<CutZoom>のみ:ロックされたフレーミング間の短く強くイージングされた動き(約0.6秒) — 密集コンテンツにプッシュイン、ホールド、見せ場でプルバック。意図的な速い動きの間のみテキストは中間スケールでも可、数秒間は不可。プルアウト時はプッシュインと同じoriginを維持し、横スライドに見えないようにする。DataSessionはこれをrunビート周辺で自動適用。<SlowZoom>はタイトルカードのみ。 - セッション真正性クローム(すべてスキーマ駆動、すべてオプション):
header(ピクセルロゴ +Claude Code vX+ モデル/cwd行、常時表示)、windowTitleIdle→windowTitleのプロンプト送信時の切り替え、プロンプトエコー(ハイライトブロック)、ライブ(Ns · ↓ N tokens)カウンターとオプションの⎿ Tip:行付きスピナー、作業中のみesc to interruptが追加されるステータスバー。追加のビート種類:answer(リッチ散文ブロック)、alert(赤ハイライト行)、toolビートは⎿子行を持つ場合あり。 - トランスクリプトのずれ禁止。 ターミナルテキストはフェードインのみ:ウィンドウ内での位置的な出現アニメーションは禁止、さらに下の行をリフローする要素のマウント/アンマウントは絶対に行わない — 一時的な行(スピナー、進捗)は固定高さスロットに配置し、その消失が何もシフトしないようにする。
- タイトルカード:テラコッタ上のほぼ黒
#1F1508のセリフ体見出し、モノ副題は68%不透明度、フェードアップ出現。見出し ≥ 132 px、副題 ≥ 52 px(1920幅時)。
コンポーネントAPI(src/ccvideo)
データ駆動層(ビデオ全体に推奨):
<GroundedVideo {...props}>— イントロカード → セッション → アウトロカード、全てgroundedVideoSchema値(キャプチャのprops.json)から。<DataSession {...props.session}>—sessionSchema値をレンダリング:オプションのヘッダー、プロンプトタイピング、スピナー、その後beats(識別ユニオン:code、tool、run、summary、answer、alert)。runビートのカットズームを自動適用;レンダリング時にコンテンツオーバーフローを警告。sessionTiming(props, fps)/groundedVideoDuration(props, fps)— 純粋なタイミング導出;calculateMetadataで使用。<Rich segments>— JSONセグメント{t: 'plain'|'kw'|'code'|'comment'|'dim'|'bold', s}をレンダリング;props.json からスタイル付きテキストへのブリッジ。
プレゼンテーションプリミティブ:
<TerminalWindow title width? height? variant?>— キャンバス上のウィンドウ(ダークテーマでは `variant=