VYBE Motion Design
Le mouvement est le message. Chaque mouvement doit dire quelque chose sur le sujet — poids, vitesse, confiance, émerveillement — ou il ne devrait pas exister.
Toutes les recettes sont pour HyperFrames : une timeline GSAP en pause par composition,
déterministe, seekable. Utilisez fromTo pour les entrées, transforms + opacity +
clipPath + filter pour l'animation, jamais les propriétés de mise en page.
Références (chargez celle dont vous avez besoin)
| Fichier | Pour |
|---|---|
references/animation-principles.md | les 12 principes appliqués à l'interface/typographie/graphismes, vocabulaire d'easing, tables de timing |
references/transitions.md | 14 recettes de transition avec code GSAP, et quand les utiliser |
references/camera-movements.md | dolly, truck, grue, orbite, zoom-through, whip, rack focus, parallax — 2D et 3D |
references/visual-effects.md | lueur, bloom, fuite de lumière, grain de film, séparation chromatique, flou de mouvement, masques, morphs |
Les dix règles
- Chorégraphiez, n'animez pas. Planifiez qui bouge en premier, qui répond, qui tient. Une scène est une phrase : sujet → verbe → objet.
- L'easing est la personnalité.
expo.out= premium/confiant ;back.out= ludique ;power2.inOut= caméra mécanique ;sine.inOut= respirant/ambiant ;none= dérive constante. Choisissez 2–3 easing par film et restez cohérent. - Rapide à l'entrée, ralentissement progressif. La plupart des entrées : 0,5–0,9s, 80% du trajet dans les 30% premiers du temps.
- Les sorties sont plus rapides que les entrées (≈60%) et utilisent des easing
.in. - Le staggering révèle la hiérarchie — 0,04–0,08s pour les lettres, 0,1–0,18s pour les mots, 0,3–0,6s pour les éléments de liste. Ne stagger jamais tout de manière identique.
- Chevauchez les actions. L'élément suivant commence avant que le précédent ne se termine
(paramètre de position
"<0.2"/ temps absolus). Séquentiel = robotique. - Pause pour lire. ≈0,3s par mot + 0,5s ; lignes de clôture ≥2s.
- Toujours quelque chose de vivant. Pendant les pauses, un push lent (
scale 1→1,04), une dérive ou un balayage lumineux empêche le cadre de mourir — mais un seul mouvement ambiant par couche. - Variez les transitions. Au maximum un fondu au noir par film. Privilégiez les coupes sur mouvement, match cuts, wipe avec masque, zoom-throughs, éléments partagés.
- Respectez le rythme. S'il y a de la musique, chaque changement majeur atterrit sur un temps
(
60/bpm) ; les hits tombent sur le temps fort, l'anticipation commence avant.
Patterns GSAP seek-safe
const tl = gsap.timeline({ paused: true });
// Entrée : montée flou-à-net (premium)
tl.fromTo("#s1-title", { opacity: 0, y: 40, filter: "blur(12px)" },
{ opacity: 1, y: 0, filter: "blur(0px)", duration: 0.9, ease: "expo.out" }, 0.2);
// Révélation par wipe de masque (éditorial)
tl.fromTo("#s1-line", { clipPath: "inset(0 100% 0 0)" }, { clipPath: "inset(0 0% 0 0)", duration: 0.8, ease: "expo.inOut" }, 0.5);
// Dispersion par glyphe (au lieu de letterSpacing — que lint rejette)
gsap.utils.toArray("#s1-word .ch").forEach((c, i, all) => {
const off = (i - (all.length - 1) / 2) * -30;
tl.fromTo(c, { x: off, opacity: 0 }, { x: 0, opacity: 1, duration: 1, ease: "expo.out" }, 1 + Math.abs(i - (all.length - 1) / 2) * 0.05);
});
// Compteur (seekable : onUpdate s'exécute à chaque seek)
const n = { v: 0 }, el = document.getElementById("s1-num");
tl.fromTo(n, { v: 0 }, { v: 97, duration: 1.4, ease: "expo.out", onUpdate: () => (el.textContent = Math.round(n.v)) }, 1.2);
// Pause ambiante
tl.fromTo("#s1-stack", { scale: 1 }, { scale: 1.04, duration: 3, ease: "sine.inOut" }, 0);
window.__timelines["s1"] = tl;
Découpage du texte : enveloppez les mots/lettres dans <span class="w|ch" style="display:inline-block">
(les transforms sont sans effet sur les éléments en ligne). Gardez les espaces à l'extérieur des spans.
Avant de livrer
- Pas deux scènes consécutives avec le même mouvement d'entrée.
- Aucune propriété tweenée deux fois sur le même élément à des moments qui se chevauchent.
npx hyperframes checkLa section Motion est propre ; pour les audits de chorégraphie exécutez le scriptanimation-map.mjsfourni avec la compétence/hyperframes-animationde HyperFrames lorsqu'elle est installée.