{"slug":"tilt-card","name":"Tilt Card","description":"3D perspective tilt on hover with cursor-tracked glare.","category":"motion","source_url":"https://beui.saura3h.xyz/r/tilt-card/raw","detail_url":"https://beui.saura3h.xyz/r/tilt-card","raw_url":"https://beui.saura3h.xyz/r/tilt-card/raw","page_url":"https://beui.saura3h.xyz/components/motion/tilt-card","dependencies":["motion","react"],"internal":["@/components/motion/tilt-card","@/lib/utils"],"files":[{"path":"components/motion/tilt-card.tsx","type":"component","content":"\"use client\";\n\nimport { motion, useMotionTemplate, useMotionValue, useSpring } from \"motion/react\";\nimport { useRef, type ReactNode } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TiltCardProps {\n  children: ReactNode;\n  max?: number;\n  glare?: boolean;\n  className?: string;\n}\n\nexport function TiltCard({ children, max = 12, glare = true, className }: TiltCardProps) {\n  const ref = useRef<HTMLDivElement>(null);\n  const rx = useMotionValue(0);\n  const ry = useMotionValue(0);\n  const gx = useMotionValue(50);\n  const gy = useMotionValue(50);\n\n  const srx = useSpring(rx, { stiffness: 200, damping: 20 });\n  const sry = useSpring(ry, { stiffness: 200, damping: 20 });\n\n  const onMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    const el = ref.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    const px = (e.clientX - rect.left) / rect.width;\n    const py = (e.clientY - rect.top) / rect.height;\n    ry.set((px - 0.5) * max);\n    rx.set((0.5 - py) * max);\n    gx.set(px * 100);\n    gy.set(py * 100);\n  };\n\n  const onLeave = () => {\n    rx.set(0);\n    ry.set(0);\n  };\n\n  const transform = useMotionTemplate`perspective(1000px) rotateX(${srx}deg) rotateY(${sry}deg)`;\n  const glareBg = useMotionTemplate`radial-gradient(circle at ${gx}% ${gy}%, color-mix(in oklch, var(--color-fg) 15%, transparent), transparent 50%)`;\n\n  return (\n    <motion.div\n      ref={ref}\n      onMouseMove={onMove}\n      onMouseLeave={onLeave}\n      style={{ transform, transformStyle: \"preserve-3d\" }}\n      className={cn(\"relative overflow-hidden rounded-2xl will-change-transform\", className)}\n    >\n      {children}\n      {glare ? (\n        <motion.div\n          aria-hidden\n          style={{ background: glareBg }}\n          className=\"pointer-events-none absolute inset-0\"\n        />\n      ) : null}\n    </motion.div>\n  );\n}\n"},{"path":"components/previews/motion/tilt-card.preview.tsx","type":"preview","content":"\"use client\";\n\nimport { TiltCard } from \"@/components/motion/tilt-card\";\n\nexport function TiltCardPreview() {\n  return (\n    <div className=\"flex items-center justify-center p-6\">\n      <TiltCard className=\"w-[280px] border border-(--color-border) bg-(--color-bg-elev) p-8\">\n        <div className=\"text-xs uppercase tracking-wider text-(--color-fg-muted)\">Premium</div>\n        <h3 className=\"mt-2 text-2xl font-semibold text-(--color-fg)\">Tilt me</h3>\n        <p className=\"mt-3 text-sm text-(--color-fg-muted)\">Move your cursor across the card to see 3D tilt + glare.</p>\n      </TiltCard>\n    </div>\n  );\n}\n"},{"path":"lib/utils.ts","type":"util","content":"import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n"}]}