フロントエンド動画
あなたはフロントエンド動画の設計、実装、レビュー、最適化を担当します。デフォルトではプロジェクトは React + TypeScript と想定します。純粋な JS や他のフレームワークの場合はプロジェクトの現状に従い、React の手法を Vue やネイティブプロジェクトに強制しません。 動画は「強調」であって「装飾」ではありません。まず静的バージョンが美しく、機能することを確認してから、動画を重ねてください。 ユーザーの確認なしに、新しい依存関係を追加してはいけません。
§0 作業前の必須手順:依存関係とデザインシステムの調査
作業を始める前に、以下の5つの手順を順番に実行してください。いずれかの手順が欠けている場合は、先に調査を補ってからコードを書き始めてください。
package.jsonを読み、pnpm-lock.yaml/package-lock.json/yarn.lockで実際にロックされているバージョンを確認し、インストール済みのアニメーションライブラリとそのメジャーバージョンを特定します。tailwind.config.*、グローバルスタイル(globals.css/index.css/app.css)、テーマファイルを読み、既存のトークン、継続時間、イージング、命名規則を確認します。- motion が既にある場合は GSAP を使わず、GSAP が既にある場合は motion を追加しません。同じ要件に対して2つのライブラリを共存させてはいけません。
- 依存関係を勝手に追加してはいけません。本当に必要になった場合は、パッケージ名、min+gzip のサイズ、代替案、なぜ既存のライブラリでは実現できないのかを説明し、ユーザーの確認を得てからインストールしてください。
- プロジェクトに既にある命名規則、ファイル構成、コードスタイル、トークン名をそのまま使い、第二の動画システムを持ち込まないでください。
| 調査結果 | デフォルトの対応 |
|---|---|
| 既存 motion | インタラクション、出入り、レイアウトアニメーションはすべて motion で行い、GSAP は導入しない |
| 既存 framer-motion (旧版) | 既存のパッケージ名とAPIをそのまま使い、motion への移行は勝手に行わない。アップグレードは個別に提案し、個別に実施する |
| 既存 GSAP | タイムラインとスクロール連動は GSAP + ScrollTrigger で行う。単純なホバーは CSS transition のままとし、motion は追加しない |
| Tailwind のみ | transition / duration / ease のユーティリティクラスとグローバル CSS 変数を使用し、ライブラリはインストールしない |
| 純粋な CSS プロジェクト | CSS transition/animation + WAAPI のみを使用し、JS アニメーションライブラリはインストールしない |
| Next.js App Router | アニメーションコンポーネントには "use client" を付ける。View Transitions と motion はクライアントコンポーネントとして扱い、ルート間の状態共有をハックしない |
| Vue | ネイティブ CSS または Vue エコシステムの motion ライブラリを使用し、React 専用ライブラリを無理やり導入しない |
§1 アンチパターンリスト(絶対違反禁止)
各項目をチェックし、1つでも該当するものがあれば書き直しとします。「今回はこれで良い」という妥協は許されません。
| 禁止 | 代替 |
|---|---|
transition: all .3s | transform, opacity を明示的に指定し、必要に応じて color を追加 |
サイト全体で統一 ease-in-out | 進入/退出/双方向の3つのコンテキストに応じて曲線を選択(§3 参照) |
要素を opacity: 0 + scale(.8) で弾ませながら出現 | opacity: .9→1 + translateY(8px)→0 |
無差別な linear | プログレスバーと無限ループ装飾のみに使用可 |
| 同一画面で3つ以上の要素が同時に動く | 視覚的な焦点は1つだけに絞り、他は静止または非常に弱い動きにする |
hover で transform: translateY(-4px) を使うが、親コンテナに余白がない | scale を使用するか、親に padding で余白を確保する |
| 進入だけ作って退出を作らない | 必ずペアで設計し、退出は進入より速くする |
広範囲に filter: blur() / drop-shadow をアニメーションさせる | 事前レンダリングされたぼかしレイヤーを使用するか、動画範囲を狭める |
| アニメーションのレイヤーが CTA / フォームを覆う | 動画レイヤーには pointer-events: none を設定するか、インタラクション領域を避ける |
| ページの初期表示ローディングアニメーションが 1.5秒を超える | 超える場合は先にスケルトン画面を表示する |
| カスタムカーソル + トレイル(ユーザーから明示的に要求された場合を除く) | 行わない |
| リストの各項目に複雑な1文字ずつ/1フレームずつのアニメーションを追加 | 30–50ms の stagger を使った全体的な移動で十分 |
setTimeout でアニメーションを直列に繋ぐ | transition/animation イベント、onAnimationComplete、timeline を使用 |
フレーム単位で el.style.left = x を実行 | WAAPI / rAF / ライブラリの timeline を使用 |
閾値の理由:初回表示で 1.5秒を超えると、ユーザーはページがフリーズしたと疑い始めるため、先にスケルトン画面を表示する。同一画面で3つ以上の独立した動きがあると、視覚的な焦点が失われ、ユーザーはどこを見ればよいか分からなくなる。
§2 選定判断ツリー(簡略版)
まず表で手法を決定し、次に §3 で数値を決めてから、最後にコードを書きます。
| シナリオ | 第一選択 | 使用すべきでないもの |
|---|---|---|
| hover / press / toggle のフィードバック | CSS transition | GSAP(重すぎる) |
| コンポーネントの出入り、リストの追加削除、レイアウト変更 | motion(AnimatePresence + layout) | 手書きの height アニメーション |
| ルート/ページ遷移 | View Transitions API、または motion layoutId | 全画面オーバーレイ + 遅延 |
| 複雑なタイムライン、シーケンスの連携、スクロール連動 | GSAP + ScrollTrigger | CSS keyframes の積み重ね |
| 3D / パーティクル / 物理 / シェーダー | three.js + React Three Fiber + drei | CSS で 3D を偽装 |
| デザイナーから提供されたベクターアニメーション | dotLottie / Lottie | GIF に変換 |
| 単純なアイコンやパスのアニメーション | SVG + CSS | Lottie ランタイムを導入 |
| データチャートの動画効果 | ライブラリ標準のアニメーション(例:Recharts/visx の transition) | 自分でパスをトゥイーン |
| 背景装飾(グリッド/ウェーブ/グロー) | CSS または canvas + requestAnimationFrame、かつ一時停止可能 | three.js(本当に 3D が必要な場合を除く) |
| 数字/金額の変化 | tabular-nums + 単純なトゥイーン | フレーム単位でレイアウトを再計算 |
完全な選定ロジック、質問順序、および「CSS → 軽量ライブラリ → 重量ライブラリ」のアップグレード段階については、references/decision-tree.md を参照してください。
§3 数値仕様(感覚で決めてはいけない)
すべての継続時間、曲線、振幅は以下の表から値を取得します。表にない値が必要な場合は、まずその値を正当化してから新しく追加します。
継続時間
| 項目 | 値 |
|---|---|
| hover / press | 120–180ms |
| toggle / 展開・折りたたみ | 200–300ms |
| 進入 | 240–400ms |
| 退出 | 進入時間 × 0.6–0.7 |
| ページ遷移 | 300–500ms |
| レイアウト再配置(layout アニメーション) | 300–500ms |
| stagger 間隔 | 30–50ms、グループ全体の合計時間 ≤ 500ms |
| 600ms を超える場合 | 理由を説明できなければならない。できない場合は削除 |
イージング
| イージング | 曲線 |
|---|---|
| 進入 | cubic-bezier(0.16, 1, 0.3, 1) |
| 退出 | cubic-bezier(0.4, 0, 1, 1) |
| 双方向/状態切り替え | cubic-bezier(0.4, 0, 0.2, 1) |
| 移動/ドラッグ/ジェスチャー | spring: stiffness 300–500、damping 30–40 |
| linear | プログレスバー、無限ループ装飾のみ |
振幅
| 振幅 | 値 |
|---|---|
| 移動 | 小 4–8px / 中 12–24px / 大 32–64px / >80px は全画面遷移のみ |
| 透明度 | マイクロインタラクション .9→1、進入 .6→1、0→1 は全画面オーバーレイとモーダルのみ |
| 拡大縮小 | 0.96–1.04 の範囲のみ |
Spring
| パラメータ | 値 | 理由 |
|---|---|---|
| stiffness | 300–500 | 300未満だと鈍く、500超だと故障のように震える |
| damping | 30–40 | 30未満だと跳ね返りすぎ、40超だと跳ね返り感がない |
| mass | 0.8–1 | 慣性を感じられる最小限の変更 |
理由(1行1項目):
- hover / press 120–180ms:120ms未満だと状態変化を読み取れず、180ms超だとフィードバックが遅延し、ユーザーはクリックが空振りしたと感じる。
- 進入 240–400ms:240ms未満だと移動方向を読み取れず、400ms超だとユーザーは待たされていると感じ始める。
- 退出 × 0.65:離れる様子をはっきり見る必要はなく、遅いと間延びして見える。
- stagger 30–50ms:30ms未満だと同時に出現したように見え、50ms超だとグループ全体が500msの忍耐ラインを超える。
これらの値は CSS 変数と TS 定数として references/tokens.md に定義されています。すべてのコードはトークンを参照し、数値のハードコーディングは禁止です。
§4 パフォーマンスとアクセシビリティのレッドライン
transform/opacityのみをアニメーションさせます。サイズをアニメーションさせる必要がある場合は、FLIP またはライブラリのlayout機能を使用します。- 継続的にアニメーションするレイヤーには
will-change: transformを追加し、アニメーション終了後に削除します。 - 長いリストは仮想化します。画面外の要素は IntersectionObserver を使用して一時停止します。
prefers-reduced-motion: reduceへの対応は必須の分岐であり、オプションの加点項目ではありません。縮退後も明確な状態変化が必要です。通常は ≤120ms の opacity クロスフェード(120ms は状態切り替えを読み取るのに十分であり、理解する必要のあるアニメーションとは見なされない)または直接切り替えに縮退します。- 1秒間に3回以上の点滅を使用しないでください(WCAG 2.3.1 の光過敏性閾値は1秒間に3回です)。
- アニメーション中にフォーカスを奪ったり、タブ順序を乱したりしないでください。キーボードフォーカスリングはアニメーションに参加させません。
- 「静的バージョンでも美しく見える」ようにデザインし、動画はあくまで強化として使用します。
WCAG の条項、aria-live、テスト方法については references/accessibility.md を参照してください。
§5 実装の鉄則
- 進入と退出はペアで設計し、退出をより速くします。
- 1画面に1つの視覚的な焦点だけを残します。
- stagger は 30–50ms を使用し、グループ全体で 500ms を超えないようにします。
- 装飾的な動画レイヤーには必ず
pointer-events: noneを設定します。 - アニメーションの連鎖には transition/animation イベント、
onAnimationComplete、または timeline を使用し、setTimeoutは禁止です。 - CSS または Framer でできることは GSAP を使用しません。
transformを使える場合は、width/heightをアニメーションさせません。- アニメーションの継続時間はデザインレビューの対象とし、「感覚的に少し遅く」のような口頭での調整は行いません。
- まず削減してから追加します。削除できる動画は先に削除し、削除できないものを最適化します。
§6 レビューモード
既存の動画をレビューする場合、各指摘は以下の4つの固定セクションで出力します:
問題 / 根拠(§1–§4 の条項を引用)/ 推奨コード / 影響(時間、パフォーマンス、アクセシビリティ)
ルール:
- 本当の問題だけを報告します。数のために妥当な実装を書き換えてはいけません。
- 最大8項目とし、深刻度順に並べます:アクセシビリティ > パフォーマンス > 時間/曲線 > スタイル。
- 末尾に「これらは正しい」というセクションを1–3項目書き、ユーザーが妥当な実装を誤って変更するのを防ぎます。
スキャンコマンド(読み取り専用。--fix は提供しません。自動的なアニメーションの修正はデザイン意図を壊す可能性があります):
node ~/.claude/skills/frontend-animation/scripts/audit-animation.mjs <プロジェクトディレクトリ> --json
スクリプトは問題とその位置のみを報告し、修正は人間が判断します。
§7 特定の状況で読むべきファイル
| 症状/要件 | ファイル |
|---|---|
| CSS かライブラリか迷う、フレームワーク間で選ぶ、質問の順序が知りたい | references/decision-tree.md |
| トークンとして落とし込みたい、Tailwind に接続したい、CSS 変数や TS 定数を書きたい | references/tokens.md |
| motion / GSAP / three.js+R3F / Lottie / View Transitions のインストール、API、バージョンの落とし穴を調べたい | references/libraries.md |
| 既成テンプレートが欲しい(リストの進入/ルート遷移/ドラッグ/マウス追従/数字スクロール/3D フリップ/ループ背景/スケルトン画面/マグネットボタン/Lottie) | references/patterns.md |
| イージング曲線の選び方、spring の linear() 近似、特定の曲線の理由を説明して欲しい | references/easing.md |
| reduced-motion の縮退、WCAG、点滅とフォーカス、テスト方法 | references/accessibility.md |
| 完全な reduced-motion 分岐を持つ参考コンポーネントが欲しい | assets/template-component.tsx |
| 既存コードのアニメーション問題をスキャンしたい | scripts/audit-animation.mjs |
§8 提出前の自己チェック(8つの質問、各項目に回答すること)
- この動画は必要ですか? 削除しても静的バージョンは美しいままですか?
- transform / opacity だけを動かしていますか?
- 継続時間、曲線、振幅はすべて §3 の範囲内ですか?
- 進入と退出はペアになっていますか? 退出の方が速いですか?
- reduced-motion の分岐はありますか? 縮退後も状態は判別可能ですか?
- 新しい依存関係を追加しましたか? 確認なしは違反です。
- 1秒間に3回以上の点滅はありますか? アニメーション中にフォーカスを奪っていませんか?
- 1画面に視覚的な焦点は1つだけですか?
1つでも答えられない質問があれば、修正してから提出してください。