Communitygithub.com

Apple Design(アップルデザイン)

Appleのインターフェースデザインと流れるような物理モーションをWeb向けに翻訳したものです。ジェスチャー駆動のUI、スプリングアニメーション、ドラッグ/スワイプ/シート操作、慣性と割り込み可能なトランジション、半透明マテリアルと奥行き、タイポグラフィ(オプティカルサイズ、トラッキング、行送り)、動きの抑制、またはAppleスタイルのインターフェースの背後にあるデザイン基盤(フィードバック、空間的一貫性、抑制)を構築またはレビューする際に使用します。

Apple Design(アップルデザイン) とは?

このスキルは、AppleのWWDCデザイントーク(特に『Designing Fluid Interfaces』2018)から抽出された、Appleのような流動的で生き生きとしたインターフェースをWeb上で構築するための包括的な原理と実践的な実装ガイドを提供します。中心となる概念は、アニメーションが現在の画面上の値から始まり、ユーザーの速度を継承し、運動量を前方に投影し、任意の瞬間に掴んで逆転できることです。スプリングアニメーションは、本質的に割り込み可能で速度を認識するため、これを実現するための主要なツールとして推奨されています。このスキルは、CSS、Pointer Events、requestAnimationFrame、MotionやFramer Motionなどのスプリングライブラリを含む主要なWebプラットフォームをサポートし、応答性、直接操作、割り込み可能性、速度の引き継ぎ、運動量の投影、空間的一貫性、ラバーバンディング、マテリアルと奥行き、マルチモーダルフィードバックなど、13の主要な設計原則をカバーしています。これは、Appleのデザイン哲学を理解し、それを具体的なWeb実装に変換したいと考えているWeb開発者やUIデザイナーにとって非常に貴重であり、フロントエンドフレームワークやライブラリに依存しない、実用的なコード例と実装戦略を提供します。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ZainR525/PersonalWebsiteZainRizvi/tree/HEAD/.claude/skills/apple-design

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

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

ドキュメント

Apple Design(アップルデザイン) は何をしますか?

初期応答

このスキルが特定の質問なしで最初に呼び出された場合、次のようにのみ応答します。

Appleスタイルの流動的なインターフェースをWeb上で構築するお手伝いをします。私の知識はAppleのWWDCデザイントークを基に、Web向けに翻訳されたものです。

ユーザーが質問するまで、他の情報は提供しないでください。

Appleがどのようにして、コンピューターのように感じられず、あなたの延長のように感じられるインターフェースを構築しているか。この知識は、AppleのWWDCデザイントーク、主に『Designing Fluid Interfaces』(WWDC 2018)から抽出され、Webプラットフォーム(CSS、Pointer Events、requestAnimationFrame、Motion/Framer Motionなどのスプリングライブラリ)向けに蒸留・翻訳されたものです。

一貫したテーマ:モーションが現在の画面上の値から始まり、ユーザーの速度を継承し、運動量を前方に投影し、任意の瞬間に掴んで逆転できるとき、インターフェースは生き生きと感じられます。 スプリングは、これらすべてを自然にするためのツールであり、本質的に割り込み可能で速度を認識するからです。

核となるアイデア

「インターフェースを私たちの考え方や動き方に合わせると、魔法のようなことが起こります——それはコンピューターのように感じられなくなり、私たちのシームレスな延長のように感じられるのです。」

インターフェースが流動的であるとは、物理的な世界のように振る舞うことです。つまり、物事が即座に応答し、連続的に動き、運動量を運び、境界で抵抗し、動きの途中で方向転換できることです。以下のすべては、それに近づくための方法です。

Appleはデザインを、人間の4つのニーズに応えるものとして位置づけています:安全性/予測可能性、理解、達成、喜び。 ここでのすべてのルールは、そのいずれかに役立ちます。

1. 応答——レイテンシをなくす

遅延が現れた瞬間、直接性の感覚は「崖から落ちる」ように失われます。応答は、他のすべてが構築される基盤です。

  • ポインターダウン時に応答し、解放時ではない。 ボタンが押された瞬間にハイライトします。click/タッチアップまでフィードバックを待つと、死んでいるように感じられます。
  • あらゆるレイテンシに注意を払う。 デバウンス、人為的なタイマー、トランジション待ち、そして約300msのタップディレイを監査します。入力パス上で必須でないものはすべて後退です。
  • フィードバックは、インタラクション中継続的でなければならず、最後だけではない。 ドラッグ、スライダー、またはドロワーの場合、ポインターと1:1で常にUIを更新し、ジェスチャーが完了したときだけアニメーションさせないでください。
