Communitygithub.com

スクロール動画サイト

完成した動画を、スクロールでフィルムを擦るアップル式のページにする。キャンバスと最適化した WebP 連番を使う。

スクロール動画サイト とは?

すでにある動画から、一枚もののスクロリーテリングページを作る。スクロール量が固定キャンバスのフレームを送り、背景の自動再生ではない。既存の連番だけを最適化することもできる。映像そのものが界面になる。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/solutionsnovaai-bit/skills/tree/HEAD/.claude/skills/scroll-video-website

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

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

ドキュメント

Scroll Video Website

使用するタイミング

以下のような場合にこのスキルを使用します:

  • Apple スタイルのスクロールアニメーションを動画から作成したい
  • スクロールで制御・スクラブする動画 Web サイトを作成したい
  • プロダクト動画をシネマティックなランディングページに変換したい
  • 動画で駆動するスコールテリング体験を構築したい
  • 動画をスクロールアニメーション用に最適化された画像シーケンスに変換したい
  • スクロールで制御する Canvas ベースのプロダクトリビールを作成したい
  • 既存のスクロール動画フレームシーケンスを最適化したい

通常の自動再生ビデオ背景や、スクロール効果とは無関係な用途には使用しないでください。

プロダクトアニメーションビューアのようなミニマルな全画面体験を作成します。ページ自体がスクロール距離を提供し、固定されたキャンバスがビューポートを埋め、ユーザーの動画から生成されたフレームシーケンスをスクラブします。アニメーション自体がインターフェースであり、従来のランディングページの背後にある背景ではありません。

呼び出し方法

このスキルには2つのモードがあります。動画からスクロール動画 Web サイトを構築するか、既存のフレームシーケンスを最適化します。最初の引数が optimize の場合は、references/optimize.md に従い、以下のビルドワークフローは実行しません。

以下の簡潔な形式を完全なビルドリクエストとして扱います:

$scroll-video-website <path/to/video.mp4>

動画パスはスキル名の後の最初の引数である必要があります。パス以降はすべて、スタイル、レイアウト、コピー、動作に関するオプションのユーザー指示です:

$scroll-video-website ./media/product-reveal.mp4
$scroll-video-website ./media/product-reveal.mp4 黒い背景とコンデンスタイポグラフィを使用

最初の例は、フレームシーケンスを生成し、以下で説明する完全なデフォルトのスクロールアニメーション Web サイトを構築することを意味します。2番目の例では、同じ動画駆動型アニメーションアーキテクチャを維持しつつ、追加された視覚的な指示に従います。このスキルを使用するエージェントがプロンプトの残りの部分を解釈して実装できるようにします。このスキルはスタイルオプションのための個別のコマンド文法を定義しません。

動画パスは、絶対パスでない限り、カレントワーキングディレクトリからの相対パスとして解釈します。スペースが含まれる場合は、ユーザーが引用符で囲む必要があります。最初に正確なパスを確認してください。ベアファイル名が見つからない場合は、依存関係、ビルド、キャッシュ、VCS ディレクトリを除外しながら、カレントプロジェクト内でファイル名の完全一致を検索します。一致が1つだけの場合は自動的に続行します。一致しないか複数一致する場合は、ユーザーに正確なパスを尋ねてください。<path/to/video.mp4> や {video_path} 内の括弧はプレースホルダーを示し、実際のパスの一部ではありません。use キーワードを要求したり解釈したりしないでください。

既存のシーケンスを最適化するには、次のように正確に指定します:

$scroll-video-website optimize

optimize コマンドはパスやその他の引数を取りません。カレントプロジェクト内で生成されたフレームシーケンスを検査します。シーケンスが1つだけ識別できる場合は続行します。複数識別できる場合はそれらを表示し、どれを最適化するか尋ねます。シーケンスが見つからないか、確信を持って認識できない場合は、フレームフォルダが見つからなかったことをユーザーに伝え、停止します。

