name: Principes d'Animation de Mouvement description: La couche artisanale du mouvement : choisir la bonne courbe d'accélération (ease-in / ease-out / ease-in-out / spring), maîtriser le timing et l'espacement, construire l'arc anticipation→action→suivi, et appliquer les 12 principes de Disney aux animations UI et vidéos produit.
Que fait Principes d'Animation de Mouvement ?
C'est la couche du goût. Elle décide comment quelque chose doit bouger pour paraître soigné et intentionnel plutôt que saccadé, flottant ou bon marché. Elle n'écrit pas le code qui exécute le mouvement — une fois que vous avez choisi la courbe, le timing et l'arc, cette décision est l'entrée d'un skill de réalisation/rendu (pour une vidéo produit, transmettez-la à product-demo-director) ou de vos transitions CSS/JS (pour l'interface). Gardez les deux tâches séparées : ce skill possède le jugement ; le skill de réalisation possède l'orchestration et la mécanique.
Déclenchez ce skill sur toute question concernant la sensation du mouvement : "rends ça moins saccadé", "plus fluide", "plus soigné", "plus vivant", "l'accélération est bizarre", "ça fait cheap", "dois-je utiliser ease-in ou ease-out ?", "spring ou interpolation ?".
Quand utiliser un skill frère à la place
Ce skill ne concerne que le jugement de la courbe/timing/arc. Reportez-vous lorsque la vraie question est :
- Quels plans, ordre des scènes ou liste de beats → video-storyboard.
- Réaliser une démo produit complète — mouvements du curseur, captures d'écran, callouts de fonctionnalités, assemblage de scène de bout en bout → product-demo-director. (Ce skill produit la spécification de mouvement qu'il consomme.)
- Animer du texte ou des lettrages — typographie qui vole/apparaît/révèle → kinetic-typography.
- Caler le mouvement sur un beat, une musique ou un effet sonore → sound-and-music-sync.
- Recadrer ou reformater pour une plateforme (9:16, 1:1, zones de sécurité) → social-video-formatter.
- Lumière, exposition, lueur ou mouvement des couleurs → motion-color-and-light.
Procédure opératoire
Diagnostiquez avant de prescrire. La plupart des mouvements "saccadés" correspondent à l'un des quatre problèmes nommés, et chacun correspond à une correction spécifique ci-dessous. Suivez les étapes dans l'ordre — la correction d'accélération ne sert à rien si le timing est mauvais, et la correction de timing ne sert à rien si l'élément n'a pas d'arc.
Étape 1 : Nommer ce qui ne va pas
Observez le mouvement (ou sa description) et classez-le. Presque chaque plainte correspond à l'un de ces cas :
- Linéaire / Robotique — se déplace à vitesse constante, s'arrête net. Pas d'accélération. Corrigez à l'Étape 2.
- Flottant / Mou — trop lent, ou accélère à l'entrée et à la sortie alors qu'il devrait snap à l'entrée. Mauvaise durée ou mauvaise courbe. Corrigez aux Étape 2 et Étape 3.
- Saccadé / Saccades — entre et sort à la même vitesse, ou chaque propriété s'anime sur la même timeline plate sans décalage. Espacement et arc manquants. Corrigez aux Étape 3 et Étape 4.
- Mort / Sans vie — techniquement correct mais ennuyeux : pas d'anticipation, pas de dépassement, pas de suivi. Arc et mouvement secondaire manquants. Corrigez aux Étape 4 et Étape 5.
Écrivez le diagnostic en une ligne avant de toucher à quoi que ce soit. "La modale est flottante parce qu'elle apparaît sur 600ms avec ease-in-out" est une correction ; "rends-la plus jolie" n'en est pas une.
Étape 2 : Choisir la courbe d'accélération
L'accélération est la forme de la vitesse en fonction du temps du mouvement. La courbe porte presque toute la qualité perçue. Associez la courbe à ce que fait l'élément :
- ease-out (départ rapide, arrivée lente) — la valeur par défaut pour ce qui entre et pour tout ce que l'utilisateur a déclenché. Elle donne une sensation de réactivité parce que le mouvement commence immédiatement, puis décélère en place. Utilisez pour : éléments qui apparaissent, menus déroulants qui s'ouvrent, un bouton qui répond, du contenu qui glisse. En cas de doute, choisissez ease-out.
- ease-in (départ lent, sortie rapide) — pour ce qui sort. L'élément accélère hors de l'écran. Utilisé seul pour une entrée, il semble lent et réactif, ce qui est la cause n°1 du "flottant". Utilisez pour : fermetures, clôtures, sorties.
- ease-in-out (lent, rapide, lent) — pour déplacer quelque chose déjà à l'écran de A à B : réorganisation de cartes, avancement d'un carrousel, basculement d'un interrupteur. Les deux extrémités sont ancrées, donc une accélération aux deux extrémités semble contrôlée. Ne l'utilisez pas pour les entrées — le démarrage lent tue la réactivité.
- spring (physique : masse, rigidité, amorti — dépasse et se stabilise) — pour un mouvement qui doit sembler vivant et physique : une modale qui apparaît, un bouton de bascule, un bouton "j'aime", une notification qui atterrit. Le léger dépassement est ce qui rend le mouvement "vivant". Ajustez l'amorti pour la personnalité : un amorti bas = plus rebondissant et ludique, un amorti haut = plus serré et corporatif.
La décision spring() vs interpolate() (quand utiliser l'un ou l'autre dans le code) est décrite dans la section Barre de qualité et dans l'artefact exécutable ci-dessous. La version courte : utilisez spring pour les transformations physiques/vivantes, et interpolate pour les valeurs précises temporalisées comme les fondus d'opacité, les couleurs et les barres de progression.
Étape 3 : Régler le timing et l'espacement
Le timing est la durée totale. L'espacement est la manière dont la distance est répartie sur cette durée — l'espacement est l'accélération rendue littérale (un ease-out a des trames regroupées à la fin). Deux règles :
- La durée varie avec la distance et la taille, pas avec le goût. Un petit élément qui se déplace sur une courte distance doit être rapide (UI : ~150–250ms). Un grand élément ou un long trajet nécessite plus de temps (~300–500ms) ou il téléporte. Un mouvement grand écran/héroïque dans une vidéo peut durer plus longtemps. Même mouvement, plus grande distance → durée plus longue.
- Entrée et sortie ne sont pas symétriques. Les sorties doivent être plus rapides que les entrées (~0,7–0,8x) — l'utilisateur en a fini avec l'élément, alors écartez-le. Des durées d'entrée/sortie égales sont une source classique de "saccadé".
Pour une vidéo produit, convertissez en trames dès que vous quittez ce skill : trames = round(secondes * fps). Ces nombres de trames sont l'entrée littérale que vous transmettez à product-demo-director (qui les transforme en plan de scène chronométré).
Étape 4 : Construire l'arc anticipation → action → suivi
Un mouvement réel est rarement un seul déplacement. Le mouvement le plus riche, le plus "vivant", comporte trois temps :
- Anticipation — un très petit pré-mouvement en sens inverse avant le mouvement principal (un bouton s'enfonce légèrement avant de surgir, une carte recule avant de glisser hors de l'écran). Cela prépare l'œil et rend l'action intentionnelle. Gardez-le petit et rapide ; trop d'anticipation ressemble à un bug.
- Action — le mouvement principal, qui reprend l'accélération de l'Étape 2 et la durée de l'Étape 3. C'est là que vit l'espacement.
- Suivi — l'élément dépasse sa cible et revient (le dépassement du spring), et tous les éléments attachés/secondaires prennent légèrement de retard sur le leader (un libellé qui rattrape la carte sur laquelle il se trouve). C'est ce qui vend le poids et la vie.
Toutes les micro-interactions n'ont pas besoin des trois — une infobulle de 150ms n'est qu'une action. Mais quand quelque chose semble "mort", il manque presque toujours l'anticipation ou le suivi. Ajoutez l'arc avant d'ajouter des fioritures.
Étape 5 : Appliquer les principes Disney pertinents
Les 12 principes de l'animation de Disney s'appliquent directement à l'interface utilisateur et au mouvement vidéo produit. Vous n'appliquez pas les douze ; vous utilisez ceux qui corrigent le problème diagnostiqué. La correspondance complète se trouve dans references/twelve-principles. Les plus utiles :
- Ralentissement à l'entrée et à la sortie → accélération (Étape 2). Le levier de qualité le plus important.
- Anticipation → le pré-mouvement (Étape 4).
- Suivi et action qui se chevauche → dépassement + éléments secondaires en retard (Étape 4). La différence entre "correct" et "vivant".
- Timing → durée et espacement (Étape 3).
- Écrasement et étirement → échelle subtile lors de l'appui/de l'impact pour suggérer la masse ; dans l'interface, limitez-vous à quelques pourcentages ou cela ressemble à un jouet.
- Mise en scène → déplacer une chose à la fois pour que l'œil sache où regarder ; n'animez jamais six choses à la fois sur la même courbe.
- Action secondaire → un petit mouvement de soutien (une ombre qui s'assombrit alors qu'une carte se soulève) qui renforce le mouvement principal sans rivaliser.
- Exagération → poussez la pose clé légèrement au-delà du réaliste ; restreinte dans l'interface, plus libre dans une vidéo produit percutante.
Étape 6 : Transmettre la spécification
Remplissez le modèle de spécification de mouvement ci-dessous — courbe, durée (et trames), les temps de l'arc, et l'appel spring vs interpolate par propriété. Cette spécification remplie est l'artefact de transmission : pour une scène vidéo produit, elle va directement dans product-demo-director ; pour l'interface, elle devient vos valeurs de transition/keyframe. Associez-la à motion-color-and-light si la scène nécessite également un mouvement de lumière/exposition, kinetic-typography si du texte est animé, et sound-and-music-sync si le timing doit correspondre à un beat.
Barre de qualité
Le mouvement est A+ uniquement si tous ces critères sont respectés :
- Le diagnostic est nommé (linéaire / flottant / saccadé / mort), et chaque changement lui est attribué. Pas de "rendu plus joli" sans raison.
- Entrées avec ease-out, sorties avec ease-in, déplacement A→B à l'écran avec ease-in-out, animations vivantes/physiques avec spring. Aucun mouvement linéaire brut ne part en production, sauf les boucles délibérées à vitesse constante (un spinner, un marquee).
- La durée varie avec la distance/taille, et la sortie est plus rapide que l'entrée.
- L'appel
spring()vsinterpolate()est explicite par propriété : spring pour les transformations physiques (scale, translate, le pop/slide/stabilisation — vous voulez le dépassement) ; interpolate pour les valeurs précises temporalisées (fondus d'opacité, couleur, progression, tout ce qui serait endommagé par un dépassement). Un fondu entraîné par un spring, ou un logo pop entraîné par un interpolate linéaire, est un défaut. - Au moins un élément d'anticipation ou de suivi est présent sur le mouvement héroïque / signature ; un mouvement sans vie manque exactement de cela.
- Une chose mène à la fois (mise en scène) ; les propriétés sont décalées plutôt que de toutes se déclencher sur une seule timeline plate.
- La courbe, la durée et les nombres de trames sont écrits et prêts à être transmis à product-demo-director ou à une transition — ce skill ne laisse jamais une décision implicite.
À NE PAS FAIRE
- Ne livrez PAS d'accélération linéaire pour les entrées ou sorties — c'est le défaut robotique et cela donne l'impression d'être inachevé. La vitesse constante n'est réservée qu'aux boucles intentionnelles.
- N'utilisez PAS ease-in pour une entrée ni ease-out pour une sortie — cela donne la sensation flottante/lente inversée. Entrées avec ease-out, sorties avec ease-in.
- N'utilisez PAS de durées d'entrée et de sortie égales ; les sorties doivent être ~0,7–0,8x plus rapides.
- N'entraînez PAS un fondu, une couleur ou une barre de progression avec un spring — le dépassement fait dépasser les valeurs et clignoter. Utilisez interpolate pour les valeurs temporalisées.
- N'entraînez PAS un pop/glissement/échelle vivant avec un interpolate linéaire quand vous voulez qu'il soit vivant — utilisez un spring pour le dépassement.
- N'animez PAS plusieurs propriétés sur une seule timeline plate ; mettez en scène et décalez-les.
- Ne faites PAS de sur-anticipation ni de sur-dépassement dans l'interface — quelques pixels / quelques pourcents. De grands pré-mouvements et des rebonds ressemblent à un bug ou à un jouet.
- Ne planifiez PAS l'ordre des plans ni n'assemblez la démo ici — transmettez la spécification à product-demo-director ; l'ordre du storyboard est géré par video-storyboard.
Sélecteur d'accélération et de spring
Script Node autonome. Enregistrez-le sous motion_pick.js et exécutez-le avec node motion_pick.js. Modifiez le tableau requests pour les éléments que vous animez ; le script retourne la courbe, une durée ajustée à la distance (en ms et trames), la durée de sortie, et l'appel spring vs interpolate. Aucune dépendance.
// Sélecteur de mouvement. Modifiez `requests`, puis : node motion_pick.js
const fps = 30 // pour vidéo produit ; UI ignore la colonne des trames
// role: 'enter' | 'exit' | 'move' | 'lively'
// distancePx: distance parcourue (définit la durée). sizePx: taille approximative de l'élément.
const requests = [
{ name: 'Modal pop-in', role: 'lively', property: 'scale', distancePx: 0, sizePx: 600 },
{ name: 'Modal backdrop', role: 'enter', property: 'opacity', distancePx: 0, sizePx: 1920 },
{ name: 'Toast slide-in', role: 'enter', property: 'translate', distancePx: 320, sizePx: 360 },
{ name: 'Toast dismiss', role: 'exit', property: 'translate', distancePx: 320, sizePx: 360 },
{ name: 'Card reorder', role: 'move', property: 'translate', distancePx: 140, sizePx: 280 },
{ name: 'Progress fill', role: 'move', property: 'width', distancePx: 800, sizePx: 800 },
]
function curveFor(role) {
if (role === 'enter') return 'ease-out'
if (role === 'exit') return 'ease-in'
if (role === 'move') return 'ease-in-out'
return 'spring' // lively
}
// La durée varie avec la distance de déplacement et la taille de l'élément. Plancher + pente, plafonné.
function durationMs(role, distancePx, sizePx) {
const reach = Math.max(distancePx, sizePx * 0.4)
let ms = 140 + reach * 0.45
ms = Math.min(Math.max(ms, 140), 600)
if (role === 'exit') ms *= 0.75 // les sorties sont plus rapides
return Math.round(ms)
}
// spring pour les transformations physiques ; interpolate pour les valeurs temporalisées.
function driver(role, property) {
const physical = property === 'scale' || property === 'translate'
if (role === 'lively') return 'spring() // veut le dépassement'
if (physical && role !== 'move') return 'spring() // physique, stabilisation vivante'
return 'interpolate() // précis, temporalisé par trame'
}
const pad = (s, n) => String(s).padEnd(n)
console.log(pad('ÉLÉMENT', 18), pad('COURBE', 12), pad('MS', 6), pad('TRAMES', 8), 'DRIVER')
for (const r of requests) {
const curve = curveFor(r.role)
const ms = durationMs(r.role, r.distancePx, r.sizePx)
const frames = Math.round((ms / 1000) * fps)
console.log(pad(r.name, 18), pad(curve, 12), pad(ms, 6), pad(frames, 8), driver(r.role, r.property))
}
Exemple de sortie
ÉLÉMENT COURBE MS TRAMES DRIVER
Modal pop-in spring 140 4 spring() // veut le dépassement
Modal backdrop ease-out 140 4 interpolate() // précis, temporalisé par trame
Toast slide-in ease-out 284 9 spring() // physique, stabilisation vivante
Toast dismiss ease-in 213 6 spring() // physique, stabilisation vivante
Card reorder ease-in-out 203 6 interpolate() // précis, temporalisé par trame
Progress fill ease-in-out 500 15 interpolate() // précis, temporalisé par trame
Modèle de spécification de mouvement
À remplir pour chaque élément animé avant de quitter ce skill. Transmettez-la à product-demo-director ou utilisez-la comme base pour vos transitions.
## Spécification de mouvement pour : {nom court}
**Rôle** : {entrée | sortie | déplacement | vivant}
**Propriété** : {scale | translate | opacity | color | ...}
**Courbe** : {ease-out | ease-in | ease-in-out | spring}
**Durée** : {ms} ms ({trames} trames @ {fps} fps)
**Appel driver** : {spring() | interpolate()}
**Temps de l'arc** : [anticipation → action → suivi]
- Anticipation : {néant | petite échelle inverse Xms / déplacement inverse Ypx}
- Action : {description rapide}
- Suivi : {dépassement attendu et/ou effets secondaires}
**Accompagnement** : {motion-color-and-light | kinetic-typography | sound-and-music-sync | aucun}
Exemple : Spécification d'une modale pop-in
## Spécification de mouvement pour : Modale pop-in
**Rôle** : vivant
**Propriété** : scale (du centre)
**Courbe** : spring
**Durée** : 200 ms (6 trames @ 30 fps)
**Appel driver** : spring() // veut le dépassement
**Temps de l'arc** : [anticipation → action → suivi]
- Anticipation : néant (démarre directement à l'échelle 0 → 1)
- Action : échelle de 0 à 1, 200ms, spring
- Suivi : le spring dépasse à ~1,05 et se stabilise en 1 sur ~100ms supplémentaires ; l'ombre s'assombrit 50ms après le pic
**Accompagnement** : motion-color-and-light (pour le fondu de fond)