stagger(30–160ms) · enter 300ms

Stagger Choreography

複数要素の入場を Micro / Standard / Dramatic / Wave の 4 preset で比較する。stagger の合計が 500ms を超えると遅く感じる——その budget 感覚を掴むためのデモ。

stagger(30–160ms) · enter 300ms

Micro cascade

20-40ms · list/grid

~480ms

Standard

50-100ms · cards/nav

~780ms

Dramatic

100-200ms · hero

~1260ms

Wave

30-60ms · dataviz

~600ms
/**
 * Stagger Choreography — 4 つの stagger preset を並べて比較する。
 * 移植元: motion-playground app/_sections/StaggerChoreography.tsx(dark 変換 M-B-2)
 */
import { motion } from 'motion/react';
import {
  durations,
  easings,
  staggerPresets,
  type StaggerKey,
} from '../../../lib/motion-tokens/playground';
import { useLabReplay } from './use-lab-replay';

const items = Array.from({ length: 6 }, (_, i) => i);

function StaggerColumn({
  presetKey,
  playKey,
}: {
  presetKey: StaggerKey;
  playKey: number;
}) {
  const preset = staggerPresets[presetKey];
  const totalMs = Math.round(
    (items.length * preset.delay + durations.cardEnter) * 1000,
  );

  return (
    <div className="rounded-xl border border-[var(--border-subtle)] bg-[var(--bg-surface)] p-4">
      <div className="mb-3 flex items-baseline justify-between gap-2">
        <div>
          <p className="text-sm font-medium text-[var(--text-primary)]">
            {preset.label}
          </p>
          <p className="mt-0.5 text-xs text-[var(--text-muted)]">{preset.note}</p>
        </div>
        <span className="font-mono text-xs tabular-nums text-[var(--text-muted)]">
          ~{totalMs}ms
        </span>
      </div>
      <div className="space-y-2">
        {items.map((i) => (
          <motion.div
            key={`${presetKey}-${playKey}-${i}`}
            initial={{ opacity: 0, x: -24 }}
            animate={{ opacity: 1, x: 0 }}
            transition={{
              duration: durations.cardEnter,
              ease: easings.md3Emphasized,
              delay: i * preset.delay,
            }}
            className="flex items-center gap-3 rounded-md bg-[var(--bg-elevated)] px-3 py-2"
          >
            <div className="h-5 w-5 rounded-full bg-[var(--text-muted)]" />
            <div className="h-1.5 flex-1 rounded-full bg-[rgba(255,255,255,0.12)]" />
          </motion.div>
        ))}
      </div>
    </div>
  );
}

export default function StaggerChoreography() {
  const { rootRef, playKey } = useLabReplay();

  return (
    <div
      ref={rootRef}
      data-lab-island
      className="grid w-full gap-3 p-4 sm:grid-cols-2 lg:grid-cols-4 lg:p-6"
    >
      <StaggerColumn presetKey="micro" playKey={playKey} />
      <StaggerColumn presetKey="standard" playKey={playKey} />
      <StaggerColumn presetKey="dramatic" playKey={playKey} />
      <StaggerColumn presetKey="wave" playKey={playKey} />
    </div>
  );
}