/* フィードバックは押下時に存在し、即座に行われる */
.button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

2. 直接操作——1:1トラッキング

「タッチとコンテンツは一緒に動くべきである。」

ユーザーが何かをドラッグするとき、それは指に貼り付いたままにならなければなりません——そして、掴んだ場所からのオフセットを尊重します。掴んだときに要素の中心にスナップすると、その錯覚は即座に壊れます。

  • setPointerCaptureを使用したPointer Eventsを使用して、ポインターが要素の境界から外れてもトラッキングが継続されるようにします。
  • 現在のポイントだけでなく、短い速度/位置の履歴(最後のいくつかのpointermoveイベント)を追跡します。解放時に速度が必要になります。
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // 掴んだ場所を尊重
  // ...速度のための位置+タイムスタンプ履歴を追跡
});

3. 割り込み可能性——最も重要な単一の原則

「思考とジェスチャーは並行して発生する。」

すべてのアニメーションは、いつでも割り込んで方向転換できなければなりません。ユーザーは、動いている要素を途中で掴んで、アニメーションが終わるのを待たずに逆転できなければなりません。閉じようとしているモーダルをユーザーが再び掴んだ場合、最初に閉じ終わってから再開するのではなく、指に従うべきです。

  • トランジション中に入力をロックアウトしてはいけません。
  • 常にプレゼンテーション(現在の)値からアニメーションし、ターゲット値からではない。 割り込み時には、要素のライブな画面上のトランスフォームを読み取り、そこから新しいアニメーションを開始します。論理的な/ターゲット値から開始すると、目に見えるジャンプが発生します。
  • ジェスチャー駆動のものには、CSSトランジションと@keyframesを避ける——これらは途中でスムーズに掴んで逆転することができません。スプリングはデフォルトで現在の値からアニメーションするため、割り込みに正確に必要なものです。
  • ジェスチャーが逆転するときは、速度をブレンドし、ハードカットしない。 逆転時に1つのアニメーションを別のアニメーションに置き換えると、速度の不連続性、つまり「レンガの壁」が生じます。再ターゲットを通じて速度を運ぶスプリングライブラリはそれを回避します。(これはiOSの加算アニメーションがネイティブに行うことです。Web上では、現在の速度から再ターゲットするスプリングライブラリを選択してください。)
  • 2Dモーションを独立したXとYのスプリングに分解する。 2D距離に対する単一のスプリングは、XとYが異なる速度を持つときに同期が取れなくなります。

4. アニメーションではなく振る舞い——スプリングを使用する

「アニメーションを、インターフェースによって規定されたものではなく、あなたとオブジェクトの間の会話として考えてください。」

スクリプト化された、固定長のアニメーションは新しい入力に応答できません。スプリングはそれができます——新しい入力は単にターゲットを変更し、モーションは連続したままです。ユーザーが触れる可能性のあるものにはスプリングを活用してください。

Appleは意図的に、物理の3つ組(質量/剛性/減衰)を、デザイナーにとってより親しみやすい2つのパラメータに置き換えました。これらで考えてください:

  • 減衰比——オーバーシュートを制御します。1.0 = 臨界減衰、バウンドなし、スムーズな整定。< 1.0 = オーバーシュートして振動します。低いほどバウンドが強くなります。
  • 応答——値がターゲットに到達する速さ(秒単位)。低いほどスナッピーになります。これは「継続時間」ではありません——スプリングに固定の継続時間はなく、整定時間はパラメータから生じます。

デフォルト:

  • ほとんどのUIは減衰1.0(臨界減衰)から始める——優雅で気を散らせません。
  • ジェスチャー自体が運動量を持っていた場合にのみ(フリック、スロー、ドラッグ解放)、バウンド(減衰〜0.8)を追加します。ちょうどフェードインしたメニューのオーバーシュートは間違っているように感じられますが、フリックしたカードのオーバーシュートは正しく感じられます。

Appleが出荷する具体的な値:

インタラクション減衰応答
移動/再配置(例:PiP)1.00.4
回転0.80.4
ドロワー/シート0.80.3

Webマッピング(Motion / Framer Motion): bounce + durationスプリングAPIは、Appleの減衰+応答に密接にマッピングされます。安全なハウススタイルは、デフォルトでdamping: 1.0スプリングをあらゆる場所に使用し、バウンドは運動量駆動の物理的インタラクションのために予約することです。

