GSAP podstawy

GSAP (GreenSock Animation Platform) to najpopularniejsza biblioteka do animacji w internecie. Korzysta z niej ponad 11 milionów stron, w tym wiele nagradzanych projektów. GSAP pozwala animować praktycznie wszystko, co JavaScript może dotknąć - elementy HTML, SVG, Three.js, komponenty Reacta, a nawet dowolne obiekty JavaScript. Dlaczego GSAP, a nie CSS animations czy Web Animations API?

  • Wydajność - GSAP optymalizuje renderowanie, omijając layout thrashing
  • Pełna kontrola nad czasem - play, pause, reverse, seek, timeScale
  • Cross-browser - działa tak samo w każdej przeglądarce
  • Timeline - zaawansowane sekwencjonowanie animacji
  • Pluginy - ScrollTrigger, Draggable, MorphSVG, MotionPath i wiele innych

Instalacja

Najprościej jest załączyć bibliotekę z CDN.
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
Użycie npm:
npm install gsap
Następnie importujemy:
import gsap from 'gsap';
// lub konkretny plugin:
import { ScrollTrigger } from 'gsap/ScrollTrigger';
Jeśli chcemy dołączyć pluginy:
// Po załadowaniu biblioteki zarejestruj pluginy:
gsap.registerPlugin(ScrollTrigger);

Podstawy - Tween

Tween to pojedyncza animacja. W GSAP mamy cztery typy: gsap.to() - Animuje od obecnej wartości do podanej gsap.from() - Animuje od podanej wartości do obecnej gsap.fromTo() - Definiujesz start i koniec gsap.set() - Natychmiast ustawia właściwości (bez animacji)

gsap.to() - najpopularniejsza metoda

gsap.to('.box', {
  x: 200,          // translateX: 200px
  duration: 2,     // czas trwania w sekundach
  ease: 'power2.out'
});

gsap.from() - animacja "od"

gsap.from('.box', {
  x: -200,
  opacity: 0,
  duration: 1.5,
  ease: 'back.out(1.7)'  // efekt "overshoot"
});

gsap.fromTo() - pełna kontrola

gsap.fromTo('.box',
  { x: 0, opacity: 0, scale: 0.5 },  // stan początkowy
  { x: 300, opacity: 1, scale: 1, duration: 2 }  // stan końcowy
);

Transformacje - co można animować?

GSAP animuje praktycznie wszystko. Oto najczęściej używane właściwości:

Translacje i obrót

gsap.to('.element', {
  x: 100,            // translateX(100px)
  y: 50,             // translateY(50px)
  rotation: 45,      // rotate(45deg)
  scale: 1.5,        // scale(1.5)
  scaleX: 2,         // scaleX(2)
  scaleY: 0.5,       // scaleY(0.5)
  skewX: 10,         // skewX(10deg)
  skewY: 5,          // skewY(5deg)
  transformOrigin: 'center top'
});

Właściwości CSS

gsap.to('.box', {
  backgroundColor: '#3498db',
  borderRadius: '20px',
  boxShadow: '0 10px 30px rgba(0,0,0,0.3)',
  padding: '40px',
  filter: 'blur(4px)',
  duration: 1
});

SVG

gsap.to('#myPath', {
  attr: {
    d: 'M10 50 Q100 10 190 50',  // morphing ścieżki
    fill: '#e74c3c',
    stroke: '#c0392b',
    strokeWidth: 4
  },
  duration: 2
});

Dowolny obiekt JavaScript

const obj = { value: 0, color: '#ff0000' };

gsap.to(obj, {
  value: 100,
  duration: 2,
  ease: 'power4.inOut',
  onUpdate: () => {
    console.log(`Wartość: ${obj.value}`);
    document.getElementById('counter').textContent = Math.round(obj.value);
  }
});

Timeline - sekwencjonowanie animacji

Timeline to kontener na tweeny, który pozwala precyzyjnie umieszczać animacje w czasie.

Podstawowe sekwencjonowanie

const tl = gsap.timeline();

tl.to('.box1', { x: 200, duration: 1 })
  .to('.box2', { y: 100, duration: 1 })
  .to('.box3', { rotation: 360, duration: 2 });
Animacje odtwarzają się jedna po drugiej.

Parametr position - precyzyjne pozycjonowanie

