Communitygithub.com

Scroll Animation (GSAP + ScrollTrigger + Lenis)

Crie animações baseadas em rolagem com GSAP, ScrollTrigger, SplitText e Lenis smooth scroll — revelações, seções fixas, rolagem horizontal, parallax, timelines com scrub, efeitos de texto — em Vanilla JS, React, Next.js, Vue/Nuxt ou Astro, com configuração, limpeza e fallbacks responsivos corretos.

O que é Scroll Animation (GSAP + ScrollTrigger + Lenis)?

Esta skill fornece um guia completo e prático para construir animações avançadas baseadas em rolagem (scroll-driven) usando GSAP, ScrollTrigger, SplitText e Lenis. Ela cobre desde a instalação e configuração de um módulo central de animação até a integração correta em frameworks como React/Next.js (com o hook `useGSAP` e o App Router), Vue/Nuxt, Astro e projetos vanilla. A documentação enfatiza as regras essenciais do ScrollTrigger que evitam 90% dos bugs comuns, como a ordem de criação, o uso de `ease: "none"` com `scrub`, e a fixação de wrappers em vez de elementos animados. Além disso, aborda práticas fundamentais de responsividade com `gsap.matchMedia()` e `prefers-reduced-motion`, performance (animando apenas transformações e opacidade), e verificação manual para garantir que a animação funcione sem saltos, duplicações ou erros de console. É a referência ideal sempre que o usuário mencionar GSAP, ScrollTrigger, Lenis, smooth scroll, parallax, pin, scrub, "animasi saat scroll", horizontal scroll ou scroll storytelling.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Scroll Animation (GSAP + ScrollTrigger + Lenis) faz?

Se as skills oficiais do GreenSock (gsap-core, gsap-scrolltrigger, gsap-react, gsap-plugins) estiverem instaladas, use-as para detalhes da API; esta skill cobre a configuração do projeto, integração e os erros que quebram sites reais.

1. Instalação

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

Todos os plugins GSAP (ScrollTrigger, SplitText, Flip, ScrollSmoother, MorphSVG, DrawSVG…) estão incluídos no pacote público gsap e são gratuitos para uso comercial. Importe de gsap/<NomeDoPlugin> e chame gsap.registerPlugin(...) uma vez.

2. Um módulo de configuração

Crie lib/motion/setup.(js|ts) (ou animations/) que seja importado uma vez no cliente:

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); // Tempo do GSAP em segundos, Lenis quer ms
  gsap.ticker.add(tick);
  gsap.ticker.lagSmoothing(0);
  return () => { gsap.ticker.remove(tick); lenis.destroy(); };
}

Use ou Lenis ou GSAP ScrollSmoother, nunca ambos.

3. Integração com frameworks

React / Next.js (App Router) — arquivos que usam GSAP precisam de "use client". Sempre use useGSAP (limpeza automática, sem execução dupla no Strict Mode):

"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 }); // seletores têm escopo neste componente
  return <section ref={root}>…</section>;
}
  • Handlers de eventos que criam animações: envolva com contextSafe do useGSAP.
  • Provedor de scroll suave: um componente cliente no layout raiz que chama initSmoothScroll() em um effect (ou ReactLenis de lenis/react com autoRaf: false e o ticker do GSAP).
  • Mudança de rota no Next.js: scroll para o topo (lenis.scrollTo(0, { immediate: true })) e ScrollTrigger.refresh() após o novo monte da página.

Vue / Nuxt — crie em onMounted dentro de gsap.context(() => {…}, rootEl), chame ctx.revert() em onUnmounted. Nuxt: plugin somente cliente (plugins/gsap.client.ts).

Astro / multi-página estático — uma <script> no layout; com View Transitions, reinicialize em astro:page-load e mate os triggers em astro:before-swap.

Vanilla — um main.js que executa após o DOM pronto; agrupe por seção em gsap.context().

4. Regras do ScrollTrigger que previnem 90% dos bugs

  • Coloque scrollTrigger em uma timeline ou tween de nível superior — nunca em tweens aninhados dentro de uma timeline.
  • Use ease: "none" com scrub.
  • A ordem de criação importa: crie triggers de cima para baixo na ordem da página (ou defina refreshPriority), especialmente com pinning.
  • Fixe um wrapper, não o elemento que você anima. Não fixe dentro de um pai com transform. Evite pinSpacing: false a menos que intencional.
  • Use valores de função (x: () => …) + invalidateOnRefresh: true para qualquer coisa que dependa do tamanho da viewport.
  • Chame ScrollTrigger.refresh() após imagens/fontes/conteúdo dinâmico alterarem o layout (window.addEventListener("load", …), document.fonts.ready).
  • Depure com markers: true — remova antes de publicar.
  • Estados iniciais ocultos: use gsap.from/fromTo ou autoAlpha definidos por JS, para que o conteúdo fique visível sem JS.
  • once: true para revelações que não devem repetir (a maioria delas).

5. Responsivo e movimento reduzido

Envolva cada cena em 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;            // layout estático, sem animação
  if (c.isDesktop) { /* cenas fixas / horizontais */ }
  if (c.isMobile)  { /* apenas fades simples para cima */ }
});

matchMedia reverte automaticamente quando as condições mudam — sem limpeza manual.

6. Performance

  • Anime x/y/scale/rotation/autoAlpha (transformações + opacidade). Evite animar width/height/top/left e filter: blur() pesado em áreas grandes.
  • Prefira uma timeline por seção em vez de dezenas de triggers separados; ScrollTrigger.batch para muitas revelações idênticas.
  • gsap.quickTo para efeitos de seguir o ponteiro.
  • Imagens grandes em cenas com scrub: use sizes adequados e evite redimensionar bitmaps enormes a cada quadro.

7. Verificação

Role a página inteira para cima e para baixo rapidamente; redimensione a janela; recarregue no meio da página; navegue para fora e volte (SPA) — sem saltos, pins duplicados ou erros no console. Teste com movimento reduzido ativado, em 375px e com limitação de CPU.

Receitas para efeitos comuns: ../motion-direction/references/patterns.md.

Habilidades Relacionadas