{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "aurora",
  "type": "registry:ui",
  "title": "Aurora",
  "description": "WebGL aurora borealis effect with simplex noise and configurable color stops.",
  "dependencies": ["ogl"],
  "files": [
    {
      "path": "registry/new-york/aurora/Aurora.vue",
      "content": "<script setup lang=\"ts\">\n  import { ref, onMounted, onBeforeUnmount } from 'vue';\n  import { useResizeObserver } from '@vueuse/core';\n  import { Renderer, Program, Mesh, Color, Triangle } from 'ogl';\n  import { cn } from '~/lib/utils';\n\n  const props = withDefaults(\n    defineProps<{\n      colorStops?: string[];\n      amplitude?: number;\n      blend?: number;\n      speed?: number;\n      class?: string;\n    }>(),\n    {\n      colorStops: () => ['#5227FF', '#7cff67', '#5227FF'],\n      amplitude: 1.0,\n      blend: 0.5,\n      speed: 1.0,\n      class: '',\n    },\n  );\n\n  const containerRef = ref<HTMLDivElement | null>(null);\n  let animationId = 0;\n  let renderer: InstanceType<typeof Renderer> | null = null;\n  let glContext: WebGLRenderingContext | null = null;\n\n  const VERT = `#version 300 es\nin vec2 position;\nvoid main() {\n  gl_Position = vec4(position, 0.0, 1.0);\n}`;\n\n  const FRAG = `#version 300 es\nprecision highp float;\nuniform float uTime;\nuniform float uAmplitude;\nuniform vec3 uColorStops[3];\nuniform vec2 uResolution;\nuniform float uBlend;\nout vec4 fragColor;\n\nvec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }\n\nfloat snoise(vec2 v) {\n  const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);\n  vec2 i = floor(v + dot(v, C.yy));\n  vec2 x0 = v - i + dot(i, C.xx);\n  vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n  vec4 x12 = x0.xyxy + C.xxzz;\n  x12.xy -= i1;\n  i = mod(i, 289.0);\n  vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));\n  vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);\n  m = m * m; m = m * m;\n  vec3 x = 2.0 * fract(p * C.www) - 1.0;\n  vec3 h = abs(x) - 0.5;\n  vec3 ox = floor(x + 0.5);\n  vec3 a0 = x - ox;\n  m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n  vec3 g;\n  g.x = a0.x * x0.x + h.x * x0.y;\n  g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n  return 130.0 * dot(m, g);\n}\n\nstruct ColorStop { vec3 color; float position; };\n\n#define COLOR_RAMP(colors, factor, finalColor) {              \\\\\n  int index = 0;                                            \\\\\n  for (int i = 0; i < 2; i++) {                               \\\\\n    ColorStop currentColor = colors[i];                    \\\\\n    bool isInBetween = currentColor.position <= factor;    \\\\\n    index = int(mix(float(index), float(i), float(isInBetween))); \\\\\n  }                                                         \\\\\n  ColorStop currentColor = colors[index];                   \\\\\n  ColorStop nextColor = colors[index + 1];                  \\\\\n  float range = nextColor.position - currentColor.position; \\\\\n  float lerpFactor = (factor - currentColor.position) / range; \\\\\n  finalColor = mix(currentColor.color, nextColor.color, lerpFactor); \\\\\n}\n\nvoid main() {\n  vec2 uv = gl_FragCoord.xy / uResolution;\n  ColorStop colors[3];\n  colors[0] = ColorStop(uColorStops[0], 0.0);\n  colors[1] = ColorStop(uColorStops[1], 0.5);\n  colors[2] = ColorStop(uColorStops[2], 1.0);\n  vec3 rampColor;\n  COLOR_RAMP(colors, uv.x, rampColor);\n  float height = snoise(vec2(uv.x * 2.0 + uTime * 0.1, uTime * 0.25)) * 0.5 * uAmplitude;\n  height = exp(height);\n  height = (uv.y * 2.0 - height + 0.2);\n  float intensity = 0.6 * height;\n  float midPoint = 0.20;\n  float auroraAlpha = smoothstep(midPoint - uBlend * 0.5, midPoint + uBlend * 0.5, intensity);\n  vec3 auroraColor = intensity * rampColor;\n  fragColor = vec4(auroraColor * auroraAlpha, auroraAlpha);\n}`;\n\n  useResizeObserver(containerRef, (entries) => {\n    if (!renderer || !containerRef.value) return;\n    const { width, height } = entries[0].contentRect;\n    renderer.setSize(width, height);\n  });\n\n  onMounted(() => {\n    const container = containerRef.value;\n    if (!container) return;\n\n    renderer = new Renderer({\n      alpha: true,\n      premultipliedAlpha: true,\n      antialias: true,\n    });\n    const gl = renderer.gl;\n    glContext = gl;\n    gl.clearColor(0, 0, 0, 0);\n    gl.enable(gl.BLEND);\n    gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n    (gl.canvas as HTMLCanvasElement).style.backgroundColor = 'transparent';\n\n    renderer.setSize(container.offsetWidth, container.offsetHeight);\n\n    const geometry = new Triangle(gl);\n    if ((geometry.attributes as Record<string, unknown>).uv) {\n      delete (geometry.attributes as Record<string, unknown>).uv;\n    }\n\n    const colorStopsArray = props.colorStops.map((hex) => {\n      const c = new Color(hex);\n      return [c.r, c.g, c.b];\n    });\n\n    const program = new Program(gl, {\n      vertex: VERT,\n      fragment: FRAG,\n      uniforms: {\n        uTime: { value: 0 },\n        uAmplitude: { value: props.amplitude },\n        uColorStops: { value: colorStopsArray },\n        uResolution: { value: [container.offsetWidth, container.offsetHeight] },\n        uBlend: { value: props.blend },\n      },\n    });\n\n    const mesh = new Mesh(gl, { geometry, program });\n    container.appendChild(gl.canvas as HTMLCanvasElement);\n\n    function update(t: number) {\n      animationId = requestAnimationFrame(update);\n      program.uniforms.uTime.value = t * 0.01 * props.speed * 0.1;\n      program.uniforms.uAmplitude.value = props.amplitude;\n      program.uniforms.uBlend.value = props.blend;\n      const stops = props.colorStops;\n      program.uniforms.uColorStops.value = stops.map((hex) => {\n        const c = new Color(hex);\n        return [c.r, c.g, c.b];\n      });\n      if (renderer) renderer.render({ scene: mesh });\n    }\n    animationId = requestAnimationFrame(update);\n  });\n\n  onBeforeUnmount(() => {\n    cancelAnimationFrame(animationId);\n    if (glContext) {\n      const canvas = glContext.canvas as HTMLCanvasElement;\n      if (canvas.parentNode) canvas.parentNode.removeChild(canvas);\n      glContext.getExtension('WEBGL_lose_context')?.loseContext();\n    }\n  });\n</script>\n\n<template>\n  <div ref=\"containerRef\" :class=\"cn('size-full', $props.class)\"></div>\n</template>\n",
      "type": "registry:ui",
      "target": "components/ui/aurora/Aurora.vue"
    },
    {
      "path": "registry/new-york/aurora/index.ts",
      "content": "export { default as Aurora } from './Aurora.vue';\n",
      "type": "registry:ui",
      "target": "components/ui/aurora/index.ts"
    }
  ]
}