const tl = gsap.timeline();

// Absolutny czas (sekundy od początku)
tl.to('.box1', { x: 200, duration: 1 }, 0);

// Relatywny czas (+=2 = 2 sekundy po poprzedniej animacji)
tl.to('.box2', { y: 100, duration: 1 }, '+=2');

// Nаłоżenie (-=0.5 = 0.5 sekundy przed końcem poprzedniej)
tl.to('.box3', { opacity: 1, duration: 1 }, '-=0.5');

// W tym samym momencie co box1
tl.to('.box4', { scale: 1.5, duration: 1 }, 0);

Etykiety (Labels) - czytelne sekwencjonowanie

const tl = gsap.timeline();

tl.to('.box1', { x: 200, duration: 1 })
  .add('scene2', '+=1')           // dodaje etykietę 1s po poprzedniej
  .to('.box2', { y: 100, duration: 1 }, 'scene2')
  .to('.box3', { rotation: 360, duration: 2 }, 'scene2+=0.5')
  .add('scene3', '+=2');

// Nawigacja po etykietach
tl.play('scene2');
tl.seek('scene3');

Kontrola Timeline

const tl = gsap.timeline();

tl.to('.box', { x: 300, duration: 2 });

// Pauzowanie
tl.pause();

// Odtwarzanie
tl.play();

// Przewijanie do konkretnej sekundy
tl.seek(1);

// Zmiana prędkości (0.5 = połowa, 2 = podwójna)
tl.timeScale(0.5);

// Odwracanie
tl.reverse();

// Ustawienie postępu (0 = początek, 1 = koniec)
tl.progress(0.5);

// Restart
tl.restart();

Właściwości specjalne

  • duration - Czas trwania (sekundy) duration: 2
  • delay - Opóźnienie startu (sekundy) delay: 1
  • repeat - Liczba powtórzeń ('-1' = nieskończenie) repeat: 3
  • yoyo - Odwraca animację co powtórzenie yoyo: true
  • stagger - Opóźnienie między elementami stagger: 0.1
  • ease - Krzywa wygładzania ease: 'power2.out'
  • onComplete - Callback po zakończeniu onComplete: myFunc
  • onUpdate - Callback na każdy tick onUpdate: update

Powtórzenia i yoyo

gsap.to('.box', {
  x: 200,
  duration: 1,
  repeat: -1,     // nieskończone powtórzenie
  yoyo: true,     // odwraca kierunek co cycle
  ease: 'power1.inOut'
});

Stagger - animacja grup elementów

// Każdy element z .dot animuje się z 0.1s opóźnienia
gsap.to('.dot', {
  y: -50,
  duration: 0.8,
  stagger: 0.1,
  ease: 'back.out(2)'
});

Easing - krzywe wygładzania

// Wbudowane easingi
gsap.to('.box', { x: 200, ease: 'power2.out' });
gsap.to('.box', { x: 200, ease: 'elastic.out(1, 0.5)' });
gsap.to('.box', { x: 200, ease: 'bounce.out' });
gsap.to('.box', { x: 200, ease: 'expo.inOut' });
gsap.to('.box', { x: 200, ease: 'circ.inOut' });
gsap.to('.box', { x: 200, ease: 'sine.inOut' });

// Easing z konfiguracją
gsap.to('.box', {
  x: 200,
  ease: 'power4.inOut',
  duration: 2
});

ScrollTrigger - animacje wyzwalane scrollowaniem

ScrollTrigger to najpopularniejszy plugin GSAP. Poniżej przykład jego podstawowego użycia.
gsap.registerPlugin(ScrollTrigger);

gsap.to('.box', {
  x: 300,
  scrollTrigger: {
    trigger: '.section',
    start: 'top center',   // kiedy górna krawędź sekcji dotyka środka viewporta
    end: 'bottom center',  // kiedy dolna krawędź sekcji dotyka środka viewporta
    scrub: true,           // animacja powiązana ze scrollowaniem
    toggleActions: 'play pause resume reverse'
  }
});

Przyklejanie elementu

gsap.to('.hero', {
  y: 0,
  scrollTrigger: {
    trigger: '.hero',
    start: 'top top',
    end: '+=500',
    scrub: true,
    pin: true,           // "przykleja" element podczas scrollowania
    anticipatePin: 1
  }
});

