Stagger & Complex Sequences — Web Animation

Stagger & Complex Sequences Stagger animation adalah teknik menganimasi sekumpulan elemen dengan delay yang berurutan, menciptakan efek "domino" yang terasa ele

Stagger & Complex Sequences

Stagger animation adalah teknik menganimasi sekumpulan elemen dengan delay yang berurutan, menciptakan efek "domino" yang terasa elegan dan terorganisir. Sequence adalah kombinasi beberapa animasi yang berjalan berurutan atau paralel.

Stagger Dasar

/* CSS — stagger manual dengan animation-delay */
.item:nth-child(1) { animation-delay: 0ms; }
.item:nth-child(2) { animation-delay: 100ms; }
.item:nth-child(3) { animation-delay: 200ms; }
.item:nth-child(4) { animation-delay: 300ms; }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}
.item { animation: fadeUp 0.5s ease-out both; }
// JavaScript — stagger programatik
function staggerIn(elements, staggerMs = 100) {
  elements.forEach((el, i) => {
    el.style.animationDelay = \`${i * staggerMs}ms\`;
    el.classList.add('animate-in');
  });
}

// Framer Motion — paling mudah
<motion.ul>
  {items.map((item, i) => (
    <motion.li
      key={item.id}
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{
        delay: i * 0.1,
        duration: 0.4,
        ease: 'easeOut',
      }}
    >
      {item.label}
    </motion.li>
  ))}
</motion.ul>

Stagger dengan Variants (Framer Motion)

Variants memungkinkan stagger yang lebih deklaratif dan powerful:

const containerVariants = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.1,    // 100ms antar child
      delayChildren: 0.2,      // 200ms sebelum child pertama
      staggerDirection: 1,     // 1 = dari awal, -1 = dari akhir
    },
  },
};

const itemVariants = {
  hidden: { opacity: 0, y: 30 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.5, ease: 'easeOut' },
  },
};

function AnimatedList({ items }) {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
    >
      {items.map((item) => (
        <motion.li key={item.id} variants={itemVariants}>
          {item.label}
        </motion.li>
      ))}
    </motion.ul>
  );
}

Stagger dari Tengah (from: center)

// GSAP — stagger dari tengah ke tepi
gsap.from('.grid-item', {
  opacity: 0,
  scale: 0.5,
  duration: 0.5,
  stagger: {
    each: 0.05,
    from: 'center',  // 'start' | 'end' | 'center' | 'random'
  },
});

// Manual — hitung delay dari center
function staggerFromCenter(elements, staggerMs) {
  const center = (elements.length - 1) / 2;
  return elements.map((el, i) => ({
    element: el,
    delay: Math.abs(i - center) * staggerMs,
  }));
}

Complex Sequences

// Framer Motion — sequence dengan useAnimate
import { useAnimate } from 'motion/react';

function IntroAnimation() {
  const [scope, animate] = useAnimate();

  async function playIntro() {
    // Sequence — berjalan berurutan
    await animate('.overlay', { opacity: 0 }, { duration: 0.5 });
    await animate('.title', { opacity: 1, y: 0 }, { duration: 0.6 });
    await animate('.subtitle', { opacity: 1, y: 0 }, { duration: 0.5, delay: 0.1 });

    // Stagger items
    await animate('.item', { opacity: 1, x: 0 }, {
      duration: 0.4,
      delay: stagger(0.1),
    });
  }

  return <div ref={scope}>...</div>;
}

Orchestrasi dengan Promise

// Menggabungkan beberapa animasi
async function runSequence() {
  // Paralel
  await Promise.all([
    animate('.left', { x: 0 }),
    animate('.right', { x: 0 }),
  ]);

  // Berurutan
  await animate('.center', { scale: 1 });
  await animate('.content', { opacity: 1 });
}

Tips Stagger yang Efektif

Stagger adalah tools yang sederhana tapi punya dampak besar pada kualitas visual animasi — buat list terasa hidup, bukan robotic.