{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "Prism-TS-CSS",
	"title": "Prism",
	"description": "Rotating prism with configurable intensity, size, and colors.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:file",
			"path": "Prism.css",
			"target": "@components/Prism.css",
			"content": ".prism-container {\n  position: relative;\n  width: 100%;\n  height: 100%;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "Prism.tsx",
			"content": "import React, { useEffect, useRef } from 'react';\nimport { Renderer, Triangle, Program, Mesh } from 'ogl';\nimport './Prism.css';\n\ntype PrismProps = {\n  height?: number;\n  baseWidth?: number;\n  animationType?: 'rotate' | 'hover' | '3drotate';\n  glow?: number;\n  offset?: { x?: number; y?: number };\n  noise?: number;\n  transparent?: boolean;\n  scale?: number;\n  hueShift?: number;\n  colorFrequency?: number;\n  hoverStrength?: number;\n  inertia?: number;\n  bloom?: number;\n  suspendWhenOffscreen?: boolean;\n  timeScale?: number;\n  lightMode?: boolean;\n};\n\nconst Prism: React.FC<PrismProps> = ({\n  height = 3.5,\n  baseWidth = 5.5,\n  animationType = 'rotate',\n  glow = 1,\n  offset = { x: 0, y: 0 },\n  noise = 0.5,\n  transparent = true,\n  scale = 3.6,\n  hueShift = 0,\n  colorFrequency = 1,\n  hoverStrength = 2,\n  inertia = 0.05,\n  bloom = 1,\n  suspendWhenOffscreen = false,\n  timeScale = 0.5,\n  lightMode = false\n}) => {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container) return;\n\n    const H = Math.max(0.001, height);\n    const BW = Math.max(0.001, baseWidth);\n    const BASE_HALF = BW * 0.5;\n    const GLOW = Math.max(0.0, glow);\n    const NOISE = Math.max(0.0, noise);\n    const offX = offset?.x ?? 0;\n    const offY = offset?.y ?? 0;\n    const SAT = transparent ? 1.5 : 1;\n    const SCALE = Math.max(0.001, scale);\n    const HUE = hueShift || 0;\n    const CFREQ = Math.max(0.0, colorFrequency || 1);\n    const BLOOM = Math.max(0.0, bloom || 1);\n    const RSX = 1;\n    const RSY = 1;\n    const RSZ = 1;\n    const TS = Math.max(0, timeScale || 1);\n    const HOVSTR = Math.max(0, hoverStrength || 1);\n    const INERT = Math.max(0, Math.min(1, inertia || 0.12));\n\n    const dpr = Math.min(2, window.devicePixelRatio || 1);\n    const renderer = new Renderer({\n      dpr,\n      alpha: transparent,\n      antialias: false\n    });\n    const gl = renderer.gl;\n    gl.disable(gl.DEPTH_TEST);\n    gl.disable(gl.CULL_FACE);\n    gl.disable(gl.BLEND);\n\n    Object.assign(gl.canvas.style, {\n      position: 'absolute',\n      inset: '0',\n      width: '100%',\n      height: '100%',\n      display: 'block'\n    } as Partial<CSSStyleDeclaration>);\n    container.appendChild(gl.canvas);\n\n    const vertex = /* glsl */ `\n      attribute vec2 position;\n      void main() {\n        gl_Position = vec4(position, 0.0, 1.0);\n      }\n    `;\n\n    const fragment = /* glsl */ `\n      precision highp float;\n\n      uniform vec2  iResolution;\n      uniform float iTime;\n\n      uniform float uHeight;\n      uniform float uBaseHalf;\n      uniform mat3  uRot;\n      uniform int   uUseBaseWobble;\n      uniform float uGlow;\n      uniform vec2  uOffsetPx;\n      uniform float uNoise;\n      uniform float uSaturation;\n      uniform float uScale;\n      uniform float uHueShift;\n      uniform float uColorFreq;\n      uniform float uBloom;\n      uniform float uCenterShift;\n      uniform float uInvBaseHalf;\n      uniform float uInvHeight;\n      uniform float uMinAxis;\n      uniform float uPxScale;\n      uniform float uTimeScale;\n      uniform float uLightMode;\n\n      vec4 tanh4(vec4 x){\n        vec4 e2x = exp(2.0*x);\n        return (e2x - 1.0) / (e2x + 1.0);\n      }\n\n      float rand(vec2 co){\n        return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453123);\n      }\n\n      float sdOctaAnisoInv(vec3 p){\n        vec3 q = vec3(abs(p.x) * uInvBaseHalf, abs(p.y) * uInvHeight, abs(p.z) * uInvBaseHalf);\n        float m = q.x + q.y + q.z - 1.0;\n        return m * uMinAxis * 0.5773502691896258;\n      }\n\n      float sdPyramidUpInv(vec3 p){\n        float oct = sdOctaAnisoInv(p);\n        float halfSpace = -p.y;\n        return max(oct, halfSpace);\n      }\n\n      mat3 hueRotation(float a){\n        float c = cos(a), s = sin(a);\n        mat3 W = mat3(\n          0.299, 0.587, 0.114,\n          0.299, 0.587, 0.114,\n          0.299, 0.587, 0.114\n        );\n        mat3 U = mat3(\n           0.701, -0.587, -0.114,\n          -0.299,  0.413, -0.114,\n          -0.300, -0.588,  0.886\n        );\n        mat3 V = mat3(\n           0.168, -0.331,  0.500,\n           0.328,  0.035, -0.500,\n          -0.497,  0.296,  0.201\n        );\n        return W + U * c + V * s;\n      }\n\n      void main(){\n        vec2 f = (gl_FragCoord.xy - 0.5 * iResolution.xy - uOffsetPx) * uPxScale;\n\n        float z = 5.0;\n        float d = 0.0;\n\n        vec3 p;\n        vec4 o = vec4(0.0);\n\n        float centerShift = uCenterShift;\n        float cf = uColorFreq;\n\n        mat2 wob = mat2(1.0);\n        if (uUseBaseWobble == 1) {\n          float t = iTime * uTimeScale;\n          float c0 = cos(t + 0.0);\n          float c1 = cos(t + 33.0);\n          float c2 = cos(t + 11.0);\n          wob = mat2(c0, c1, c2, c0);\n        }\n\n        const int STEPS = 100;\n        for (int i = 0; i < STEPS; i++) {\n          p = vec3(f, z);\n          p.xz = p.xz * wob;\n          p = uRot * p;\n          vec3 q = p;\n          q.y += centerShift;\n          d = 0.1 + 0.2 * abs(sdPyramidUpInv(q));\n          z -= d;\n          o += (sin((p.y + z) * cf + vec4(0.0, 1.0, 2.0, 3.0)) + 1.0) / d;\n        }\n\n        o = tanh4(o * o * (uGlow * uBloom) / 1e5);\n\n        vec3 col = o.rgb;\n        float n = rand(gl_FragCoord.xy + vec2(iTime));\n        col += (n - 0.5) * uNoise;\n        col = clamp(col, 0.0, 1.0);\n\n        float L = dot(col, vec3(0.2126, 0.7152, 0.0722));\n        col = clamp(mix(vec3(L), col, uSaturation), 0.0, 1.0);\n\n        if(abs(uHueShift) > 0.0001){\n          col = clamp(hueRotation(uHueShift) * col, 0.0, 1.0);\n        }\n\n        if (uLightMode > 0.5) {\n          float peak = max(col.r, max(col.g, col.b));\n          vec3 chroma = pow(clamp(col / max(peak, 0.0001), 0.0, 1.0), vec3(1.14));\n          gl_FragColor = vec4(mix(vec3(1.0), chroma, o.a * 0.94), 1.0);\n        } else {\n          gl_FragColor = vec4(col, o.a);\n        }\n      }\n    `;\n\n    const geometry = new Triangle(gl);\n    const iResBuf = new Float32Array(2);\n    const offsetPxBuf = new Float32Array(2);\n\n    const program = new Program(gl, {\n      vertex,\n      fragment,\n      uniforms: {\n        iResolution: { value: iResBuf },\n        iTime: { value: 0 },\n        uHeight: { value: H },\n        uBaseHalf: { value: BASE_HALF },\n        uUseBaseWobble: { value: 1 },\n        uRot: { value: new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]) },\n        uGlow: { value: GLOW },\n        uOffsetPx: { value: offsetPxBuf },\n        uNoise: { value: NOISE },\n        uSaturation: { value: SAT },\n        uScale: { value: SCALE },\n        uHueShift: { value: HUE },\n        uColorFreq: { value: CFREQ },\n        uBloom: { value: BLOOM },\n        uCenterShift: { value: H * 0.25 },\n        uInvBaseHalf: { value: 1 / BASE_HALF },\n        uInvHeight: { value: 1 / H },\n        uMinAxis: { value: Math.min(BASE_HALF, H) },\n        uPxScale: {\n          value: 1 / ((gl.drawingBufferHeight || 1) * 0.1 * SCALE)\n        },\n        uTimeScale: { value: TS },\n        uLightMode: { value: lightMode ? 1.0 : 0.0 }\n      }\n    });\n    const mesh = new Mesh(gl, { geometry, program });\n\n    const resize = () => {\n      const w = container.clientWidth || 1;\n      const h = container.clientHeight || 1;\n      renderer.setSize(w, h);\n      iResBuf[0] = gl.drawingBufferWidth;\n      iResBuf[1] = gl.drawingBufferHeight;\n      offsetPxBuf[0] = offX * dpr;\n      offsetPxBuf[1] = offY * dpr;\n      program.uniforms.uPxScale.value = 1 / ((gl.drawingBufferHeight || 1) * 0.1 * SCALE);\n    };\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n    resize();\n\n    const rotBuf = new Float32Array(9);\n    const setMat3FromEuler = (yawY: number, pitchX: number, rollZ: number, out: Float32Array) => {\n      const cy = Math.cos(yawY),\n        sy = Math.sin(yawY);\n      const cx = Math.cos(pitchX),\n        sx = Math.sin(pitchX);\n      const cz = Math.cos(rollZ),\n        sz = Math.sin(rollZ);\n      const r00 = cy * cz + sy * sx * sz;\n      const r01 = -cy * sz + sy * sx * cz;\n      const r02 = sy * cx;\n\n      const r10 = cx * sz;\n      const r11 = cx * cz;\n      const r12 = -sx;\n\n      const r20 = -sy * cz + cy * sx * sz;\n      const r21 = sy * sz + cy * sx * cz;\n      const r22 = cy * cx;\n\n      out[0] = r00;\n      out[1] = r10;\n      out[2] = r20;\n      out[3] = r01;\n      out[4] = r11;\n      out[5] = r21;\n      out[6] = r02;\n      out[7] = r12;\n      out[8] = r22;\n      return out;\n    };\n\n    const NOISE_IS_ZERO = NOISE < 1e-6;\n    let raf = 0;\n    const t0 = performance.now();\n    const startRAF = () => {\n      if (raf) return;\n      raf = requestAnimationFrame(render);\n    };\n    const stopRAF = () => {\n      if (!raf) return;\n      cancelAnimationFrame(raf);\n      raf = 0;\n    };\n\n    const rnd = () => Math.random();\n    const wX = (0.3 + rnd() * 0.6) * RSX;\n    const wY = (0.2 + rnd() * 0.7) * RSY;\n    const wZ = (0.1 + rnd() * 0.5) * RSZ;\n    const phX = rnd() * Math.PI * 2;\n    const phZ = rnd() * Math.PI * 2;\n\n    let yaw = 0,\n      pitch = 0,\n      roll = 0;\n    let targetYaw = 0,\n      targetPitch = 0;\n    const lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n\n    const pointer = { x: 0, y: 0, inside: true };\n    const onMove = (e: PointerEvent) => {\n      const ww = Math.max(1, window.innerWidth);\n      const wh = Math.max(1, window.innerHeight);\n      const cx = ww * 0.5;\n      const cy = wh * 0.5;\n      const nx = (e.clientX - cx) / (ww * 0.5);\n      const ny = (e.clientY - cy) / (wh * 0.5);\n      pointer.x = Math.max(-1, Math.min(1, nx));\n      pointer.y = Math.max(-1, Math.min(1, ny));\n      pointer.inside = true;\n    };\n    const onLeave = () => {\n      pointer.inside = false;\n    };\n    const onBlur = () => {\n      pointer.inside = false;\n    };\n\n    let onPointerMove: ((e: PointerEvent) => void) | null = null;\n    if (animationType === 'hover') {\n      onPointerMove = (e: PointerEvent) => {\n        onMove(e);\n        startRAF();\n      };\n      window.addEventListener('pointermove', onPointerMove, { passive: true });\n      window.addEventListener('mouseleave', onLeave);\n      window.addEventListener('blur', onBlur);\n      program.uniforms.uUseBaseWobble.value = 0;\n    } else if (animationType === '3drotate') {\n      program.uniforms.uUseBaseWobble.value = 0;\n    } else {\n      program.uniforms.uUseBaseWobble.value = 1;\n    }\n\n    const render = (t: number) => {\n      const time = (t - t0) * 0.001;\n      program.uniforms.iTime.value = time;\n\n      let continueRAF = true;\n\n      if (animationType === 'hover') {\n        const maxPitch = 0.6 * HOVSTR;\n        const maxYaw = 0.6 * HOVSTR;\n        targetYaw = (pointer.inside ? -pointer.x : 0) * maxYaw;\n        targetPitch = (pointer.inside ? pointer.y : 0) * maxPitch;\n        const prevYaw = yaw;\n        const prevPitch = pitch;\n        const prevRoll = roll;\n        yaw = lerp(prevYaw, targetYaw, INERT);\n        pitch = lerp(prevPitch, targetPitch, INERT);\n        roll = lerp(prevRoll, 0, 0.1);\n        program.uniforms.uRot.value = setMat3FromEuler(yaw, pitch, roll, rotBuf);\n\n        if (NOISE_IS_ZERO) {\n          const settled =\n            Math.abs(yaw - targetYaw) < 1e-4 && Math.abs(pitch - targetPitch) < 1e-4 && Math.abs(roll) < 1e-4;\n          if (settled) continueRAF = false;\n        }\n      } else if (animationType === '3drotate') {\n        const tScaled = time * TS;\n        yaw = tScaled * wY;\n        pitch = Math.sin(tScaled * wX + phX) * 0.6;\n        roll = Math.sin(tScaled * wZ + phZ) * 0.5;\n        program.uniforms.uRot.value = setMat3FromEuler(yaw, pitch, roll, rotBuf);\n        if (TS < 1e-6) continueRAF = false;\n      } else {\n        rotBuf[0] = 1;\n        rotBuf[1] = 0;\n        rotBuf[2] = 0;\n        rotBuf[3] = 0;\n        rotBuf[4] = 1;\n        rotBuf[5] = 0;\n        rotBuf[6] = 0;\n        rotBuf[7] = 0;\n        rotBuf[8] = 1;\n        program.uniforms.uRot.value = rotBuf;\n        if (TS < 1e-6) continueRAF = false;\n      }\n\n      renderer.render({ scene: mesh });\n      if (continueRAF) {\n        raf = requestAnimationFrame(render);\n      } else {\n        raf = 0;\n      }\n    };\n\n    interface PrismContainer extends HTMLElement {\n      __prismIO?: IntersectionObserver;\n    }\n\n    if (suspendWhenOffscreen) {\n      const io = new IntersectionObserver(entries => {\n        const vis = entries.some(e => e.isIntersecting);\n        if (vis) startRAF();\n        else stopRAF();\n      });\n      io.observe(container);\n      startRAF();\n      (container as PrismContainer).__prismIO = io;\n    } else {\n      startRAF();\n    }\n\n    return () => {\n      stopRAF();\n      ro.disconnect();\n      if (animationType === 'hover') {\n        if (onPointerMove) window.removeEventListener('pointermove', onPointerMove as EventListener);\n        window.removeEventListener('mouseleave', onLeave);\n        window.removeEventListener('blur', onBlur);\n      }\n      if (suspendWhenOffscreen) {\n        const io = (container as PrismContainer).__prismIO as IntersectionObserver | undefined;\n        if (io) io.disconnect();\n        delete (container as PrismContainer).__prismIO;\n      }\n      if (gl.canvas.parentElement === container) container.removeChild(gl.canvas);\n    };\n  }, [\n    height,\n    baseWidth,\n    animationType,\n    glow,\n    noise,\n    offset?.x,\n    offset?.y,\n    scale,\n    transparent,\n    hueShift,\n    colorFrequency,\n    timeScale,\n    hoverStrength,\n    inertia,\n    bloom,\n    suspendWhenOffscreen,\n    lightMode\n  ]);\n\n  return <div className=\"prism-container\" ref={containerRef} />;\n};\n\nexport default Prism;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"ogl@^1.0.11"
	]
}