Communitygithub.com

grahama1970/apple-design

L'approche d'Apple en matière de design d'interface et de mouvement physique et fluide, adaptée au web. À utiliser lors de la création ou de la révision d'IU gestuelles, d'animations à ressort, d'interactions de glissement/de balayage/de feuille, de transitions avec élan et interruptibles, de matériaux translucides et de profondeur, de typographie (ciblage optique, tracking, interlignage), de mouvement réduit, ou des principes de conception (feedback, cohérence spatiale, retenue) qui sous-tendent les interfaces de style Apple.

Qu'est-ce que apple-design ?

Ce skill décrit les principes de conception d'interface d'Apple, en particulier ceux présentés dans les conférences WWDC (notamment *Designing Fluid Interfaces* de 2018), et les traduit en techniques web concrètes. Il se concentre sur la création d'interfaces qui semblent vivantes et réactives en utilisant des animations à ressort, une manipulation directe, une interruption fluide, et une gestion précise de la vélocité. Le skill est destiné aux développeurs utilisant des frameworks comme Motion ou Framer Motion, et couvre des aspects allant de la réponse instantanée au toucher jusqu'à la conception de matériaux translucides et de profondeur. Il est utile pour tous ceux qui souhaitent implémenter des interactions gestuelles (glissement, balayage, feuillets) avec un rendu naturel et fluide, en évitant les animations à durée fixe et en privilégiant les ressorts pour leur interruptibilité et leur capacité à hériter de la vélocité de l'utilisateur.

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

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Apple Design

Comment Apple construit des interfaces qui cessent de ressembler à un ordinateur et commencent à ressentir comme une extension de vous-même. Ces connaissances proviennent des présentations de design d'Apple à la WWDC — principalement Designing Fluid Interfaces (WWDC 2018) — distillées et traduites pour la plateforme web (CSS, Pointer Events, requestAnimationFrame, bibliothèques de ressorts comme Motion/Framer Motion).

Le fil conducteur : une interface semble vivante lorsque le mouvement part de la valeur actuelle à l'écran, hérite de la vélocité de l'utilisateur, projette l'élan vers l'avant et peut être saisie et inversée à tout instant. Les ressorts sont l'outil qui rend tout cela naturel, car ils sont intrinsèquement interruptibles et conscients de la vélocité.

L'idée centrale

« Lorsque nous alignons l'interface sur notre façon de penser et de bouger, quelque chose de magique se produit — elle cesse de ressembler à un ordinateur et commence à ressentir comme une extension transparente de nous-mêmes. »

Une interface est fluide lorsqu'elle se comporte comme le monde physique : les choses répondent instantanément, bougent en continu, portent de l'élan, résistent aux limites et peuvent être redirigées en plein mouvement. Tout ce qui suit est un moyen de s'en rapprocher.

Apple conçoit le design comme servant quatre besoins humains : la sécurité/la prévisibilité, la compréhension, l'accomplissement et la joie. Chaque règle ici sert l'un d'eux.

1. Réponse — éliminer la latence

Dès que le décalage apparaît, la sensation de directeté « tombe d'une falaise ». La réponse est le fondement sur lequel tout le reste est construit.

  • Répondez au pointeur-enfoncé, pas au relâchement. Mettez en surbrillance un bouton dès qu'il est pressé. Attendre le click/le relâchement du toucher pour montrer un feedback semble mort.
  • Soyez vigilant face à chaque latence. Auditez les « debounces », les temporisateurs artificiels, les délais de transition et le délai de ~300 ms du tap. Tout ce qui se trouve sur le chemin d'entrée et qui n'est pas essentiel est une régression.
  • Le feedback doit être continu pendant l'interaction, pas seulement à la fin. Pour un glissement, un curseur ou un tiroir, mettez à jour l'UI 1:1 avec le pointeur tout au long du parcours — n'animez jamais uniquement lorsque le geste est terminé.
/* Le feedback vit sur la pression, et il est instantané */
.button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

2. Manipulation directe — suivi 1:1

« Le toucher et le contenu doivent bouger ensemble. »

Lorsque l'utilisateur fait glisser quelque chose, cela doit rester collé au doigt — et respecter le décalage par rapport à l'endroit où il l'a saisi. Accrocher à l'élément au centre lors de la saisie brise l'illusion immédiatement.

  • Utilisez Pointer Events avec setPointerCapture pour que le suivi continue même lorsque le pointeur quitte les limites de l'élément.
  • Suivez un court historique de vélocité/position (les derniers événements pointermove), pas seulement le point actuel — vous aurez besoin de la vélocité lors du relâchement.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respecter l'endroit où ils ont saisi
  // ...suivre l'historique de position + timestamp pour la vélocité
});

