{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "strands",
  "type": "registry:block",
  "title": "Strands",
  "description": "Strands",
  "files": [
    {
      "path": "components/usages/strandsusage.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport Strands from \"@/registry/open-source/strands\";\n\nimport { Slider } from \"../ui/slider\";\nimport { Switch } from \"../ui/switch\";\n\nexport default function Usage() {\n\tconst [color1, setColor1] = useState(\"#F97316\");\n\tconst [color2, setColor2] = useState(\"#7C3AED\");\n\tconst [color3, setColor3] = useState(\"#06B6D4\");\n\tconst [count, setCount] = useState(3);\n\tconst [speed, setSpeed] = useState(0.5);\n\tconst [amplitude, setAmplitude] = useState(1);\n\tconst [waviness, setWaviness] = useState(1);\n\tconst [thickness, setThickness] = useState(0.7);\n\tconst [glow, setGlow] = useState(2.6);\n\tconst [taper, setTaper] = useState(3);\n\tconst [spread, setSpread] = useState(1);\n\tconst [hueShift, setHueShift] = useState(0);\n\tconst [intensity, setIntensity] = useState(0.6);\n\tconst [saturation, setSaturation] = useState(2);\n\tconst [opacity, setOpacity] = useState(1);\n\tconst [scale, setScale] = useState(1.5);\n\tconst [glass, setGlass] = useState(false);\n\tconst [refraction, setRefraction] = useState(1);\n\tconst [dispersion, setDispersion] = useState(1);\n\tconst [glassSize, setGlassSize] = useState(1);\n\n\tconst colors = [color1, color2, color3];\n\n\treturn (\n\t\t<div className=\"h-screen w-screen overflow-auto\">\n\t\t\t<div className=\"h-screen w-full\">\n\t\t\t\t<Strands\n\t\t\t\t\tcolors={colors}\n\t\t\t\t\tcount={count}\n\t\t\t\t\tspeed={speed}\n\t\t\t\t\tamplitude={amplitude}\n\t\t\t\t\twaviness={waviness}\n\t\t\t\t\tthickness={thickness}\n\t\t\t\t\tglow={glow}\n\t\t\t\t\ttaper={taper}\n\t\t\t\t\tspread={spread}\n\t\t\t\t\thueShift={hueShift}\n\t\t\t\t\tintensity={intensity}\n\t\t\t\t\tsaturation={saturation}\n\t\t\t\t\topacity={opacity}\n\t\t\t\t\tscale={scale}\n\t\t\t\t\tglass={glass}\n\t\t\t\t\trefraction={refraction}\n\t\t\t\t\tdispersion={dispersion}\n\t\t\t\t\tglassSize={glassSize}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"h-screen flex flex-col gap-7 p-6\">\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 1\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color1}\n\t\t\t\t\t\tonChange={(e) => setColor1(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 2\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color2}\n\t\t\t\t\t\tonChange={(e) => setColor2(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 3\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color3}\n\t\t\t\t\t\tonChange={(e) => setColor3(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\n\t\t\t\t<label>count</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={1}\n\t\t\t\t\tmax={10}\n\t\t\t\t\tstep={1}\n\t\t\t\t\tvalue={[count]}\n\t\t\t\t\tonValueChange={([value]) => setCount(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>speed</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[speed]}\n\t\t\t\t\tonValueChange={([value]) => setSpeed(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>amplitude</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[amplitude]}\n\t\t\t\t\tonValueChange={([value]) => setAmplitude(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>waviness</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.2}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[waviness]}\n\t\t\t\t\tonValueChange={([value]) => setWaviness(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>thickness</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.2}\n\t\t\t\t\tmax={4}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[thickness]}\n\t\t\t\t\tonValueChange={([value]) => setThickness(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glow</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[glow]}\n\t\t\t\t\tonValueChange={([value]) => setGlow(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>taper</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.5}\n\t\t\t\t\tmax={6}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[taper]}\n\t\t\t\t\tonValueChange={([value]) => setTaper(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>spread</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[spread]}\n\t\t\t\t\tonValueChange={([value]) => setSpread(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>hue shift</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.01}\n\t\t\t\t\tvalue={[hueShift]}\n\t\t\t\t\tonValueChange={([value]) => setHueShift(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>intensity</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[intensity]}\n\t\t\t\t\tonValueChange={([value]) => setIntensity(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>saturation</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={2}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[saturation]}\n\t\t\t\t\tonValueChange={([value]) => setSaturation(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>opacity</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[opacity]}\n\t\t\t\t\tonValueChange={([value]) => setOpacity(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>scale</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[scale]}\n\t\t\t\t\tonValueChange={([value]) => setScale(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glass ball</label>\n\t\t\t\t<Switch checked={glass} onCheckedChange={setGlass} />\n\n\t\t\t\t<label>refraction</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[refraction]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setRefraction(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>dispersion</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={4}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[dispersion]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setDispersion(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glass size</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.01}\n\t\t\t\t\tvalue={[glassSize]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setGlassSize(value)}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:block",
      "target": "~/example.tsx"
    },
    {
      "path": "components/usages/strandsusage.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\n\nimport Strands from \"@/registry/open-source/strands\";\n\nimport { Slider } from \"../ui/slider\";\nimport { Switch } from \"../ui/switch\";\n\nexport default function Usage() {\n\tconst [color1, setColor1] = useState(\"#F97316\");\n\tconst [color2, setColor2] = useState(\"#7C3AED\");\n\tconst [color3, setColor3] = useState(\"#06B6D4\");\n\tconst [count, setCount] = useState(3);\n\tconst [speed, setSpeed] = useState(0.5);\n\tconst [amplitude, setAmplitude] = useState(1);\n\tconst [waviness, setWaviness] = useState(1);\n\tconst [thickness, setThickness] = useState(0.7);\n\tconst [glow, setGlow] = useState(2.6);\n\tconst [taper, setTaper] = useState(3);\n\tconst [spread, setSpread] = useState(1);\n\tconst [hueShift, setHueShift] = useState(0);\n\tconst [intensity, setIntensity] = useState(0.6);\n\tconst [saturation, setSaturation] = useState(2);\n\tconst [opacity, setOpacity] = useState(1);\n\tconst [scale, setScale] = useState(1.5);\n\tconst [glass, setGlass] = useState(false);\n\tconst [refraction, setRefraction] = useState(1);\n\tconst [dispersion, setDispersion] = useState(1);\n\tconst [glassSize, setGlassSize] = useState(1);\n\n\tconst colors = [color1, color2, color3];\n\n\treturn (\n\t\t<div className=\"h-screen w-screen overflow-auto\">\n\t\t\t<div className=\"h-screen w-full\">\n\t\t\t\t<Strands\n\t\t\t\t\tcolors={colors}\n\t\t\t\t\tcount={count}\n\t\t\t\t\tspeed={speed}\n\t\t\t\t\tamplitude={amplitude}\n\t\t\t\t\twaviness={waviness}\n\t\t\t\t\tthickness={thickness}\n\t\t\t\t\tglow={glow}\n\t\t\t\t\ttaper={taper}\n\t\t\t\t\tspread={spread}\n\t\t\t\t\thueShift={hueShift}\n\t\t\t\t\tintensity={intensity}\n\t\t\t\t\tsaturation={saturation}\n\t\t\t\t\topacity={opacity}\n\t\t\t\t\tscale={scale}\n\t\t\t\t\tglass={glass}\n\t\t\t\t\trefraction={refraction}\n\t\t\t\t\tdispersion={dispersion}\n\t\t\t\t\tglassSize={glassSize}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t\t<div className=\"h-screen flex flex-col gap-7 p-6\">\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 1\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color1}\n\t\t\t\t\t\tonChange={(e) => setColor1(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 2\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color2}\n\t\t\t\t\t\tonChange={(e) => setColor2(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\t\t\t\t<label className=\"flex items-center gap-3\">\n\t\t\t\t\tcolor 3\n\t\t\t\t\t<input\n\t\t\t\t\t\ttype=\"color\"\n\t\t\t\t\t\tvalue={color3}\n\t\t\t\t\t\tonChange={(e) => setColor3(e.target.value)}\n\t\t\t\t\t\tclassName=\"h-8 w-12 cursor-pointer rounded border bg-transparent\"\n\t\t\t\t\t/>\n\t\t\t\t</label>\n\n\t\t\t\t<label>count</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={1}\n\t\t\t\t\tmax={10}\n\t\t\t\t\tstep={1}\n\t\t\t\t\tvalue={[count]}\n\t\t\t\t\tonValueChange={([value]) => setCount(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>speed</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[speed]}\n\t\t\t\t\tonValueChange={([value]) => setSpeed(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>amplitude</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[amplitude]}\n\t\t\t\t\tonValueChange={([value]) => setAmplitude(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>waviness</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.2}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[waviness]}\n\t\t\t\t\tonValueChange={([value]) => setWaviness(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>thickness</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.2}\n\t\t\t\t\tmax={4}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[thickness]}\n\t\t\t\t\tonValueChange={([value]) => setThickness(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glow</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[glow]}\n\t\t\t\t\tonValueChange={([value]) => setGlow(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>taper</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.5}\n\t\t\t\t\tmax={6}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[taper]}\n\t\t\t\t\tonValueChange={([value]) => setTaper(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>spread</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[spread]}\n\t\t\t\t\tonValueChange={([value]) => setSpread(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>hue shift</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.01}\n\t\t\t\t\tvalue={[hueShift]}\n\t\t\t\t\tonValueChange={([value]) => setHueShift(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>intensity</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[intensity]}\n\t\t\t\t\tonValueChange={([value]) => setIntensity(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>saturation</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={2}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[saturation]}\n\t\t\t\t\tonValueChange={([value]) => setSaturation(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>opacity</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[opacity]}\n\t\t\t\t\tonValueChange={([value]) => setOpacity(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>scale</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.1}\n\t\t\t\t\tvalue={[scale]}\n\t\t\t\t\tonValueChange={([value]) => setScale(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glass ball</label>\n\t\t\t\t<Switch checked={glass} onCheckedChange={setGlass} />\n\n\t\t\t\t<label>refraction</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={3}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[refraction]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setRefraction(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>dispersion</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0}\n\t\t\t\t\tmax={4}\n\t\t\t\t\tstep={0.05}\n\t\t\t\t\tvalue={[dispersion]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setDispersion(value)}\n\t\t\t\t/>\n\n\t\t\t\t<label>glass size</label>\n\t\t\t\t<Slider\n\t\t\t\t\tmin={0.3}\n\t\t\t\t\tmax={1}\n\t\t\t\t\tstep={0.01}\n\t\t\t\t\tvalue={[glassSize]}\n\t\t\t\t\tdisabled={!glass}\n\t\t\t\t\tonValueChange={([value]) => setGlassSize(value)}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/open-source/strands.tsx",
      "content": "import { Renderer, Program, Mesh, Color, Triangle, RenderTarget } from 'ogl';\nimport { useEffect, useRef, CSSProperties } from 'react';\n\nconst MAX_STRANDS = 12;\nconst MAX_COLORS = 8;\n\nconst VERT = `#version 300 es\nin vec2 position;\nvoid main() {\n  gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst FRAG = `#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform vec2 uResolution;\nuniform vec3 uColors[${MAX_COLORS}];\nuniform int uColorCount;\nuniform int uStrandCount;\nuniform float uSpeed;\nuniform float uAmplitude;\nuniform float uWaviness;\nuniform float uThickness;\nuniform float uGlow;\nuniform float uTaper;\nuniform float uSpread;\nuniform float uHueShift;\nuniform float uIntensity;\nuniform float uOpacity;\nuniform float uScale;\nuniform float uSaturation;\n\nout vec4 fragColor;\n\nconst float PI = 3.14159265;\n\nvec3 spectrum(float t) {\n  return 0.5 + 0.5 * cos(2.0 * PI * (t + vec3(0.00, 0.33, 0.67)));\n}\n\nvec3 samplePalette(float t) {\n  t = fract(t);\n  float scaled = t * float(uColorCount);\n  int idx = int(floor(scaled));\n  float blend = fract(scaled);\n  int nextIdx = idx + 1;\n  if (nextIdx >= uColorCount) nextIdx = 0;\n  return mix(uColors[idx], uColors[nextIdx], blend);\n}\n\nvec3 strandColor(float t) {\n  if (uColorCount > 0) return samplePalette(t);\n  return spectrum(t);\n}\n\nvoid main() {\n  vec2 uv = (gl_FragCoord.xy - 0.5 * uResolution) / uResolution.y;\n  uv /= max(uScale, 0.0001);\n\n  float e = 0.06 + uIntensity * 0.94;\n  float env = pow(max(cos(uv.x * PI * 1.3), 0.0), uTaper);\n\n  vec3 col = vec3(0.0);\n\n  for (int i = 0; i < ${MAX_STRANDS}; i++) {\n    if (i >= uStrandCount) break;\n\n    float fi = float(i);\n    float ph = fi * 1.7 * uSpread;\n    float freq = (2.0 + fi * 0.35) * uWaviness;\n    float spd = 1.4 + fi * 1.2;\n\n    float tt = uTime * uSpeed;\n    float w = sin(uv.x * freq + tt * spd + ph) * 0.60\n            + sin(uv.x * freq * 1.1 - tt * spd * 0.7 + ph * 1.7) * 0.40;\n\n    float amp = (0.1 + 0.02 * e) * env * uAmplitude;\n    float y = w * amp;\n\n    float d = abs(uv.y - y);\n    float thick = (0.001 + 0.05 * e) * (0.35 + env) * uThickness;\n    float g = thick / (d + thick * 0.45);\n    g = g * g;\n\n    float h = fi / float(uStrandCount) + uv.x * 0.30 + uTime * 0.04 + uHueShift;\n    col += strandColor(h) * g * env;\n  }\n\n  col *= 0.45 + 0.7 * e;\n  col = 1.0 - exp(-col * uGlow);\n\n  float gray = dot(col, vec3(0.2126, 0.7152, 0.0722));\n  col = max(mix(vec3(gray), col, uSaturation), 0.0);\n\n  float lum = max(max(col.r, col.g), col.b);\n  float alpha = clamp(lum, 0.0, 1.0) * uOpacity;\n\n  fragColor = vec4(col * uOpacity, alpha);\n}\n`;\n\nconst GLASS_FRAG = `#version 300 es\nprecision highp float;\n\nuniform sampler2D uScene;\nuniform vec2 uResolution;\nuniform float uRadius;\nuniform float uRefraction;\nuniform float uDispersion;\n\nout vec4 fragColor;\n\nvec2 toUv(vec2 p) {\n  return p * (uResolution.y / uResolution) + 0.5;\n}\n\nvoid main() {\n  vec2 p = (gl_FragCoord.xy - 0.5 * uResolution) / uResolution.y;\n  float d = length(p);\n  float r = uRadius;\n\n  float edge = fwidth(d) * 1.5;\n  float mask = 1.0 - smoothstep(r - edge, r + edge, d);\n  if (mask <= 0.0) {\n    fragColor = vec4(0.0);\n    return;\n  }\n\n  // sphere height: 0 at the rim, 1 at the center\n  float z = sqrt(max(r * r - d * d, 0.0)) / r;\n  float nd = d / r; // 0 at the center, 1 at the rim\n\n  // refraction is confined to a narrow band near the rim; the rest stays undistorted\n  vec2 dir = d > 0.0 ? p / d : vec2(0.0);\n  float lens = smoothstep(0.85, 1.0, nd) * pow(nd, 6.0);\n  vec2 offset = -dir * lens * uRefraction * 0.15;\n  vec2 disp = -dir * lens * uDispersion * 0.012;\n\n  vec3 light;\n  light.r = texture(uScene, toUv(p + offset - disp)).r;\n  light.g = texture(uScene, toUv(p + offset)).g;\n  light.b = texture(uScene, toUv(p + offset + disp)).b;\n\n  // neutral fresnel rim (no color tint so the glass stays clear)\n  float fres = pow(1.0 - z, 3.0);\n  vec3 rim = vec3(1.0) * fres * 0.18;\n\n  // specular highlight from the upper-left\n  vec2 lightDir = normalize(vec2(-0.55, 0.6));\n  float spec = pow(max(dot(p / max(r, 1e-4), lightDir), 0.0), 6.0);\n  spec *= smoothstep(r, r * 0.55, d);\n\n  vec3 emissive = light + rim + vec3(spec) * 0.4;\n  float emissiveA = clamp(max(max(emissive.r, emissive.g), emissive.b), 0.0, 1.0);\n\n  // almost clear glass body: only a faint neutral darkening, mostly near the rim\n  float bodyA = 0.05 + fres * 0.05;\n\n  // composite emissive light over the clear body (premultiplied)\n  float outA = emissiveA + bodyA * (1.0 - emissiveA);\n  vec3 outRGB = emissive;\n\n  outRGB *= mask;\n  outA *= mask;\n\n  fragColor = vec4(outRGB, outA);\n}\n`;\n\nexport interface StrandsProps {\n    colors?: string[];\n    count?: number;\n    speed?: number;\n    amplitude?: number;\n    waviness?: number;\n    thickness?: number;\n    glow?: number;\n    taper?: number;\n    spread?: number;\n    hueShift?: number;\n    intensity?: number;\n    saturation?: number;\n    opacity?: number;\n    scale?: number;\n    glass?: boolean;\n    refraction?: number;\n    dispersion?: number;\n    glassSize?: number;\n    className?: string;\n    style?: CSSProperties;\n}\n\nconst buildPalette = (colors: string[]): number[][] => {\n    const filled = colors && colors.length ? colors : ['#ffffff'];\n    const padded: number[][] = [];\n    for (let i = 0; i < MAX_COLORS; i++) {\n        const hex = filled[i] ?? filled[filled.length - 1];\n        const c = new Color(hex);\n        padded.push([c.r, c.g, c.b]);\n    }\n    return padded;\n};\n\nexport default function Strands({\n    colors = ['#FF4242', '#7C3AED', '#06B6D4', '#EAB308'],\n    count = 3,\n    speed = 0.5,\n    amplitude = 1,\n    waviness = 1,\n    thickness = 0.7,\n    glow = 2.6,\n    taper = 3,\n    spread = 1,\n    hueShift = 0,\n    intensity = 0.6,\n    saturation = 1.5,\n    opacity = 1,\n    scale = 1.5,\n    glass = false,\n    refraction = 1,\n    dispersion = 1,\n    glassSize = 1,\n    className = '',\n    style\n}: StrandsProps) {\n    const propsRef = useRef<Required<Omit<StrandsProps, 'className' | 'style'>>>({\n        colors,\n        count,\n        speed,\n        amplitude,\n        waviness,\n        thickness,\n        glow,\n        taper,\n        spread,\n        hueShift,\n        intensity,\n        saturation,\n        opacity,\n        scale,\n        glass,\n        refraction,\n        dispersion,\n        glassSize\n    });\n    propsRef.current = {\n        colors,\n        count,\n        speed,\n        amplitude,\n        waviness,\n        thickness,\n        glow,\n        taper,\n        spread,\n        hueShift,\n        intensity,\n        saturation,\n        opacity,\n        scale,\n        glass,\n        refraction,\n        dispersion,\n        glassSize\n    };\n\n    const ctnDom = useRef<HTMLDivElement>(null);\n\n    useEffect(() => {\n        const ctn = ctnDom.current;\n        if (!ctn) return;\n\n        const renderer = new Renderer({\n            alpha: true,\n            premultipliedAlpha: true,\n            antialias: true\n        });\n        const gl = renderer.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.style.backgroundColor = 'transparent';\n\n        const geometry = new Triangle(gl);\n        if (geometry.attributes.uv) {\n            delete geometry.attributes.uv;\n        }\n\n        const program = new Program(gl, {\n            vertex: VERT,\n            fragment: FRAG,\n            uniforms: {\n                uTime: { value: 0 },\n                uResolution: { value: [ctn.offsetWidth, ctn.offsetHeight] },\n                uColors: { value: buildPalette(propsRef.current.colors) },\n                uColorCount: { value: Math.min(propsRef.current.colors.length, MAX_COLORS) },\n                uStrandCount: { value: Math.min(propsRef.current.count, MAX_STRANDS) },\n                uSpeed: { value: speed },\n                uAmplitude: { value: amplitude },\n                uWaviness: { value: waviness },\n                uThickness: { value: thickness },\n                uGlow: { value: glow },\n                uTaper: { value: taper },\n                uSpread: { value: spread },\n                uHueShift: { value: hueShift },\n                uIntensity: { value: intensity },\n                uOpacity: { value: opacity },\n                uScale: { value: scale },\n                uSaturation: { value: saturation }\n            }\n        });\n\n        const mesh = new Mesh(gl, { geometry, program });\n\n        const renderTarget = new RenderTarget(gl, {\n            width: ctn.offsetWidth,\n            height: ctn.offsetHeight\n        });\n\n        const glassProgram = new Program(gl, {\n            vertex: VERT,\n            fragment: GLASS_FRAG,\n            uniforms: {\n                uScene: { value: renderTarget.texture },\n                uResolution: { value: [ctn.offsetWidth, ctn.offsetHeight] },\n                uRadius: { value: 0.46 * glassSize },\n                uRefraction: { value: refraction },\n                uDispersion: { value: dispersion }\n            }\n        });\n        const glassMesh = new Mesh(gl, { geometry, program: glassProgram });\n\n        ctn.appendChild(gl.canvas);\n\n        function resize() {\n            if (!ctn) return;\n            const width = ctn.offsetWidth;\n            const height = ctn.offsetHeight;\n            renderer.setSize(width, height);\n            program.uniforms.uResolution.value = [width, height];\n            renderTarget.setSize(width, height);\n            glassProgram.uniforms.uResolution.value = [width, height];\n        }\n        window.addEventListener('resize', resize);\n        resize();\n\n        let animateId = 0;\n        const update = (t: number) => {\n            animateId = requestAnimationFrame(update);\n            const current = propsRef.current;\n            program.uniforms.uTime.value = t * 0.001;\n            program.uniforms.uColors.value = buildPalette(current.colors);\n            program.uniforms.uColorCount.value = Math.min(current.colors.length, MAX_COLORS);\n            program.uniforms.uStrandCount.value = Math.min(Math.max(Math.round(current.count), 1), MAX_STRANDS);\n            program.uniforms.uSpeed.value = current.speed;\n            program.uniforms.uAmplitude.value = current.amplitude;\n            program.uniforms.uWaviness.value = current.waviness;\n            program.uniforms.uThickness.value = current.thickness;\n            program.uniforms.uGlow.value = current.glow;\n            program.uniforms.uTaper.value = current.taper;\n            program.uniforms.uSpread.value = current.spread;\n            program.uniforms.uHueShift.value = current.hueShift;\n            program.uniforms.uIntensity.value = current.intensity;\n            program.uniforms.uOpacity.value = current.opacity;\n            program.uniforms.uScale.value = current.scale;\n            program.uniforms.uSaturation.value = current.saturation;\n\n            if (current.glass) {\n                renderer.render({ scene: mesh, target: renderTarget });\n                glassProgram.uniforms.uScene.value = renderTarget.texture;\n                glassProgram.uniforms.uRefraction.value = current.refraction;\n                glassProgram.uniforms.uDispersion.value = current.dispersion;\n                glassProgram.uniforms.uRadius.value = 0.46 * current.glassSize;\n                renderer.render({ scene: glassMesh });\n            } else {\n                renderer.render({ scene: mesh });\n            }\n        };\n        animateId = requestAnimationFrame(update);\n\n        return () => {\n            cancelAnimationFrame(animateId);\n            window.removeEventListener('resize', resize);\n            if (ctn && gl.canvas.parentNode === ctn) {\n                ctn.removeChild(gl.canvas);\n            }\n            gl.getExtension('WEBGL_lose_context')?.loseContext();\n        };\n        // eslint-disable-next-line react-hooks/exhaustive-deps\n    }, []);\n\n    return <div ref={ctnDom} className={`relative w-full h-full bg-transparent ${className}`} style={style} />;\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/slider.tsx",
      "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\nimport * as SliderPrimitive from \"@radix-ui/react-slider\";\r\n\r\nconst Slider = React.forwardRef<\r\n\tReact.ElementRef<typeof SliderPrimitive.Root>,\r\n\tReact.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>\r\n>(({ className, ...props }, ref) => (\r\n\t<SliderPrimitive.Root\r\n\t\tref={ref}\r\n\t\tclassName={cn(\r\n\t\t\t\"relative flex w-full touch-none select-none items-center\",\r\n\t\t\tclassName\r\n\t\t)}\r\n\t\t{...props}\r\n\t>\r\n\t\t<SliderPrimitive.Track className=\"relative h-2 w-full grow overflow-hidden rounded-full bg-secondary\">\r\n\t\t\t<SliderPrimitive.Range className=\"absolute h-full bg-primary\" />\r\n\t\t</SliderPrimitive.Track>\r\n\t\t<SliderPrimitive.Thumb className=\"block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\" />\r\n\t\t<SliderPrimitive.Thumb className=\"block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\" />\r\n\t</SliderPrimitive.Root>\r\n));\r\nSlider.displayName = SliderPrimitive.Root.displayName;\r\n\r\nexport { Slider };\r\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/switch.tsx",
      "content": "\"use client\";\r\n\r\nimport React from \"react\";\r\n\r\nimport { cn } from \"@/registry/utilities/cn\";\r\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\r\n\r\nconst Switch = React.forwardRef<\r\n\tReact.ElementRef<typeof SwitchPrimitives.Root>,\r\n\tReact.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>\r\n>(({ className, ...props }, ref) => (\r\n\t<SwitchPrimitives.Root\r\n\t\tclassName={cn(\r\n\t\t\t\"peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\r\n\t\t\tclassName\r\n\t\t)}\r\n\t\t{...props}\r\n\t\tref={ref}\r\n\t>\r\n\t\t<SwitchPrimitives.Thumb\r\n\t\t\tclassName={cn(\r\n\t\t\t\t\"pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0\"\r\n\t\t\t)}\r\n\t\t/>\r\n\t</SwitchPrimitives.Root>\r\n));\r\nSwitch.displayName = SwitchPrimitives.Root.displayName;\r\n\r\nexport { Switch };\r\n",
      "type": "registry:ui"
    }
  ]
}