映画的なスクローリーテリング
基本アーキテクチャ(譲れない条件)
- 単一ピン、単一タイムライン。 ヒーロー(またはメインチャプター)は、N ビューポート高の間ピン留めされるコンテナを持ち、進行度 0→1 ですべてを制御します。複数のスクロールアニメーションが競合する場合、それは単なるエフェクト付きの Web ページであり、これではありません。
- 絶対にスクロールジャッキングをしない。 ユーザーはネイティブスクロールで速度を制御し、アニメーションはそれに応じて「スクラブ」されます(
scrub: true)。ホイールを乗っ取ったり、ユーザーに代わってスクロールを移動させることは禁止です。 - 単一のアニメーションループ。 Lenis を GSAP のティッカーに統合する(
autoRaf: false)か、ネイティブスクロールとスクラブを使用します。2 つのループが競合することはジャンクの最大の原因であり、アセットを最適化しても解決しません。 - テキストは DOM 内に配置し、キャンバスにオーバーレイし、進行度に応じてレイヤーを制御します。キャンバス内にコピーをレンダリングしてはいけません。
フレームシーケンス(Apple タイプの手法)
- 推奨ソース:実際のビデオ →
ffmpegでフレームに変換(fps=12..24、画面解像度に合わせて拡大縮小)。WebP(q≈68-75)でエクスポートし、結果を見ながら微調整します(直感ではなく)。 - 最大約 90~120 フレーム。モバイルでは半分または 720p バージョンを配信します。
- スライディングウィンドウ方式で読み込む:現在のフレームの周囲 ±6~10 フレームを維持し、シーケンス全体をデコードしてはいけません(フル 1080p シーケンスは iOS Safari を強制終了させます)。
- プリロードには
IntersectionObserver(rootMargin 約 800px)、requestIdleCallbackによるデコード、fetchPriority="low"(ヒーローを除く)を使用します。 - キャンバスは
devicePixelRatioを 1.5 に制限し、cover/containを計算して設定。デコード済みのフレームのみを描画します。該当するフレームがない場合は、最も近い既に読み込まれているフレームを使用します(決して黒を描画しない)。 - キャッシュは不変(
Cache-Control: public, max-age=31536000, immutable)とし、ファイル名はバージョン管理します。 prefers-reduced-motionや低速接続時のフォールバック:静的ポスター+ピン留めなしの通常チャプター。- 後処理が不要な場合のよりシンプルな代替手段:フレームごとに
<img>のsrcを交換する(キャンバスなしで、すべてのブラウザで信頼性が高い)。
ビデオスクラブ(<video> を使用する場合)
currentTimeは、単一のrequestAnimationFrame内で進行度によって制御し、スムージングを適用。シークを統合します(Safari はキューを蓄積します)。- 100% シーク可能にするために blob として読み込む。GOP を短く(数フレームごとにキーフレーム)エンコードするか、スクラブがカクつきます。
- 絶対に autoplay は使用しない。スクロールによって動きます。
チャプターとオーバーレイ
- ビートは進行度の範囲(10%、35%、60%、85%...)で定義し、フェードイン/アウトと、リズムのために左右交互に入力を行います。
- 各チャプターのテキストは、正しいセマンティックな順序で DOM に保持し、SEO に対応します。
- 水平ギャラリー:セクションをピン留めし、
xを進行度にリンク。カードは中央に向かってスケールします。
パフォーマンスと検証
- アニメーションは
transform、opacity、filterのみに制限。will-changeは必要な場面でのみ使用し、終了後に削除します。 - フレームレートは
requestAnimationFrameでローカルと実際のモバイル端末(可能であれば)で測定。目標は中級ノート PC で 60fps。 - ヘッドレスキャプチャはキャンバスを黒く読み取る可能性があります(バッファが保存されていない)。DOM で検証する(計算済みスタイル、要素、
window.debugに公開された状態)、および減速モードを有効にして検証します。 - 375/768/1280/1440 でテスト。デスクトップブラウザのリサイズは iOS のメモリクラッシュを再現しません。QA レポートにその旨を記載します。
推奨データ構造
「プレーン」の順序付けられた配列。各プレーンは { tipo: 'frames' | 'overlay' | 'galeria', ... } です。ムービーの順序を変更するには、リストを並べ替えます。フレームはパターンで参照します(/seq/plano-01/0001.webp)。