awwwards-motion-design について
コーディングエージェント向けに、監査、演出計画、実装指針でウェブアニメーション制作を整理するデザインスキルです。動きの一貫性と目的を重視し、モーション低減設定にも配慮します。
主な機能
- 01モーション要件の監査
- 02一貫したモーションスタイルの策定
- 03ページ要素ごとのアニメーション割り当て
- 04スタガーとスプリングベースのイージング
- 05モーション低減設定への配慮
活用シーン
- 01マーケティングページのアニメーションを計画
- 02インタラクティブUIに一貫したフィードバックを追加
- 03ページ全体のモーション適用状況を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ yu-369/ vibecurb --skill awwwards-motion-designインストール後、Claude Code で/awwwards-motion-designを入力して読み込まれたか確認します。
詳細
Awwwards級のモーションデザイン
アニメーション、トランジション、マイクロインタラクション、スクロールエフェクト、ページ遷移、キネティックタイポグラフィ、パララックス、ホバー時の物理挙動、ローディングシーケンスなど、ウェブインターフェースに生命感と高級感をもたらすものをユーザーが求めたときに、このスキルが発動します。モーションは品質を表す言語です。静的なページと、1プロジェクトあたり20万ドルを請求するスタジオが丹念に作り上げたような体験との差を生み出します。
パイプライン
┌───────────────────────────────────────────────────────────────────────┐
│ │
│ BRIEF IN ──→ Phase 1: Motion Audit ──→ Phase 2: Choreography │
│ (classify, extract (sequence map, timing │
│ motion intent) sheet, easing palette) │
│ │
│ ──→ Phase 3: Build │
│ (implement layer by layer: │
│ entry → scroll → hover → │
│ transitions → ambient) │
│ │
│ ──→ Phase 4: Motion Diff │
│ (60fps check, feel check, │
│ reduced-motion audit) │
│ │
│ Each phase has a ✓ Quality Gate. Failing a gate blocks the next. │
│ │
└───────────────────────────────────────────────────────────────────────┘
基本理念
コードに触れる前に、これらの原則を理解してください。どのような美的好みよりも優先されます。品質基準は、Appleの基調講演、Linearアプリ、Stripeのホームページ、Vercelのダッシュボード、Raycastです。 アニメーションが apple.com で場違いに見えるなら、十分な品質ではありません。
Apple基準。 Appleは汎用的なCSSトランジションを使いません。Appleが使うのは、オーバーシュートして、落ち着き、物理的なオブジェクトのように息づくアニメーション、つまりスプリング物理です。iOSのすべてのインタラクションは、実物に触れているように感じられます。ボタンは押し縮みし、シートは勢いを伴って滑り込み、要素は穏やかなバウンスとともに落ち着きます。アニメーションにも、同じような物理的で手触りのある品質が必要です。要素の動きが「物理的」または「生き生き」ではなく、「デジタル」あるいは「計算された」ように感じられるなら、イージングが間違っています。
すべてのアニメーションには理由が必要です。 「なぜこれが動くのか?」という問いに、機能的な答え(注意を誘導する、状態変化を伝える、フィードバックを提供する、空間的な関係を示す)を返せないなら、そのアニメーションは削除してください。目的のないモーションはノイズです。
最良のアニメーションは目立ちません。 ユーザーは「いいアニメーションだ」と思うのではなく、「使い心地がいい」と感じるべきです。アニメーションがコンテンツではなく、それ自体に注意を向けさせるなら、やりすぎです。Appleは、アニメーションが終わるまでユーザーを待たせることはありません。アニメーションはインタラクションに奉仕するものであり、その逆ではありません。
一貫性がすべてです。 すべてのアニメーションで同じイージングの系統、同じ強度、同じモーション言語を使うページは、ひとつのスタジオが作ったように感じられます。フェードアップ、弾むスプリング、左からのスライド、スケールポップが混在するページは、寄せ集めのように感じられます。モーションの個性をひとつ選び、すべてに徹底してください。 アニメーションの種類を絞って一貫性を保つほうが、網羅性を重視して多様な動きを使うより、常に優れています。どちらかを選ぶ必要があるなら、網羅性を犠牲にして一貫性を優先してください。一貫して美しく連携する8つのアニメーションがあるページは、統一感のない30のアニメーションがあるページに勝ります。
キュービックベジェよりスプリング物理を。 イージングの頂点が
cubic-bezier(0.25, 0.1, 0.25, 1)だとされた時代は終わりました。Material Design 3 Expressiveはスプリングベースのモーションに移行しています。AppleはiOS 7以降、スプリングアニメーションを使っています。ウェブも追いつきました。CSSのlinear()により、オーバーシュートと収束を伴う真のスプリング物理を実現できます。スプリングのオーバーシュートが適切でない環境や背景のモーションだけにキュービックベジェを使い、主要なアニメーションにはすべてスプリング由来のイージングを使ってください。
アニメーションを決めるのはイージングです。 300msのリニアトランジションと300msのスプリングトランジションは、継続時間こそ同じですが、性質はまったく異なります。2万ドルのスタジオ制作サイトとテンプレートを分けるのは、カーブです。「デフォルト」のイーズなど存在しません。すべてのカーブは、特定の感情的な性質を持つ、意図的で慎重な選択です。
スタッガーが階層を生み出します。 複数の要素をアニメーションさせるとき、すべてを同時に動かしてはいけません。スタッガーは視覚的な階層に相当するモーションで、どこを最初に、次に、そしてその次に見るべきかを目に伝えます。Appleはミリ秒単位の精度でスタッガーを使います。あなたもそうしてください。
モーションはユーザーを尊重します。 すべてのアニメーションは
prefers-reduced-motionに従わなければなりません。例外はありません。この設定を有効にするユーザーには、前庭障害やモーションへの過敏性がある場合も、単に静止した表示を好む場合もあります。モーションの軽減は、アニメーションをなくすことではありません。移動、パララックス、スケール、スプリングのオーバーシュートをなくすことです。継続時間を短くした不透明度のみのフェードなら許容されます。 すべての要素がモーション予算に見合う価値を発揮します。 マーケティングページやランディングページでは、画面上のすべての要素に、少なくとも1種類のモーション(登場、スクロール時の表示、ホバー、またはアンビエントモーション)を付けます。アニメーションのあるページで動かない要素は、生き生きとしたディスプレイにあるドット抜けです。機能的なアプリのUIでは、モーションは使用頻度に応じて制限します。
使用頻度 モーション予算 1日100回以上(キーボードショートカット、コマンドパレット、コアナビゲーション) アニメーションは一切なし。絶対に。 速度こそが使い心地です。 1日数十回(ホバー状態、リストのナビゲーション、トグル) 最小限にします。素早く、ほとんど気づかない程度のフィードバックのみです。 ときどき(モーダル、ドロワー、トースト、設定パネル) イージングパレットに沿った標準的なモーションです。 まれ/初回のみ(オンボーディング、空の状態、成功、祝賀) 楽しさを最大限にします。スプリング、バウンス、ゆとりのあるスタッガーを使います。 厳守ルール: キーボードから開始された操作は、アニメーションさせてはいけません。1日に200回も開閉をアニメーションさせるコマンドパレットは、ユーザーに嫌われるようになります。最速のインターフェースが勝ちます。
アニメーション適用範囲の必須ルール
これは譲れないルールです。画面上のすべての要素にモーションを付けます。 「ほとんどの要素」ではありません。「重要な要素」だけでもありません。すべての要素です。ページ上の要素を1つずつ確認し、この表に従ってモーションを割り当ててください。要素がこの表に載っていない場合でも、最低限、スクロールをトリガーとするフェードインを付けます。
→ 必須要素アニメーションマップ
ページ上のすべての要素について、この表を埋めてください。各行には必ず少なくとも1つの✓を付けてください。空欄の行がある場合、実装は未完了です。
| 要素 | 表示時のアニメーション | スクロール時の表示 | ホバー/フォーカス時の状態 | 常時/マイクロアニメーション | 割り当て済み |
|---|---|---|---|---|---|
| ナビゲーションバー | 上からスライドダウン+フェードイン | - | リンクの下線がスライド、メニュー項目がスプリングスケール | - | ✓ |
| ロゴ | フェードイン(最初の要素、遅延0ms) | - | ホバー時にわずかにscale(1.05) | - | ✓ |
| ナビリンク | 左から右へ順番にフェードイン | - | 下線のスライド+色の変化 | - | ✓ |
| ヒーロー見出し | 単語ごとのマスク表示、または文字分割 | - | - | - | ✓ |
| ヒーローの補足テキスト | フェードアップ+ぼかし解除(見出しの後に順番に表示) | - | - | - | ✓ |
| ヒーローのCTAボタン | スケールイン+フェードイン(ヒーロー内の最後の要素) | - | 押し込みの立体感(圧縮+内側の影)+浮き上がり+クリック時の波紋 | ほのかな光のパルス | ✓ |
| ヒーローの背景 | スケール(1.05→1)+フェードイン(Ken Burns効果の落ち着き) | ゆっくりとした視差効果 | - | グラデーションの変化、または粒子の移動 | ✓ |
| セクション見出し | - | 単語ごとのマスク表示、またはフェードアップ+ぼかし解除 | - | - | ✓ |
| セクションの補足テキスト | - | フェードアップ(見出しから80ms遅れて表示) | - | - | ✓ |
| 本文の段落 | - | 行ごとの表示、またはフェードアップ | - | - | ✓ |
| カード | - | 順番にフェードアップ(カードごとに80ms間隔) | 浮き上がり(-4px)+影の拡大+枠線の発光+3D傾斜 | - | ✓ |
| カードのアイコン/画像 | - | スケールイン(カードの表示後) | カードのホバー時にわずかに回転、または色を変化 | - | ✓ |
| カードのタイトル | - | カードの表示に含める | カードのホバー時に色を変化 | - | ✓ |
| カードの説明 | - | カードの表示に含める | カードのホバー時に不透明度を上げる | - | ✓ |
| 画像 | - | クリップパスによるワイプ表示、またはスケールイン | ホバー時にKen Burns効果でズーム | - | ✓ |
| ボタン(すべて) | - | 親要素とともにフェードアップ | 押し込みの立体感+浮き上がり+影+クリック時の波紋 | - | ✓ |
| インラインリンク | - | 親要素の表示に含める | 下線のスライド+色の変化 | - | ✓ |
| 入力フィールド | - | 親要素とともにフェードアップ | フォーカス時に枠線が発光+ラベルが浮き上がる | - | ✓ |
| バッジ/ピル | - | スケールイン+フェードイン | ホバー時に背景色を変化 | ほのかに弾むように浮遊 | ✓ |
| 区切り線 | - | 中央から幅が広がる(scaleX 0→1) | - | - | ✓ |
| お客様の声の引用 | - | フェードアップ+ぼかし解除+スライド | - | - | ✓ |
| アバター | - | 枠線リングのアニメーションとともにスケールイン | ホバー時にリングがパルス | - | ✓ |
| 統計/数値 | - | カウンターアニメーション(0からカウントアップ) | - | - | ✓ |
| フッター | - | フェードアップ(最後のセクション) | リンクの下線がスライド | - | ✓ |
| フッターリンク | - | 順番に表示 | 下線のスライド+色の変化 | - | ✓ |
| ソーシャルアイコン | - | 順番にスケールイン | 浮き上がり+ブランドカラーへの変化 | - | ✓ |
| 背景の図形 | - | - | - | 浮遊アニメーション+視差効果 | ✓ |
| 装飾要素 | - | 回転しながら表示、またはスケールイン | - | ゆっくり回転、または浮遊 | ✓ |
| スクロールインジケーター | ヒーローの読み込み後にフェードイン | - | - | 穏やかなバウンスを繰り返す | ✓ |
| プログレスバー | - | イージングを使って幅が広がる(scaleX 0→1) | - | - | ✓ |
| ツールチップ | - | - | - | トリガーから上に浮かびながらフェードイン | ✓ |
| アコーディオン | - | 親要素とともにフェードアップ | ホバー時に枠線/背景を変化 | 高さが滑らかに広がる | ✓ |
| タブ | - | 親要素とともにフェードアップ | 背景が変化 | インジケーターがスライド+コンテンツがクロスフェード | ✓ |
| モーダル | - | - | - | 背景がフェードイン+コンテンツがスケールイン | ✓ |
| トースト/通知 | - | - | - | 端からスライドイン+自動で消える | ✓ |
⚠ アニメーション漏れの警告: 最もよくある失敗は、ヒーローと最初のセクションだけをアニメーションさせ、スクロールせずに見える範囲より下をすべて静止させてしまうことです。すべてのセクションに、スクロールをトリガーとした表示アニメーションが必要です。すべてのインタラクティブ要素に、ホバー時のフィードバックが必要です。ページを上から下まで確認し、網羅できているか検証してください。スクロールして、アニメーションせずにただ「そこにある」だけのセクションが見つかった場合、実装に問題があります。
→ カバレッジ検証スイープ
すべてのアニメーションを作成したら、このスイープを実施します。ページを開き、自然な読書ペースで上から下までスクロールします。ビューポートに入るすべての要素について、次を確認します。
- 画面内に入るときにアニメーションしますか? いいえの場合 → スクロール表示を追加します
- ホバーできますか? はいの場合 → ホバー時のフィードバックがありますか? いいえの場合 → ホバー状態を追加します
- 操作できますか(クリック可能、フォーカス可能)? はいの場合 → アクティブ状態/フォーカス状態がありますか? いいえの場合 → 追加します
- 装飾要素ですか? はいの場合 → 周囲に動き(浮遊、回転、脈動)がありますか? いいえの場合 → 追加します
- テキスト要素ですか? はいの場合 → 少なくともフェードアップで表示されますか? いいえの場合 → 追加します
アニメーションのカバレッジが100%のページは、生き生きと感じられます。カバレッジが80%のページには、目がすぐに気づく動きのない箇所が残ります。
フェーズ1:モーション監査
コードを書く前に、モーション要件を分類します。
→ モーションのコンテキストを分類する
| 項目 | 回答 |
|---|---|
| ページの種類 | マーケティング用ランディングページ / プロダクトアプリ / ポートフォリオ / Eコマース / エディトリアル / ダッシュボード |
| モーションの密度 | ミニマル(Apple風の抑制) / 中程度(Stripeレベル) / 豊富(Awwwards風の実験的な表現) |
| モーションの主な目的 | 注意を導く / 状態を伝える / 雰囲気を作る / コンテンツを表示する / 楽しさを生み出す |
| スクロールの挙動 | 標準スクロール / スクロール連動アニメーション / スクロールジャック式セクション / スティッキー表示 |
| ページ遷移 | なし(SPAで即時切り替え) / クロスフェード / スライド / モーフィング / カスタムシーケンス |
| フレームワーク | Vanilla CSS/JS / Framer Motion (React) / GSAP / Motion One / CSSのみ |
→ モーションの個性を固定する(必須)
これは、パイプライン全体で最も重要な決定です。ページ上のすべてのアニメーションは、同じ個性に属している必要があります。異なる個性が混在したページは、3人の開発者がそれぞれアニメーションを付けたかのように感じられます。
1つだけ選びます。
| 個性 | 特徴 | イージングの基本 | 時間の範囲 | 代表的な動き | 参考例 |
|---|---|---|---|---|---|
| 精密 | キレがあり、速く、行き過ぎがありません。すべての動きに機能的な役割があり、装飾的な動きはありません。メスのように無駄がありません。 | --ease-out + --ease-snap | 100-250ms | 即時のフィードバック、鋭いスタッガー | Linearアプリ、Raycast、Vercelダッシュボード |
| 物理的 | スプリングベースで、触覚的です。オブジェクトには重みがあり、動きには行き過ぎ、収束、勢いがあります。実物に触れているような感覚です。 | --spring-snappy + --spring-smooth | 300-600ms(スプリングの収束) | スプリングによる表示、勢いのあるドラッグ、押下時の圧縮 | Apple.com、iOS、Dynamic Island |
| 映画的 | 劇的で、ゆっくり盛り上がり、演劇的に表示されます。ページそのものがショーです。スクロール連動のストーリー展開を使います。 | --ease-dramatic + --spring-smooth | 500-900ms | クリップパスによる表示、テキストの分割、スクロール固定シーケンス | Stripeのホームページ、Awwwards風の実験的な表現 |
いったん固定したら、その個性によって以降のすべてが制約されます。使用するカーブ、速度、スタッガーの量、スプリングを使うか、周囲に動きを加えるかが決まります。個性を混在させてはいけません。 精密なページに弾むスプリング要素が1つだけあると、破綻します。映画的なページに100msのツールチップのスナップがあると、破綻します。一貫性があるからこそ、モーションに「一人のデザイナーが設計した」という感覚が生まれます。
→ モーションのレイヤーを特定する
ページを見て、動かすべき要素に印を付けます。それぞれを次のいずれかのレイヤーに分類します。
| モーションレイヤー | 対象 | 優先度 |
|---|---|---|
| 表示時 | 初回描画時の表示、ファーストビューの読み込みアニメーション | P0 - 必須 |
| スクロール | ユーザーのスクロールに応じて表示される要素、視差効果、スティッキーシーケンス | P0 - 必須 |
| ホバー/フォーカス | ボタンの浮き上がり、カードの傾き、リンクの下線、押し込みによる奥行き効果 | P0 - 必須 |
| 状態 | ページ遷移、タブの切り替え、モーダルの開閉、アコーディオン、メニュー | P1 - あると望ましい |
| 周囲の動き | 浮遊する要素、グラデーションの変化、パーティクルシステム、カーソルの光彩 | P2 - 仕上げのレイヤー |
| 動的表現 | テキストの分割、1文字ずつの表示、単語の切り替え | P2 - 仕上げのレイヤー |
→ モーションブリーフを出力する
モーション戦略を2〜3行で記述します。ロックされたパーソナリティ名を必ず含めてください。
"モーションブリーフ: PHYSICAL パーソナリティ。すべてのセクションにずらしたスプリングの登場(--spring-snappy)。ビューポートしきい値20%でのスクロールトリガー表示。すべてのインタラクティブ要素に押し込み圧縮。セクション見出しにはスプリングで滑らかなテキスト表示。アンビエントパーティクルはなし(パーソナリティの競合)。イージングの核心: 登場には spring-snappy、状態変化には spring-smooth、ホバーにのみ ease-snap。"
✓ 品質ゲート: 監査
フェーズ2に進む前に、次を確認してください:
- モーションコンテキストが分類されている(ページ種別、密度、目的)
- モーションパーソナリティがロックされている(Surgical / Physical / Cinematic)
- 動くすべての要素がモーションレイヤーにタグ付けされている
- Element Animation Map がページ上のすべての要素について記入されている - 空の行はありません
- モーションブリーフが書かれている(パーソナリティ名を含む)
- フレームワークが選択されている
フェーズ2: コレオグラフィー
モーションはコレオグラフィーです。すべての要素には登場のキュー、持続時間、イージングカーブ、そして周囲の要素との関係があります。このフェーズではタイミングシート、つまりページの楽譜を作成します。
→ イージングパレット
これはスキル全体の中で最も重要なセクションです。イージングパレットはページ上のすべてのアニメーションの感情的な言語を定義します。間違ったカーブを使うことは、交響曲で間違った音を弾くようなものです - 音楽家でなくてもそれを感じ取れます。
パレットには3つの階層があり、品質の高い順に並んでいます。ブラウザの対応が許す限り、最も高い階層を使用してください。
ティア1: CSS linear() によるスプリング物理 - ゴールドスタンダード
これは Apple が使っているものです。これは Material Design 3 Expressive が使っているものです。これが20万ドルのスタジオサイトとテンプレートを分けるものです。CSS linear() は、オーバーシュートと収束を伴う真のスプリング物理を可能にします - これは cubic-bezier() では根本的に実現できません。
/* BLUEPRINT: Spring-based easing palette via CSS linear()
WHY: Real spring physics create motion that feels PHYSICAL.
Objects in the real world don't follow cubic-bezier curves -
they have mass, momentum, and elasticity. Springs overshoot
their target and settle back, which reads as "alive" to the
human eye. This is why every iOS animation feels tangible.
These curves were generated from spring physics simulations
with specific mass/stiffness/damping parameters. The linear()
function plots the spring's position at discrete time steps,
which the browser interpolates smoothly between. */
:root {
/* 1. APPLE SNAPPY SPRING - Primary entrance/reveal easing
Physics: mass=1, stiffness=400, damping=30
Character: Explosive start, tiny overshoot (~2%), soft settle.
This is the iOS sheet-present / notification-arrive curve.
Use on: hero entries, scroll reveals, modal opens, everything
that "arrives" on screen. This is your DEFAULT curve. */
--spring-snappy: linear(
0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.9%,
0.938 16.7%, 1.017 19.4%, 1.067 22.5%, 1.089 26.0%,
1.079 30.3%, 1.049 36.0%, 1.024 42.6%, 1.011 50.3%,
1.004 59.2%, 1.001 69.3%, 1
);
--spring-snappy-duration: 0.55s;
/* 2. APPLE SMOOTH SPRING - State changes, position shifts
Physics: mass=1, stiffness=200, damping=24
Character: Gentle acceleration, visible overshoot (~5%),
two-phase settle. Feels like a precision instrument.
This is the iOS page-transition / tab-switch curve.
Use on: page transitions, tab switches, carousel slides,
anything moving from position A to position B. */
--spring-smooth: linear(
0, 0.004, 0.016 2.3%, 0.063 4.7%, 0.141 7.2%,
0.25 9.9%, 0.601 16.5%, 0.815 21.0%, 0.929 25.2%,
0.987 29.0%, 1.025 33.5%, 1.042 38.0%, 1.04 43.5%,
1.027 50.0%, 1.013 57.5%, 1.005 67.0%, 1.001 79.0%, 1
);
--spring-smooth-duration: 0.7s;
/* 3. APPLE BOUNCY SPRING - Playful micro-interactions
Physics: mass=1, stiffness=500, damping=18
Character: Very fast, pronounced overshoot (~12%), visible
bounce-settle. Feels playful, energetic, delightful.
Use SPARINGLY on: toggles, like buttons, notification pops,
small badges, emoji reactions. NEVER on large elements. */
--spring-bouncy: linear(
0, 0.014, 0.055 1.8%, 0.218 3.7%, 0.867 8.5%,
1.085 10.7%, 1.212 12.9%, 1.264 15.0%, 1.262 17.0%,
1.217 19.5%, 1.098 24.0%, 1.035 28.5%, 0.993 33.0%,
0.981 38.0%, 0.988 45.0%, 0.998 55.0%, 1.001 68.0%, 1
);
--spring-bouncy-duration: 0.5s;
/* 4. MATERIAL 3 EMPHASIZED - Google's expressive motion standard
Source: Material Design 3 motion spec (legacy cubic-bezier fallback)
Character: Very slow start, dramatic acceleration, gentle decelerate.
This is the M3 "emphasized" transition for container transforms,
shared element transitions, and FAB expansions.
Use on: container morphs, expand/collapse, shared transitions. */
--m3-emphasized: cubic-bezier(0.05, 0.7, 0.1, 1.0);
--m3-emphasized-duration: 0.5s;
/* 5. MATERIAL 3 EMPHASIZED as SPRING - for spring-capable contexts
Physics: mass=1, stiffness=300, damping=22
The spring equivalent of M3 Emphasized - with the overshoot
that Google's spec now recommends via their spring system. */
--m3-spring: linear(
0, 0.007, 0.029 2.0%, 0.118 4.2%, 0.508 10.9%,
0.797 15.4%, 0.951 19.2%, 1.029 22.2%, 1.074 25.6%,
1.088 29.2%, 1.075 33.6%, 1.045 39.5%, 1.02 46.5%,
1.007 55.0%, 1.001 66.0%, 1
);
--m3-spring-duration: 0.6s;
}
ティア2: プレミアムな3次ベジェ曲線 - 強力なフォールバック
linear() をサポートしていないブラウザ向け、またはスプリングのオーバーシュートが不適切な二次的アニメーション(アンビエントモーション、背景の遷移、色の変化)向けです。
:root {
/* 6. SNAPPY DECEL - Tier 2 fallback for spring-snappy
The best cubic-bezier approximation of the Apple snappy spring,
minus the overshoot. Still far better than CSS keyword easings.
Use when linear() is unavailable, or for secondary reveals. */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
/* 7. SMOOTH IN-OUT - for ambient position shifts
Neither Material 3 nor Apple style - this is the Awwwards
agency standard for smooth lateral movements, carousel
auto-play, and background panning. */
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
/* 8. ENERGETIC SNAP - for hover responses, interactive feedback
Faster than --ease-out, designed for immediate tactile response.
The curve front-loads 80% of the motion into the first 30% of
the duration, creating a "snap" sensation. */
--ease-snap: cubic-bezier(0.22, 1, 0.36, 1);
/* 9. DRAMATIC IN-OUT - for hero reveals, cinematic entrances
Extremely slow start ("winding up"), explosive middle,
graceful deceleration. Use for the ONE theatrical moment
per page - the hero heading reveal, a page transition wipe. */
--ease-dramatic: cubic-bezier(0.77, 0, 0.175, 1);
/* 10. CUBIC SPRING APPROXIMATION - bouncy without linear()
The y2 value exceeds 1.0, causing overshoot. This is the
closest cubic-bezier can get to a spring. Less natural than
linear() springs but works everywhere. */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
}
ティア3: CSS キーワードイージング - 禁止
ease、ease-in、ease-out、ease-in-out、linear - これらの CSS キーワードは、タイポグラフィにおける Comic Sans に相当します。キャラクターも、意図も、魂もゼロです。これらはブラウザがデフォルトを必要としたから存在するのであって、デザイナーが選んだからではありません。
| CSS キーワード | 禁止されている理由 | 代わりに使うもの |
|---|---|---|
ease | 何にも合わない汎用カーブ。「これについて考えなかった」イージング。 | --spring-snappy または --ease-out |
ease-in | 遅い開始、速い終了 - 壁に向かって加速するオブジェクト。ほぼ決して望ましくない。 | --ease-dramatic(遅い開始が必要な場合) |
ease-out | ease よりはマシだが、それでも味気なく個性のない減速。 | --spring-snappy または --ease-out(カスタムのもの) |
ease-in-out | 「これを滑らかに見せたい」というデフォルトで、何にも見えない。 | --spring-smooth または --ease-in-out(カスタムのもの) |
linear | 自然界でオブジェクトは一定速度で動かない。ロボット的で死んでいるように感じる。 | 無限ループでの animation-timing-function にのみ許容(マーキー、スピナー) |
⚠ ドリフト警告: コードベースのどこかで transition: all 0.3s ease と書いたなら、その実装は品質基準を満たしていません。すべてのトランジションはパレットの名前付きカーブを使わなければなりません。例外はありません。近道もありません。イージングパレットは、モーション体験全体の DNA です。
→ 3カーブ上限(重要)
これが結束を生み出す制約です。上記の10カーブから、各プロジェクトはちょうど3つを選びます - プライマリ、セカンダリ、ユーティリティを1つずつ。ページ上のすべてのアニメーションはこの3つのいずれかを使います。例外はありません。同じファミリーの3カーブは1つの声のように響き、10カーブは委員会のように響きます。
| パーソナリティ | プライマリ(登場、表示) | セカンダリ(状態変化、遷移) | ユーティリティ(ホバー、フィードバック、環境演出) |
|---|---|---|---|
| 精密 | --ease-out | --ease-in-out | --ease-snap |
| 物理的 | --spring-snappy | --spring-smooth | --ease-snap |
| シネマティック | --ease-dramatic | --spring-smooth | --ease-in-out |
これらは推奨プリセットです。プロジェクトの要件に応じて、カーブを1つ置き換えてもかまいません(例:遊び心のあるプロダクトでは、--spring-snappy を --spring-bouncy に置き換える)。ただし、合計で3つを超えてはいけません。4つ目のカーブを追加したくなった場合は、最初の3つのうちどれかの選択を見直してください。
→ Tier 1 と Tier 2 の選び方:
| アニメーションの種類 | 使用するティア | 理由 |
|---|---|---|
| ヒーローの登場、ページ読み込み時の表示 | Tier 1(--spring-snappy) | 第一印象を左右します。物理的で上質な感触が必要です。 |
| スクロール時の表示 | Tier 1(--spring-snappy) | ユーザーはこれを何十回も目にします。ひとつひとつに生き生きとした感触が必要です。 |
| ボタン/カードのホバー | Tier 2(--ease-snap) | ホバーは素早く機能的なものです。ホバー時のスプリングのオーバーシュートは、ぎこちなく感じられます。 |
| ボタンのクリック/アクティブ状態 | Tier 1(--spring-bouncy) | クリック時のフィードバックには、スプリングの弾みによる心地よい「ポップ」感が効果的です。 |
| モーダル/ダイアログを開く | Tier 1(--spring-smooth) | モーダルは空間的な動きであり、どこかから現れます。スプリングを使うと実在感が生まれます。 |
| タブ切り替え/カルーセル | Tier 1(--spring-smooth) | 位置の変化には、勢いと収束が必要です。 |
| 背景色の変化 | Tier 2(--ease-in-out) | 色には質量がありません。色にスプリングを使うと不自然です。 |
| グラデーションのアニメーション | Tier 2(--ease-in-out)または linear | 環境演出の動きです。スプリングは必要ありません。 |
| ページ遷移 | Tier 1(--spring-smooth) | ページ遷移は空間的に大きな動きです。物理的な感触が必要です。 |
| ツールチップの表示 | Tier 2(--ease-snap) | 素早く機能的で、芝居がかった動きではありません。 |
| アコーディオンの展開 | Tier 1(--spring-snappy)または Tier 1(--m3-spring) | 高さの変化がスプリングで収束すると、上質な感触になります。 |
| 浮遊/環境演出 | CSS の linear キーワード | 連続ループにイージングは必要ありません。一定速度が正解です。 |
→ Framer Motion / Motion のスプリング相当値:
/* BLUEPRINT: Framer Motion spring presets matching the CSS palette
WHY: When using Framer Motion (React), use these spring configs
instead of the CSS linear() values. Framer Motion's spring()
computes physics natively, giving even smoother results than
the CSS approximation. These match the FEEL of the CSS palette. */
const springs = {
// Matches --spring-snappy: fast, minimal overshoot
snappy: { type: "spring", stiffness: 400, damping: 30, mass: 1 },
// Matches --spring-smooth: gentle, visible settle
smooth: { type: "spring", stiffness: 200, damping: 24, mass: 1 },
// Matches --spring-bouncy: playful pop
bouncy: { type: "spring", stiffness: 500, damping: 18, mass: 1 },
// Matches --m3-spring: Material 3 emphasized
emphasized: { type: "spring", stiffness: 300, damping: 22, mass: 1 },
// For hover responses (no spring, just fast decel)
snap: { type: "tween", duration: 0.35, ease: [0.22, 1, 0.36, 1] },
};
// Usage:
// <motion.div transition={springs.snappy} />
// <motion.div transition={springs.smooth} />
→ GSAP のスプリング相当値:
/* BLUEPRINT: GSAP spring-like easing
WHY: GSAP doesn't use spring physics natively, but its
CustomEase plugin can replicate the feel. For standard use,
these "power" easings are the closest GSAP equivalents. */
// snappy: "power3.out" or CustomEase
// smooth: "power2.inOut"
// bouncy: "back.out(1.7)" - the 1.7 controls overshoot amount
// dramatic: "expo.inOut"
// snap: "power4.out"
// For true springs in GSAP, use the gsap-spring plugin:
// gsap.to(".element", { x: 100, ease: "spring({stiffness: 400, damping: 30})" });
→ タイミングシート
すべてのアニメーションを順番に整理します。これがスコアです。
| 要素 | トリガー | 遅延 | 継続時間 | イージング | 変形 | 備考 |
|---|---|---|---|---|---|---|
| ナビゲーション | ページ読み込み | 0ms | 600ms | --ease-out | opacity 0→1, y -20→0 | 最初に表示される要素 |
| ヒーローのアイブロウ | ページ読み込み | 100ms | 700ms | --ease-out | opacity 0→1, y 20→0, blur 8→0 | 段階表示の開始 |
| ヒーローの見出し | ページ読み込み | 200ms | 800ms | --ease-out | opacity 0→1, y 30→0, blur 8→0 | 中心となる焦点 |
| ヒーローのサブテキスト | ページ読み込み | 320ms | 700ms | --ease-out | opacity 0→1, y 20→0 | 見出しが表示された後 |
| ヒーローのCTA | ページ読み込み | 440ms | 600ms | --ease-out | opacity 0→1, y 20→0, scale 0.95→1 | ヒーロー内で最後に表示 |
| セクションの見出し | スクロール(20%表示) | 0ms | 800ms | --ease-out | opacity 0→1, y 40→0 | セクションごと |
| カード | スクロール(15%表示) | 0/80/160ms | 700ms | --ease-out | opacity 0→1, y 30→0 | カードごとに段階表示 |
| CTAボタン | ホバー | 0ms | 500ms | --ease-snap | y 0→-2px, シャドウを強める | 即座に反応 |
| カード | ホバー | 0ms | 400ms | --ease-snap | y 0→-4px, シャドウを強める | 浮き上がる効果 |
タイミングのルール:
| ルール | 値 | 理由 |
|---|---|---|
| 入場シーケンスの最大合計時間 | 800ms | 800msを超えると、ページの読み込みが遅く感じられます |
| 段階表示の間隔 | 80-150ms | 80ms未満では同時に見えます。150msを超えるともたついて感じられます |
| ホバーへの反応 | 体感開始まで ≤ 150ms | ユーザーが即座にフィードバックを感じられる必要があります |
| スクロール時の表示時間 | 600-900ms | 気づける程度に長く、閲覧を妨げない程度に短くします |
| ページ遷移 | 300-500ms | 流れを妨げない程度に速く、遷移を認識できる程度に遅くします |
| マイクロインタラクション(トグル、チェックボックス) | 200-350ms | 演出ではなく、機能的なフィードバックです |
⚠ ブレの警告: AIアニメーションで最もよくある失敗は、すべてを遅くしすぎることです。すべてのセクションを1.5秒かけてフェードインさせると、ページが段階的に表示されるのではなく、読み込み中のように感じられます。スクロール時の表示は900ms未満にしてください。ホバーへの反応は500ms未満にしてください。ページの入場全体は800ms未満にしてください。
→ 段階表示の振り付け
段階表示とは「各項目を100msずつ遅らせる」ことではありません。視覚的な階層に従って段階表示します。
正しい段階表示の順序(上から下へ=最初から最後へ):
1. Container/background (instant or 0ms)
2. Primary content (heading, hero image) - 100ms
3. Supporting content (subtext, description) - 220ms
4. Interactive elements (CTAs, buttons) - 340ms
5. Decorative elements (badges, accents) - 440ms
グリッド内の段階表示(カード、特徴):
For a 3-column grid, stagger left-to-right:
Card 1: 0ms
Card 2: 80ms
Card 3: 160ms
For a 2x3 grid, stagger top-left to bottom-right:
Row 1: 0ms, 80ms, 160ms
Row 2: 120ms, 200ms, 280ms
⚠ ブレの警告: 6~8項目を超えて段階表示しないでください。カードが12枚ある場合、最初の4~6枚を段階表示し、残りはまとめて表示します。12項目を段階表示すると1.2秒以上かかり、項目が1つずつ表示されるのを見ているうちに、ユーザーは待ちきれなくなります。
✓ 品質ゲート:振り付け
フェーズ3に進む前に、次の項目を確認します。
- イージングのパレットが定義されている(CSSのキーワードイージングを使っていない)
- タイミングシートに動く要素がすべて含まれている
- 900msを超えるアニメーションがない
- ページの入場シーケンス全体が800ms未満である
- 段階表示の間隔が80~150msである
- 段階表示がDOMの順序ではなく、視覚的な階層に従っている
- 個別に段階表示する項目が6~8個を超えていない
フェーズ3:モーションを構築する(フレームワークに依存しないルール)
レイヤーごとに実装します。各レイヤーは前のレイヤーを土台にします。レイヤーを飛ばさないでください。膨大な定型コードのブロックを出力しないでください。 代わりに、実際のコードを生成する際は次の制約を適用してください。
物理的な正確さに関するルール
これらのルールはレイヤーを問わず、すべてのアニメーションに適用されます。違反すると、自動品質チェックで不合格になります。
| ルール | 仕様 | 理由 |
|---|---|---|
scale(0) を使用しない | opacity: 0 と組み合わせ、最小でも scale(0.9) から開始します。範囲:UI は 0.9-0.97、控えめな表示は 0.95-0.97。 | 現実世界では、完全な無から何かが現れることはありません。scale(0) は登場ではなく、レンダリングの不具合のように見えます。 |
| 起点を考慮したトランスフォーム | ポップオーバー、ツールチップ、ドロップダウンでは、transform-origin をトリガー要素の位置に設定します。モーダルは例外です。モーダルはトリガーではなくビューポートを基準にするため、transform-origin: center を維持します。 | 要素が起点から広がると、空間的な流れが生まれます。要素自身の中心から広がると、表示のきっかけとなった操作とのつながりが感じられなくなります。 |
| すべての押下操作にフィードバックを設定 | 押下可能な要素すべてに、:active { transform: scale(0.97); transition: transform 160ms var(--ease-snap) } を設定します。控えめな範囲:0.95-0.98。 | ボタンが押下時に見た目上縮むと、インターフェースが操作を受け付けたことを確認できます。押下フィードバックがないと、実際の遅延にかかわらず、UI の応答性が低く感じられます。 |
transition: all を禁止 | 常に対象のプロパティを明示します。例:transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out)。 | transition: all は、変化するすべてのプロパティをアニメーションします。これには background-color、box-shadow、border も含まれ、GPU を使わない描画処理や視覚的な乱れの原因になります。 |
| 非対称のタイミング | 意図的なユーザー操作(押下、長押し、削除の確認)は遅くします。システムの応答(解除、閉じる、確定)は速くします。例:長押し削除のオーバーレイは、押下時に 2s linear で塗りつぶし、指を離すと 200ms var(--ease-out) で元に戻します。 | ユーザーが判断している間は遅くすることで、操作の主導権をユーザーに与えられます。システムの応答を速くすると、ユーザーは安心できます。タイミングが対称的だと、機械的に感じられます。 |
レイヤー 1:登場アニメーション(ページ読み込み時)
ファーストビュー内のすべての要素に、順序を考慮した登場アニメーションを設定します。
- 制約: 視覚的な階層(コンテナ → 見出し → 補足テキスト → CTA → 装飾要素)に基づいて、時間差のある登場アニメーションを使用します。
- CSS:
@keyframesを使用し、transform: translateY(24px)とfilter: blur(6px)から0に変化させ、--ease-outを適用します。animation-delayで時間差を設定します。 - Framer Motion:
staggerChildren: 0.12を使用します。子要素はフェードアップしながらぼかしが解除されるようにします。 - GSAP:
.from()トゥイーンを使ってgsap.timeline()を使用します。ease: "power3.out"を設定します。トゥイーンは-=0.5で重ねます。
レイヤー 2:スクロールに連動する表示
ファーストビューより下の要素は、ユーザーがスクロールして画面内に入ると表示されます。
- 制約: スクロールジャッキング(デフォルトのスクロール動作の抑止)は使用しないでください。スクロール連動(スクラブ)またはしきい値をトリガーとする表示を使用します。
- Vanilla JS: しきい値
0.15、rootMargin: "-50px"でIntersectionObserverを使用します。ぎこちない再アニメーションを防ぐため、最初のトリガー後に監視を解除します。CSS トランジションをトリガーするis-visibleクラスを追加します。 - GSAP:
ScrollTriggerを使用します。固定表示されるナラティブセクションでは、pin: trueとscrub: 1を使用して、アニメーションの進行をスクロール位置に直接連動させます。
レイヤー 3:割り込みへの対応ルール
完了前に再トリガーされる可能性のあるアニメーション(トーストの連続表示、トグル、アコーディオンの連打、すばやいホバー)は、割り込みを適切に処理する必要があります。再トリガー時にアニメーションが最初から再開すると、視覚的なカクつきが生じます。
| 仕組み | 割り込み時の動作 | 使用する場面 |
|---|---|---|
| CSS transitions | 現在の値を起点に目標値を更新します。途中で反転しても滑らかです | ホバー、トグル、アコーディオンの展開/折りたたみなど、すばやくトリガーされる状態変化 |
CSS @keyframes | フレーム 0 から再開するため、ジャンプが生じます | 1 度だけ実行される表示アニメーション(unobserve を使うスクロール時の表示など)、アンビエントループ |
CSS @starting-style | JS を使わずに開始状態を定義し、初回レンダリング時にブラウザーが開始値から遷移します | useEffect を使った回避策を使わずに要素を表示するアニメーション。data-mounted パターンに代わる最新の方法 |
WAAPI (element.animate()) | CSS スレッドのパフォーマンスを保ちながら、JS で制御できます。ハードウェアアクセラレーションに対応し、割り込み可能で、ライブラリーのオーバーヘッドがありません | CSS のパフォーマンスを保ちつつ、JS でタイミングを制御する必要があるプログラムによるシーケンス |
| スプリング(Framer Motion / GSAP) | 割り込み時にも速度を引き継ぎます。最も優れた方法です | ジェスチャー駆動のモーション、ドラッグ操作、ユーザーが動作の途中でつかめるあらゆる場面 |
500ms ルール: ユーザーが 500ms 以内に同じアニメーションを 2 回トリガーできる場合(すばやいクリック、ホバーのすばやい切り替え、トーストの連続表示)、CSS transitions またはスプリングを使用する必要があります。Keyframes ではカクつきが生じます。
レイヤー 8:状態遷移
UI の状態(モーダル、アコーディオン、タブ)間を滑らかに遷移させます。
- モーダル: ネイティブの
<dialog>要素を使用します。::backdropをフェードさせ、ダイアログ自体を拡大・移動させて、2 層の浮き上がり効果を作ります。モーダルはscale(0.95)とopacity: 0から始め、scale(0)にはしません。transform-origin: centerを指定します(モーダルはビューポートを基準に配置されます)。 - アコーディオン: CSS Grid の
grid-template-rows: 0frから1frへの変化を使うと、JS の計算なしで高さを滑らかにアニメーションできます。 - タブ: アクティブ状態を単にクロスフェードさせるだけでは不十分です。アクティブなタブの座標まで
transform: translateXで移動するスライディングインジケーター(絶対位置指定の線)を使い、物理的なつながりを表現します。 - クロスフェードの仕上げ: クロスフェード中に 2 つの状態(古いコンテンツと新しいコンテンツ)が目に見えて重なる場合、中間の遷移中に
filter: blur(2px)を加えると、1 つの変化として自然に見せられます。ぼかしは16px未満にしてください。強いぼかしは、特に Safari で GPU に大きな負荷をかけます。
Layer 8.5:ジェスチャーとドラッグの物理特性
ドラッグ、スワイプ、または閉じることができるサーフェス(ドロワー、シート、トースト、カード、カルーセル)には、次の原則を適用します。
| 原則 | 実装 |
|---|---|
| 速度に基づく閉じ方 | 固定距離のしきい値を超えるまでドラッグすることを求めてはいけません。速度を計算します:Math.abs(dragDistance) / elapsedMs。速度が > 0.11 なら、距離に関係なく閉じます。素早くフリックするだけで十分です。 |
| 慣性の投影 | リリース時に、指数減衰を使って停止位置を投影します:projectedEnd = current + (velocity / 1000) * decayRate / (1 - decayRate)。ここで decayRate ≈ 0.998 です。リリース位置ではなく、投影された位置から最も近いターゲットにスナップします。 |
| 境界でのラバーバンド効果 | 自然な境界(例:ドロワーを最大高さより上に引き上げる)を越えてドラッグする場合、段階的な抵抗を適用します:rubberband(overshoot, dimension, 0.55) = (overshoot * dimension * 0.55) / (dimension + 0.55 * abs(overshoot))。急停止させてはいけません。物理的な物体のように、要素が滑らかに減速するようにします。 |
| ポインターキャプチャ | ドラッグ開始時に element.setPointerCapture(e.pointerId) を呼び出します。これにより、ポインターが要素の範囲外に出ても追跡が続きます。 |
| マルチタッチ保護 | ドラッグが始まったら、追加のタッチポイントを無視します:if (isDragging) return。これを行わずにドラッグ中に指を切り替えると、要素が新しい位置にジャンプします。 |
| 速度の引き継ぎ | ジェスチャーが終了してスプリングアニメーションが始まるとき、指を離した際の速度をスプリングの初期速度として渡します。ドラッグ段階から静止アニメーションへの視覚的な継ぎ目が生じてはいけません。 |
Layer 9:ローディングとプリローダーのシーケンス
- 制約: プリローダーは最小限にします。数値カウンター付きのシンプルな拡大する線(scaleX)は、回転する円よりも高級感があります。
- タイミング: 2.5秒を超える人為的な最小読み込み時間を設定してはいけません。リソース(
document.fonts.ready、画像)の読み込みが完了したら、プリローダーを(例:clip-pathを使って)消去し、ただちに Layer 1 のヒーロー表示を開始します。
レイヤー 10:特徴的なマイクロアニメーション
各ページにつき、以下から1〜3個を厳選してください。控えめに使うことが特徴づけにつながります。すべてが特別なら、何も特別ではなくなります。最大限の注目に値する1つの要素だけ(ヒーロー見出し、メインのCTA、注目ビジュアルのいずれか。3つすべてではありません)に適用してください。ページの残りの部分には、標準的なリビールの手法を使います。このコントラストが、特徴的な瞬間を際立たせます。
- テキストのスクランブル/デコード: ヒーロー見出しや数値に使います。本来のテキストに確定する前に、ランダムな文字(
!<>-_\\/[]{}-=+*^?#_)を次々に表示します。 - ボーダーの描画: ボーダーをフェードインする代わりに、疑似要素を
scaleX/scaleYで0から1へ拡大し、遅延に段階をつけて、ペンで縁をなぞるように見せます。 - クリック時のリップル: メインボタンを押したとき、
e.clientX / e.clientY(カーソル位置)を正確な中心として放射状グラデーションの円を発生させ、不透明度を0にしながら4xまで拡大します。 - ローディング時のシマー: 非同期データに使います。
-20degの角度をつけた線形グラデーションのbackground-positionを200%から-200%へ動かします。 - 変形するブロブ背景: ヒーローに奥行きを加えます。絶対配置した要素に8つの値を持つ
border-radius(例:60% 40% 30% 70% / 60% 30% 70% 40%)を設定し、約8秒かけてアニメーションさせます。 - 傾きのあるパララックスカード: ホバー時にマウス位置を追跡し、
data-depthの倍率に基づいて内部レイヤーをわずかにtranslate(x,y)させ、3Dジオラマのような効果を作ります。 - ツールチップの浮き上がり: ホバーしてから100ms遅らせて、ツールチップを下から浮き上がらせます。これにより、カーソルが通り過ぎたときに誤って一瞬表示されるのを防ぎます。遅延の省略ルール: グループ内のツールチップがすでに開いている場合、同じツールバー/グループ内の次のツールチップは、遅延もアニメーションもなしですぐに開きます。これにより、ツールバー全体を素早く操作できます。
- カーソルに引き寄せられる要素: インタラクティブ要素が、カーソルが約40pxの近接範囲に入ると、カーソルに向かってわずかに引き寄せられます。オフセットにはスプリング補間を使います。マウスの動きを直接追跡すると機械的に感じられますが、スプリング補間を使えば生き生きとした印象になります。
- グラデーションボーダー:
@property --gradient-angleを使ったconic-gradientを3秒かけて直線的にアニメーションさせ、生き生きと回転する縁を作ります。 - カーソルトレイル: 要望がある場合は、カーソルを正確に追跡する小さな点と、わずかな遅延の補間(lerp)で追従する大きめの中空円を使い、弾力のある動きを表現します。タッチデバイスでは非表示にします。
- クリップパスによるリビール: 大きなセクション間の切り替えでは、
clip-path: circle(0% at 50% 50%)の円を150%まで広げて、次のセクションを表示します。
フェーズ 4:モーション差分
アニメーションをモーションブリーフおよびタイミングシートと照らし合わせて比較します。すべてのカテゴリを確認してください。不合格が1つでもあれば、納品できません。
⚡ カバレッジチェック(必須 — 最初に実行)
| チェック | 合格/不合格 |
|---|---|
| ページ上のすべての見出しに、スクロール表示またはエントリーアニメーションがある | |
| すべての段落/本文テキストに、最低限フェードアップ表示がある | |
| すべてのカードに、スクロール表示とホバー状態(浮き上がり+影)がある | |
| すべてのボタンに、ホバー(浮き上がり/ワイプ/色変化)+アクティブ(押下)+フォーカス可視状態がある | |
| すべてのリンクに、ホバー時の下線アニメーションまたは色の変化がある | |
| すべての画像に、表示アニメーション(クリップパス、スケールイン、またはフェード)がある | |
| すべての入力欄に、フォーカス状態(グロー、境界線の変化、またはラベルアニメーション)がある | |
| すべてのセクションに、スクロールをトリガーとするエントリーアニメーションがある(ただ「そこにあるだけ」のセクションがない) | |
| すべての装飾要素に、環境的な動き(浮遊、回転、パルス)がある | |
| すべての区切り/線に、拡張(scaleX)またはフェードによるアニメーションがある | |
| すべてのアイコンに、ホバー時のフィードバック(色、スケール、または回転の変化)がある | |
| スクロールして表示されたとき、統計値/数値が0からカウントアップする | |
| ナビゲーションバーに、ページ読み込み時のエントリーアニメーションがある | |
| フッターのコンテンツに、スクロールをトリガーとする順次表示がある | |
| ページ全体を上から下までスクロールして確認したとき、静的な要素が一つもない |
⚠ 不合格の行が一つでもある場合は、作業を進める前に戻って不足しているアニメーションを追加してください。これは必須です。アニメーションの適用率が90%のページには、プレミアムな印象を損なう動きのない箇所が残ります。
印象チェック
| チェック | 合格/不合格 |
|---|---|
| ページの表示が合計800ms以内に完了する | |
| アニメーションなしで突然表示される要素がない | |
| 順次表示が視覚的な階層に従っている(見出し、補足テキスト、CTAの順) | |
| スクロール表示が自然なタイミング(要素が約15~20%表示された時点)でトリガーされる | |
| ホバー時のフィードバックがすぐに始まる(体感で150ms以内) | |
| 遅く感じたり、ユーザーを待たせたりするアニメーションがない | |
| コンテンツではなくアニメーション自体が目立つことがない | |
| **一貫性テスト:**ページを動きだけに注目して見てください(目をぼかします)。すべてのアニメーションが同じ系統に属していると感じられますか?速度の範囲、強さ、個性は一貫していますか? | |
| **総合テスト:**どれか一つのアニメーションが派手でなくても、ページに「プレミアム」な印象がありますか?目標は、目立つ演出を一つ加えることではなく、目立たない正しい選択を20個積み重ねることです |
イージングチェック
| チェック | 合格/不合格 |
|---|---|
| 表示されるアニメーションにCSSキーワードのイージング(ease、ease-in、ease-out)を使用していない | |
| すべてのエントリーアニメーションで --ease-out(きびきびと減速)が使われている | |
| すべてのホバー操作で --ease-snap(勢いよく動き出す)が使われている | |
| すべての状態遷移で --ease-in-out(滑らか)が使われている | |
| ページ全体でイージングのパレットに一貫性がある |
パフォーマンスチェック
| チェック | 合格/不合格 |
|---|---|
すべてのアニメーションで、transform と opacity のみを使用している(clip-pathによる表示とfilter:blurによるエントリーを除く) | |
top、left、width、height、margin、padding をアニメーションしていない | |
transition: all をどこにも使わず、すべてのトランジションで対象のプロパティを明示している | |
will-change を、実際にアニメーションしている要素にのみ適用している | |
アニメーション完了後(1回限りのアニメーションの場合)に will-change を削除している | |
スクロールする要素に backdrop-filter を使っていない(fixed/stickyのみ) | |
スクロールリスナーで { passive: true } を使っている | |
| すべてのアニメーション中、ページが60fpsを維持している(DevTools → Performanceで確認) | |
| レイアウトの読み取りと書き込みをループ内で行うレイアウトスラッシングがない | |
Framer Motion:負荷の高いページでは x/y/scale の省略記法プロパティを使わず、GPUアクセラレーションのために animate={{ transform: "translateX(100px)" }} を使用している | |
子要素のtransformを親要素のCSS変数で制御していない(例:--swipe-amount)。スタイル再計算が頻発しないよう、要素に直接 transform を設定している |
アクセシビリティの確認
| 確認項目 | PASS/FAIL |
|---|---|
すべての動きが prefers-reduced-motion: reduce に従っている | |
| モーションを抑えたときの代替表示は、不透明度のみのフェード(トランスフォーム、視差、スプリングのオーバーシュートなし)になっている | |
ホバーアニメーションが @media (hover: hover) and (pointer: fine) の条件下にある — タッチデバイスではタップ時にホバーが発生し、誤作動の原因になるため | |
分割表示のテキストに、元のテキストを保持する aria-label がある | |
| 重要な情報がアニメーションのみによって伝えられていない | |
| フォーカス状態が明確に表示され、アニメーションによって隠されていない | |
| 自動再生アニメーション(マーキー、浮遊、グラデーション)を一時停止できる(WCAG 2.2.2) | |
| タッチデバイスではカスタムカーソルが表示されない |
技術的な確認
| 確認項目 | PASS/FAIL |
|---|---|
| スクロール時の表示にスクロールイベントリスナーではなく、IntersectionObserver を使用している | |
スクロール連動アニメーションで、スクロールイベントによるトリガーではなく scrub を使用している | |
Lenis を使用する場合、タッチデバイスでは smoothTouch: false にしている | |
| 明確な理由がない限り、ネイティブのスクロール動作を上書きするスクロールジャッキングを行っていない | |
| モバイルでは視差を無効にしている(性能の低いデバイスでは動作がぎこちなくなるため) | |
| モバイル/タッチデバイスではカスタムカーソルを無効にしている | |
| プリローダーが最大 3 秒以内にコンテンツを表示する | |
| アニメーションの初期化前に FOUC(スタイル未適用コンテンツのちらつき)が発生しない |
構成の確認
| 確認項目 | PASS/FAIL |
|---|---|
| 画面上で同時に動作する複雑なアニメーションが最大 2~3 個である | |
| 動きが競合していない(同時に 2 つの要素が注意を奪い合っていない) | |
| アンビエントモーション(浮遊、グラデーション)がインタラクティブな動きを妨げていない | |
| アニメーションの密度がモーションブリーフ(最小/中程度/豊富)に合っている | |
| パーソナリティの一貫性を維持: ページ上のすべてのアニメーションが、選択したパーソナリティ(Surgical/Physical/Cinematic)に沿っている。パーソナリティの逸脱はゼロ。 | |
| イージングカーブは最大 3 種を維持: ページ全体で使用するイージングカーブは 3 種のみ。CSS を grep し、4 種目のカーブが見つかったら、パレットから逸脱している。 | |
強度の一貫性: スクロール時の表示ではすべて同じトランスフォーム距離を使用する(例:translateY(24px) に統一し、20/30/40/60 を混在させない)。ホバー時の浮き上がりではすべて同じオフセットを使用する(例:-4px に統一し、混在させない)。スタッガーの遅延もすべて同じ増分を使用する。 | |
| 特徴的なマイクロアニメーションは、あちこちに散らさず、注目させたい要素の最大 1~3 個に使用する |
アンチパターン
プレミアムな動きを素人っぽいアニメーションに変えてしまう、具体的な失敗例です。すべて確認してください。
❌ つぎはぎモーション
セクションごとに異なるイージングの種類を使用しています。ここではスプリング、あちらではドラマチックなカーブ、別の場所ではリニアなスナップ。それぞれのアニメーションは単体では問題なくても、ページ全体がつぎはぎに感じられます。修正: フェーズ 1 でパーソナリティを選び、イージングカーブは最大 3 種に制限します。すべてのアニメーションを同じイージングの種類にそろえます。ヒーローで --spring-snappy を使うなら、スクロール時の表示にも --spring-snappy を使います。カードのホバーに --ease-snap を使うなら、インタラクティブな要素すべてのホバーに --ease-snap を使います。一貫性が、ページが「プレミアム」に感じられるか「まとまりがない」と感じられるかを決める最大の要因です。
❌ 遅すぎる表示
すべてが 1.5 秒かけてフェードインします。ページの読み込みが止まっているように感じられます。修正: 表示アニメーションは 800ms 未満にします。ユーザーが求めているのはコンテンツであり、幕が上がるのを待つことではありません。
❌ スクロールカーニバル
すべての要素が異なるアニメーションになっています。ある要素は左からスライドし、別の要素は跳ね、さらに別の要素は回転しながら現れます。修正: スクロール時の表示には、1 種類のアニメーション(ぼかし解除を伴うフェードアップ)をすべてに使用します。一貫性は意図的なデザインとして伝わります。
❌ ホバーディスコ
ボタンは 1.1 倍に拡大し、カードは回転し、リンクはさまざまな色に点滅します。修正: ホバーエフェクトは控えめにします。カードは 2px 浮き上がらせて影を広げ、ボタンは背景色を変化させます。ユーザーを驚かせてはいけません。
❌ 視差スープ
すべてのセクションに、視差レイヤーが 5 層あります。前景、中景、背景がそれぞれ異なる速さで動きます。修正: 1 つのビューポートあたりの視差レイヤーは最大 2 層にします。控えめに動く背景を 1 つ、浮遊する要素を 1 つにします。それ以上は乗り物酔いの原因になります。
❌ テキストの分解演出
すべての見出しで文字を分割し、ランダムな位置から再構成しています。修正: 文字分割はページあたり最大1つの見出しに限定してください。セクション見出しには単語単位の表示演出を使います。それ以外にはシンプルなフェードアップを使います。
❌ 終わらないプリローダー
コンテンツが表示される前に、凝ったアニメーションを伴う5秒間のプリローダーを表示しています。修正: プリローダーは最大2.5秒にしてください。コンテンツの読み込みがそれより早く終わった場合は、プリローダーも早く終了します。人為的な遅延は決して追加しないでください。
❌ 動きを減らす設定への未対応
prefers-reduced-motion メディアクエリがどこにもありません。修正: すべてのアニメーションで prefers-reduced-motion: reduce を条件にし、代替表示は不透明度の変化だけにしてください。
❌ レイアウトをアニメーションする演出
width、height、top、left、padding、margin、border-radius をアニメーションしています。修正: アニメーションするのは transform と opacity だけにしてください。width/height の代わりに transform: scale() を使います。top/left の代わりに transform: translate() を使います。
フレームワーク選定マトリクス
| プロジェクトで使用しているもの... | 使用するモーションスタック |
|---|---|
| Vanilla HTML/CSS/JS | CSS キーフレーム+トランジション+IntersectionObserver。スクロール固定や複雑なタイムラインが必要な場合のみ GSAP を追加します |
| React(フレームワークなし) | Framer Motion(motion/react)。AnimatePresence、レイアウトアニメーション、ジェスチャー検出に対応しています |
| Next.js | Framer Motion+ページ遷移には View Transitions API |
| Vue | <Transition>/<TransitionGroup> コンポーネント+スクロールには GSAP |
| Astro | View Transitions API(組み込み)+CSS アニメーション+スクロールには GSAP |
| Svelte | 組み込みの transition: および animate: ディレクティブ+スクロールには GSAP |
GSAP を使うべき場面:
- スクロールに応じてコンテンツが変化する、スクロール固定(スティッキー)シーケンス
- 横スクロールのセクション
- 複数のアニメーションが重なり合う複雑なタイムライン
- SplitText プラグインを使ったテキスト分割(有料ですが、クラス最高の品質です)
CSS で十分な場面:
- 登場時のアニメーション(キーフレーム+animation-delay)
- ホバー時の状態(トランジション)
- シンプルなスクロール時の表示演出(IntersectionObserver+CSS トランジション)
- 浮遊感のある動き/アンビエントな動き(キーフレーム+無限ループ)
- アコーディオン/タブの状態変化(トランジション)
Apple レベルのモーション基準
これらは、Apple/Awwwards のモーションをそれ以外と分ける、譲れない基準です。フレームワークにかかわらず適用されます。しっかり覚えてください。
スプリング物理は必須です。 主要なアニメーション(登場、表示、モーダル、トランジション)にはすべて、CSS の
linear()スプリングカーブまたは Framer Motion のスプリングを使用してください。cubic-bezier が許容されるのは、ホバー、色の変化、アンビエントなど、補助的なモーションに限られます。ページが「物理的」ではなく「デジタル」に感じられるなら、イージングが間違っています。
Material 3 Expressive が基準です。 Google の M3 Expressive イージングである
cubic-bezier(0.05, 0.7, 0.1, 1.0)が、あらゆるトランジションに求められる最低限の品質です。イージングがこれほど意図的でない場合は、置き換えてください。
すべてのカーブは意識的に選びます。 同じ 400ms のアニメーションでも、
ease、cubic-bezier(0.16, 1, 0.3, 1)、スプリングのlinear()では、感情に与える反応がまったく異なります。それぞれ、一般的、プロフェッショナル、生き生きとした印象になります。各カーブを選んだ理由を説明できなければなりません。
スタガーがストーリーを生みます。 要素が同時に現れるのは、データの羅列です。順番に現れるのは、ストーリーです。スタガーの順序が、そのまま視覚的な階層になります。Apple は 80~120ms の精度でスタガーを設定しています。
モーションは、抑制と強さの両立です。 受賞歴のあるサイトは、アニメーションの数が多いのではなく、少ない一方で、それぞれがより洗練されています。単語をマスクした、スプリング物理によるテキスト表示ひとつのほうが、ありきたりなフェードイン 20 個より価値があります。常に量より質を重視してください。
パフォーマンスは妥協できません。 45fps のアニメーションは、アニメーションがないより悪いものです。アニメーション化するのは
transform、opacity、filterのみにしてください。CPU をスロットリングしてテストしてください。60fps に達しない場合は、達するまでシンプルにしてください。will-changeは必要な箇所に限定して使用してください。
モーション軽減への対応は必須です。 すべてのアニメーションは
prefers-reduced-motionの条件に従わせてください。軽減版では、短い時間の不透明度のみのフェードを使用します。トランスフォーム、パララックス、スプリングのオーバーシュート、スクロール連動のシーケンスは使いません。
最終テストです。 ページのスクリーンショットを撮り、apple.com、linear.app、vercel.com、stripe.com のいずれかの隣に並べてください。モーションデザインが別の惑星のもののように見えるなら、最初からやり直してください。それらのサイトのページとして違和感がなければ、合格です。