Goal: Create a "Charge" button animation.
Visual behavior: A fighting-game / special-move style button. At rest: dark background, label "Hover to Charge". On hover: a green bar starts filling from left to right over 1.5 seconds. The label changes to "Charging...". When the bar reaches 100%: the button fires — the bar turns gold, a pulsing yellow glow box-shadow appears, the label becomes "⚡ FIRED!", and text turns dark. This fired state lasts 800ms, then resets to idle. Moving the mouse away before full charge cancels and resets the bar instantly.
Technique: Use useRef for phaseRef (to avoid stale closure in event handlers) and useState for rendering. Track charge progress with requestAnimationFrame: on mouseenter, record startRef.current = performance.now(), then in each rAF tick compute pct = Math.min((now - start) / 1500 * 100, 100), call setChargeWidth(pct), and recurse until 100%. At 100%, enter fired state and set a setTimeout for 800ms to reset. On mouseleave, if phase is 'charging', cancelAnimationFrame and reset. The fill bar is an absolutely-positioned span with width set to the chargeWidth percentage — no CSS transitions on width since rAF updates it fast enough.
Accessibility: Under prefers-reduced-motion, skip the rAF loop and disable the glow box-shadow.
My stack: {{USER_STACK}}
My styling: {{USER_STYLING}}
My constraints: {{USER_CONSTRAINTS}}
Return a single self-contained component. Do not introduce dependencies beyond what I've listed.
Paste into Claude, ChatGPT, or Cursor. Edit YOUR_STACK /
YOUR_STYLING / YOUR_CONSTRAINTS before sending.