プロジェクトとソースビデオの確立

編集を開始する前に:

  1. プロジェクト構造、スクリプト、フレームワーク、スタイリング、ルーティング、アセット規約、ローカル指示を検査します。
  2. 上記の呼び出しルールを使用してユーザー提供の動画を特定します。動画またはパスが指定されておらず、確信を持って特定できない場合は、実装前にそれを要求します。
  3. 既存の作業スタックを再利用します。既存のプロジェクトがすでに機能している場合、置き換えプロジェクトをスキャフォールディングしないでください。
  4. 利用可能な場合は ffprobe を使用して、動画の寸法、長さ、フレームレート、フレーム数、ファイルサイズを検査します。
  5. 無関係な動作は維持し、必要な最小限の一貫性のある変更のみを行います。

代替アートワークを作成したり、提供された映像を置き換えたりしないでください。ビルドに必要な場合を除き、ソース動画を複製しないでください。

動画をフレームシーケンスに変換する

デフォルトのレンダリングパスは、video.currentTime ではなく、番号付きの WebP フレームシーケンスです。プロジェクトの public/static アセット領域に、ゼロ埋めされた名前(frames/frame_0001.webp など)でフレームを抽出します。

  • 最大30 fps でソースのフレームレートを維持します。動画が長い場合は、ペイロードが実用的な範囲に収まるよう、約240~300フレームにサンプリングします。
  • ソースのアスペクト比を維持します。WebP 品質は78~82程度の適切な値を使用し、設定が適切であると決めつけずに結果を検査します。
  • 実際に抽出されたフレーム数を実装に記録します。推測による定数をそのままにしないでください。
  • 抽出には ffmpeg を推奨します。代表的なコマンドは ffmpeg -i input.mp4 -vf fps=30 -c:v libwebp -quality 80 frames/frame_%04d.webp です。入力、fps、出力パス、既存のプロジェクトツールに合わせて調整してください。
  • 無関係なアセットを削除したり上書きしたりしないでください。出力先にすでにシーケンスが存在する場合は、それを置き換える前に、そのシーケンスがこのアニメーションに属するものであることを確認します。

フレーム抽出が利用できない場合、または結果のフレームペイロードが明らかに不適切な場合にのみ、直接の一時停止ビデオシークを使用します。フォールバックする場合は、トレードオフを説明し、同じ固定ステージ、双方向、スムーズなスクロール動作を維持します。

リファレンスエクスペリエンスに合わせる

ユーザーからレイアウトやコピーの追加指示がない場合、キャンバスのみのページを生成します:

  • 白いページと、100vw × 100vh をカバーする固定、オーバーフローヒドゥンのステージ
  • 意図的なスクラブを実現するための十分な非表示のドキュメント高さ。約8秒または約240フレームのソースの場合、約 400vh
  • ナビゲーションバー、カード、見出し、コールトゥアクション、グラデーション、または作為的なマーケティングコピーはなし
  • ステージを埋めるキャンバス。各フレームを cover ジオメトリで描画し、両軸で中央に配置
  • 最初のフレームの準備ができた後にのみ短い不透明度リビールを表示し、空白フレームのフラッシュを防止
  • 被写体に合う場合にのみ控えめな画像処理を適用。例: 白い背景、わずかなコントラスト調整、白背景のプロダクトレンダリングには mix-blend-mode: multiply

ユーザーがコンテンツを要求した場合は、それを控えめに保ち、キャンバスの視覚的な支配力を低下させることなく、アニメーション内の意図的な瞬間の上または間に配置します。ネイティブの Canvas とブラウザ API で十分な場合に、アニメーション依存関係を導入しないでください。

キャンバスのスクラビングを実装する

aria-hidden キャンバスを含む固定またはスティッキーステージを使用します。デバイスピクセル比に合わせてバッキングバッファのサイズを設定しますが、最大2程度に制限し、描画測定は CSS ピクセルのままにします。リサイズ時に新しい DPR スケールを適用する前にキャンバスの transform をリセットし、スケーリングが蓄積しないようにします。

