{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tilt-surface",
  "title": "Tilt Surface",
  "description": "Perspective surface response with optional glare and static mobile fallback.",
  "registryDependencies": [
    "https://components.exe.xyz/r/use-reduced-motion.json"
  ],
  "files": [
    {
      "path": "src/components/effects/tilt-surface.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { useReducedMotion } from \"@/hooks/use-reduced-motion\"\n\n/*\n * SPDX-License-Identifier: MIT\n * Inspired by Amicro's Tilt Card by Syed Subhan Uddin.\n * Upstream: https://github.com/Subhan-code/Amicro--Micro-transitions-\n * Source: registry/ui/hover/tilt-card.tsx\n * Audited revision: 07adc1640084940f045875e2bb1b682c90f30c3c\n * This implementation is an original accessible React/CSS adaptation.\n */\n\nexport type TiltSurfaceProps = React.HTMLAttributes<HTMLDivElement> & {\n  maxTilt?: number\n  depth?: number\n  glare?: boolean\n}\n\nexport function TiltSurface({\n  maxTilt = 7,\n  depth = 18,\n  glare = true,\n  className = \"\",\n  style,\n  children,\n  onPointerMove,\n  onPointerLeave,\n  onBlur,\n  ...props\n}: TiltSurfaceProps) {\n  const ref = React.useRef<HTMLDivElement>(null)\n  const reduced = useReducedMotion()\n\n  const reset = React.useCallback(() => {\n    const element = ref.current\n    if (!element) return\n    element.style.setProperty(\"--tilt-rx\", \"0deg\")\n    element.style.setProperty(\"--tilt-ry\", \"0deg\")\n    element.style.setProperty(\"--tilt-glare-x\", \"50%\")\n    element.style.setProperty(\"--tilt-glare-y\", \"50%\")\n    element.dataset.active = \"false\"\n  }, [])\n\n  return (\n    <div\n      ref={ref}\n      data-tilt-surface=\"\"\n      data-active=\"false\"\n      className={`relative ${className}`}\n      style={\n        {\n          \"--tilt-rx\": \"0deg\",\n          \"--tilt-ry\": \"0deg\",\n          \"--tilt-depth\": `${depth}px`,\n          \"--tilt-glare-x\": \"50%\",\n          \"--tilt-glare-y\": \"50%\",\n          ...style,\n        } as React.CSSProperties\n      }\n      onPointerMove={(event) => {\n        onPointerMove?.(event)\n        if (reduced || event.pointerType !== \"mouse\") return\n        const rect = event.currentTarget.getBoundingClientRect()\n        const x = (event.clientX - rect.left) / rect.width\n        const y = (event.clientY - rect.top) / rect.height\n        event.currentTarget.style.setProperty(\n          \"--tilt-rx\",\n          `${(0.5 - y) * maxTilt * 2}deg`\n        )\n        event.currentTarget.style.setProperty(\n          \"--tilt-ry\",\n          `${(x - 0.5) * maxTilt * 2}deg`\n        )\n        event.currentTarget.style.setProperty(\"--tilt-glare-x\", `${x * 100}%`)\n        event.currentTarget.style.setProperty(\"--tilt-glare-y\", `${y * 100}%`)\n        event.currentTarget.dataset.active = \"true\"\n      }}\n      onPointerLeave={(event) => {\n        onPointerLeave?.(event)\n        reset()\n      }}\n      onBlur={(event) => {\n        onBlur?.(event)\n        reset()\n      }}\n      {...props}\n    >\n      <style>{`\n        [data-tilt-surface] {\n          perspective: 900px;\n          transform: rotateX(var(--tilt-rx)) rotateY(var(--tilt-ry));\n          transform-style: preserve-3d;\n          transition: transform 220ms cubic-bezier(.16,1,.3,1);\n          will-change: transform;\n        }\n        [data-tilt-surface][data-active=\"true\"] { transition-duration: 70ms; }\n        [data-tilt-surface] > [data-tilt-content] {\n          transform: translateZ(var(--tilt-depth));\n          transform-style: preserve-3d;\n        }\n        [data-tilt-surface] > [data-tilt-glare] {\n          background: radial-gradient(circle at var(--tilt-glare-x) var(--tilt-glare-y), rgb(255 255 255 / .22), transparent 46%);\n          inset: 0;\n          opacity: 0;\n          pointer-events: none;\n          position: absolute;\n          transition: opacity 180ms ease;\n        }\n        [data-tilt-surface][data-active=\"true\"] > [data-tilt-glare] { opacity: 1; }\n        @media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {\n          [data-tilt-surface] { transform: none !important; }\n          [data-tilt-surface] > [data-tilt-content] { transform: none; }\n          [data-tilt-surface] > [data-tilt-glare] { display: none; }\n        }\n      `}</style>\n      <div data-tilt-content=\"\">{children}</div>\n      {glare ? <span data-tilt-glare=\"\" aria-hidden=\"true\" /> : null}\n    </div>\n  )\n}\n",
      "type": "registry:ui",
      "target": "src/components/effects/tilt-surface.tsx"
    }
  ],
  "meta": {
    "collection": "motion-effects",
    "license": "MIT",
    "usage": "<TiltSurface className=\"rounded-xl border p-6\">\n  <article>Product preview</article>\n</TiltSurface>",
    "source": "https://github.com/Subhan-code/Amicro--Micro-transitions-",
    "sourcePath": "registry/ui/hover/tilt-card.tsx",
    "sourceRevision": "07adc1640084940f045875e2bb1b682c90f30c3c"
  },
  "type": "registry:ui"
}