Skip to content
back to lab

Hello GSAP

A springy square entrance using the site's own motion tokens — the lab's hello world.

preview
sketch.tsx· read-onlyedit
function Sketch() {
  const ref = useRef(null)
  const [round, setRound] = useState(0)

  useEffect(() => {
    const ctx = gsap.context(() => {
      gsap.from(".box", {
        y: 40,
        opacity: 0,
        rotation: -12,
        ease: EASE.jelly,
        duration: 0.9,
        stagger: STAGGER.base,
      })
    }, ref)
    // Cleanup keeps re-runs leak-free: react-live re-evaluates on every edit.
    return () => ctx.revert()
  }, [round])

  return (
    <div
      ref={ref}
      className="flex h-full min-h-56 flex-col items-center justify-center gap-6"
    >
      <div className="flex gap-4">
        <div className="box h-14 w-14 rounded-sm border-2 border-border bg-accent-cyan shadow-hard" />
        <div className="box h-14 w-14 rounded-sm border-2 border-border bg-accent-pink shadow-hard" />
        <div className="box h-14 w-14 rounded-sm border-2 border-border bg-accent-lilac shadow-hard" />
      </div>
      <button
        type="button"
        onClick={() => setRound((r) => r + 1)}
        className="rounded-sm border-2 border-border bg-brand px-4 py-1.5 font-mono text-xs font-bold uppercase tracking-wider text-on-brand shadow-hard transition-all hover:shadow-hard-sm hover:translate-x-[1px] hover:translate-y-[1px] active:translate-x-[2px] active:translate-y-[2px] active:shadow-none"
      >
        replay
      </button>
    </div>
  )
}

render(<Sketch />)
end of editor
what's in scope

Sketches run with these values already available — no imports needed. Anything Tailwind can style, gsap can move.

react
React
useState
useEffect
useRef
useMemo
useCallback
useLayoutEffect
motion
gsap
EASE
DURATION
STAGGER
utils
cn
icons
ArrowRight
Check
Heart
Moon
Sparkles
Star
Sun
Zap