3. Interruptibilité — le principe le plus important

« La pensée et le geste se produisent en parallèle. »

Chaque animation doit être interruptible et redirigeable à tout moment. Un utilisateur doit pouvoir saisir un élément en mouvement en plein vol et l'inverser sans attendre la fin de l'animation. Une fenêtre modale en cours de fermeture que l'utilisateur saisit à nouveau doit suivre le doigt — pas d'abord se fermer complètement, puis se rouvrir.

  • Ne verrouillez jamais l'entrée pendant une transition.
  • Animez toujours à partir de la valeur de présentation (actuelle), jamais de la valeur cible. Lors d'une interruption, lisez la transformation en direct de l'élément et démarrez la nouvelle animation à partir de là. Partir de la valeur logique/cible provoque un saut visible.
  • Évitez les transitions CSS et les @keyframes pour tout ce qui est piloté par le geste — ils ne peuvent pas être saisis facilement et inversés en plein vol. Les ressorts animent à partir de la valeur actuelle par défaut, ce qui est exactement ce dont l'interruption a besoin.
  • Lorsqu'un geste s'inverse, mélangez la vélocité — ne la coupez pas brusquement. Remplacer une animation par une autre lors d'une inversion crée une discontinuité de vélocité, un « mur de briques ». Les bibliothèques de ressorts qui transportent la vélocité lors d'un ré-ciblage l'évitent. (C'est ce que font les animations additives d'iOS nativement ; sur le web, choisissez une bibliothèque de ressorts qui se ré-cible à partir de la vélocité actuelle.)
  • Décomposez le mouvement 2D en ressorts X et Y indépendants. Un seul ressort sur une distance 2D se désynchronise lorsque X et Y ont des vélocités différentes.

4. Comportement plutôt qu'animation — utilisez des ressorts

« Pensez à l'animation comme à une conversation entre vous et l'objet, pas quelque chose de prescrit par l'interface. »

Une animation pré-écrite à durée fixe ne peut pas répondre à une nouvelle entrée. Un ressort le peut — une nouvelle entrée change simplement la cible, et le mouvement reste continu. Utilisez des ressorts pour tout ce qu'un utilisateur peut toucher.

Apple a délibérément remplacé le triplet physique (masse/raideur/amortissement) par deux paramètres adaptés aux concepteurs. Pensez en ces termes :

  • Rapport d'amortissement — contrôle le dépassement. 1.0 = amortissement critique, pas de rebond, stabilisation lisse. < 1.0 = dépasse et oscille. Plus bas = plus rebondissant.
  • Réponse — la rapidité avec laquelle la valeur atteint la cible, en secondes. Plus bas = plus vif. Ce n'est pas la « durée » — un ressort n'a pas de durée fixe ; son temps de stabilisation émerge des paramètres.

Valeurs par défaut :

  • Commencez la plupart des IU à amortissement 1.0 (amortissement critique) — élégant et non distrayant.
  • Ajoutez du rebond (amortissement ~0.8) uniquement lorsque le geste lui-même portait de l'élan (un flick, un lancer, un relâchement de glissement). Un dépassement sur un menu qui vient de s'ouvrir semble faux ; un dépassement sur une carte que vous avez lancée semble juste.

Valeurs concrètes fournies par Apple :

InteractionAmortissementRéponse
Déplacer / repositionner (ex. PiP)1.00.4
Rotation0.80.4
Tiroir / feuille0.80.3

Cartographie web (Motion / Framer Motion) : l'API ressort bounce + duration correspond étroitement à l'amortissement et la réponse d'Apple. Un style de base sûr est d'utiliser des ressorts damping: 1.0 partout par défaut ; réservez le rebond pour les interactions physiques pilotées par l'élan.

import { animate } from 'motion';

// Amortissement critique par défaut (pas de dépassement)
animate(el, { y: 0 }, { type: 'spring', bounce: 0, duration: 0.4 });

// Interaction avec élan — un peu de rebond, uniquement parce qu'un flick l'a précédé
animate(el, { y: target }, { type: 'spring', bounce: 0.2, duration: 0.4 });

5. Transfert de vélocité — la jointure entre le glissement et l'animation

