{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "GlassSurface-TS-CSS",
	"title": "GlassSurface",
	"description": "Advanced Apple-style glass surface with real-time distortion + lighting.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "GlassSurface.css",
			"target": "@components/GlassSurface.css",
			"content": ".glass-surface {\n  position: relative;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  overflow: hidden;\n  transition: opacity 0.26s ease-out;\n}\n\n.glass-surface__filter {\n  width: 100%;\n  height: 100%;\n  pointer-events: none;\n  position: absolute;\n  inset: 0;\n  opacity: 0;\n  z-index: -1;\n}\n\n.glass-surface__content {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  padding: 0.5rem;\n  border-radius: inherit;\n  position: relative;\n  z-index: 1;\n}\n\n.glass-surface--svg {\n  background: light-dark(hsl(0 0% 100% / var(--glass-frost, 0)), hsl(0 0% 0% / var(--glass-frost, 0)));\n  backdrop-filter: var(--filter-id) saturate(var(--glass-saturation, 1));\n  box-shadow:\n    0 0 2px 1px light-dark(color-mix(in oklch, black, transparent 85%), color-mix(in oklch, white, transparent 65%))\n      inset,\n    0 0 10px 4px light-dark(color-mix(in oklch, black, transparent 90%), color-mix(in oklch, white, transparent 85%))\n      inset,\n    0px 4px 16px rgba(17, 17, 26, 0.05),\n    0px 8px 24px rgba(17, 17, 26, 0.05),\n    0px 16px 56px rgba(17, 17, 26, 0.05),\n    0px 4px 16px rgba(17, 17, 26, 0.05) inset,\n    0px 8px 24px rgba(17, 17, 26, 0.05) inset,\n    0px 16px 56px rgba(17, 17, 26, 0.05) inset;\n}\n\n.glass-surface--fallback {\n  background: rgba(255, 255, 255, 0.25);\n  backdrop-filter: blur(12px) saturate(1.8) brightness(1.1);\n  -webkit-backdrop-filter: blur(12px) saturate(1.8) brightness(1.1);\n  border: 1px solid rgba(255, 255, 255, 0.3);\n  box-shadow:\n    0 8px 32px 0 rgba(31, 38, 135, 0.2),\n    0 2px 16px 0 rgba(31, 38, 135, 0.1),\n    inset 0 1px 0 0 rgba(255, 255, 255, 0.4),\n    inset 0 -1px 0 0 rgba(255, 255, 255, 0.2);\n}\n\n@media (prefers-color-scheme: dark) {\n  .glass-surface--fallback {\n    background: rgba(255, 255, 255, 0.1);\n    backdrop-filter: blur(12px) saturate(1.8) brightness(1.2);\n    -webkit-backdrop-filter: blur(12px) saturate(1.8) brightness(1.2);\n    border: 1px solid rgba(255, 255, 255, 0.2);\n    box-shadow:\n      inset 0 1px 0 0 rgba(255, 255, 255, 0.2),\n      inset 0 -1px 0 0 rgba(255, 255, 255, 0.1);\n  }\n}\n\n@supports not (backdrop-filter: blur(10px)) {\n  .glass-surface--fallback {\n    background: rgba(255, 255, 255, 0.4);\n    box-shadow:\n      inset 0 1px 0 0 rgba(255, 255, 255, 0.5),\n      inset 0 -1px 0 0 rgba(255, 255, 255, 0.3);\n  }\n\n  .glass-surface--fallback::before {\n    content: '';\n    position: absolute;\n    inset: 0;\n    background: rgba(255, 255, 255, 0.15);\n    border-radius: inherit;\n    z-index: -1;\n  }\n}\n\n@supports not (backdrop-filter: blur(10px)) {\n  @media (prefers-color-scheme: dark) {\n    .glass-surface--fallback {\n      background: rgba(0, 0, 0, 0.4);\n    }\n\n    .glass-surface--fallback::before {\n      background: rgba(255, 255, 255, 0.05);\n    }\n  }\n}\n\n.glass-surface:focus-visible {\n  outline: 2px solid light-dark(#007aff, #0a84ff);\n  outline-offset: 2px;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "GlassSurface.tsx",
			"content": "import React, { useEffect, useRef, useState, useId } from 'react';\nimport './GlassSurface.css';\n\nexport interface GlassSurfaceProps {\n  children?: React.ReactNode;\n  width?: number | string;\n  height?: number | string;\n  borderRadius?: number;\n  borderWidth?: number;\n  brightness?: number;\n  opacity?: number;\n  blur?: number;\n  displace?: number;\n  backgroundOpacity?: number;\n  saturation?: number;\n  distortionScale?: number;\n  redOffset?: number;\n  greenOffset?: number;\n  blueOffset?: number;\n  xChannel?: 'R' | 'G' | 'B';\n  yChannel?: 'R' | 'G' | 'B';\n  mixBlendMode?:\n    | 'normal'\n    | 'multiply'\n    | 'screen'\n    | 'overlay'\n    | 'darken'\n    | 'lighten'\n    | 'color-dodge'\n    | 'color-burn'\n    | 'hard-light'\n    | 'soft-light'\n    | 'difference'\n    | 'exclusion'\n    | 'hue'\n    | 'saturation'\n    | 'color'\n    | 'luminosity'\n    | 'plus-darker'\n    | 'plus-lighter';\n  className?: string;\n  style?: React.CSSProperties;\n}\n\nconst GlassSurface: React.FC<GlassSurfaceProps> = ({\n  children,\n  width = 200,\n  height = 80,\n  borderRadius = 20,\n  borderWidth = 0.07,\n  brightness = 50,\n  opacity = 0.93,\n  blur = 11,\n  displace = 0,\n  backgroundOpacity = 0,\n  saturation = 1,\n  distortionScale = -180,\n  redOffset = 0,\n  greenOffset = 10,\n  blueOffset = 20,\n  xChannel = 'R',\n  yChannel = 'G',\n  mixBlendMode = 'difference',\n  className = '',\n  style = {}\n}) => {\n  const id = useId();\n  const filterId = `glass-filter-${id}`;\n  const redGradId = `red-grad-${id}`;\n  const blueGradId = `blue-grad-${id}`;\n\n  const [svgSupported, setSvgSupported] = useState<boolean>(false);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n  const feImageRef = useRef<SVGFEImageElement>(null);\n  const redChannelRef = useRef<SVGFEDisplacementMapElement>(null);\n  const greenChannelRef = useRef<SVGFEDisplacementMapElement>(null);\n  const blueChannelRef = useRef<SVGFEDisplacementMapElement>(null);\n  const gaussianBlurRef = useRef<SVGFEGaussianBlurElement>(null);\n\n  const generateDisplacementMap = () => {\n    const rect = containerRef.current?.getBoundingClientRect();\n    const actualWidth = rect?.width || 400;\n    const actualHeight = rect?.height || 200;\n    const edgeSize = Math.min(actualWidth, actualHeight) * (borderWidth * 0.5);\n\n    const svgContent = `\n      <svg viewBox=\"0 0 ${actualWidth} ${actualHeight}\" xmlns=\"http://www.w3.org/2000/svg\">\n        <defs>\n          <linearGradient id=\"${redGradId}\" x1=\"100%\" y1=\"0%\" x2=\"0%\" y2=\"0%\">\n            <stop offset=\"0%\" stop-color=\"#0000\"/>\n            <stop offset=\"100%\" stop-color=\"red\"/>\n          </linearGradient>\n          <linearGradient id=\"${blueGradId}\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n            <stop offset=\"0%\" stop-color=\"#0000\"/>\n            <stop offset=\"100%\" stop-color=\"blue\"/>\n          </linearGradient>\n        </defs>\n        <rect x=\"0\" y=\"0\" width=\"${actualWidth}\" height=\"${actualHeight}\" fill=\"black\"></rect>\n        <rect x=\"0\" y=\"0\" width=\"${actualWidth}\" height=\"${actualHeight}\" rx=\"${borderRadius}\" fill=\"url(#${redGradId})\" />\n        <rect x=\"0\" y=\"0\" width=\"${actualWidth}\" height=\"${actualHeight}\" rx=\"${borderRadius}\" fill=\"url(#${blueGradId})\" style=\"mix-blend-mode: ${mixBlendMode}\" />\n        <rect x=\"${edgeSize}\" y=\"${edgeSize}\" width=\"${actualWidth - edgeSize * 2}\" height=\"${actualHeight - edgeSize * 2}\" rx=\"${borderRadius}\" fill=\"hsl(0 0% ${brightness}% / ${opacity})\" style=\"filter:blur(${blur}px)\" />\n      </svg>\n    `;\n\n    return `data:image/svg+xml,${encodeURIComponent(svgContent)}`;\n  };\n\n  const updateDisplacementMap = () => {\n    feImageRef.current?.setAttribute('href', generateDisplacementMap());\n  };\n\n  useEffect(() => {\n    updateDisplacementMap();\n    [\n      { ref: redChannelRef, offset: redOffset },\n      { ref: greenChannelRef, offset: greenOffset },\n      { ref: blueChannelRef, offset: blueOffset }\n    ].forEach(({ ref, offset }) => {\n      if (ref.current) {\n        ref.current.setAttribute('scale', (distortionScale + offset).toString());\n        ref.current.setAttribute('xChannelSelector', xChannel);\n        ref.current.setAttribute('yChannelSelector', yChannel);\n      }\n    });\n\n    gaussianBlurRef.current?.setAttribute('stdDeviation', displace.toString());\n  }, [\n    width,\n    height,\n    borderRadius,\n    borderWidth,\n    brightness,\n    opacity,\n    blur,\n    displace,\n    distortionScale,\n    redOffset,\n    greenOffset,\n    blueOffset,\n    xChannel,\n    yChannel,\n    mixBlendMode\n  ]);\n\n  useEffect(() => {\n    if (!containerRef.current) return;\n\n    const resizeObserver = new ResizeObserver(() => {\n      setTimeout(updateDisplacementMap, 0);\n    });\n\n    resizeObserver.observe(containerRef.current);\n\n    return () => {\n      resizeObserver.disconnect();\n    };\n  }, []);\n\n  useEffect(() => {\n    setTimeout(updateDisplacementMap, 0);\n  }, [width, height]);\n\n  useEffect(() => {\n    setSvgSupported(supportsSVGFilters());\n  }, []);\n\n  const supportsSVGFilters = () => {\n    if (typeof window === 'undefined' || typeof document === 'undefined') {\n      return false;\n    }\n\n    const isWebkit = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);\n    const isFirefox = /Firefox/.test(navigator.userAgent);\n\n    if (isWebkit || isFirefox) {\n      return false;\n    }\n\n    const div = document.createElement('div');\n    div.style.backdropFilter = `url(#${filterId})`;\n\n    return div.style.backdropFilter !== '';\n  };\n\n  const containerStyle: React.CSSProperties = {\n    ...style,\n    width: typeof width === 'number' ? `${width}px` : width,\n    height: typeof height === 'number' ? `${height}px` : height,\n    borderRadius: `${borderRadius}px`,\n    '--glass-frost': backgroundOpacity,\n    '--glass-saturation': saturation,\n    '--filter-id': `url(#${filterId})`\n  } as React.CSSProperties;\n\n  return (\n    <div\n      ref={containerRef}\n      className={`glass-surface ${svgSupported ? 'glass-surface--svg' : 'glass-surface--fallback'} ${className}`}\n      style={containerStyle}\n    >\n      <svg className=\"glass-surface__filter\" xmlns=\"http://www.w3.org/2000/svg\">\n        <defs>\n          <filter id={filterId} colorInterpolationFilters=\"sRGB\" x=\"0%\" y=\"0%\" width=\"100%\" height=\"100%\">\n            <feImage ref={feImageRef} x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" preserveAspectRatio=\"none\" result=\"map\" />\n\n            <feDisplacementMap ref={redChannelRef} in=\"SourceGraphic\" in2=\"map\" id=\"redchannel\" result=\"dispRed\" />\n            <feColorMatrix\n              in=\"dispRed\"\n              type=\"matrix\"\n              values=\"1 0 0 0 0\n                      0 0 0 0 0\n                      0 0 0 0 0\n                      0 0 0 1 0\"\n              result=\"red\"\n            />\n\n            <feDisplacementMap\n              ref={greenChannelRef}\n              in=\"SourceGraphic\"\n              in2=\"map\"\n              id=\"greenchannel\"\n              result=\"dispGreen\"\n            />\n            <feColorMatrix\n              in=\"dispGreen\"\n              type=\"matrix\"\n              values=\"0 0 0 0 0\n                      0 1 0 0 0\n                      0 0 0 0 0\n                      0 0 0 1 0\"\n              result=\"green\"\n            />\n\n            <feDisplacementMap ref={blueChannelRef} in=\"SourceGraphic\" in2=\"map\" id=\"bluechannel\" result=\"dispBlue\" />\n            <feColorMatrix\n              in=\"dispBlue\"\n              type=\"matrix\"\n              values=\"0 0 0 0 0\n                      0 0 0 0 0\n                      0 0 1 0 0\n                      0 0 0 1 0\"\n              result=\"blue\"\n            />\n\n            <feBlend in=\"red\" in2=\"green\" mode=\"screen\" result=\"rg\" />\n            <feBlend in=\"rg\" in2=\"blue\" mode=\"screen\" result=\"output\" />\n            <feGaussianBlur ref={gaussianBlurRef} in=\"output\" stdDeviation=\"0.7\" />\n          </filter>\n        </defs>\n      </svg>\n\n      <div className=\"glass-surface__content\">{children}</div>\n    </div>\n  );\n};\n\nexport default GlassSurface;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": []
}