Communitygithub.com

marvinmcv-svg/SCCS-Landing-page

L'approche d'Apple en matière de conception d'interfaces et de mouvements physiques et fluides, adaptée pour le web. À utiliser lors de la création ou de la révision d'interfaces pilotées par gestes, d'animations à ressort, d'interactions de glissement/balayage/panneau, de momentum et de transitions interruptibles, de matériaux translucides et de profondeur, de typographie (taille optique, crénage, interlignage), de mouvement réduit, ou des principes fondamentaux de conception (feedback, cohérence spatiale, retenue) derrière les interfaces de type Apple.

Qu'est-ce que SCCS-Landing-page ?

Cette compétence fournit aux développeurs web une base de connaissances complète pour concevoir des interfaces utilisateur de style Apple, en se basant sur les présentations de conception de la WWDC d'Apple, notamment *Designing Fluid Interfaces* (WWDC 2018). Elle couvre des principes essentiels comme la réactivité, la manipulation directe, l'interruptibilité des animations, l'utilisation de ressorts physiques, et le transfert de vélocité. La compétence propose des traductions concrètes pour le web, avec des exemples de code en CSS et JavaScript (Pointer Events, `requestAnimationFrame`, bibliothèques de ressorts comme Motion/Framer Motion). Elle est idéale pour les développeurs travaillant avec des frameworks comme React, Vue ou Svelte, et ceux qui utilisent des outils d'IA comme Anthropic Claude Code, Cursor, ou Codex pour créer des applications natives ou web avec une expérience utilisateur proche de celle d'Apple.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/marvinmcv-svg/SCCS-Landing-page/tree/HEAD/.claude/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

Conception Apple

Réponse Initiale

Lorsque cette compétence est invoquée pour la première fois sans question spécifique, répondez uniquement avec :

Je suis prêt à vous aider à construire des interfaces fluides de style Apple sur le web. Mes connaissances proviennent des présentations de conception de la WWDC d'Apple, adaptées pour le web.

Ne fournissez aucune autre information tant que l'utilisateur n'a pas posé de question.

Comment Apple construit des interfaces qui cessent de ressembler à un ordinateur et commencent à ressembler à une extension de vous-même. Ces connaissances proviennent des présentations de conception de la WWDC d'Apple — principalement Designing Fluid Interfaces (WWDC 2018) — distillées et adaptées à 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 attrapée 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, il se produit quelque chose de magique : elle cesse de ressembler à un ordinateur et commence à ressembler à 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, transportent 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 la conception comme servant quatre besoins humains : sécurité/prévisibilité, compréhension, accomplissement et joie. Chaque règle ici en sert un.

1. Réponse — éliminer la latence

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

  • Répondez au pointer-down, pas au relâchement. Mettez en surbrillance un bouton dès qu'il est pressé. Attendre le click/touch-up pour montrer un retour donne une sensation de mort.
  • Soyez vigilant sur chaque latence. Auditez les debounces, les minuteries artificielles, les attentes de transition et le délai de tap d'environ 300 ms. Tout ce qui se trouve sur le chemin d'entrée 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 — n'animez jamais seulement lorsque le geste se termine.