Lorsqu'un geste se termine, l'animation doit continuer à la vélocité exacte du doigt, afin qu'il n'y ait pas de jointure visible entre le glissement et l'animation. C'est le détail qui sépare le plus le « fluide » du « acceptable ».

Passez la vélocité de relâchement du pointeur comme vélocité initiale du ressort. Certaines API de ressort veulent une vélocité relative — normalisez-la par la distance restante jusqu'à la cible :

relativeVelocity = gestureVelocity / (targetValue − currentValue)

Exemple : élément à y=50, cible y=150 (100 px à parcourir), doigt se déplaçant à 50 px/s → vélocité initiale du ressort = 50 / 100 = 0.5. Framer Motion / Motion acceptent directement la vélocité absolue en px/s (option velocity), vous lui passez donc généralement la valeur brute.

6. Projection d'élan — animer vers où le geste va

« Prenez une petite entrée et faites-en une grande sortie. »

Ne vous accrochez pas à la limite la plus proche à partir du point de relâchement. Utilisez la vélocité pour projeter la position de repos — exactement comme la décélération de défilement — puis accrochez-vous à la cible la plus proche de ce point projeté. C'est ce qui fait qu'un flick semble lancer l'élément.

La fonction de projection exacte d'Apple (d'après le code d'exemple de Designing Fluid Interfaces) :

// decelerationRate ≈ 0.998 pour une sensation de défilement normale ; 0.99 pour plus vif
function project(initialVelocity /* px/s */, decelerationRate = 0.998) {
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}

const projectedEndpoint = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedEndpoint);   // choisir la cible à partir de la projection
animateSpringTo(target, { velocity: releaseVelocity }); // puis transférer la vélocité (§5)

Remarque : le v²/(2·decel) du manuel de physique n'est pas ce qu'Apple utilise — utilisez la forme de décroissance exponentielle ci-dessus. C'est le comportement standard dans les bons feuillets inférieurs et carrousels (Vaul, Embla).

7. Cohérence spatiale — chemins symétriques, origines ancrées

« Si quelque chose disparaît d'une certaine manière, nous nous attendons à ce qu'il émerge de là d'où il vient. »

  • Entrez et sortez par le même chemin. Un panneau qui glisse depuis la droite doit se fermer vers la droite. Entrer par la droite / sortir par le bas semble déconnecté et déroutant.
  • Ancrez les interactions à leur source. Un menu, un popover ou une feuille doit provenir de l'élément qui l'a déclenché — définissez transform-origin sur le déclencheur, afin que la relation spatiale entre le bouton et le contenu soit évidente. (C'est le même point de conscience de l'origine que les popovers qui se déploient à partir de leur déclencheur, pas de leur centre.)
  • Reflétez l'assouplissement sur les transitions réversibles afin que le chemin de sortie corresponde au chemin de retour (utilisez des points de contrôle cubiques de Bézier inverses pour les deux directions).

8. Indice dans la direction du geste

Les humains prédisent un état final à partir d'une trajectoire. Le mouvement intermédiaire doit indiquer où les choses vont — les modules du Centre de contrôle « grandissent vers le haut et vers l'extérieur en direction de votre doigt. » Faites en sorte que les images intermédiaires pointent vers le résultat, pas seulement interpoler aveuglément vers celui-ci.

9. Effet « rubber-banding » — limites douces

À une limite, résistez progressivement plutôt que de vous arrêter brusquement. Un arrêt brusque est perçu comme « gelé » ; une résistance continue est perçue comme « réactif, mais il n'y a rien de plus ici. » Appliquez un amortissement qui augmente plus l'utilisateur dépasse la limite.

// Plus on dépasse la limite, moins l'élément suit — les vraies choses ralentissent avant de s'arrêter
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

10. Détails de conception des gestes (la liste de contrôle « sensation »)

  • Tap : mettez en surbrillance au toucher-enfoncé (instantané), validez au toucher-relâché. Ajoutez environ 10 px d'hystérésis/de marge de hit autour de la cible, et permettez l'annulation en glissant ailleurs et en revenant.
  • Glissement/balayage : exigez un petit seuil de mouvement (hystérésis, ~10 px) avant de vous engager dans une direction, puis suivez 1:1.
  • Détectez tous les gestes plausibles en parallèle dès le premier mouvement, puis annulez en toute confiance les perdants une fois l'intention claire. Évitez les reconnaisseurs qui ne rapportent qu'un état final (événements de type swipeleft) — ils jettent le suivi continu dont vous avez besoin pour le feedback.
  • Minimisez les délais de désambiguïsation. La détection de double-tap retarde inévitablement les simples tap ; ne payez ce coût que là où le double-tap existe vraiment.

