import type { CSSProperties } from "vue"; const REST: CSSProperties = { transform: "perspective(1000px) rotateX(0deg) rotateY(0deg) translateY(0px) scale3d(1, 1, 1)", }; /** Pointer-follow 3D tilt + spotlight position for a card, batched to one update per frame. */ export function useCardTilt() { const style = ref({}); let frame = 0; let el: HTMLElement | null = null; let clientX = 0; let clientY = 0; const apply = () => { frame = 0; if (!el) return; const rect = el.getBoundingClientRect(); const x = clientX - rect.left; const y = clientY - rect.top; el.style.setProperty("--mouse-x", `${x}px`); el.style.setProperty("--mouse-y", `${y}px`); const centerX = rect.width / 2; const centerY = rect.height / 2; const rotateX = ((y - centerY) / centerY) * -7; const rotateY = ((x - centerX) / centerX) * 7; style.value = { transform: `perspective(1000px) rotateX(${rotateX.toFixed(1)}deg) rotateY(${rotateY.toFixed(1)}deg) translateY(-6px) scale3d(1.02, 1.02, 1.02)`, }; }; function onMouseMove(e: MouseEvent) { el = e.currentTarget as HTMLElement; clientX = e.clientX; clientY = e.clientY; if (!frame) frame = requestAnimationFrame(apply); } function onMouseLeave() { if (frame) cancelAnimationFrame(frame); frame = 0; el = null; style.value = REST; } onBeforeUnmount(() => { if (frame) cancelAnimationFrame(frame); }); return { style, onMouseMove, onMouseLeave }; }