Communitygithub.com

nkurunziza-saddy/motion

Construit l'animation pour l'interface produit sur le web. Décide si quelque chose doit bouger, puis pourquoi, quel outil (CSS transition, WAAPI, Motion, spring), quelles propriétés, courbe, durée, interruption, sortie et chemin de mouvement réduit, et écrit le code. Couvre également le décalage et la chorégraphie, les gestes (glisser, flick, panneaux), les tokens d'animation et les performances d'animation.

Qu'est-ce que motion ?

Cette compétence guide la construction d'animations UI de manière systématique et performante. Elle impose un ordre de décision rigoureux : d'abord déterminer si l'élément doit vraiment bouger (fréquence d'utilisation), puis nommer le but (spatial, état, retour, continuité, explication), avant de choisir l'outil le plus économique (CSS transition, @keyframes, WAAPI ou Motion). L'objectif est d'éviter les animations inutiles, coûteuses en performance ou maladroites. La compétence détaille les propriétés à animer (transform, opacity), les courbes et durées appropriées, la gestion des interruptions et des sorties, ainsi que le mouvement réduit. Elle inclut également des règles de chorégraphie (rôles, délais, direction) et des paires « cassé / corrigé » illustrant les erreurs fréquentes. Elle fait référence à des fichiers complémentaires (tokens, recettes, gestes, performance) pour les valeurs exactes et les cas complexes. Fonctionne avec tout projet web (framework agnostique) mais particulièrement adaptée aux environnements React avec Motion.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/nkurunziza-saddy/hmm-interfaces/tree/HEAD/motion

Demander à votre IA préférée

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

Documentation

Que fait motion ?

Cette compétence construit l'animation. Elle étend la section motion de product-ui/references/values.md, qui contient les chiffres arrêtés (courbes d'assouplissement, échelle de pression, rebond, décalage, le tableau des durées, durées des toasts et de mise en page, distances de déplacement, ratio sortie/entrée). Ces chiffres ne sont pas répétés ici ; cette compétence ajoute l'ordre des décisions, les tokens, les recettes et les modes d'échec.

Avant toute décision, appliquer product-ui §1 (le journal des goûts et la préséance) et §5 (quelle compétence possède quoi).

L'ordre des décisions

Parcourir ces étapes de haut en bas. Chaque étape peut terminer le travail. Zéro ligne d'animation est un résultat valide, et vous le dites.

1. Doit-il bouger ? Le filtre de fréquence

