{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-gradientBlinds",
  "title": "Hero · Gradient Blinds",
  "description": "Hero · Gradient Blinds section.",
  "dependencies": [
    "lucide-react",
    "ogl"
  ],
  "files": [
    {
      "path": "registry/talizen/hero/hero-gradientBlinds/hero-gradientBlinds.tsx",
      "content": "import { useState } from 'react'\nimport { Twitter, Instagram, Linkedin, Menu, X } from 'lucide-react'\nimport GradientBlinds from './GradientBlinds'\n\nexport function HeroGradientBlinds() {\n  const navItems = ['Features', 'About', 'Newsletter', 'Newsletter']\n  const [menuOpen, setMenuOpen] = useState(false)\n  const MenuIcon = menuOpen ? X : Menu\n\n  return (\n    <div className=\"relative min-h-screen w-full bg-[#050505] text-white overflow-hidden font-sans\">\n      {/* Background Effect */}\n      <div className=\"absolute inset-0 z-0 opacity-60\">\n        <GradientBlinds\n          gradientColors={['#000000', '#1a4d2e', '#4ade80', '#1a4d2e', '#000000']}\n          blindCount={24}\n          angle={0}\n          noise={0.1}\n          spotlightRadius={0.4}\n          spotlightOpacity={0.8}\n          spotlightSoftness={1.2}\n          distortAmount={2}\n        />\n        {/* Dark overlay to ensure text readability and match the screenshot's depth */}\n        <div\n          className=\"absolute inset-0 \n        pointer-events-none bg-gradient-to-b from-black via-transparent to-black opacity-80\"\n        />\n      </div>\n\n      {/* Navigation */}\n      <nav className=\"relative z-[100] mx-auto flex max-w-7xl items-center justify-between gap-3 px-5 py-6 sm:px-6 md:px-12 md:py-8\">\n        <div className=\"text-xl font-bold tracking-tight italic\">StartupSprint</div>\n\n        <div className=\"hidden md:flex items-center space-x-8 text-sm font-medium text-gray-400\">\n          {navItems.map((item, index) => (\n            <a\n              key={`${item}-${index}`}\n              href=\"#\"\n              className={`hover:text-white transition-colors ${\n                index === navItems.length - 1 ? 'border-b border-white/20 pb-0.5' : ''\n              }`}\n            >\n              {item}\n            </a>\n          ))}\n        </div>\n\n        <button className=\"hidden cursor-pointer rounded-full bg-white px-6 py-2.5 text-sm font-bold text-black shadow-lg transition-colors hover:bg-gray-200 sm:inline-flex\">\n          Join The Waitlist\n        </button>\n\n        <button\n          type=\"button\"\n          onClick={() => setMenuOpen((open) => !open)}\n          aria-label={menuOpen ? 'Close menu' : 'Open menu'}\n          aria-expanded={menuOpen}\n          aria-controls=\"gradient-blinds-mobile-menu\"\n          className=\"inline-grid size-11 place-items-center rounded-full border border-white/12 bg-white/8 text-white backdrop-blur transition hover:bg-white/14 md:hidden\"\n        >\n          <MenuIcon className=\"size-5\" aria-hidden=\"true\" />\n        </button>\n\n        <div\n          id=\"gradient-blinds-mobile-menu\"\n          className={`absolute left-5 right-5 top-[calc(100%+8px)] z-[110] overflow-hidden rounded-[18px] border border-white/12 bg-black/88 p-2 shadow-[0_24px_80px_rgba(0,0,0,0.46)] backdrop-blur-xl transition duration-200 md:hidden ${\n            menuOpen ? 'translate-y-0 opacity-100' : 'pointer-events-none -translate-y-2 opacity-0'\n          }`}\n        >\n          <div className=\"grid text-sm font-medium text-gray-300\">\n            {navItems.map((item, index) => (\n              <a\n                key={`${item}-mobile-${index}`}\n                href=\"#\"\n                onClick={() => setMenuOpen(false)}\n                className=\"rounded-[14px] px-4 py-3 transition hover:bg-white/8 hover:text-white\"\n              >\n                {item}\n              </a>\n            ))}\n          </div>\n          <button\n            type=\"button\"\n            onClick={() => setMenuOpen(false)}\n            className=\"mt-2 flex min-h-11 w-full cursor-pointer items-center justify-center rounded-full bg-white px-5 text-sm font-bold text-black transition-colors hover:bg-gray-200\"\n          >\n            Join The Waitlist\n          </button>\n        </div>\n      </nav>\n\n      {/* Hero Content */}\n      <main className=\"relative z-10 pointer-events-none flex flex-col items-center justify-center pt-16 pb-12 px-5 text-center max-w-4xl mx-auto sm:px-6 sm:pt-24\">\n        {/* Waitlist Badge */}\n        <div className=\"inline-flex items-center space-x-2 bg-white/5 backdrop-blur-md border border-white/10 px-3 py-1.5 rounded-full mb-8\">\n          <div className=\"flex -space-x-2\">\n            {[1, 2, 3].map((i) => (\n              <div\n                key={i}\n                className=\"w-6 h-6 rounded-full border-2 border-black bg-gray-800 flex items-center justify-center overflow-hidden\"\n              >\n                <img src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${i + 10}`} alt=\"User\" />\n              </div>\n            ))}\n          </div>\n          <span className=\"text-[11px] md:text-sm font-medium text-gray-300\">\n            2.4K currently on the waitlist\n          </span>\n        </div>\n\n        {/* Headline */}\n        <h1\n          className=\"text-[2.75rem] sm:text-5xl md:text-8xl \n        pointer-events-none\n        font-medium tracking-tight mb-4 text-white drop-shadow-sm\"\n        >\n          Building the Future\n        </h1>\n        <h2\n          className=\"text-4xl sm:text-5xl md:text-7xl \n        pointer-events-none font-light italic mb-8 text-gray-100 font-serif\"\n        >\n          One Startup at a Time.\n        </h2>\n\n        {/* Description */}\n        <p\n          className=\"max-w-md mx-auto \n        pointer-events-none text-gray-400 text-sm md:text-base leading-relaxed mb-10\"\n        >\n          Be the first to know when we launch. <br className=\"hidden md:block\" />\n          Join the waitlist and get exclusive early access.\n        </p>\n\n        {/* CTA Form */}\n        <div\n          className=\"w-full max-w-md bg-white/5 border border-white/10 p-1.5 rounded-[22px] flex flex-col gap-2 items-stretch mb-12 backdrop-blur-sm sm:flex-row sm:items-center sm:rounded-full sm:gap-0\n      pointer-events-auto\"\n        >\n          <input\n            type=\"email\"\n            placeholder=\"Enter Your Email\"\n            className=\"min-w-0 flex-1 bg-transparent px-4 py-2 outline-none text-white text-sm sm:px-6\"\n          />\n          <button\n            className=\"bg-white text-black px-6 py-2.5 rounded-full text-sm font-bold hover:bg-gray-200 transition-colors \n          cursor-pointer whitespace-nowrap\"\n          >\n            Join The Waitlist\n          </button>\n        </div>\n\n        {/* Social Icons */}\n        <div className=\"flex items-center space-x-5\">\n          <a\n            href=\"#\"\n            className=\"w-10 h-10 flex items-center justify-center rounded-full bg-white/5 border border-white/10 hover:bg-white/10 transition-colors\"\n          >\n            <Twitter size={16} />\n          </a>\n          <a\n            href=\"#\"\n            className=\"w-10 h-10 flex items-center justify-center rounded-full bg-white/5 border border-white/10 hover:bg-white/10 transition-colors\"\n          >\n            <Instagram size={16} />\n          </a>\n          <a\n            href=\"#\"\n            className=\"w-10 h-10 flex items-center justify-center rounded-full bg-white/5 border border-white/10 hover:bg-white/10 transition-colors text-white\"\n          >\n            <Linkedin size={16} fill=\"white\" />\n          </a>\n        </div>\n      </main>\n\n      {/* Decorative vertical blinds at bottom for more depth (optional tweak for style) */}\n      <div className=\"absolute bottom-0 left-0 w-full h-1/2 pointer-events-none bg-gradient-to-t from-black to-transparent z-0\" />\n    </div>\n  )\n}\n\nexport default HeroGradientBlinds\n\nexport const metadata = {\n  title: 'StartupSprint - Building the Future One Startup at a Time',\n  description:\n    'Be the first to know when we launch. Join the waitlist and get exclusive early access to the future of startups.',\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/talizen/hero/hero-gradientBlinds/GradientBlinds.tsx",
      "content": "import React, { useEffect, useRef } from 'react';\nimport { Renderer, Program, Mesh, Triangle } from 'ogl';\n\nexport interface GradientBlindsProps {\n    className?: string;\n    dpr?: number;\n    paused?: boolean;\n    gradientColors?: string[];\n    angle?: number;\n    noise?: number;\n    blindCount?: number;\n    blindMinWidth?: number;\n    mouseDampening?: number;\n    mirrorGradient?: boolean;\n    spotlightRadius?: number;\n    spotlightSoftness?: number;\n    spotlightOpacity?: number;\n    distortAmount?: number;\n    shineDirection?: 'left' | 'right';\n    mixBlendMode?: string;\n}\n\nconst MAX_COLORS = 8;\nconst hexToRGB = (hex: string): [number, number, number] => {\n    const c = hex.replace('#', '').padEnd(6, '0');\n    const r = parseInt(c.slice(0, 2), 16) / 255;\n    const g = parseInt(c.slice(2, 4), 16) / 255;\n    const b = parseInt(c.slice(4, 6), 16) / 255;\n    return [r, g, b];\n};\nconst prepStops = (stops?: string[]) => {\n    const base = (stops && stops.length ? stops : ['#FF9FFC', '#5227FF']).slice(0, MAX_COLORS);\n    if (base.length === 1) base.push(base[0]);\n    while (base.length < MAX_COLORS) base.push(base[base.length - 1]);\n    const arr: [number, number, number][] = [];\n    for (let i = 0; i < MAX_COLORS; i++) arr.push(hexToRGB(base[i]));\n    const count = Math.max(2, Math.min(MAX_COLORS, stops?.length ?? 2));\n    return { arr, count };\n};\n\nconst GradientBlinds: React.FC<GradientBlindsProps> = ({\n    className,\n    dpr,\n    paused = false,\n    gradientColors,\n    angle = 0,\n    noise = 0.3,\n    blindCount = 16,\n    blindMinWidth = 60,\n    mouseDampening = 0.15,\n    mirrorGradient = false,\n    spotlightRadius = 0.5,\n    spotlightSoftness = 1,\n    spotlightOpacity = 1,\n    distortAmount = 0,\n    shineDirection = 'left',\n    mixBlendMode = 'lighten'\n}) => {\n    const containerRef = useRef<HTMLDivElement | null>(null);\n    const rafRef = useRef<number | null>(null);\n    const programRef = useRef<Program | null>(null);\n    const meshRef = useRef<Mesh<Triangle> | null>(null);\n    const geometryRef = useRef<Triangle | null>(null);\n    const rendererRef = useRef<Renderer | null>(null);\n    const mouseTargetRef = useRef<[number, number]>([0, 0]);\n    const lastTimeRef = useRef<number>(0);\n    const firstResizeRef = useRef<boolean>(true);\n\n    useEffect(() => {\n        const container = containerRef.current;\n        if (!container) return;\n\n        const renderer = new Renderer({\n            dpr: dpr ?? (typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1),\n            alpha: true,\n            antialias: true\n        });\n        rendererRef.current = renderer;\n        const gl = renderer.gl;\n        const canvas = gl.canvas as HTMLCanvasElement;\n\n        canvas.style.width = '100%';\n        canvas.style.height = '100%';\n        canvas.style.display = 'block';\n        container.appendChild(canvas);\n\n        const vertex = `\nattribute vec2 position;\nattribute vec2 uv;\nvarying vec2 vUv;\n\nvoid main() {\n  vUv = uv;\n  gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\n        const fragment = `\n#ifdef GL_ES\nprecision mediump float;\n#endif\n\nuniform vec3  iResolution;\nuniform vec2  iMouse;\nuniform float iTime;\n\nuniform float uAngle;\nuniform float uNoise;\nuniform float uBlindCount;\nuniform float uSpotlightRadius;\nuniform float uSpotlightSoftness;\nuniform float uSpotlightOpacity;\nuniform float uMirror;\nuniform float uDistort;\nuniform float uShineFlip;\nuniform vec3  uColor0;\nuniform vec3  uColor1;\nuniform vec3  uColor2;\nuniform vec3  uColor3;\nuniform vec3  uColor4;\nuniform vec3  uColor5;\nuniform vec3  uColor6;\nuniform vec3  uColor7;\nuniform int   uColorCount;\n\nvarying vec2 vUv;\n\nfloat rand(vec2 co){\n  return fract(sin(dot(co, vec2(12.9898,78.233))) * 43758.5453);\n}\n\nvec2 rotate2D(vec2 p, float a){\n  float c = cos(a);\n  float s = sin(a);\n  return mat2(c, -s, s, c) * p;\n}\n\nvec3 getGradientColor(float t){\n  float tt = clamp(t, 0.0, 1.0);\n  int count = uColorCount;\n  if (count < 2) count = 2;\n  float scaled = tt * float(count - 1);\n  float seg = floor(scaled);\n  float f = fract(scaled);\n\n  if (seg < 1.0) return mix(uColor0, uColor1, f);\n  if (seg < 2.0 && count > 2) return mix(uColor1, uColor2, f);\n  if (seg < 3.0 && count > 3) return mix(uColor2, uColor3, f);\n  if (seg < 4.0 && count > 4) return mix(uColor3, uColor4, f);\n  if (seg < 5.0 && count > 5) return mix(uColor4, uColor5, f);\n  if (seg < 6.0 && count > 6) return mix(uColor5, uColor6, f);\n  if (seg < 7.0 && count > 7) return mix(uColor6, uColor7, f);\n  if (count > 7) return uColor7;\n  if (count > 6) return uColor6;\n  if (count > 5) return uColor5;\n  if (count > 4) return uColor4;\n  if (count > 3) return uColor3;\n  if (count > 2) return uColor2;\n  return uColor1;\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n    vec2 uv0 = fragCoord.xy / iResolution.xy;\n\n    float aspect = iResolution.x / iResolution.y;\n    vec2 p = uv0 * 2.0 - 1.0;\n    p.x *= aspect;\n    vec2 pr = rotate2D(p, uAngle);\n    pr.x /= aspect;\n    vec2 uv = pr * 0.5 + 0.5;\n\n    vec2 uvMod = uv;\n    if (uDistort > 0.0) {\n      float a = uvMod.y * 6.0;\n      float b = uvMod.x * 6.0;\n      float w = 0.01 * uDistort;\n      uvMod.x += sin(a) * w;\n      uvMod.y += cos(b) * w;\n    }\n    float t = uvMod.x;\n    if (uMirror > 0.5) {\n      t = 1.0 - abs(1.0 - 2.0 * fract(t));\n    }\n    vec3 base = getGradientColor(t);\n\n    vec2 offset = vec2(iMouse.x/iResolution.x, iMouse.y/iResolution.y);\n  float d = length(uv0 - offset);\n  float r = max(uSpotlightRadius, 1e-4);\n  float dn = d / r;\n  float spot = (1.0 - 2.0 * pow(dn, uSpotlightSoftness)) * uSpotlightOpacity;\n  vec3 cir = vec3(spot);\n  float stripe = fract(uvMod.x * max(uBlindCount, 1.0));\n  if (uShineFlip > 0.5) stripe = 1.0 - stripe;\n    vec3 ran = vec3(stripe);\n\n    vec3 col = cir + base - ran;\n    col += (rand(gl_FragCoord.xy + iTime) - 0.5) * uNoise;\n\n    fragColor = vec4(col, 1.0);\n}\n\nvoid main() {\n    vec4 color;\n    mainImage(color, vUv * iResolution.xy);\n    gl_FragColor = color;\n}\n`;\n\n        const { arr: colorArr, count: colorCount } = prepStops(gradientColors);\n        const uniforms: {\n            iResolution: { value: [number, number, number] };\n            iMouse: { value: [number, number] };\n            iTime: { value: number };\n            uAngle: { value: number };\n            uNoise: { value: number };\n            uBlindCount: { value: number };\n            uSpotlightRadius: { value: number };\n            uSpotlightSoftness: { value: number };\n            uSpotlightOpacity: { value: number };\n            uMirror: { value: number };\n            uDistort: { value: number };\n            uShineFlip: { value: number };\n            uColor0: { value: [number, number, number] };\n            uColor1: { value: [number, number, number] };\n            uColor2: { value: [number, number, number] };\n            uColor3: { value: [number, number, number] };\n            uColor4: { value: [number, number, number] };\n            uColor5: { value: [number, number, number] };\n            uColor6: { value: [number, number, number] };\n            uColor7: { value: [number, number, number] };\n            uColorCount: { value: number };\n        } = {\n            iResolution: {\n                value: [gl.drawingBufferWidth, gl.drawingBufferHeight, 1]\n            },\n            iMouse: { value: [0, 0] },\n            iTime: { value: 0 },\n            uAngle: { value: (angle * Math.PI) / 180 },\n            uNoise: { value: noise },\n            uBlindCount: { value: Math.max(1, blindCount) },\n            uSpotlightRadius: { value: spotlightRadius },\n            uSpotlightSoftness: { value: spotlightSoftness },\n            uSpotlightOpacity: { value: spotlightOpacity },\n            uMirror: { value: mirrorGradient ? 1 : 0 },\n            uDistort: { value: distortAmount },\n            uShineFlip: { value: shineDirection === 'right' ? 1 : 0 },\n            uColor0: { value: colorArr[0] },\n            uColor1: { value: colorArr[1] },\n            uColor2: { value: colorArr[2] },\n            uColor3: { value: colorArr[3] },\n            uColor4: { value: colorArr[4] },\n            uColor5: { value: colorArr[5] },\n            uColor6: { value: colorArr[6] },\n            uColor7: { value: colorArr[7] },\n            uColorCount: { value: colorCount }\n        };\n\n        const program = new Program(gl, {\n            vertex,\n            fragment,\n            uniforms\n        });\n        programRef.current = program;\n\n        const geometry = new Triangle(gl);\n        geometryRef.current = geometry;\n        const mesh = new Mesh(gl, { geometry, program });\n        meshRef.current = mesh;\n\n        const resize = () => {\n            const rect = container.getBoundingClientRect();\n            renderer.setSize(rect.width, rect.height);\n            uniforms.iResolution.value = [gl.drawingBufferWidth, gl.drawingBufferHeight, 1];\n\n            if (blindMinWidth && blindMinWidth > 0) {\n                const maxByMinWidth = Math.max(1, Math.floor(rect.width / blindMinWidth));\n\n                const effective = blindCount ? Math.min(blindCount, maxByMinWidth) : maxByMinWidth;\n                uniforms.uBlindCount.value = Math.max(1, effective);\n            } else {\n                uniforms.uBlindCount.value = Math.max(1, blindCount);\n            }\n\n            if (firstResizeRef.current) {\n                firstResizeRef.current = false;\n                const cx = gl.drawingBufferWidth / 2;\n                const cy = gl.drawingBufferHeight / 2;\n                uniforms.iMouse.value = [cx, cy];\n                mouseTargetRef.current = [cx, cy];\n            }\n        };\n\n        resize();\n        const ro = new ResizeObserver(resize);\n        ro.observe(container);\n\n        const onPointerMove = (e: PointerEvent) => {\n            const rect = canvas.getBoundingClientRect();\n            const scale = (renderer as unknown as { dpr?: number }).dpr || 1;\n            const x = (e.clientX - rect.left) * scale;\n            const y = (rect.height - (e.clientY - rect.top)) * scale;\n            mouseTargetRef.current = [x, y];\n            if (mouseDampening <= 0) {\n                uniforms.iMouse.value = [x, y];\n            }\n        };\n        canvas.addEventListener('pointermove', onPointerMove);\n\n        const loop = (t: number) => {\n            rafRef.current = requestAnimationFrame(loop);\n            uniforms.iTime.value = t * 0.001;\n            if (mouseDampening > 0) {\n                if (!lastTimeRef.current) lastTimeRef.current = t;\n                const dt = (t - lastTimeRef.current) / 1000;\n                lastTimeRef.current = t;\n                const tau = Math.max(1e-4, mouseDampening);\n                let factor = 1 - Math.exp(-dt / tau);\n                if (factor > 1) factor = 1;\n                const target = mouseTargetRef.current;\n                const cur = uniforms.iMouse.value;\n                cur[0] += (target[0] - cur[0]) * factor;\n                cur[1] += (target[1] - cur[1]) * factor;\n            } else {\n                lastTimeRef.current = t;\n            }\n            if (!paused && programRef.current && meshRef.current) {\n                try {\n                    renderer.render({ scene: meshRef.current });\n                } catch (e) {\n                    console.error(e);\n                }\n            }\n        };\n        rafRef.current = requestAnimationFrame(loop);\n\n        return () => {\n            if (rafRef.current) cancelAnimationFrame(rafRef.current);\n            canvas.removeEventListener('pointermove', onPointerMove);\n            ro.disconnect();\n            if (canvas.parentElement === container) {\n                container.removeChild(canvas);\n            }\n            const callIfFn = <T extends object, K extends keyof T>(obj: T | null, key: K) => {\n                if (obj && typeof obj[key] === 'function') {\n                    (obj[key] as unknown as () => void).call(obj);\n                }\n            };\n            callIfFn(programRef.current, 'remove');\n            callIfFn(geometryRef.current, 'remove');\n            callIfFn(meshRef.current as unknown as { remove?: () => void }, 'remove');\n            callIfFn(rendererRef.current as unknown as { destroy?: () => void }, 'destroy');\n            programRef.current = null;\n            geometryRef.current = null;\n            meshRef.current = null;\n            rendererRef.current = null;\n        };\n    }, [\n        dpr,\n        paused,\n        gradientColors,\n        angle,\n        noise,\n        blindCount,\n        blindMinWidth,\n        mouseDampening,\n        mirrorGradient,\n        spotlightRadius,\n        spotlightSoftness,\n        spotlightOpacity,\n        distortAmount,\n        shineDirection\n    ]);\n\n    return (\n        <div\n            ref={containerRef}\n            className={`w-full h-full overflow-hidden relative ${className}`}\n            style={{\n                ...(mixBlendMode && {\n                    mixBlendMode: mixBlendMode as React.CSSProperties['mixBlendMode']\n                })\n            }}\n        />\n    );\n};\n\nexport default GradientBlinds;\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "hero"
  ],
  "type": "registry:block"
}