Animacja SVG podczas scrollowania

// Oblicz długość ścieżki SVG
const path = document.querySelector('#draw-path');
const length = path.getTotalLength();

// Ukryj ścieżkę
gsap.set(path, {
  strokeDasharray: length,
  strokeDashoffset: length
});

// Animuj "rysowanie" podczas scrollowania
gsap.to(path, {
  strokeDashoffset: 0,
  ease: 'none',
  scrollTrigger: {
    trigger: '.section',
    start: 'top center',
    end: 'bottom center',
    scrub: true
  }
});

Parallax effect

// Tło porusza się wolniej niż treść
gsap.to('.parallax-bg', {
  y: -200,
  ease: 'none',
  scrollTrigger: {
    trigger: '.parallax-section',
    start: 'top bottom',
    end: 'bottom top',
    scrub: true
  }
});

Sekwencja w ScrollTrigger

const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.reveal-section',
    start: 'top 80%',
    end: 'top 20%',
    scrub: 1, // 1s opóźnienia dla płynności
    pin: true
  }
});

tl.from('.reveal-section .title', {
  opacity: 0,
  y: 60,
  duration: 1
})
.from('.reveal-section .text', {
  opacity: 0,
  y: 40,
  duration: 1
}, '-=0.5')
.from('.reveal-section .image', {
  scale: 0.8,
  opacity: 0,
  duration: 1
}, '-=0.5');

Multiple ScrollTriggers z markerami (debug)

gsap.utils.toArray('.section').forEach((section, i) => {
  gsap.from(section.querySelector('.content'), {
    scrollTrigger: {
      trigger: section,
      start: 'top center+=100',
      end: 'bottom center',
      scrub: true,
      // markers: true, // odkomentuj w celu debugowania
      onEnter: () => section.classList.add('active'),
      onLeave: () => section.classList.remove('active'),
      onEnterBack: () => section.classList.add('active'),
      onLeaveBack: () => section.classList.remove('active')
    },
    x: 0,
    opacity: 1,
    duration: 1,
    ease: 'power2.out'
  });
});

ScrollSmoother - płynne scrollowanie

ScrollSmoother dodaje "inercję" scrollowaniu, nadając animacji bardziej płynne odczucie.
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);

const smoother = ScrollSmoother.create({
  wrapper: '#smooth-wrapper',
  content: '#smooth-content',
  smooth: 1.5,       // czas wygładzania (im więcej, tym płynniej)
  smoothTouch: 0.1,  // mniejsze wygładzanie na dotyku
  normalizeScroll: true,
  ignoreMobileResize: true
});

// Zaktualizuj ScrollTrigger po zmianie layoutu
ScrollTrigger.addEventListener('refresh', () => smoother.scrollTop(s smoother.scrollTop()));
ScrollTrigger.refresh();

Animacja SVG - animacja ścieżek

Przykład morphingu ścieżki SVG:
gsap.to('#shape', {
  attr: {
    d: 'M10 10 H90 V90 H10 L10 10 Z'  // nowa ścieżka
  },
  duration: 2,
  ease: 'power2.inOut'
});
Animacja SVG z CSS:
gsap.to('#mySVG', {
  x: 100,
  y: 50,
  rotation: 45,
  scale: 1.2,
  duration: 1.5,
  ease: 'back.out(1.7)'
});

Animacja kolorów

gsap.to('.box', {
  backgroundColor: '#3498db',
  color: '#ffffff',
  borderColor: '#2980b9',
  duration: 1.5,
  ease: 'power2.inOut'
});

Animacja wartości niestandardowych (bez DOM)

const stats = { value: 0, angle: 0 };

const tl = gsap.timeline({
  onUpdate: () => {
    console.log(`Wartość: ${stats.value.toFixed(1)}, Kąt: ${stats.angle.toFixed(1)}°`);
  },
  onComplete: () => {
    console.log('Animacja zakończona!');
  }
});

tl.to(stats, { value: 100, duration: 2, ease: 'power4.out' })
  .to(stats, { angle: 360, duration: 1, ease: 'power2.inOut' }, '-=1');