import { animate } from 'motion';

// 臨界減衰デフォルト(オーバーシュートなし)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// 運動量インタラクション——少しバウンド、それが先行するフリックがあった場合のみ
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. 速度の引き継ぎ——ドラッグとアニメーションの間の継ぎ目

ジェスチャーが終了したとき、アニメーションは指の正確な速度で継続しなければならず、ドラッグとアニメーションの間に目に見える継ぎ目があってはなりません。これは「流動的」と「まあまあ」を最も区別する詳細です。

ポインターの解放速度をスプリングの初速度として渡します。一部のスプリングAPIは相対速度を必要とします——それをターゲットまでの残りの距離で正規化します:

relativeVelocity = gestureVelocity / (targetValue − currentValue)

例:要素がy=50、ターゲットがy=150(残り100px)、指が50px/sで移動→スプリング初速度 = 50 / 100 = 0.5。Framer Motion / Motionは絶対px/s速度を直接受け入れるため(velocityオプション)、通常は生の値を渡します。

6. 運動量の投影——ジェスチャーが向かっている場所にアニメーションする

「小さな入力を受け取り、大きな出力を生成する。」

解放点から最も近い境界にスナップしないでください。速度を使用して静止位置を投影します——スクロールの減速とまったく同じように——そして、その投影された点に最も近いターゲットにスナップします。これにより、フリックが要素を投げているように感じられます。

Appleの正確な投影関数(『Designing Fluid Interfaces』サンプルコードから):

// decelerationRate ≈ 0.998(通常のスクロール感覚の場合)、0.99(よりスナッピーな場合)
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}

const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint);   // 投影からターゲットを選択
animateSpringTo(target, { velocity: releaseVelocity }); // 次に速度を引き継ぐ(§5)

注意:物理学の教科書にある v²/(2·dec) は、Appleが出荷しているものではありません——上記の指数減衰形式を使用してください。これは優れたボトムシートやカルーセル(Vaul、Embla)での標準的な動作です。

7. 空間的一貫性——対称的なパス、固定された原点

「何かが一方から消えた場合、それが来た場所から現れることを期待します。」

  • 同じパスに沿って出入りする。 右からスライドインするパネルは、右に閉じなければなりません。右から入って下から出るのは、まとまりがなく混乱を招きます。
  • インタラクションをその発生源に固定する。 メニュー、ポップオーバー、またはシートは、それをトリガーした要素から発生するべきです——transform-originをトリガーに設定し、ボタンとコンテンツの間の空間的関係が明確になるようにします。(これは、ポップオーバーがその中心ではなくトリガーからスケーリングするという、同じ原点認識のポイントです。)
  • 可逆的なトランジションではイージングをミラーリングする これにより、出力パスが戻りのパスと一致します(2つの方向に対して逆の3次ベジェ制御点を使用します)。

8. ジェスチャーの方向をほのめかす

人間は軌道から最終状態を予測します。中間のフレームは、物事がどこに向かっているかを示すべきです——コントロールセンターモジュールは「あなたの指に向かって上と外に成長します」。中間フレームが結果を指し示すようにし、単に盲目的に補間しないでください。

9. ラバーバンディング——ソフトな境界

境界では、ハードストップする代わりに徐々に抵抗します。ハードストップは「フリーズした」と読まれます。連続的な抵抗は「応答性はあるが、ここにはもう何もない」と読まれます。ユーザーが境界を超えてドラッグするほど、減衰が増加するものを適用します。

// 境界を超えるほど、要素の追従は少なくなる——実際の物体は止まる前に減速する
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

10. ジェスチャーデザインの詳細(「フィール」チェックリスト)

  • タップ: タッチダウン時(即座)にハイライトし、タッチアップ時にコミットします。ターゲットの周りに約10pxのヒステリシス/ヒットパディングを追加し、ドラッグアウェイとバックによるキャンセルを許可します。
  • ドラッグ/スワイプ: 方向にコミットする前に小さな移動しきい値(ヒステリシス、約10px)を必要とし、その後1:1で追跡します。
  • 最初の動きから並行してすべての妥当なジェスチャーを検出し、意図が明確になったら自信を持って敗者をキャンセルします。最終的な状態のみを報告する認識器(swipeleftタイプのイベント)は避けてください——それらはフィードバックに必要な連続的な追跡を捨ててしまいます。
  • 曖昧性解消の遅延を最小限に抑える。 ダブルタップ検出は避けられずにシングルタップを遅延させます。ダブルタップが実際に存在する場合にのみ、そのコストを支払ってください。

