Communitygithub.com

KILN-skills/scroll-animation

Créez des animations pilotées par le défilement avec GSAP, ScrollTrigger, SplitText et le défilement fluide Lenis — révélations, sections épinglées, défilement horizontal, parallaxe, timelines synchronisées, effets de texte — en vanilla JS, React, Next.js, Vue/Nuxt ou Astro, avec une configuration, un nettoyage et des alternatives responsives corrects.

Qu'est-ce que scroll-animation ?

Cette compétence fournit un guide complet pour la création d'animations basées sur le défilement en utilisant GSAP, ScrollTrigger et Lenis. Elle couvre l'installation, l'intégration avec des frameworks modernes (React, Next.js, Vue/Nuxt, Astro, vanilla JS), les bonnes pratiques pour éviter les bugs courants, la gestion du responsive et de la réduction de mouvement, ainsi que des conseils de performance. L'utilisateur est guidé pour créer un module de configuration unique, intégrer correctement les animations dans chaque framework, et utiliser `gsap.matchMedia()` pour des adaptations responsives. La compétence met l'accent sur les règles essentielles de ScrollTrigger qui évitent 90% des bugs et sur les techniques de performance comme l'animation des propriétés `x/y/scale/rotation/autoAlpha`.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/KILN-skills/kiln/tree/HEAD/skills/scroll-animation

Demander à votre IA préférée

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

Documentation

Scroll Animation (GSAP + ScrollTrigger + Lenis)

Si les compétences officielles de GreenSock (gsap-core, gsap-scrolltrigger, gsap-react, gsap-plugins) sont installées, utilisez-les pour les détails de l'API ; cette compétence couvre la configuration du projet, l'intégration et les erreurs qui cassent les sites en production.

1. Installation

npm i gsap lenis
npm i @gsap/react   # React / Next.js uniquement

Tous les plugins GSAP (ScrollTrigger, SplitText, Flip, ScrollSmoother, MorphSVG, DrawSVG…) sont fournis dans le package public gsap et sont gratuits pour un usage commercial. Importez depuis gsap/<NomPlugin> et appelez gsap.registerPlugin(...) une seule fois.

2. Un module de configuration unique

Créez lib/motion/setup.(js|ts) (ou animations/) qui est importé une fois côté client :

import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import Lenis from "lenis";
import "lenis/dist/lenis.css";

gsap.registerPlugin(ScrollTrigger, SplitText);

export function initSmoothScroll() {
  if (matchMedia("(prefers-reduced-motion: reduce)").matches) return null;
  const lenis = new Lenis();
  lenis.on("scroll", ScrollTrigger.update);
  const tick = (time) => lenis.raf(time * 1000); // GSAP time is seconds, Lenis wants ms
  gsap.ticker.add(tick);
  gsap.ticker.lagSmoothing(0);
  return () => { gsap.ticker.remove(tick); lenis.destroy(); };
}

Utilisez soit Lenis soit GSAP ScrollSmoother, pas les deux.

3. Intégration framework

React / Next.js (App Router) — les fichiers utilisant GSAP doivent avoir "use client". Utilisez toujours useGSAP (nettoyage automatique, pas de double exécution en mode strict) :

"use client";
import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(useGSAP, ScrollTrigger);

export function Features() {
  const root = useRef<HTMLElement>(null);
  useGSAP(() => {
    const mm = gsap.matchMedia();
    mm.add("(prefers-reduced-motion: no-preference)", () => {
      gsap.from(".feature", {
        autoAlpha: 0, y: 32, stagger: 0.08, ease: "power3.out",
        scrollTrigger: { trigger: root.current, start: "top 75%" },
      });
    });
  }, { scope: root }); // les sélecteurs sont limités à ce composant
  return <section ref={root}>…</section>;
}
  • Gestionnaires d'événements qui créent des animations : enveloppez avec contextSafe de useGSAP.
  • Fournisseur de défilement fluide : un composant client dans la mise en page racine qui appelle initSmoothScroll() dans un effet (ou ReactLenis de lenis/react avec autoRaf: false et le ticker GSAP).
  • Changement de route dans Next.js : défiler vers le haut (lenis.scrollTo(0, { immediate: true })) et ScrollTrigger.refresh() après le montage de la nouvelle page.

Vue / Nuxt — créez dans onMounted à l'intérieur de gsap.context(() => {…}, rootEl), appelez ctx.revert() dans onUnmounted. Nuxt : plugin côté client (plugins/gsap.client.ts).

Astro / site multi-pages statique — une balise <script> dans la mise en page ; avec View Transitions, réinitialisez sur astro:page-load et supprimez les triggers sur astro:before-swap.

Vanilla — un seul main.js qui s'exécute après le DOM ready ; regroupez par section dans gsap.context().

4. Règles ScrollTrigger qui évitent 90% des bugs

  • Mettez scrollTrigger sur une timeline ou un tween de premier niveau — jamais sur des tweens imbriqués dans une timeline.
  • Utilisez ease: "none" avec scrub.
  • L'ordre de création compte : créez les triggers de haut en bas dans l'ordre de la page (ou définissez refreshPriority), surtout avec l'épinglage.
  • Épinglez un conteneur, pas l'élément que vous animez. N'épinglez pas à l'intérieur d'un parent avec transform. Évitez pinSpacing: false sauf si c'est intentionnel.
  • Utilisez des valeurs de fonction (x: () => …) + invalidateOnRefresh: true pour tout ce qui dépend de la taille de la fenêtre.
  • Appelez ScrollTrigger.refresh() après que les images/polices/contenu dynamique changent la mise en page (window.addEventListener("load", …), document.fonts.ready).
  • Déboguez avec markers: true — supprimez avant la mise en production.
  • États initiaux cachés : utilisez gsap.from/fromTo ou autoAlpha défini par JS, pour que le contenu soit visible sans JS.
  • once: true pour les révélations qui ne doivent pas se rejouer (la plupart d'entre elles).

5. Responsive & réduction de mouvement

Enveloppez chaque scène dans gsap.matchMedia() :

const mm = gsap.matchMedia();
mm.add({
  isDesktop: "(min-width: 1024px)",
  isMobile: "(max-width: 1023px)",
  motionOK: "(prefers-reduced-motion: no-preference)",
}, ({ conditions: c }) => {
  if (!c.motionOK) return;            // mise en page statique, pas d'animation
  if (c.isDesktop) { /* scènes épinglées / horizontales */ }
  if (c.isMobile)  { /* simples fondus vers le haut uniquement */ }
});

matchMedia se réinitialise automatiquement lorsque les conditions changent — pas de nettoyage manuel.

6. Performance

  • Animez x/y/scale/rotation/autoAlpha (transformations + opacité). Évitez d'animer width/height/top/left et les filter: blur() lourds sur de grandes zones.
  • Préférez une timeline par section plutôt que des dizaines de triggers séparés ; ScrollTrigger.batch pour de nombreuses révélations identiques.
  • gsap.quickTo pour les effets de suivi du pointeur.
  • Grandes images dans les scènes synchronisées : utilisez des sizes appropriés, et évitez de redimensionner de gros bitmaps à chaque frame.

7. Vérification

Faites défiler toute la page rapidement vers le haut et vers le bas ; redimensionnez la fenêtre ; rechargez au milieu de la page ; naviguez ailleurs et revenez (SPA) — pas de sauts, pas d'épingles dupliquées, pas d'erreurs dans la console. Testez avec la réduction de mouvement activée, à 375px de largeur, et avec un ralentissement CPU.

Recettes pour les effets courants : ../motion-direction/references/patterns.md.

Skills associés