11. Fluidité au niveau de la frame

La fluidité concerne ce qui se trouve dans les images, pas seulement le taux d'images par seconde.

  • Maintenez le changement de position par frame en dessous du seuil de perception pour éviter le scintillement.
  • Pour les mouvements très rapides, un flou de mouvement / étirement subtil encode la vitesse et est mieux perçu qu'une traînée nette et dure.
  • requestAnimationFrame est l'horloge synchronisée à l'affichage du web (Apple utilise CADisplayLink). Animez uniquement les propriétés compatibles avec le compositeur — transform et opacity — et faites un indice avec will-change là où le mouvement est imminent.

12. Matériaux et profondeur — la translucidité transmet la hiérarchie

Apple utilise des matériaux translucides comme une couche fonctionnelle flottante qui apporte de la structure sans voler l'attention. Sur le web, approchez-vous avec backdrop-filter.

  • Construisez les barres de navigation/barres d'outils/feuilles comme des couches translucides (backdrop-filter: blur() + un fond semi-transparent) avec le contenu défilant en dessous — pas des barres opaques qui consomment une bande fixe.
  • Le poids du matériau encode la hiérarchie : les matériaux plus foncés/plus lourds séparent les régions structurelles (barres latérales) ; les matériaux plus clairs attirent l'attention sur les éléments interactifs (boutons). N'empilez jamais une surface translucide claire sur une autre — la lisibilité s'effondre.
  • Les surfaces plus grandes doivent être perçues comme plus épaisses : un flou plus fort + une ombre plus profonde que les petits éléments. Considérez une ombre contextuelle — plus lourde sur un contenu chargé/texté pour la séparation, plus légère sur des fonds unis.
  • Assombrissez pour concentrer, séparez pour maintenir le flux. Une tâche modale associe la surface à un écran d'assombrissement et repousse le fond vers l'arrière/le bas. Un panneau parallèle non bloquant utilise la translucidité et le décalage sans écran d'assombrissement afin que le flux ne soit pas interrompu. Pour les feuilles empilées, assombrissez et repoussez progressivement chaque couche parente.
  • La vibrancy maintient la lisibilité du texte sur des fonds changeants. Sur les surfaces floutées/translucides, n'utilisez pas de texte gris uni — utilisez un contraste plus élevé, un poids légèrement plus lourd et une légère augmentation de l'espacement des lettres. Mettez la couleur sur une couche solide, pas sur le premier plan translucide.
  • Effets de bord de défilement, pas de séparateurs durs. Au lieu d'une bordure de 1 px sous un en-tête collant, dégradez un petit masque de flou/dégradé là où le contenu rencontre le chrome flottant — uniquement là où l'IU flottante chevauche réellement le contenu.
  • Matérialisez, ne vous contentez pas d'atténuer. Pour les surfaces en verre/flou, animez le rayon de flou et l'échelle ensemble à l'entrée/à la sortie, afin que la surface soit perçue comme un matériau réel qui arrive plutôt qu'un fondu d'opacité uni.
.toolbar {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(20px) saturate(180%);
  border-top: 1px solid rgba(255, 255, 255, 0.4); /* bord supérieur lumineux = lumière attrapant le matériau */
}

13. Feedback multimodal — mouvement + son + haptique

Trois règles pour combiner les sens (d'après Designing Audio-Haptic Experiences) :

  1. Causalité — il doit être évident ce qui a causé le feedback. Déclenchez-le sur l'événement causal réel (le basculement du commutateur, l'élément qui s'encastre), et faites correspondre son caractère à la physicalité de l'action.
  2. Harmonie — le visuel, le son et l'haptique doivent se déclencher sur la même image. La latence entre eux détruit l'illusion. Ne laissez pas une transition CSS prendre du retard sur l'audio/l'haptique (API Vibration).
  3. Utilité — ajoutez du feedback uniquement là où il mérite sa place. Réservez l'haptique/le son pour les moments significatifs (succès, erreur, validation, enclenchement). Le trop-plein de feedback apprend aux utilisateurs à tout ignorer.

14. Mouvement réduit et accessibilité

Mouvement réduit ne signifie pas absence de feedback

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.

Skills associés