Demandez combien de fois par jour un seul utilisateur voit cet élément. Les niveaux sont dans values.md. En pratique :

  • Initiated au clavier, ou vu 100+ fois par jour : pas d'animation. Pourquoi : le mouvement répété se transforme en délai.
  • Vu des dizaines de fois par jour (survol, changement d'onglet, sélection de ligne) : rien, ou un changement de couleur instantané.
  • Les données que l'utilisateur lit ou manipule (un nombre dans un tableau, un graphique dans un tableau de bord en direct) ne bougent jamais pour le style. Pourquoi : l'animation détourne l'œil de ce qui est lu.
  • Si le filtre dit non, n'écrivez aucune animation. Dites quel niveau il a atteint et proposez l'alternative statique (un changement d'état instantané).

2. Nommer le but

Choisissez un mot : spatial (d'où il vient ou où il va), état (ceci a changé), retour (je vous ai entendu), continuité (empêche un saut), explication (moments rares uniquement). Impossible d'en nommer un : arrêtez. Pourquoi : « c'est joli » sur un élément fréquent est la principale source de sensation de lenteur dans l'interface.

3. Choisir l'outil : le moins cher qui fonctionne

BesoinOutil
Un état basculé par classe, attribut, survol ou pressionCSS transition
Entrée depuis display: none, popover ou dialog@starting-style + transition-behavior: allow-discrete
Une séquence unique, un décalage, ou une animation qui doit s'exécuter pendant que la page est occupéeCSS @keyframes
JS décide quand ; vous avez besoin d'annuler, inverser, finished, ou FLIPWAAPI el.animate()
Springs, transfert de vélocité, sortie d'un nœud React qui se démonte, mise en page partagéeMotion (motion/react)

Si l'élément est un composant entier (menu, toast, tiroir), utilisez une bibliothèque qui gère le focus, et demandez pick-library. N'installez jamais Motion pour un fondu. Pourquoi : CSS s'exécute hors du thread principal et ne coûte rien en bundle.

4. Propriétés

  • Animer transform et opacity ; filter uniquement pour un flou d'échange ≤ 2px. Nommer chaque propriété ; jamais transition: all.
  • Changements de hauteur et de disposition : voir references/recipes.md (lignes de grille, FLIP). Ne jamais animer width, top, left ou margin pour déplacer quelque chose. Pourquoi : chacun force une mise en page à chaque image.
  • Ne jamais animer box-shadow. Fondu de l'opacity d'un pseudo-élément à la place.
  • Les pourcentages translate sont relatifs à la taille de l'élément lui-même, donc translateY(100%) convient pour les tiroirs et les toasts de toute hauteur.

5. Courbe et durée, adaptées à l'usage

Ne choisissez jamais le nombre le plus proche de votre estimation. Indiquez l'usage (« fermeture de menu », « échange d'icône »), puis prenez cette ligne dans references/tokens.md. Si aucune ligne ne correspond à l'usage, ajoutez un nouveau token nommé d'après l'usage ; ne détournez pas un token existant. Pourquoi : un token est une déclaration sur le but de l'animation, donc un nombre proche avec le mauvais usage est le mauvais token.

  • Entrée ou sortie : --ease-out. Déplacement à l'écran : --ease-in-out. Tiroirs : --ease-drawer. Couleur : ease. Spinners : linear. Jamais ease-in.
  • Tout ce qui est déplaçable ou interruptible en plein vol utilise un spring, pas une courbe. Pourquoi : une courbe ne peut pas accepter la vélocité que la main de l'utilisateur avait.
  • Sensation de lenteur : réduisez d'abord la durée, puis la distance, et seulement ensuite touchez à la courbe.

6. Interruption

  • Tout ce que l'utilisateur peut déclencher deux fois par seconde est une transition ou un spring, jamais @keyframes. Pourquoi : une transition recible depuis la valeur actuelle ; les keyframes redémarrent et sautent.
  • WAAPI : annulez l'ancienne animation après avoir lu la valeur actuelle, et démarrez la nouvelle à partir de celle-ci (references/recipes.md).
  • Un interrupteur actionné 10 fois doit se terminer dans le bon état sans saut. Testez-le.

7. Sortie

  • La sortie par défaut est un fondu, plus court que l'entrée (le fichier tokens a chaque paire).
  • Tout ce qui a une direction (tiroir, panneau, toast glissé) part par où il est venu.
  • L'élément qui sort cesse de prendre de l'espace immédiatement, donc les frères comblent l'écart pendant qu'il fond.
  • Les sorties sont simultanées et jamais décalées. Pourquoi : l'utilisateur a déjà décidé de partir.

8. Mouvement réduit, livré avec l'animation

L'opacité et la couleur restent. Les diapositives, l'échelle, le flou et le rebond disparaissent ; les diapositives deviennent des fondus, le rebond devient 0. Ne jamais utiliser l'animation comme seul signal. Modèle dans references/recipes.md.

Chorégraphie

Classez chaque élément en mouvement avant de le chronométrer :

RôleTraitement
Principal (la chose à remarquer)Bouge en premier, parcourt le plus de distance
SupportSuit, parcourt moins
DécorationFondu sur place, ou rien
Statique (conteneurs, chrome)Ne bouge jamais
  • Une entrée par conteneur. Si le panneau glisse, son contenu est déjà là. Pourquoi : deux entrées superposées font attendre l'utilisateur deux fois.
  • Ordre par importance, pas par ordre DOM. Le délai reste aux étapes de values.md (40ms entre les éléments, 100ms entre le titre, le texte et les actions). Variez la distance et la durée selon le rôle plutôt que le délai.
  • Limiter le décalage d'une liste à l'index 6 (un dernier délai de 240ms) ; les éléments au-delà partagent ce délai. L'entrée fonctionne pendant qu'il joue.
  • Ne jamais décaler un menu, une palette de commandes, le contenu d'un onglet ou toute ouverture répétée.
  • Restez immobile : tout ce que l'utilisateur s'apprête à cliquer, tout ce qui est déjà à l'écran lorsque la page se recharge, et une mise à jour qui arrive dans les 150ms suivant la précédente (sautez à l'état final).
  • La direction suit le sens : le suivant entre par la droite, le retour par la gauche ; les choses que l'utilisateur a déclenchées s'agrandissent à partir du déclencheur.

Charger en cas de besoin

  • references/tokens.md : chargez pour toute durée exacte, distance, échelle, flou, courbe d'assouplissement ou valeur de spring, et pour tokeniser une base de code existante.
  • references/recipes.md : chargez lors de la construction d'un menu, popover, dialog, tiroir, toast, entrée de liste, échange d'icône, changement de hauteur, indicateur d'onglet ou changement de nombre.
  • references/gestures.md : chargez pour le glissement, le swipe, le flick, les panneaux, ou tout ce qui suit un pointeur.
  • references/performance.md : chargez lorsque l'animation perd des images, avant d'utiliser will-change, et lorsque les mises à jour arrivent rapidement.

Paires

CasséCorrigéPourquoi
.menu { transition: all 300ms ease-in }transition: opacity 200ms, transform 200ms var(--ease-out)Propriétés nommées ; ease-in est lent ; menus ≤ 200ms
scale(0) vers scale(1)scale(0.95) et opacity: 0 vers 1Rien n'apparaît de rien
Popover se met à l'échelle depuis son centretransform-origin: var(--transform-origin)Il doit grandir à partir de son déclencheur
.open { animation: slide-in 300ms }transition: transform sur l'état basculéLes keyframes sautent lorsqu'elles sont interrompues
Chaque ligne animation-delay: i * 120msmin(i, 6) * 40msLa dernière ligne arrive en moins de 300ms
Le tiroir disparaît en fondu après être entré en glissantIl glisse vers l'arrière par où il est venuLa direction est l'explication
Relâchement du glissement sur un ease-out fixeUn spring amorcé avec la vélocité de relâchementL'élan de la main continue
setY(y) dans pointermoveel.style.transform = ...Pas de nouveau rendu par image

Avant de terminer

Cherchez dans le diff, puis vérifiez.

RechercherCorrection
transition: all, will-change sur *, ease-inPropriétés nommées, supprimez, --ease-out
scale(0), transform-origin: center sur un popover0.95, l'origine du déclencheur (les dialogues restent centrés)
@keyframes sur une classe qui basculeUne transition
Une durée au-dessus de sa ligne dans tokens.md, ou un nombre pas dans tokens.mdLe token de l'usage
Animation sur les gestionnaires keydown ou une paletteSupprimez-la
width, height, top, left, box-shadow dans une transitiontransform, opacity, ou la recette
Pas de chemin prefers-reduced-motionAjoutez-le

Vérifiez dans l'application en cours d'exécution : jouez-la à 4× (panneau Animations des DevTools, ou multipliez les durées), spammez n'importe quel interrupteur, testez avec le mouvement réduit activé, et limitez le CPU à 4×. Dites lesquels de ces tests vous n'avez pas pu exécuter.

Individual skills in this repo

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

nkurunziza-saddy/break

Stress-tests a piece of UI with worst-case data and every reachable state, then reports what broke with a numbered fix for each. Use it when the user types /break, or asks to "break this", "stress-test", "try the worst case", "what happens with long names", "check the empty and error states" or "find the edge cases" on a component or screen.

nkurunziza-saddy/layout

Structure and space in product UI on the web. It sets the spacing scale, grouping, alignment, density (compact or comfortable), hit areas, app shells (sidebar, toolbar, content, inspector), max widths, container-query responsiveness, dropdown and popover sizing, room for long and translated text, layout stability (no shift on load) and sticky elements that must not cover focus.

nkurunziza-saddy/pick-library

Picks the right library for a frontend task from a curated, status-checked list, instead of hand-rolling it or installing an abandoned package. Use it when the user asks "what should I use for…", "is there a library for…", or names a package, and when you are about to build a toast, command menu, drawer, date picker, table, virtual list, drag and drop, chart, OTP input, animated number, theme switch, form validation…

nkurunziza-saddy/surfaces

What product UI is made of on the web. It sets elevation levels with exact shadow recipes for light and dark mode, when to use a shadow and when a border, the transparent border for forced-colours mode, a small radius scale with concentric nesting, image outlines, every interactive state as a surface change (hover, pressed, selected, disabled, focus-visible), icons (one set, currentColor, outline and fill, stroke tha…

Skills associés