Communitygithub.com

grahama1970/apple-design

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

apple-design とは?

このスキルは、AppleのWWDCデザイントーク(特に2018年の「Designing Fluid Interfaces」)から抽出された、Appleのインターフェースデザイン哲学をウェブプラットフォーム(CSS、Pointer Events、requestAnimationFrame、Motion/Framer Motionなどのスプリングライブラリ)に翻訳した包括的なガイドです。中核となる原則は、ユーザーの操作に即座に反応し、物理的な慣性を持ち、常に割り込み可能でリダイレクト可能なインターフェースを作成することです。応答性、直接操作、割り込み可能性、スプリングベースのアニメーション、速度の引き継ぎ、慣性投影、空間的一貫性、ラバーバンディング、マテリアルデザイン、マルチモーダルフィードバック、アクセシビリティなど、14の主要な設計原則を詳細にカバーしています。各原則は、具体的なコード例、CSSスニペット、JavaScript実装(Pointer Events setPointerCapture、速度履歴の追跡、慣性投影関数など)とともに説明されています。このスキルは、Claude Code、Cursor、CodexなどのAIエージェントが、Appleスタイルのジェスチャー駆動UIを構築またはレビューする際に、設計上の判断を下すための実用的なリファレンスとして機能します。Motionライブラリのスプリングパラメータ(bounceとduration)をAppleの減衰比(damping)と応答(response)にマッピングする方法や、Appleの正確な慣性投影アルゴリズム(指数減衰形式)など、ウェブ開発者にとって具体的で実装可能なアドバイスを提供します。

対応~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/grahama1970/agent-skills/tree/main/skills/apple-design

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

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

ドキュメント

Apple Design

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

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

核となるアイデア

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

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

Appleはデザインを4つの人間のニーズに奉仕するものとして捉えています:安全性/予測可能性、理解、達成、そして喜び。 ここにあるすべてのルールは、そのうちの1つに奉仕します。

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

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

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

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

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

ユーザーが何かをドラッグするとき、それは指に固定されたままである必要があり — そしてそれを掴んだ位置からのオフセットを尊重しなければなりません。掴んだときに要素の中央にスナップすると、すぐに幻想が壊れます。

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

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

「思考とジェスチャーは並行して起こります。」

すべてのアニメーションは、いつでも割り込み可能でリダイレクト可能でなければなりません。ユーザーは、アニメーションが終了するのを待たずに、動いている要素を空中で掴んで逆転させることができなければなりません。ユーザーが再び掴んだ閉じるモーダルは、指に従うべきです — 最初に閉じ終えてから再び開くのではありません。

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

4. アニメーションよりも動作 — スプリングを使用する

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

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

Appleは意図的に物理トリプレット(質量/剛性/減衰)を、2つのデザイナーに優しいパラメータに置き換えました。これらで考えてください:

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

デフォルト:

  • ほとんどのUIを減衰1.0(臨界減衰)で開始します — 優雅で注意をそらしません。
  • ジェスチャー自体が慣性を運んだ場合にのみ(フリック、スロー、ドラッグリリース)、バウンス(減衰〜0.8)を追加します。単にフェードインしたメニューでのオーバーシュートは間違っていると感じられます。フリックしたカードでのオーバーシュートは正しいと感じられます。

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

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

ウェブマッピング(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 for normal scroll feel; 0.99 for snappier
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·decel)はAppleが出荷するものではありません — 上記の指数減衰形式を使用してください。これは、優れたボトムシートやカルーセル(Vaul、Embla)における標準的な動作です。

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

「何かがある方法で消えるなら、私たちはそれが来た場所から現れることを期待します。」

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

8. ジェスチャーの方向を暗示する

人間は軌道から最終状態を予測します。中間のモーションは、物事がどこに向かっているかを示すはずです — Control Centerモジュールは「指に向かって上と外に成長します」。中間フレームが結果を指し示し、盲目的に補間するだけではないようにします。

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はウェブの表示同期クロックです(AppleはCADisplayLinkを使用します)。コンポジターに優しいプロパティ — transformとopacity — のみをアニメーションし、モーションが差し迫っている場所ではwill-changeでヒントを与えます。

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

Appleは、焦点を奪うことなく構造をもたらす浮遊機能レイヤーとして半透明マテリアルを使用します。ウェブでは、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. 調和 — ビジュアル、サウンド、ハプティクスは同じフレームで発火しなければなりません。それらの間のレイテンシは幻想を破壊します。CSSトランジションがオーディオ/ハプティクス(Vibration API)より遅れないようにします。
  3. ユーティリティ — フィードバックは、それが価値を得る場所にのみ追加します。ハプティクス/サウンドは意味のある瞬間(成功、エラー、コミット、スナップ)のために予約します。過剰なフィードバックは、ユーザーがそれらすべてを無視するように訓練します。

14. 動きの抑制とアクセシビリティ

動きの抑制はフィードバックがないことを意味しません。

…

[翻訳のため省略]

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

grahama1970/acceptance-contract