Poniżej pełny kod przykładu animacji landing page.
<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>GSAP Landing Page</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: 'Segoe UI', sans-serif; background: #0a0a0a; color: white; }
    .section { min-height: 100vh; display: flex; align-items: center; justify-content: center; flex-direction: column; }
    .hero { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
    .hero h1 { font-size: 4rem; opacity: 0; transform: translateY(50px); }
    .hero p { font-size: 1.5rem; opacity: 0; margin-top: 1rem; }
    .content { background: #0a0a0a; }
    .cards { display: flex; gap: 2rem; margin-top: 3rem; }
    .card { background: #1a1a2e; padding: 2rem; border-radius: 12px; width: 250px; opacity: 0; transform: translateY(60px); }
    .card h3 { color: #667eea; margin-bottom: 0.5rem; }
    .scroll-section { min-height: 200vh; background: #0f0f23; position: relative; }
    .pin-box { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 3rem; color: #667eea; }
  </style>
</head>
<body>
  <div class="section hero">
    <h1>Witaj w GSAP</h1>
    <p>Potężne animacje dla nowoczesnego webu</p>
  </div>

  <div class="section content">
    <h2>Możliwości GSAP</h2>
    <div class="cards">
      <div class="card"><h3>Transformacje</h3><p>x, y, rotation, scale i wiele więcej</p></div>
      <div class="card"><h3>ScrollTrigger</h3><p>Animacje wyzwalane scrollowaniem</p></div>
      <div class="card"><h3>Timeline</h3><p>Precyzyjne sekwencjonowanie</p></div>
    </div>
  </div>

  <div class="scroll-section">
    <div class="pin-box">Scrolluj!</div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
  <script>
    gsap.registerPlugin(ScrollTrigger);

    // Hero entrance
    gsap.to('.hero h1', {
      opacity: 1,
      y: 0,
      duration: 1,
      delay: 0.3,
      ease: 'power3.out'
    });

    gsap.to('.hero p', {
      opacity: 1,
      y: 0,
      duration: 1,
      delay: 0.6,
      ease: 'power3.out'
    });

    // Cards stagger
    gsap.to('.card', {
      opacity: 1,
      y: 0,
      duration: 0.8,
      stagger: 0.2,
      scrollTrigger: {
        trigger: '.cards',
        start: 'top 80%',
        toggleActions: 'play none none reverse'
      },
      ease: 'back.out(1.7)'
    });

    // Pinning section
    gsap.to('.pin-box', {
      scale: 2,
      rotation: 360,
      scrollTrigger: {
        trigger: '.scroll-section',
        start: 'top top',
        end: 'bottom bottom',
        scrub: true,
        pin: true
      }
    });
  </script>
</body>
</html>

Wskazówki i best practices

1. Używaj transformacji zamiast layout properties
// Dobrze - wydajne
gsap.to('.box', { x: 200, y: 100, rotation: 45 });

// Źle - powoduje re-layout
gsap.to('.box', { left: 200, top: 100 });
2. Zawsze cleanup w React
x
useEffect(() => {
  const ctx = gsap.context(() => {
    // animacje
  });
  return () => ctx.revert(); // ← zawsze!
}, []);
3. scrub z opóźnieniem dla płynności
scrollTrigger: {
  scrub: 1,   // 1s opóźnienia - bardziej eleganckie
  // scrub: true  // true = natychmiastowe (bardziej responsywne)
}
4. Debugowanie z markerami
scrollTrigger: {
  trigger: '.section',
  start: 'top center',
  end: 'bottom center',
  scrub: true,
  markers: true  // pokazuje strefy start/end - odkomentuj przy debugu
}
5. Stagger z gridem
gsap.to('.grid-item', {
  opacity: 1,
  y: 0,
  stagger: {
    each: 0.05,
    grid: 'auto',
    from: 'center'  // animacja rozchodzi się od środka
  },
  scrollTrigger: {
    trigger: '.grid',
    start: 'top 80%'
  }
});
GSAP to złoty standard animacji w JavaScript. Jego moc leży w:
  • Prostym API - gsap.to() wystarcza na start
  • Timeline - zaawansowane sekwencjonowanie
  • ScrollTrigger - animacje wyzwalane scrollowaniem w 5 liniach kodu
  • Wydajności - GSAP omija problemy z renderowaniem w przeglądarce
  • Uniwersalności - HTML, SVG, Canvas, React, Vue, Three.js - działa wszędzie