/* 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ù ils l'ont attrapé. S'accrocher au centre de l'élément dès la saisie rompt immédiatement l'illusion.

  • 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é au relâchement.
el.addEventListener('pointerdown', (e) => {
  el.setPointerCapture(e.pointerId);
  const grabOffset = e.clientY - el.getBoundingClientRect().top; // respecte l'endroit où ils ont attrapé
  // ...suit la position + l'horodatage 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 attraper un élément en mouvement en plein vol et l'inverser sans attendre la fin de l'animation. Une modale en cours de fermeture que l'utilisateur rattrape doit suivre le doigt — pas d'abord terminer la fermeture, puis se rouvrir.

  • Ne verrouillez jamais l'entrée pendant une transition.
  • Animez toujours à partir de la valeur présentée (actuelle), jamais la valeur cible. Lors d'une interruption, lisez la transformation en direct de l'élément à l'écran et démarrez la nouvelle animation à partir de là. Démarrer à partir de la valeur logique/cible provoque un saut visible.
  • Évitez les transitions CSS et @keyframes pour tout ce qui est piloté par les gestes — elles ne peuvent pas être facilement attrapées et inversées 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 à un point d'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 reciblage l'évitent. (C'est ce que les animations additives d'iOS font nativement ; sur le web, choisissez une bibliothèque de ressorts qui recible à 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

« Considérez 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 douce. < 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 une « 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 UI avec un amortissement de 1.0 (amortissement critique) — gracieux et non distrayant.
  • Ajoutez du rebond (amortissement ~0.8) uniquement lorsque le geste lui-même transportait de l'élan (un flick, un lancer, un relâchement de glissement). Un dépassement sur un menu qui vient de s'estomper semble faux ; un dépassement sur une carte que vous avez lancée semble correct.

Valeurs concrètes qu'Apple expédie :

InteractionAmortissementRéponse
Déplacement / repositionnement (ex. PiP)1.00.4
Rotation0.80.4
Tiroir / panneau0.80.3

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

import { animate } from 'motion';

// Valeur par défaut à amortissement critique (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 « correct ».

Transmettez 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 à 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), donc vous lui passez généralement la valeur brute.

6. Projection d'élan — animez vers l'endroit où le geste va

« Prenez une petite entrée et faites 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 du 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 (issue du code d'exemple Designing Fluid Interfaces) :

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

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

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

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

« Si quelque chose disparaît d'un côté, nous nous attendons à ce qu'il émerge 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, une popover ou un panneau 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 pour que le chemin de sortie corresponde au chemin de retour (utilisez des points de contrôle cubiques-bézier inverses pour les deux directions).

8. Faites un indice dans la direction du geste

Les humains prédisent un état final à partir d'une trajectoire. Les images intermédiaires doivent télégraphier 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 d'élastique — limites douces

À une limite, résistez progressivement au lieu 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 vérification du « ressenti »)

  • Tap : mise en surbrillance au toucher-down (instantané), validation au toucher-up. Ajoutez environ 10 px d'hystérésis/marge de hit autour de la cible, et autorisez l'annulation en glissant loin et en revenant.
  • Glissement/balayage : exigez un petit seuil de mouvement (hystérésis, environ 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 signalent 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 taps simples ; ne payez ce coût que là où le double-tap existe vraiment.

11. Fluidité au niveau de l'image

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

  • Maintenez le changement de position par image en dessous du seuil de perception pour éviter l'effet stroboscopique.
  • Pour les mouvements très rapides, un *flou / étirement de mouvement subtil encode la vitesse et se lit mieux qu'une traînée dure et nette.
  • requestAnimationFrame est l'horloge synchrone avec 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 une structure sans voler l'attention. Sur le web, approximez avec backdrop-filter.

  • Construisez les barres de navigation/barres d'outils/panneaux sous forme de couches translucides (backdrop-filter: blur() + un arrière-plan semi-transparent) avec un contenu défilant en dessous — pas de barres opaques qui consomment une bande fixe.
  • Le poids du matériau encode la hiérarchie : des matériaux plus foncés/plus lourds séparent les régions structurelles (barres latérales) ; des matériaux plus légers attirent l'attention sur les éléments interactifs (boutons). Ne superposez jamais une surface translucide claire sur une autre — la lisibilité s'effondre.
  • Les surfaces plus grandes doivent paraître 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é/texte pour la séparation, plus légère sur des arrière-plans simples.
  • Assombrissez pour concentrer, séparez pour maintenir le flux. Une tâche modale associe la surface à un voile d'assombrissement et repousse/abaisse l'arrière-plan. Un panneau parallèle non bloquant utilise la translucidité et le décalage sans voile afin que le flux ne soit pas interrompu. Pour les panneaux empilés, assombrissez et repoussez progressivement chaque couche parente.
  • La vibrancy maintient la lisibilité du texte sur des arrière-plans changeants. Sur des surfaces floues/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 d'1 px sous un en-tête collant, fondez un petit masque de flou/dégradé là où le contenu rencontre le chrome flottant — uniquement là où l'UI flottante chevauche réellement le contenu.
  • Matérialisez, ne vous contentez pas d'estomper. Pour les surfaces en verre/flou, animez le rayon de flou et l'échelle ensemble à l'entrée/sortie, afin que la surface soit perçue comme un matériau réel qui arrive plutôt qu'une simple atténuation d'opacité.
.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 brillant = 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 se met en place), 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 un

…

[tronqué pour la traduction]

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés