{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "orbital-glow-background",
  "type": "registry:ui",
  "title": "OrbitalGlowBackground",
  "description": "Luminous elliptical rings surround a soft, slowly shifting core. WebGL rendering with static CSS fallback, reduced-motion support and bounded offscreen rendering.",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json"
  ],
  "cssVars": {
    "theme": {
      "shader-background-base": "var(--dt-color-background)",
      "shader-background-accent": "var(--dt-color-primary)",
      "shader-background-secondary": "var(--dt-color-info)"
    }
  },
  "files": [
    {
      "path": "packages/components/src/components/orbital-glow-background/orbital-glow-background.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/orbital-glow-background/orbital-glow-background.tsx",
      "content": "\"use client\";\n\nimport { forwardRef } from \"react\";\nimport { ShaderBackground } from \"../shader-backgrounds/shader-background\";\nimport type { ShaderBackgroundProps } from \"../shader-backgrounds/types\";\n\nexport type OrbitalGlowBackgroundProps = ShaderBackgroundProps;\n\n/** Luminous elliptical rings surround a soft, slowly shifting core. */\nexport const OrbitalGlowBackground = forwardRef<\n  HTMLDivElement,\n  OrbitalGlowBackgroundProps\n>(function OrbitalGlowBackground(props, ref) {\n  return <ShaderBackground {...props} ref={ref} effect=\"orbital-glow\" />;\n});\n"
    },
    {
      "path": "packages/components/src/components/orbital-glow-background/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/orbital-glow-background/index.ts",
      "content": "export {\n  OrbitalGlowBackground,\n  type OrbitalGlowBackgroundProps,\n} from \"./orbital-glow-background\";\n"
    },
    {
      "path": "packages/components/src/components/shader-backgrounds/shader-background.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/shader-backgrounds/shader-background.tsx",
      "content": "\"use client\";\n\nimport { forwardRef, useEffect, useRef, type CSSProperties } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { createBackgroundRenderer, type BackgroundRenderer } from \"./renderer\";\nimport {\n  backgroundIntensities,\n  backgroundSpeeds,\n  type ShaderBackgroundEffect,\n  type ShaderBackgroundProps,\n} from \"./types\";\n\nconst fallback: Record<ShaderBackgroundEffect, string> = {\n  \"liquid-mesh\":\n    \"radial-gradient(ellipse at 20% 35%,var(--shader-background-accent),transparent 65%),radial-gradient(ellipse at 80% 70%,var(--shader-background-secondary),transparent 65%)\",\n  \"silk-flow\":\n    \"repeating-linear-gradient(155deg,transparent 0%,var(--shader-background-accent) 12%,transparent 21%,var(--shader-background-secondary) 27%,transparent 33%)\",\n  \"caustic-light\":\n    \"repeating-radial-gradient(ellipse at 30% 60%,transparent 0 18px,var(--shader-background-accent) 20px,transparent 24px 55px),radial-gradient(ellipse at 80% 10%,var(--shader-background-secondary),transparent 70%)\",\n  \"contour-field\":\n    \"repeating-radial-gradient(ellipse at 70% 120%,transparent 0 24px,var(--shader-background-accent) 25px,transparent 27px 45px)\",\n  \"orbital-glow\":\n    \"radial-gradient(ellipse at 60% 50%,transparent 29%,var(--shader-background-accent) 30%,transparent 31% 39%,var(--shader-background-secondary) 40%,transparent 42%),radial-gradient(ellipse at 60% 50%,var(--shader-background-secondary),transparent 30%)\",\n};\n\n/** Internal host shared by the five independently installable public components. */\nexport const ShaderBackground = forwardRef<\n  HTMLDivElement,\n  ShaderBackgroundProps & { effect: ShaderBackgroundEffect }\n>(function ShaderBackground(\n  {\n    effect,\n    animate = true,\n    speed = \"normal\",\n    intensity = \"subtle\",\n    seed = 1,\n    interactive = false,\n    children,\n    className,\n    style,\n    ...props\n  },\n  forwardedRef,\n) {\n  const rootRef = useRef<HTMLDivElement>(null),\n    layerRef = useRef<HTMLDivElement>(null);\n  const elapsed = useRef(0);\n  useEffect(() => {\n    const root = rootRef.current,\n      layer = layerRef.current;\n    if (!root || !layer) return;\n    const motion = matchMedia(\"(prefers-reduced-motion: reduce)\"),\n      contrast = matchMedia(\"(forced-colors: active)\"),\n      colorScheme = matchMedia(\"(prefers-color-scheme: dark)\"),\n      mouse = matchMedia(\"(hover: hover) and (pointer: fine)\");\n    let disposed = false,\n      visible = false,\n      skipped = false,\n      printing = false,\n      failed = false;\n    let renderer: BackgroundRenderer | null = null,\n      canvas: HTMLCanvasElement | null = null;\n    let frame = 0,\n      last = 0;\n    const target: [number, number] = [0, 0],\n      pointer: [number, number] = [0, 0];\n    const state = (value: string) => {\n      root.dataset.state = value;\n    };\n    const cancel = () => {\n      if (frame) cancelAnimationFrame(frame);\n      frame = 0;\n      last = 0;\n    };\n    const allowed = () =>\n      !disposed &&\n      animate &&\n      !motion.matches &&\n      !contrast.matches &&\n      !document.hidden &&\n      visible &&\n      !skipped &&\n      !printing;\n    const lost = (event: Event) => {\n      event.preventDefault();\n      cancel();\n      renderer?.dispose();\n      renderer = null;\n      failed = true;\n      state(\"fallback\");\n    };\n    const restored = () => {\n      release();\n      failed = false;\n      reconcile();\n    };\n    const release = () => {\n      cancel();\n      renderer?.dispose();\n      renderer = null;\n      if (canvas) {\n        canvas.removeEventListener(\"webglcontextlost\", lost);\n        canvas.removeEventListener(\"webglcontextrestored\", restored);\n        const gl = canvas.getContext(\"webgl\");\n        if (gl && !gl.isContextLost())\n          gl.getExtension(\"WEBGL_lose_context\")?.loseContext();\n        canvas.remove();\n        canvas = null;\n      }\n      target[0] = target[1] = pointer[0] = pointer[1] = 0;\n      state(\"static\");\n    };\n    const tick = (now: number) => {\n      frame = 0;\n      if (!allowed()) {\n        release();\n        return;\n      }\n      if (!renderer) return;\n      const dt = last ? (now - last) / 1000 : 1 / 30;\n      if (!last || dt >= 1 / 30) {\n        last = now;\n        elapsed.current += Math.min(dt, 0.1) * backgroundSpeeds[speed];\n        const follow = 1 - Math.exp(-Math.min(dt, 0.1) * 6);\n        pointer[0] += (target[0] - pointer[0]) * follow;\n        pointer[1] += (target[1] - pointer[1]) * follow;\n        try {\n          renderer.draw(elapsed.current, pointer);\n        } catch {\n          failed = true;\n          release();\n          state(\"fallback\");\n          return;\n        }\n      }\n      frame = requestAnimationFrame(tick);\n    };\n    const reconcile = () => {\n      if (!mouse.matches || !interactive) target[0] = target[1] = 0;\n      if (!allowed()) {\n        release();\n        return;\n      }\n      if (failed || renderer) return;\n      if (root.clientWidth < 1 || root.clientHeight < 1) return;\n      canvas = document.createElement(\"canvas\");\n      canvas.className = \"absolute inset-0 h-full w-full\";\n      canvas.setAttribute(\"aria-hidden\", \"true\");\n      canvas.addEventListener(\"webglcontextlost\", lost);\n      canvas.addEventListener(\"webglcontextrestored\", restored);\n      layer.append(canvas);\n      try {\n        renderer = createBackgroundRenderer(\n          canvas,\n          root,\n          effect,\n          backgroundIntensities[intensity],\n          seed,\n        );\n        renderer.draw(elapsed.current, pointer);\n        state(\"running\");\n        frame = requestAnimationFrame(tick);\n      } catch {\n        failed = true;\n        release();\n        state(\"fallback\");\n      }\n    };\n    const resize = () => {\n      if (!allowed()) {\n        release();\n        return;\n      }\n      if (renderer) {\n        if (!renderer.resize()) release();\n      } else reconcile();\n    };\n    const recolor = () => {\n      if (renderer) {\n        try {\n          renderer.colors();\n        } catch {\n          failed = true;\n          release();\n          state(\"fallback\");\n        }\n      } else reconcile();\n    };\n    const move = (event: PointerEvent) => {\n      if (\n        !interactive ||\n        !mouse.matches ||\n        event.pointerType !== \"mouse\" ||\n        event.buttons ||\n        !allowed()\n      )\n        return;\n      const box = root.getBoundingClientRect();\n      target[0] = Math.max(\n        -1,\n        Math.min(1, ((event.clientX - box.left) / box.width) * 2 - 1),\n      );\n      target[1] = Math.max(\n        -1,\n        Math.min(1, 1 - ((event.clientY - box.top) / box.height) * 2),\n      );\n    };\n    const leave = () => {\n      target[0] = target[1] = 0;\n    };\n    const beforePrint = () => {\n        printing = true;\n        reconcile();\n      },\n      afterPrint = () => {\n        printing = false;\n        reconcile();\n      };\n    const contentVisibility = (event: Event) => {\n      skipped = Boolean((event as Event & { skipped: boolean }).skipped);\n      reconcile();\n    };\n    const intersection =\n      typeof IntersectionObserver !== \"undefined\"\n        ? new IntersectionObserver(([entry]) => {\n            visible = !!entry?.isIntersecting;\n            reconcile();\n          })\n        : null;\n    intersection?.observe(root);\n    if (!intersection) visible = true;\n    const observer =\n      typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(resize) : null;\n    observer?.observe(root);\n    const styles = new MutationObserver(recolor);\n    for (\n      let ancestor: HTMLElement | null = root;\n      ancestor;\n      ancestor = ancestor.parentElement\n    )\n      styles.observe(ancestor, {\n        attributes: true,\n        attributeFilter: [\n          \"style\",\n          \"class\",\n          \"data-theme\",\n          \"data-brand\",\n          \"data-density\",\n        ],\n      });\n    root.addEventListener(\"pointermove\", move);\n    root.addEventListener(\"pointerleave\", leave);\n    root.addEventListener(\"pointercancel\", leave);\n    layer.addEventListener(\n      \"contentvisibilityautostatechange\",\n      contentVisibility,\n    );\n    document.addEventListener(\"visibilitychange\", reconcile);\n    window.addEventListener(\"resize\", resize);\n    window.addEventListener(\"blur\", leave);\n    window.addEventListener(\"beforeprint\", beforePrint);\n    window.addEventListener(\"afterprint\", afterPrint);\n    [motion, contrast, mouse].forEach((m) =>\n      m.addEventListener(\"change\", reconcile),\n    );\n    colorScheme.addEventListener(\"change\", recolor);\n    reconcile();\n    return () => {\n      disposed = true;\n      intersection?.disconnect();\n      observer?.disconnect();\n      styles.disconnect();\n      root.removeEventListener(\"pointermove\", move);\n      root.removeEventListener(\"pointerleave\", leave);\n      root.removeEventListener(\"pointercancel\", leave);\n      layer.removeEventListener(\n        \"contentvisibilityautostatechange\",\n        contentVisibility,\n      );\n      document.removeEventListener(\"visibilitychange\", reconcile);\n      window.removeEventListener(\"resize\", resize);\n      window.removeEventListener(\"blur\", leave);\n      window.removeEventListener(\"beforeprint\", beforePrint);\n      window.removeEventListener(\"afterprint\", afterPrint);\n      [motion, contrast, mouse].forEach((m) =>\n        m.removeEventListener(\"change\", reconcile),\n      );\n      colorScheme.removeEventListener(\"change\", recolor);\n      release();\n    };\n  }, [effect, animate, speed, intensity, seed, interactive]);\n  return (\n    <div\n      {...props}\n      ref={(node) => {\n        rootRef.current = node;\n        if (typeof forwardedRef === \"function\") forwardedRef(node);\n        else if (forwardedRef) forwardedRef.current = node;\n      }}\n      data-slot={`${effect}-background`}\n      data-effect={effect}\n      data-state=\"static\"\n      data-animate={animate}\n      data-speed={speed}\n      data-intensity={intensity}\n      data-interactive={interactive}\n      className={cn(\n        \"group/shader-bg bg-background text-foreground relative isolate overflow-hidden\",\n        className,\n      )}\n      style={\n        {\n          backgroundColor: \"var(--shader-background-base)\",\n          \"--shader-background-base\": \"var(--dt-color-background)\",\n          \"--shader-background-accent\": \"var(--dt-color-primary)\",\n          \"--shader-background-secondary\": \"var(--dt-color-info)\",\n          ...style,\n        } as CSSProperties\n      }\n    >\n      <div\n        aria-hidden=\"true\"\n        data-slot=\"shader-background-fallback\"\n        className=\"pointer-events-none absolute inset-0 forced-colors:hidden\"\n        style={{\n          backgroundImage: fallback[effect],\n          opacity: backgroundIntensities[intensity] * 0.55,\n        }}\n      />\n      <div\n        ref={layerRef}\n        aria-hidden=\"true\"\n        data-slot=\"shader-background-layer\"\n        className=\"pointer-events-none invisible absolute inset-0 group-data-[state=running]/shader-bg:visible motion-reduce:!invisible print:!invisible forced-colors:!invisible\"\n        style={{\n          contentVisibility: \"auto\",\n          containIntrinsicSize: \"auto 500px\",\n        }}\n      />\n      <div data-slot=\"shader-background-content\" className=\"relative z-10\">\n        {children}\n      </div>\n    </div>\n  );\n});\n"
    },
    {
      "path": "packages/components/src/components/shader-backgrounds/renderer.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/shader-backgrounds/renderer.ts",
      "content": "import { backgroundFragment, backgroundVertex } from \"./shaders\";\nimport { bufferSize, type ShaderBackgroundEffect } from \"./types\";\n\nexport interface BackgroundRenderer {\n  resize: () => boolean;\n  colors: () => void;\n  draw: (time: number, pointer: readonly [number, number]) => void;\n  dispose: () => void;\n}\n\nexport function createBackgroundRenderer(\n  canvas: HTMLCanvasElement,\n  root: HTMLElement,\n  effect: ShaderBackgroundEffect,\n  intensity: number,\n  seed: number,\n): BackgroundRenderer {\n  const gl = canvas.getContext(\"webgl\", {\n    alpha: false,\n    antialias: false,\n    depth: false,\n    stencil: false,\n    powerPreference: \"low-power\",\n  });\n  if (!gl) throw new Error(\"WebGL unavailable\");\n  const shaders: WebGLShader[] = [];\n  let program: WebGLProgram | null = null,\n    buffer: WebGLBuffer | null = null;\n  const dispose = () => {\n    if (buffer) gl.deleteBuffer(buffer);\n    if (program) gl.deleteProgram(program);\n    shaders.forEach((s) => gl.deleteShader(s));\n    shaders.length = 0;\n    buffer = program = null;\n  };\n  try {\n    program = gl.createProgram();\n    if (!program) throw new Error(\"No program\");\n    for (const [type, source] of [\n      [gl.VERTEX_SHADER, backgroundVertex],\n      [gl.FRAGMENT_SHADER, backgroundFragment(effect)],\n    ] as const) {\n      const shader = gl.createShader(type);\n      if (!shader) throw new Error(\"No shader\");\n      shaders.push(shader);\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      gl.attachShader(program, shader);\n    }\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS))\n      throw new Error(gl.getProgramInfoLog(program) ?? \"Shader failed\");\n    gl.useProgram(program);\n    buffer = gl.createBuffer();\n    if (!buffer) throw new Error(\"No buffer\");\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 3, -1, -1, 3]),\n      gl.STATIC_DRAW,\n    );\n    const position = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(position);\n    gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);\n    const uniform = (name: string) => gl.getUniformLocation(program!, name);\n    const timeUniform = uniform(\"u_time\"),\n      pointerUniform = uniform(\"u_pointer\"),\n      resolutionUniform = uniform(\"u_resolution\");\n    gl.uniform1f(uniform(\"u_intensity\"), intensity);\n    gl.uniform1f(\n      uniform(\"u_seed\"),\n      (Number.isFinite(seed) ? seed % 1000 : 1) * 0.137,\n    );\n    const limits = gl.getParameter(gl.MAX_VIEWPORT_DIMS) as Int32Array;\n    const limit = Math.min(limits[0]!, limits[1]!, 4096);\n    const resize = () => {\n      const size = bufferSize(\n        root.clientWidth,\n        root.clientHeight,\n        window.devicePixelRatio || 1,\n        limit,\n      );\n      if (!size) return false;\n      if (canvas.width !== size[0] || canvas.height !== size[1]) {\n        canvas.width = size[0];\n        canvas.height = size[1];\n      }\n      gl.viewport(0, 0, canvas.width, canvas.height);\n      gl.uniform2f(resolutionUniform, canvas.width, canvas.height);\n      return true;\n    };\n    const colors = () => {\n      const probe = document.createElement(\"span\");\n      probe.style.cssText =\n        \"position:absolute;visibility:hidden;pointer-events:none\";\n      probe.setAttribute(\"aria-hidden\", \"true\");\n      const swatch = document.createElement(\"canvas\");\n      swatch.width = swatch.height = 1;\n      const ctx = swatch.getContext(\"2d\", { willReadFrequently: true });\n      if (!ctx) throw new Error(\"Color conversion unavailable\");\n      root.append(probe);\n      try {\n        for (const name of [\"base\", \"accent\", \"secondary\"]) {\n          probe.style.color = `var(--shader-background-${name})`;\n          ctx.clearRect(0, 0, 1, 1);\n          ctx.fillStyle = getComputedStyle(probe).color;\n          ctx.fillRect(0, 0, 1, 1);\n          const pixel = ctx.getImageData(0, 0, 1, 1).data;\n          gl.uniform3f(\n            uniform(`u_${name}`),\n            pixel[0]! / 255,\n            pixel[1]! / 255,\n            pixel[2]! / 255,\n          );\n        }\n      } finally {\n        probe.remove();\n      }\n    };\n    const draw = (time: number, pointer: readonly [number, number]) => {\n      gl.uniform1f(timeUniform, time);\n      gl.uniform2f(pointerUniform, pointer[0], pointer[1]);\n      gl.drawArrays(gl.TRIANGLES, 0, 3);\n    };\n    if (!resize()) throw new Error(\"Empty background\");\n    colors();\n    draw(0, [0, 0]);\n    if (gl.isContextLost() || gl.getError() !== gl.NO_ERROR)\n      throw new Error(\"GPU initialization failed\");\n    return { resize, colors, draw, dispose };\n  } catch (error) {\n    dispose();\n    throw error;\n  }\n}\n"
    },
    {
      "path": "packages/components/src/components/shader-backgrounds/shaders.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/shader-backgrounds/shaders.ts",
      "content": "import type { ShaderBackgroundEffect } from \"./types\";\n\nconst common = `\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\nuniform vec2 u_resolution;\nuniform vec2 u_pointer;\nuniform float u_time;\nuniform float u_seed;\nuniform float u_intensity;\nuniform vec3 u_base;\nuniform vec3 u_accent;\nuniform vec3 u_secondary;\nconst float TAU = 6.2831853;\nfloat hash(vec2 p) {\n  p = fract(p * vec2(0.1031, 0.11369));\n  p += dot(p, p.yx + 19.19);\n  return fract((p.x + p.y) * p.x);\n}\nfloat noise(vec2 p) {\n  vec2 a = floor(p), b = fract(p);\n  b = b * b * (3.0 - 2.0 * b);\n  return mix(mix(hash(a), hash(a+vec2(1.,0.)), b.x),\n             mix(hash(a+vec2(0.,1.)), hash(a+1.), b.x), b.y);\n}\nfloat field(vec2 p) {\n  return noise(p)*0.57 + noise(p*2.03+7.1)*0.28 + noise(p*4.11+19.2)*0.15;\n}\nvec2 coordinates() {\n  vec2 p = (gl_FragCoord.xy / u_resolution - 0.5);\n  p.x *= u_resolution.x / u_resolution.y;\n  return p + u_pointer * 0.075;\n}\nvoid outputColor(vec3 color, float strength) {\n  gl_FragColor = vec4(mix(u_base, color, clamp(strength*u_intensity, 0., 1.)), 1.);\n}\n`;\n\n// Each program compiles only its own material, sharing no third-party shader code.\nconst effects: Record<ShaderBackgroundEffect, string> = {\n  \"liquid-mesh\": `\nvoid main() {\n  vec2 p=coordinates(); float t=u_time*0.22+u_seed;\n  p += vec2(sin(p.y*3.2+t), cos(p.x*2.8-t))*0.16;\n  vec2 a=vec2(sin(t*.7)*.55, cos(t*.5)*.23);\n  vec2 b=vec2(cos(t*.6)*.65, sin(t*.8)*.3);\n  float pool=exp(-dot(p-a,p-a)*2.8);\n  float other=exp(-dot(p-b,p-b)*3.8);\n  float fold=.5+.5*sin(p.x*2.7+p.y*3.1+t);\n  vec3 color=mix(u_accent,u_secondary,clamp(other*.8+fold*.3,0.,1.));\n  outputColor(color,.18+pool*.7+other*.35);\n}`,\n  \"silk-flow\": `\nvoid main() {\n  vec2 p=coordinates(); float t=u_time*.26+u_seed;\n  float bend=sin(p.x*1.7+t)*.55 + sin(p.y*2.4-t*.6)*.28;\n  float fabric=p.y*8.0+p.x*3.0+bend*4.0;\n  float folds=pow(.5+.5*sin(fabric),3.0);\n  float seam=pow(.5+.5*sin(fabric+0.8),14.0);\n  float thread=.94+.06*sin(fabric*15.0);\n  vec3 color=mix(u_accent,u_secondary,.5+.5*sin(fabric*.3+t*.4));\n  outputColor(color,(folds*.7+seam*.35)*thread+.035);\n}`,\n  \"caustic-light\": `\nvoid main() {\n  vec2 p=coordinates()*4.; float t=u_time*.25+u_seed;\n  p += vec2(sin(p.y*1.2+t),cos(p.x*.9-t))*.5;\n  float a=sin(p.x*2.+sin(p.y+t))+cos(p.y*2.3-t*.7);\n  float b=sin(p.y*2.8+cos(p.x-t))+cos(p.x*1.9+t*.6);\n  float ridge=pow(max(0.,1.-abs(a*b)*1.6),7.);\n  float water=.5+.5*sin(p.x*.6+p.y*.8+t*.3);\n  vec3 color=mix(u_accent,u_secondary,water);\n  outputColor(color,.12+ridge*.85);\n}`,\n  \"contour-field\": `\nvoid main() {\n  vec2 p=coordinates()*2.2; float t=u_time*.075+u_seed;\n  vec2 warp=vec2(field(p+vec2(t,0.)),field(p+vec2(7.3,-t)));\n  float terrain=field(p+warp*1.7+vec2(t*.25,-t*.3));\n  float bands=terrain*13.;\n  float edge=abs(fract(bands)-.5);\n  float aa=clamp(38./u_resolution.y,.025,.14);\n  float line=1.-smoothstep(.025,.025+aa,edge);\n  vec3 color=mix(u_accent,u_secondary,terrain);\n  outputColor(color,.035+line*.85);\n}`,\n  \"orbital-glow\": `\nvoid main() {\n  vec2 p=coordinates(); float t=u_time*.16+u_seed;\n  p-=vec2(.18*sin(t*.3),.08*cos(t*.4));\n  float light=0., hue=0.;\n  for(int i=0;i<4;i++) {\n    float f=float(i), angle=.35+f*.6;\n    vec2 q=mat2(cos(angle),-sin(angle),sin(angle),cos(angle))*p;\n    q.y*=1.55+f*.17;\n    float radius=.25+f*.115;\n    float d=abs(length(q)-radius);\n    float arc=.3+.7*pow(.5+.5*cos(atan(q.y,q.x)-t-f*1.7),3.);\n    float ring=(exp(-d*95.)*.65+exp(-d*15.)*.17)*arc;\n    light+=ring; hue+=ring*f/3.;\n  }\n  float core=exp(-dot(p,p)*18.)*.18;\n  vec3 color=mix(u_accent,u_secondary,clamp(hue/max(light,.001),0.,1.));\n  outputColor(color,light+core);\n}`,\n};\n\nexport const backgroundVertex = `attribute vec2 a_position; void main(){gl_Position=vec4(a_position,0.,1.);}`;\nexport const backgroundFragment = (effect: ShaderBackgroundEffect) =>\n  common + effects[effect];\n"
    },
    {
      "path": "packages/components/src/components/shader-backgrounds/types.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/shader-backgrounds/types.ts",
      "content": "import type { HTMLAttributes } from \"react\";\n\nexport type ShaderBackgroundEffect =\n  | \"liquid-mesh\"\n  | \"silk-flow\"\n  | \"caustic-light\"\n  | \"contour-field\"\n  | \"orbital-glow\";\n\nexport interface ShaderBackgroundProps extends HTMLAttributes<HTMLDivElement> {\n  /** False uses the static CSS composition and allocates no WebGL context. */\n  animate?: boolean;\n  speed?: \"slow\" | \"normal\" | \"fast\";\n  intensity?: \"faint\" | \"subtle\" | \"bold\";\n  /** Finite seeds choose a repeatable initial composition. */\n  seed?: number;\n  /** Gentle mouse parallax. Off by default; never captures touch input. */\n  interactive?: boolean;\n}\n\nexport function bufferSize(\n  width: number,\n  height: number,\n  dpr: number,\n  limit = 4096,\n) {\n  if (\n    ![width, height, dpr, limit].every(Number.isFinite) ||\n    width <= 0 ||\n    height <= 0 ||\n    limit < 1\n  )\n    return null;\n  const scale = Math.min(\n    Math.max(dpr, 0.5),\n    1.5,\n    Math.sqrt(1_000_000 / (width * height)),\n    limit / width,\n    limit / height,\n  );\n  return [\n    Math.max(1, Math.floor(width * scale)),\n    Math.max(1, Math.floor(height * scale)),\n  ] as const;\n}\n\nexport const backgroundSpeeds = { slow: 0.35, normal: 0.65, fast: 1 };\nexport const backgroundIntensities = { faint: 0.3, subtle: 0.6, bold: 0.9 };\n"
    },
    {
      "path": "packages/components/src/utils/cn.ts",
      "type": "registry:file",
      "target": "~/components/dethink/utils/cn.ts",
      "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"
    }
  ]
}
