{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "intelligence-glow",
  "title": "Intelligence Glow",
  "description": "An AI-style answer types under a question while a soft glow breathes along an underline.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "files": [
    {
      "path": "registry/remocn/intelligence-glow/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont as loadSans } from \"@remotion/google-fonts/InstrumentSans\";\nimport { loadFont as loadSerif } from \"@remotion/google-fonts/InstrumentSerif\";\nimport { loadFont as loadManrope } from \"@remotion/google-fonts/Manrope\";\nimport { useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nconst { fontFamily: sans } = loadSans(\"normal\", {\n  weights: [\"500\"],\n  subsets: [\"latin\"],\n});\nconst { fontFamily: serif } = loadSerif(\"italic\", {\n  weights: [\"400\"],\n  subsets: [\"latin\"],\n});\nconst manrope = loadManrope(\"normal\", {\n  weights: [\"500\", \"600\"],\n  subsets: [\"latin\"],\n});\n\nexport interface IntelligenceGlowProps {\n  /** Asked while the edge glow breathes. */\n  question?: string;\n  /** First word of the answer, set in a serif italic. */\n  answerLead?: string;\n  /** Rest of the answer, resolves word by word after the lead. */\n  answer?: string;\n  /** Show the remocn logo under the answer on the poster frame. */\n  showLogo?: boolean;\n  accent?: string;\n  theme?: \"dark\" | \"light\";\n  speed?: number;\n}\n\nconst REMOCN_R_PATH =\n  \"M 0.01 0.81 C 0.01 1.73, 0.36 2.79, 1.09 4.13 C 4.91 11.04, 13.45 17.16, 21.7 18.9 C 22.94 19.16, 23.18 19.16, 51.39 19.27 C 76.07 19.36, 80.02 19.4, 81.32 19.57 C 89.89 20.69, 96.2 24.68, 99.38 31.01 C 103.19 38.56, 102.53 50.1, 97.91 57.07 C 94.66 61.96, 89.68 64.99, 83.26 66 C 82.81 66.07, 70.18 66.83, 55.2 67.69 C 24.82 69.43, 27.03 69.23, 24.18 70.4 C 19.9 72.15, 14.84 75.7, 10.65 79.89 C 4.86 85.68, 1.3 91.91, 0.25 98.13 C 0.12 98.85, 0.08 103.13, 0.04 116.66 L 0 134.26 9.5 134.26 L 19 134.26 19.05 119.41 C 19.1 103.27, 19.08 103.82, 19.82 101.04 C 21.79 93.65, 27.86 88.75, 36.45 87.63 C 37.23 87.53, 39.41 87.5, 43.57 87.53 C 50.12 87.59, 50.75 87.65, 53.22 88.45 C 56.61 89.56, 59.67 91.86, 62.02 95.07 C 62.52 95.76, 69.35 103.85, 77.2 113.07 C 85.04 122.28, 91.63 130.04, 91.85 130.32 C 92.07 130.59, 92.5 131.34, 92.82 131.97 C 93.52 133.35, 94.11 133.93, 95.06 134.13 C 95.5 134.23, 98.97 134.26, 106.36 134.23 L 117.01 134.19 100.82 113.07 C 91.91 101.45, 84.52 91.78, 84.39 91.57 C 83.36 89.89, 83.66 87.53, 85.09 86 C 85.79 85.25, 86.36 84.94, 88.07 84.38 C 96.18 81.72, 104.15 76.62, 109.97 70.36 C 120.59 58.93, 124.06 44.32, 119.44 30.43 C 114.59 15.81, 101.93 4.02, 87.64 0.83 C 83.93 0.01, 88.09 0.08, 41.85 0.04 L 0.01 0 0.01 0.81 Z\";\n\n/** Full logo as on remocn.dev: R mark + \"emocn\" in Manrope 600. */\nfunction RemocnLogo({ fontSize, color }: { fontSize: number; color: string }) {\n  return (\n    <div\n      style={{\n        display: \"flex\",\n        alignItems: \"baseline\",\n        color,\n        fontFamily: manrope.fontFamily,\n        fontWeight: 600,\n        fontSize,\n        letterSpacing: \"-0.025em\",\n        lineHeight: 1,\n      }}\n    >\n      <svg\n        viewBox=\"0 0 124.06 134.26\"\n        style={{ height: \"0.76em\", width: \"auto\" }}\n        aria-hidden\n      >\n        <path fill=\"currentColor\" d={REMOCN_R_PATH} />\n      </svg>\n      <span style={{ marginLeft: \"0.04em\" }}>emocn</span>\n    </div>\n  );\n}\n\n// gradients.sh \"halo\" on dark (its blue stop becomes the accent), \"ribbon\"\n// on light. The light is the only gradient in the shot.\nconst THEMES = {\n  dark: {\n    bg: \"#030306\",\n    fg: \"#F3F2EF\",\n    glow: [\"#FFF4EC\", \"#FFB36B\", \"#E2457A\", \"\"],\n    haze: 0.85,\n    core: 0.95,\n    grain: 0.06,\n  },\n  light: {\n    bg: \"#F5F4F0\",\n    fg: \"#121214\",\n    glow: [\"#FFC83D\", \"#FF8A3D\", \"#FF3D9A\", \"#7A5CFF\"],\n    haze: 0.7,\n    core: 0.85,\n    grain: 0.04,\n  },\n} as const;\n\nconst EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);\nconst EASE_IO = Easing.bezier(0.65, 0, 0.35, 1);\nconst CLAMP = {\n  extrapolateLeft: \"clamp\",\n  extrapolateRight: \"clamp\",\n} as const;\n\n// Beats (frames at speed 1).\nconst Q_IN = 2;\nconst THINK = 32;\nconst RIPPLES = [36, 54];\nconst BLOBS = 16;\nconst Q_OUT = 76;\nconst SQUEEZE = [80, 100] as const;\nconst NARROW = [88, 110] as const;\nconst A_IN = 100;\nconst A_STAGGER = 4;\nconst LOGO_IN = 132;\n\nfunction Grain({ opacity }: { opacity: number }) {\n  const id = `g${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n  return (\n    <svg\n      width=\"100%\"\n      height=\"100%\"\n      style={{ position: \"absolute\", inset: 0, opacity, pointerEvents: \"none\" }}\n      aria-hidden\n    >\n      <filter id={id}>\n        <feTurbulence\n          type=\"fractalNoise\"\n          baseFrequency=\"0.9\"\n          numOctaves={2}\n          seed={7}\n          stitchTiles=\"stitch\"\n        />\n        <feColorMatrix values=\"0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 0 0.5  0 0 0 0.9 0\" />\n      </filter>\n      <rect width=\"100%\" height=\"100%\" filter={`url(#${id})`} />\n    </svg>\n  );\n}\n\nfunction rw(r: { left: number; right: number }) {\n  return r.right - r.left;\n}\n\nfunction lerp(a: number, b: number, k: number) {\n  return a + (b - a) * k;\n}\n\nexport function IntelligenceGlow({\n  question = \"Make a launch film for Friday?\",\n  answerLead = \"Done.\",\n  answer = \"14 shots, cut to the beat.\",\n  showLogo = true,\n  accent = \"#3B5BFD\",\n  theme = \"dark\",\n  speed = 1,\n}: IntelligenceGlowProps) {\n  const t = useCurrentFrame() * speed;\n  const { width: W, height: H } = useVideoConfig();\n  const u = H / 720;\n  const c = THEMES[theme];\n  const glow = c.glow.map((col) => col || accent);\n\n  // A looping band of the palette, drifted sideways so the colours travel\n  // around the frame while it breathes.\n  const loop = [glow[3], glow[2], glow[1], glow[2], glow[3]];\n  const band = `linear-gradient(90deg, ${loop.join(\", \")})`;\n  const drift = `${((t * 0.45) % 100).toFixed(2)}% 50%`;\n  // Breath: slow swell, deeper and quicker while \"thinking\".\n  const thinking = interpolate(\n    t,\n    [THINK - 6, THINK + 6, Q_OUT, Q_OUT + 8],\n    [0, 1, 1, 0],\n    CLAMP,\n  );\n  const breath =\n    0.5 +\n    0.5 * Math.sin((t / (44 - thinking * 14)) * Math.PI * 2 - Math.PI / 2);\n  const swell = 1 + breath * (0.18 + thinking * 0.22);\n  const intro = interpolate(t, [0, 14], [0.55, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n\n  // Answer metrics. Lead word in serif italic at 1.14x so the x-heights meet.\n  const aWords = answer.split(\" \").filter(Boolean);\n  const estEm = answerLead.length * 0.42 * 1.14 + answer.length * 0.43 + 0.3;\n  const aSize = Math.min(78 * u, (W * 0.86) / estEm);\n  const aY = H * 0.46;\n  const lineY = aY + aSize * 0.78;\n  const lineW = Math.min(W * 0.8, estEm * aSize * 1.02);\n  const lineT = 3 * u;\n\n  // Collapse: top and bottom bands squeeze to the answer rule, then the\n  // strip narrows to the answer's width.\n  const sq = interpolate(t, [SQUEEZE[0], SQUEEZE[1]], [0, 1], {\n    ...CLAMP,\n    easing: EASE_IO,\n  });\n  const nw = interpolate(t, [NARROW[0], NARROW[1]], [0, 1], {\n    ...CLAMP,\n    easing: EASE_IO,\n  });\n  const ring = {\n    top: lerp(0, lineY, sq),\n    bottom: lerp(H, lineY, sq),\n    left: lerp(0, (W - lineW) / 2, nw),\n    right: lerp(W, (W + lineW) / 2, nw),\n  };\n\n  // \"Thinking\" pulses: the light swells inward, three times.\n  const ripple = RIPPLES.reduce((acc, start) => {\n    const k = interpolate(t, [start, start + 24], [0, 1], CLAMP);\n    return acc + Math.sin(k * Math.PI) ** 1.6;\n  }, 0);\n  // Pools of light riding the ring's perimeter: long and shallow along an\n  // edge, rounder at the corners. Overlapping, they read as one band of light\n  // whose depth and colour keep changing.\n  const rwid = rw(ring);\n  const rhgt = ring.bottom - ring.top;\n  const per = 2 * (rwid + rhgt);\n  const zone = 160 * u;\n  const blobsOut = interpolate(sq, [0.6, 1], [1, 0], CLAMP);\n  const blobs = Array.from({ length: BLOBS }, (_, i) => {\n    const dd = (((i + 0.5) / BLOBS + t * 0.0015) % 1) * per;\n    let x: number;\n    let y: number;\n    let horizontal: boolean;\n    let corner: number;\n    if (dd < rwid) {\n      x = ring.left + dd;\n      y = ring.top;\n      horizontal = true;\n      corner = Math.min(dd, rwid - dd);\n    } else if (dd < rwid + rhgt) {\n      x = ring.right;\n      y = ring.top + dd - rwid;\n      horizontal = false;\n      corner = Math.min(dd - rwid, rwid + rhgt - dd);\n    } else if (dd < 2 * rwid + rhgt) {\n      x = ring.right - (dd - rwid - rhgt);\n      y = ring.bottom;\n      horizontal = true;\n      corner = Math.min(dd - rwid - rhgt, 2 * rwid + rhgt - dd);\n    } else {\n      x = ring.left;\n      y = ring.bottom - (dd - 2 * rwid - rhgt);\n      horizontal = false;\n      corner = Math.min(dd - 2 * rwid - rhgt, per - dd);\n    }\n    const m = 0.5 + 0.5 * Math.min(1, corner / zone);\n    const hw = horizontal ? m : 1 - m;\n    const wob = Math.sin(t / 21 + i * 2.3);\n    const depth =\n      74 * u * swell * (1 + ripple * 0.9) * (0.8 + 0.3 * wob) * (1 - sq * 0.85);\n    const a = lerp(depth, rwid * 0.2 + 40 * u, hw);\n    const b = lerp(rhgt * 0.27 + 20 * u, depth, hw);\n    return {\n      key: i,\n      x,\n      y,\n      a,\n      b,\n      color: glow[[3, 2, 1, 2, 3, 1, 2][i % 7]],\n      opacity:\n        c.haze * intro * blobsOut * (0.8 + 0.2 * wob) * (1 + ripple * 0.25),\n    };\n  });\n  const rule = interpolate(t, [SQUEEZE[1] - 9, SQUEEZE[1] + 3], [0, 1], {\n    ...CLAMP,\n    easing: EASE_IO,\n  });\n\n  // Question: words rise in, shimmer while thinking, dissolve as the light\n  // collapses.\n  const qWords = question.split(\" \").filter(Boolean);\n  const qSize = Math.min(\n    90 * u,\n    (W * 0.74) / Math.max(6, question.length * 0.3),\n  );\n  const qOut = interpolate(t, [Q_OUT, Q_OUT + 16], [0, 1], {\n    ...CLAMP,\n    easing: Easing.bezier(0.5, 0, 0.75, 0),\n  });\n  const shimmerPos = interpolate(t, [THINK, Q_OUT], [-2, qWords.length + 4]);\n\n  const logoIn = interpolate(t, [LOGO_IN, LOGO_IN + 16], [0, 1], {\n    ...CLAMP,\n    easing: EASE_OUT,\n  });\n\n  return (\n    <AbsoluteFill style={{ background: c.bg, overflow: \"hidden\" }}>\n      {blobs.map((bl) =>\n        bl.opacity > 0.002 ? (\n          <div\n            key={bl.key}\n            style={{\n              position: \"absolute\",\n              left: bl.x - bl.a,\n              top: bl.y - bl.b,\n              width: bl.a * 2,\n              height: bl.b * 2,\n              background: `radial-gradient(closest-side, ${bl.color} 0%, color-mix(in oklab, ${bl.color} 62%, transparent) 32%, color-mix(in oklab, ${bl.color} 20%, transparent) 66%, transparent 100%)`,\n              opacity: bl.opacity,\n              mixBlendMode: theme === \"dark\" ? \"screen\" : \"multiply\",\n            }}\n          />\n        ) : null,\n      )}\n\n      {/* The rule the light settles into, with a soft bloom of its own. */}\n      {rule > 0 ? (\n        <>\n          <div\n            style={{\n              position: \"absolute\",\n              left: ring.left + rw(ring) * 0.05,\n              width: rw(ring) * 0.9,\n              top: lineY - 12 * u,\n              height: 24 * u,\n              borderRadius: 999,\n              backgroundImage: band,\n              backgroundSize: \"200% 100%\",\n              backgroundPosition: drift,\n              filter: `blur(${16 * u}px)`,\n              opacity: rule * 0.55,\n            }}\n          />\n          <div\n            style={{\n              position: \"absolute\",\n              left: ring.left,\n              width: rw(ring),\n              top: lineY - lineT / 2,\n              height: lineT,\n              borderRadius: 999,\n              backgroundImage: band,\n              backgroundSize: \"200% 100%\",\n              backgroundPosition: drift,\n              opacity: rule * c.core,\n            }}\n          />\n        </>\n      ) : null}\n\n      {/* Question */}\n      {qOut < 1 ? (\n        <div\n          style={{\n            position: \"absolute\",\n            left: W * 0.1,\n            right: W * 0.1,\n            top: 0,\n            bottom: 0,\n            display: \"flex\",\n            alignItems: \"center\",\n            justifyContent: \"center\",\n            opacity: 1 - qOut,\n            filter: qOut > 0 ? `blur(${qOut * 14 * u}px)` : undefined,\n            transform: `translateY(${-qOut * 14 * u}px) scale(${1 - qOut * 0.04})`,\n          }}\n        >\n          <div\n            style={{\n              fontFamily: sans,\n              fontWeight: 500,\n              fontSize: qSize,\n              lineHeight: 1.06,\n              letterSpacing: \"-0.035em\",\n              color: c.fg,\n              textAlign: \"center\",\n              textWrap: \"balance\",\n              maxWidth: W * 0.72,\n            }}\n          >\n            {qWords.map((w, i) => {\n              const k = interpolate(\n                t,\n                [Q_IN + i * 3, Q_IN + i * 3 + 14],\n                [0, 1],\n                {\n                  ...CLAMP,\n                  easing: EASE_OUT,\n                },\n              );\n              const d = i - shimmerPos;\n              const shimmer = thinking * (1 - Math.exp(-(d * d) / 2.2));\n              return (\n                <span\n                  key={`${i}-${w}`}\n                  style={{\n                    display: \"inline-block\",\n                    marginRight: i < qWords.length - 1 ? \"0.24em\" : 0,\n                    opacity: k * (1 - shimmer * 0.55),\n                    transform: `translateY(${(1 - k) * 0.28}em)`,\n                    filter: k < 1 ? `blur(${(1 - k) * 8 * u}px)` : undefined,\n                  }}\n                >\n                  {w}\n                </span>\n              );\n            })}\n          </div>\n        </div>\n      ) : null}\n\n      {/* Answer */}\n      {t >= A_IN - 1 ? (\n        <div\n          style={{\n            position: \"absolute\",\n            left: 0,\n            right: 0,\n            top: aY - aSize * 0.62,\n            height: aSize * 1.1,\n            display: \"flex\",\n            justifyContent: \"center\",\n            alignItems: \"baseline\",\n            whiteSpace: \"nowrap\",\n            color: c.fg,\n          }}\n        >\n          {[answerLead, ...aWords].map((w, i) => {\n            const lead = i === 0;\n            const s = A_IN + i * A_STAGGER;\n            const k = interpolate(t, [s, s + 16], [0, 1], {\n              ...CLAMP,\n              easing: EASE_OUT,\n            });\n            return (\n              <span\n                key={`${i}-${w}`}\n                style={{\n                  display: \"inline-block\",\n                  fontFamily: lead ? serif : sans,\n                  fontStyle: lead ? \"italic\" : \"normal\",\n                  fontWeight: lead ? 400 : 500,\n                  fontSize: lead ? aSize * 1.14 : aSize,\n                  letterSpacing: lead ? \"-0.02em\" : \"-0.035em\",\n                  lineHeight: 1,\n                  marginRight:\n                    i === aWords.length ? 0 : lead ? \"0.26em\" : \"0.22em\",\n                  opacity: k,\n                  transform: `translateY(${(1 - k) * 0.3}em)`,\n                  filter: k < 1 ? `blur(${(1 - k) * 10 * u}px)` : undefined,\n                }}\n              >\n                {w}\n              </span>\n            );\n          })}\n        </div>\n      ) : null}\n\n      {showLogo && logoIn > 0 ? (\n        <div\n          style={{\n            position: \"absolute\",\n            left: 0,\n            right: 0,\n            top: H * 0.82,\n            display: \"flex\",\n            justifyContent: \"center\",\n            opacity: logoIn,\n            transform: `translateY(${(1 - logoIn) * 10 * u}px)`,\n          }}\n        >\n          <RemocnLogo fontSize={26 * u} color={c.fg} />\n        </div>\n      ) : null}\n      <Grain opacity={c.grain} />\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/intelligence-glow.tsx"
    }
  ],
  "type": "registry:component"
}