クリップされたページ全体の進行状況をフレームシーケンス全体にマッピングします:

const range = document.documentElement.scrollHeight - innerHeight
const progress = range > 0 ? Math.min(1, Math.max(0, scrollY / range)) : 0
targetFrame = progress * (frameCount - 1)

前方へのスクロールでアニメーションが進み、逆方向へのスクロールで逆方向に進む必要があります。スクロールおよびリサイズハンドラーは、安価な測定値またはターゲットのみを更新する必要があります。単一の requestAnimationFrame ループを実行し、フレームレートに依存しない指数補間で浮動小数点のプレイヘッドをスムージングします:

const dt = Math.min((now - lastTime) / 1000, 0.1)
const alpha = 1 - Math.exp(-dt * 9)
currentFrame += (targetFrame - currentFrame) * alpha

プレイヘッドの両側の整数フレームを描画し、次のフレームを小数部分でクロスフェードします。最初にキャンバスの背景をクリアまたはペイントし、描画後に globalAlpha をリセットし、リサイズ時に再描画します。

フレームをプログレッシブにロードする

シーケンス全体の最初のペイントをブロックしないでください:

  1. 最初にフレーム1をロードし、描画して、キャンバスを表示します。
  2. タイムライン全体に均等に分散されたフレームをキューに入れます。例: 8フレームごと。これにより、早期にシークする場合の近くのフォールバックが提供されます。
  3. 残りのすべてのフレームをキューに入れます。

リクエストされたフレームとロードされたフレームを別々に追跡し、優先パスと残りのパスが同じ画像を2回リクエストしないようにします。リクエストされたフレームがまだロード中の間は、最も近いロード済みフレームを描画します。画像のロード失敗を処理し、シーケンスの残りが停止しないようにします。

プロジェクトのベースパスとデプロイメントターゲットで機能するアセット URL 戦略を使用します。所有するコンポーネントがアンマウントされるときに、スクロール、リサイズ、メディアクエリリスナー、オブザーバー、アニメーションフレームをクリーンアップします。

レスポンシブ動作とアクセシビリティ

狭い画面でも cover レンダリングを維持し、意図的なトリミングを受け入れます。画像を歪めないでください。デスクトップとモバイルサイズで重要な被写体の配置を確認します。表示されるコンテンツが追加される場合は、モバイルビューポートの変更とセーフエリアを考慮します。

prefers-reduced-motion: reduce の場合は、スクラビングを停止し、最初の適切なフレームを保持します。ページコンテンツにアクセス可能であることを維持し、スクロールをハイジャックしないでください。装飾的なキャンバスは、冗長なスクリーンリーダーコンテンツを作成しないでください。

結果を確認する

プロジェクトのチェックを実行し、可能であればブラウザで結果を検査します。以下を確認します:

  • 最初と最後のスクロール位置が、最初と最後の抽出されたフレームにそれぞれ到達すること
  • 前方および逆方向のスクロールが連続的に感じられ、不連続なジャンプ、再生、フラッシュ、または空白のキャンバスが表示されないこと
  • フレームリクエストが重複しておらず、欠落または遅いフレームが近くのロード済みフォールバックを使用していること
  • cover トリミング、DPR リサイズ、キャンバススケーリングがデスクトップおよびモバイルサイズで機能すること
  • モーション低減設定で静的フレームが保持され、コンポーネントのクリーンアップが完了していること
  • 生成されたシーケンスが期待される数、寸法、順序、および許容可能な合計サイズであること
  • 無関係なプロジェクト動作が引き続き機能すること

最後に、エクスペリエンスの概要、抽出されたフレーム数とペイロード、実行されたチェック、および残っているソースメディアの制限事項を要約して終了します。

関連スキル