{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tilt-card",
  "title": "Tilt Card",
  "description": "A card that leans toward the pointer as though it were a physical object.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/tilt-card/tilt-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\nexport type TiltCardProps = React.HTMLAttributes<HTMLDivElement> & {\n  /** Furthest the card leans, in degrees. */\n  maxTilt?: number\n  /** How far the card comes toward the pointer, in pixels. */\n  lift?: number\n  /** Adds a sheen that moves against the lean. */\n  glare?: boolean\n  perspective?: number\n}\n\n/**\n * A card that leans toward the pointer as though it were a physical object on\n * the page. The lean is written to custom properties on the element, so a grid\n * of these renders nothing while the pointer crosses it.\n */\nexport function TiltCard({\n  maxTilt = 9,\n  lift = 6,\n  glare = false,\n  perspective = 900,\n  className,\n  style,\n  children,\n  onPointerMove,\n  onPointerLeave,\n  ...rootProps\n}: TiltCardProps) {\n  const ref = React.useRef<HTMLDivElement>(null)\n  const reduced = React.useRef(false)\n\n  React.useEffect(() => {\n    reduced.current = window.matchMedia(\n      \"(prefers-reduced-motion: reduce)\"\n    ).matches\n  }, [])\n\n  const move = (event: React.PointerEvent<HTMLDivElement>) => {\n    const element = ref.current\n    if (element && !reduced.current) {\n      const rect = element.getBoundingClientRect()\n      const x = (event.clientX - rect.left) / rect.width - 0.5\n      const y = (event.clientY - rect.top) / rect.height - 0.5\n\n      element.style.setProperty(\n        \"--tilt-x\",\n        `${(-y * maxTilt * 2).toFixed(2)}deg`\n      )\n      element.style.setProperty(\n        \"--tilt-y\",\n        `${(x * maxTilt * 2).toFixed(2)}deg`\n      )\n      element.style.setProperty(\"--tilt-lift\", `${lift}px`)\n      element.style.setProperty(\"--tilt-glare-x\", `${(x + 0.5) * 100}%`)\n      element.style.setProperty(\"--tilt-glare-y\", `${(y + 0.5) * 100}%`)\n      element.style.setProperty(\"--tilt-glare-on\", \"1\")\n    }\n\n    onPointerMove?.(event)\n  }\n\n  const leave = (event: React.PointerEvent<HTMLDivElement>) => {\n    const element = ref.current\n    if (element) {\n      element.style.setProperty(\"--tilt-x\", \"0deg\")\n      element.style.setProperty(\"--tilt-y\", \"0deg\")\n      element.style.setProperty(\"--tilt-lift\", \"0px\")\n      element.style.setProperty(\"--tilt-glare-on\", \"0\")\n    }\n\n    onPointerLeave?.(event)\n  }\n\n  return (\n    <div\n      style={{ perspective: `${perspective}px` }}\n      className=\"[transform-style:preserve-3d]\"\n    >\n      <div\n        ref={ref}\n        data-slot=\"tilt-card\"\n        onPointerMove={move}\n        onPointerLeave={leave}\n        className={cn(\n          \"border-border bg-card text-card-foreground relative isolate overflow-hidden rounded-[var(--radius)] border\",\n          \"transition-transform duration-200 ease-out will-change-transform motion-reduce:transition-none\",\n          \"[transform:perspective(var(--tilt-perspective))_rotateX(var(--tilt-x,0deg))_rotateY(var(--tilt-y,0deg))_translateZ(var(--tilt-lift,0px))]\",\n          \"motion-reduce:[transform:none]\",\n          glare &&\n            \"after:pointer-events-none after:absolute after:inset-0 after:bg-[radial-gradient(50%_50%_at_var(--tilt-glare-x,50%)_var(--tilt-glare-y,50%),color-mix(in_oklch,var(--foreground)_14%,transparent),transparent)] after:opacity-[var(--tilt-glare-on,0)] after:transition-opacity after:duration-200 after:content-['']\",\n          className\n        )}\n        style={\n          {\n            \"--tilt-perspective\": `${perspective}px`,\n            ...style,\n          } as React.CSSProperties\n        }\n        {...rootProps}\n      >\n        {children}\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "scene",
    "card",
    "pointer",
    "3d"
  ],
  "type": "registry:ui"
}