Turn a client brief, zip bundle, directory, or single requirements file into a typed acceptance-contract bundle with extracted requirements, acceptance checks, open questions, an immutable-goal draft, and a create-report-backed decision report. Use when users say acceptance contract, brief to requirements, freeze the goal, create immutable goal, amend immutable goal, build a Battle requirements bundle, or extract requirements from this bundle.

grahama1970/agent-ecosystem

Canonical map and shared contracts for the agent-governance ecosystem: the pi.receipt_envelope.v1 boundary envelope, the component graph, and the rules for which component owns which schema. Use when wiring a skill or extension into the shared receipt world, when asking how shame, triage-error, tau, ask, project-watchdog, ops-herdr, ponytail, and Memory fit together, or when validating an envelope.

grahama1970/agentic-evals

Agentic evaluation of skills using multi-trial fixtures, deterministic command assertions, trajectory checks, safety constraints, and evidence-backed readiness scoring. Use when users ask for agentic evals, multi-trial skill evaluation, skill trajectory validation, or readiness scoring for a skill workflow.

grahama1970/agent-inbox

File-based inter-agent messaging with headless dispatch. Check inbox, send bugs/requests to other projects, automatically spawn headless agents to fix bugs, and track progress via task-monitor.

grahama1970/agents-registry

Generate and query the centralized agent identity registry. Scans .pi/agents/*/AGENTS.md, parses frontmatter, outputs agents-registry.json and optionally syncs to /memory for semantic search.

grahama1970/agent-status

Artifact-driven status surfaces for long-running project-agent work. Maintains status.json, events.jsonl, proof manifests, and a stale-aware STATUS.html so humans can tell where the agent is, what passed, what is still unproven, and what decision or action is next — without dashboard theater.

grahama1970/align

Round-based context alignment before execution. Use when the human, project agent, WebGPT, scillm, ask, dogpile, memory, or project-knowledge may each hold different facts about a task; especially before ambiguous design, infographic, product workflow, high-stakes implementation, plan-iterate, project-infographic, or multi-review work.

grahama1970/analytics

Flexible data science analytics for any dataset. Auto-discovers schema, recommends charts, exports to create-figure. Works with JSONL, JSON, CSV from any source.

grahama1970/analyze-chatterbox-emotions

Evaluate generated Chatterbox voice files as voice-quality artifacts: affect match, arousal/valence proxies, pause placement, intelligibility inputs, clipping, loudness, and discontinuity flags. Use when reviewing Chatterbox emotional tags, pauses, Turbo/base affect delivery, Persona Dream utterance renders, or whether generated speech matches an intended product-facing affect.

grahama1970/analyze-elf

Reverse-engineer features from ELF binaries. Extracts CLI commands, state machines, protocols, Zod schemas, and data models. Automatically generates a /create-walkthrough prosecution brief with Mermaid diagrams. Uses /treesitter for AST analysis of bundled JS/TS source.

grahama1970/animation-vocabulary

Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

grahama1970/anonymize-data

Anonymize supported CSV, JSON, UTF-8 text, and SQLite files using an explicit policy through the oai-trial project. Use for anonymize data, pseudonymize exports, redact policy literals, or discover and explicitly approve fuzzy name aliases. The skill is a thin CLI/Docker interface, not another engine.

grahama1970/anvil

Heavy-duty "No-Vibes" debugging and hardening orchestrator. Use this for complex, stubborn bugs where `review-code` has failed, or for "Red Teaming" (hardening) a codebase. Runs multiple agents in parallel (Thunderdome) using git worktree isolation.

grahama1970/argue

Multi-persona structured debate orchestrator. Personas research via /dogpile, consult colleagues via /ask, and argue toward nuanced synthesis on complex questions.

grahama1970/arxiv

Search arXiv for papers and extract knowledge into memory. Use `search` to find papers, `learn` to extract knowledge.

grahama1970/ask

Use when the user asks to query project memory, ask an oracle, use supported browser-backed reviewers, run Tau roundtable/single-handler workflows, ask Pi-native subagents from within Pi, run persona/deep-review workflows, generate image prompts, check OS/project health through composed skills, or run an ask DAG. This skill is the executable /ask runtime; do not replace it with an informal subagent, plain web search, or hand-written review; inside Pi, explicit Pi-native subagent targets are routed through the pi-subagents tool as an Ask target type.

grahama1970/assess

Step back and critically reassess project state. Use when asked to "assess", "step back", "fresh eyes", "check alignment", "sanity check", "health check", "prune documentation", or "evaluate what's working". Offers documentation pruning and doc-code alignment analysis. Offer to run after major changes (don't auto-run).

grahama1970/assistant

Shared GPT + classifier inference gateway for persona monitor tasks. Routes validation and classification through a 4-tier cascade: heuristic → classifier → local GPT → scillm.

grahama1970/assistant-lab

Self-improvement workbench for /assistant. All the tools needed to diagnose, train, evaluate, and promote models in a continuous loop. The "warm pond" where /assistant evolves its own inference stack.

grahama1970/batch-quality

Pre-flight validation and quality gates for batch LLM operations. ACTUALLY tests samples through LLM before burning tokens. Uses SPARTA contracts for DuckDB validation queries. Integrates with task-monitor for enforced quality gates.

関連スキル