11. フレームレベルのスムーズさ

スムーズさとは、フレームレートだけでなく、フレーム内にあるものについてです。

  • ストロボ効果を避けるために、フレームごとの位置変化を知覚しきい値以下に保ちます。
  • 非常に速いモーションの場合、微妙なモーションブラー/ストレッチが速度をエンコードし、硬く鋭い筋よりもよく読み取れます。
  • requestAnimationFrameはWebのディスプレイ同期クロックです(AppleはCADisplayLinkを使用します)。コンポジッターに適したプロパティのみをアニメーションさせます——transformとopacity——そして、モーションが差し迫っている場所ではwill-changeでヒントを与えます。

12. マテリアルと奥行き——半透明が階層を伝える

Appleは半透明マテリアルを、フォーカスを奪うことなく構造をもたらす浮遊する機能レイヤーとして使用します。Web上では、backdrop-filterで近似します。

  • ナビゲーション/ツールバー/シートを半透明レイヤーとして構築する(backdrop-filter: blur() + 半透明の背景)、コンテンツはその下をスクロールします——固定ストリップを消費する不透明なバーではありません。
  • マテリアルの重みが階層をエンコードする: より暗く/より重いマテリアルは構造領域(サイドバー)を分離します。より明るいマテリアルはインタラクティブ要素(ボタン)に注意を引き付けます。明るい半透明の表面を別の上に重ねてはいけません——可読性が崩れます。
  • より大きな表面はより厚く読まれるべき: 小さなチップよりも強いブラーと深いシャドウ。コンテキストに応じたシャドウを検討してください——分離のために忙しい/テキストコンテンツの上ではより強く、プレーンな背景の上ではより軽く。
  • フォーカスするために暗くし、流れを維持するために分離する。 モーダルタスクは、表面と暗くするスリムを組み合わせ、背景を押し戻し/下げます。パラレルで非ブロッキングなパネルは、フローを壊さないようにスリムなしで半透明とオフセットを使用します。積み重ねられたシートの場合、各親レイヤーを徐々に暗くし、押し戻します。
  • ビブランシーは、変化する背景の上でテキストを読みやすく保ちます。 ぼやけた/半透明の表面の上では、フラットなグレーのテキストを使用しないでください——より高いコントラスト、わずかに太いウェイト、そして小さな文字間隔のバンプを使用してください。色は半透明の前景ではなく、ソリッドなレイヤーに配置してください。
  • ハードな仕切りではなく、スクロールエッジ効果。 スティッキーヘッダーの下の1pxのボーダーの代わりに、コンテンツが浮遊するクロームと重なる場所に小さなぼかし/グラデーションマスクをフェードさせます——浮遊UIが実際にコンテンツと重なる場所にのみ。
  • 単にフェードするのではなく、マテリアライズする。 ガラス/ぼかし表面の場合、出入り時にブラー半径とスケールを一緒にアニメーションさせ、表面が単なる不透明度のフェードではなく、到着する実際のマテリアルとして読み取られるようにします。
.toolbar {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 1px solid rgba(255, 255, 255, 0.4); /* 明るい上端 = マテリアルに当たる光 */
}

13. マルチモーダルフィードバック——モーション + サウンド + ハプティクス

感覚を組み合わせるための3つのルール(『Designing Audio-Haptic Experiences』から):

  1. 因果関係——フィードバックの原因が明らかでなければなりません。実際の因果イベント(トグルが切り替わる、アイテムが元の位置に収まる)でトリガーし、その特性をアクションの物理性に合わせます。
  2. 調和——視覚、サウンド、ハプティクスは同じフレームで発火しなければなりません。それらの間のレイテンシは錯覚を破壊します。アニメーションが遅延を許さないのと同様に、感覚間の遅延も許してはいけません。
  3. 一貫性——同じクラスのアクションは、同じフィードバックを生成しなければなりません。あるトグルが「クリック」し、別のトグルが沈黙している場合、それは不安定で信頼できなくなります。

注意:Appleは、HIDデバイスの世界(ホイール、トラックパッド)にプレシジョン(精密)とアジリティ(機敏性)の概念も含めており、それもここにマッピングできます。ユーザーが速く動けば動くほど、システムはより遠くに投影します。

関連スキル