Skill: gsap-rendimiento-animaciones

Animaciones a 60fps
sin una sola caída de frame

Patrones de rendimiento GSAP aplicados en la landing de Roast Analytics — transforms, quickTo, stagger eficiente y ScrollTrigger sin layout thrashing.

FPS durante animación de scroll — antes vs después Roast Analytics — landing v3
60fps — Después ~22fps — Antes
60
FPS estables (optimizado)
22
FPS promedio (sin optimizar)
173%
Mejora de rendimiento
Características clave

Patrones que aplicamos

Cada regla de la skill puesta en práctica con código real del proyecto Roast Analytics.

Transform + Opacity únicamente
Animamos solo x, y, scale, rotation y opacity. Nunca left, top, width o height — se mantiene en el compositor.
🖱️
quickTo() para el cursor
El cursor personalizado usa gsap.quickTo() en x/y, reutilizando un único tween por propiedad en lugar de crear miles en cada mousemove.
📦
Stagger eficiente en listas
Las 6 feature cards se animan con un solo gsap.to(cards, { stagger: 0.08 }) en lugar de 6 tweens independientes con delay manual.
🎯
will-change selectivo
Solo los elementos que van a animar tienen will-change: transform, opacity en CSS. No se aplica a todos los divs "por si acaso".
🔄
ScrollTrigger sin thrashing
ScrollTrigger.refresh() se llama una vez al terminar la carga, con debounce en resize. No en cada evento de scroll.
🧹
Limpieza de tweens off-screen
Animaciones de secciones fuera del viewport se pausan o eliminan. Los ScrollTriggers se destruyen al salir del componente en React/Vue.

Antes vs. Después

Ejemplos reales del refactor aplicado a la landing de Roast Analytics.

Evitar — Movimiento con left/top
// ❌ Causa layout thrashing en cada frame
gsap.to(".card", {
  left: "200px",
  top: "50px",
  width: "300px",
  duration: 0.6,
  ease: "power2.out"
});

// Resultado: layout recalculation en
// cada tick → jank en gama media
Correcto — Movimiento con x/y
// ✅ Solo compositor — 0 layout cost
gsap.to(".card", {
  x: 200,
  y: 50,
  scaleX: 1.15,
  duration: 0.6,
  ease: "power2.out"
});

// Resultado: translateX/translateY en GPU
// → 60fps estables en todos los devices
Evitar — Nuevo tween en mousemove
// ❌ Crea cientos de tweens por segundo
document.addEventListener("mousemove", (e) => {
  gsap.to("#cursor", {
    x: e.pageX,
    y: e.pageY,
    duration: 0.3
  });
});

// ~60 tweens/seg → memory pressure
// → frames saltados en scroll simultáneo
Correcto — gsap.quickTo()
// ✅ Un solo tween, actualizado por quickTo
const xTo = gsap.quickTo("#cursor", "x", {
  duration: 0.4, ease: "power3"
});
const yTo = gsap.quickTo("#cursor", "y", {
  duration: 0.4, ease: "power3"
});

document.addEventListener("mousemove", (e) => {
  xTo(e.pageX); yTo(e.pageY);
});
Evitar — Tweens separados con delay
// ❌ 6 tweens independientes, mayor overhead
const cards = document.querySelectorAll(".feat-card");
cards.forEach((card, i) => {
  gsap.from(card, {
    opacity: 0, y: 28,
    delay: i * 0.08,  // manual!
    duration: 0.55
  });
});

// Resultado: 6 tweens con delay calculado
// a mano — gestión duplicada
Correcto — stagger unificado
// ✅ Un solo tween con stagger interno
const cards = gsap.utils.toArray(".feat-card");

gsap.from(cards, {
  opacity: 0,
  y: 28,
  duration: 0.55,
  stagger: 0.08,  // GSAP lo gestiona
  ease: "power2.out"
});

// GSAP reutiliza internamente el tween
// y calcula el timing automáticamente
Métricas de rendimiento

Resultados tras el refactor

Medidos con Chrome DevTools Performance en MacBook Air M1 y Moto G6 (low-end).

FPS estables
60
antes: ~22fps en scroll
Layout recalcs / scroll
0
antes: 18–24 por frame
Tweens activos (mousemove)
2
antes: ~120 por segundo
JS heap (scroll section)
4.2 MB
antes: 38 MB por tweens
Paint cost / frame
0 ms
solo compositor (transform)
Lighthouse Performance
98
antes: 61 — mejora +60%

Do & Don't

Referencia rápida extraída directamente de la skill gsap-rendimiento-animaciones.

✓ Hacer siempre
  • Animar solo transform (x, y, scale, rotation) y opacity; se procesan en el compositor GPU.
  • Poner will-change: transform en CSS únicamente en los elementos que van a animar.
  • Usar gsap.quickTo() para propiedades actualizadas con alta frecuencia (cursor, scroll parallax).
  • Usar stagger en lugar de muchos tweens independientes con delay manual.
  • Llamar ScrollTrigger.refresh() solo cuando el layout cambia de verdad; debounced en resize.
  • Pausar o matar animaciones de secciones off-screen y en componentes desmontados.
  • Hacer lecturas DOM antes que escrituras; dejar que GSAP agrupe las escrituras internamente.
✗ Evitar siempre
  • Animar left, top, width, height, margin o padding para movimiento — disparan layout en cada frame.
  • Poner will-change o force3D: true en todos los elementos "por precaución".
  • Crear un nuevo gsap.to() dentro de mousemove sin usar quickTo.
  • Lanzar cientos de tweens simultáneos sin validar en dispositivos de gama baja.
  • Reusar timelines creadas cada frame; crearlas una vez y reproducirlas.
  • Ignorar la limpieza: tweens y ScrollTriggers huérfanos siguen consumiendo CPU.
  • Llamar ScrollTrigger.refresh() en cada evento de scroll o resize sin debounce.