From 0638425c6748d88d5b62566ddc8ba67992178650 Mon Sep 17 00:00:00 2001 From: Oliver Bryan Date: Sun, 25 Jan 2026 09:36:30 +0000 Subject: [PATCH] requestAnimationFrame loop that tracks elapsed time for wobble animation --- DEVELOPMENT_PLAN.md | 4 ++-- src/hooks/useWobbleAnimation.ts | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/hooks/useWobbleAnimation.ts diff --git a/DEVELOPMENT_PLAN.md b/DEVELOPMENT_PLAN.md index 1e2bdcd..9186277 100644 --- a/DEVELOPMENT_PLAN.md +++ b/DEVELOPMENT_PLAN.md @@ -150,8 +150,8 @@ src/ ### Tasks -- [ ] Create `lib/noise.ts` - export shared simplex instance -- [ ] Create `lib/shapes/wobble.ts`: +- [x] Create `lib/noise.ts` - export shared simplex instance +- [x] Create `lib/shapes/wobble.ts`: - `applyWobble(points, time, amount, noiseScale)` - displace points using noise - [ ] Create `useWobbleAnimation.ts` - RAF loop, tracks elapsed time - [ ] Update `MorphableShape.tsx` to apply wobble each frame diff --git a/src/hooks/useWobbleAnimation.ts b/src/hooks/useWobbleAnimation.ts new file mode 100644 index 0000000..97aa4b7 --- /dev/null +++ b/src/hooks/useWobbleAnimation.ts @@ -0,0 +1,38 @@ +import { useEffect, useRef, useState } from "react"; + +// requestAnimationFrame loop that tracks elapsed time for wobble animation +export function useWobbleAnimation(speed: number): number { + const [time, setTime] = useState(0); + const rafRef = useRef(0); + const lastFrameRef = useRef(0); + + useEffect(() => { + if (speed === 0) { + return; + } + + const animate = (timestamp: number) => { + if (lastFrameRef.current === 0) { + lastFrameRef.current = timestamp; + } + + const delta = timestamp - lastFrameRef.current; + lastFrameRef.current = timestamp; + + // speed 50 = 1x, speed 100 = 2x, speed 0 = 0x + const speedMultiplier = speed / 50; + setTime((t) => t + (delta / 1000) * speedMultiplier); + + rafRef.current = requestAnimationFrame(animate); + }; + + rafRef.current = requestAnimationFrame(animate); + + return () => { + cancelAnimationFrame(rafRef.current); + lastFrameRef.current = 0; + }; + }, [speed]); + + return time; +}