"use client"; import { useState, useEffect, useRef, useCallback } from "react"; export function useStaggerReveal(count: number, baseDelay = 80) { const [visible, setVisible] = useState>(new Set()); useEffect(() => { const timers: ReturnType[] = []; for (let i = 0; i < count; i++) { timers.push( setTimeout( () => setVisible((prev) => new Set(prev).add(i)), baseDelay * (i + 1) + 200 ) ); } return () => timers.forEach(clearTimeout); }, [count, baseDelay]); return visible; } export function useMountTransition(delay = 50) { const [mounted, setMounted] = useState(false); useEffect(() => { const t = setTimeout(() => setMounted(true), delay); return () => clearTimeout(t); }, [delay]); return mounted; } export function useWiggle(durationMs = 1500, onComplete: () => void) { const [wiggling, setWiggling] = useState(false); const [progress, setProgress] = useState(0); const startTime = useRef(0); const rafId = useRef(0); const completeTimer = useRef>(null); const completedRef = useRef(false); const stop = useCallback(() => { setWiggling(false); setProgress(0); cancelAnimationFrame(rafId.current); if (completeTimer.current) clearTimeout(completeTimer.current); }, []); const tick = useCallback(() => { const elapsed = Date.now() - startTime.current; const p = Math.min(1, elapsed / durationMs); setProgress(p); if (p < 1) { rafId.current = requestAnimationFrame(tick); } }, [durationMs]); const start = useCallback(() => { completedRef.current = false; startTime.current = Date.now(); setWiggling(true); setProgress(0); rafId.current = requestAnimationFrame(tick); completeTimer.current = setTimeout(() => { completedRef.current = true; stop(); onComplete(); }, durationMs); }, [durationMs, onComplete, tick, stop]); const release = useCallback(() => { if (!completedRef.current) stop(); }, [stop]); // cleanup on unmount useEffect(() => () => { cancelAnimationFrame(rafId.current); if (completeTimer.current) clearTimeout(completeTimer.current); }, []); const handlers = { onPointerDown: start, onPointerEnter: start, onPointerUp: release, onPointerLeave: release, }; return { wiggling, progress, handlers }; }