{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "beam-split",
  "title": "Beam Split",
  "description": "A light beam splits a bold headline and a serif italic phrase appears in the gap.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "files": [
    {
      "path": "registry/remocn/beam-split/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont as loadDisplay } from \"@remotion/google-fonts/BricolageGrotesque\";\nimport { loadFont as loadSerif } from \"@remotion/google-fonts/InstrumentSerif\";\nimport type React from \"react\";\nimport { useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nconst { fontFamily: display } = loadDisplay(\"normal\", {\n  weights: [\"500\"],\n  subsets: [\"latin\"],\n});\nconst { fontFamily: serif } = loadSerif(\"italic\", {\n  weights: [\"400\"],\n  subsets: [\"latin\"],\n});\n\n// gradients.sh \"beam\" palette (bg #02030a): #f4f7ff, #8fb4ff, #3d5bff, #1a1660.\nconst BEAM = [\"#f4f7ff\", \"#8fb4ff\", \"#3d5bff\", \"#1a1660\", \"#02030a\"] as const;\n\n// Advance widths (1/1000 em), ASCII 32–126, measured with HarfBuzz.\nconst BRICO_500 = [\n  246, 266, 317, 613, 630, 947, 756, 159, 305, 290, 395, 516, 165, 339, 196,\n  354, 656, 320, 583, 595, 595, 600, 646, 494, 646, 641, 207, 188, 516, 516,\n  516, 413, 952, 671, 666, 671, 691, 599, 578, 706, 709, 275, 358, 666, 508,\n  909, 747, 716, 629, 719, 660, 641, 553, 718, 657, 957, 653, 600, 560, 315,\n  342, 300, 547, 578, 283, 567, 618, 555, 617, 570, 380, 589, 608, 260, 266,\n  561, 257, 913, 608, 604, 618, 617, 411, 535, 380, 599, 547, 827, 534, 591,\n  500, 353, 260, 331, 516,\n];\nconst SERIF_ITALIC = [\n  170, 275, 374, 629, 424, 591, 525, 235, 346, 346, 449, 531, 219, 426, 219,\n  258, 461, 248, 404, 373, 394, 387, 411, 365, 437, 414, 299, 301, 531, 531,\n  531, 358, 665, 457, 479, 475, 536, 454, 411, 514, 545, 250, 251, 499, 414,\n  665, 542, 540, 469, 541, 525, 424, 461, 537, 458, 653, 545, 478, 427, 326,\n  256, 326, 431, 372, 355, 474, 431, 351, 474, 348, 273, 401, 476, 288, 266,\n  447, 240, 745, 521, 414, 450, 425, 368, 302, 272, 508, 412, 609, 450, 418,\n  385, 320, 252, 320, 531,\n];\nconst TRACK = -0.035;\nconst SERIF_TRACK = -0.01;\n\nexport interface BeamSplitProps {\n  title?: string;\n  inner?: string;\n  accent?: string;\n  theme?: \"dark\" | \"light\";\n  speed?: number;\n}\n\nconst CLAMP = {\n  extrapolateLeft: \"clamp\",\n  extrapolateRight: \"clamp\",\n} as const;\n\n// Cap height and line-box baseline (lineHeight 1) per face.\nconst CAP = 0.66;\nconst BASE = 0.83;\nconst SERIF_CAP = 0.72;\nconst SERIF_BASE = 0.84;\n\nconst RISE_AT = -6;\nconst RISE_END = 14;\nconst BEAM_AT = 10;\nconst BEAM_END = 30;\nconst OPEN_AT = 34;\nconst OPEN_END = 60;\nconst CLOSE_AT = 92;\nconst CLOSE_END = 116;\n\nconst OUT = Easing.bezier(0.22, 1, 0.36, 1);\nconst DRAW = Easing.bezier(0.7, 0, 0.2, 1);\nconst MOVE = Easing.bezier(0.65, 0, 0.35, 1);\n\nconst STAGES = {\n  dark: { bg: \"#0A0A0B\", fg: \"#F3F2EF\" },\n  light: { bg: \"#F5F4F0\", fg: \"#121214\" },\n};\n\nfunction widthEm(text: string, table: number[], track: number) {\n  let w = 0;\n  for (const ch of text) {\n    const code = ch.charCodeAt(0);\n    const adv = code >= 32 && code < 127 ? table[code - 32] : 600;\n    w += adv / 1000 + track;\n  }\n  return Math.max(w, 0.5);\n}\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 Line({\n  text,\n  baseline,\n  size,\n  color,\n  italic = false,\n}: {\n  text: string;\n  baseline: number;\n  size: number;\n  color: string;\n  italic?: boolean;\n}) {\n  return (\n    <div\n      style={{\n        position: \"absolute\",\n        left: 0,\n        right: 0,\n        top: baseline - (italic ? SERIF_BASE : BASE) * size,\n        display: \"flex\",\n        justifyContent: \"center\",\n      }}\n    >\n      <div\n        style={{\n          fontFamily: italic ? serif : display,\n          fontStyle: italic ? \"italic\" : \"normal\",\n          fontWeight: italic ? 400 : 500,\n          fontSize: size,\n          lineHeight: 1,\n          letterSpacing: `${italic ? SERIF_TRACK : TRACK}em`,\n          paddingLeft: `${-(italic ? SERIF_TRACK : TRACK)}em`,\n          whiteSpace: \"nowrap\",\n          color,\n        }}\n      >\n        {text}\n      </div>\n    </div>\n  );\n}\n\nfunction Edge({\n  y,\n  draw,\n  width,\n  lw,\n  accent,\n  glowUp,\n  glowDown,\n  fall,\n}: {\n  y: number;\n  draw: number;\n  width: number;\n  lw: number;\n  accent: string;\n  glowUp: number;\n  glowDown: number;\n  fall: number;\n}) {\n  const fade =\n    \"linear-gradient(to right, transparent 0%, #000 7%, #000 93%, transparent 100%)\";\n  const strip: React.CSSProperties = {\n    position: \"absolute\",\n    left: 0,\n    width,\n    WebkitMaskImage: fade,\n    maskImage: fade,\n  };\n  return (\n    <div\n      style={{\n        position: \"absolute\",\n        left: 0,\n        top: 0,\n        width: width * draw,\n        height: \"100%\",\n        overflow: \"hidden\",\n      }}\n    >\n      {glowUp > 0 ? (\n        <div\n          style={{\n            ...strip,\n            top: y - lw / 2 - fall,\n            height: fall,\n            opacity: glowUp,\n            background: `linear-gradient(to top, ${accent}, transparent)`,\n          }}\n        />\n      ) : null}\n      {glowDown > 0 ? (\n        <div\n          style={{\n            ...strip,\n            top: y + lw / 2,\n            height: fall,\n            opacity: glowDown,\n            background: `linear-gradient(to bottom, ${accent}, transparent)`,\n          }}\n        />\n      ) : null}\n      <div\n        style={{\n          ...strip,\n          top: y - lw / 2,\n          height: lw,\n          background: accent,\n        }}\n      />\n    </div>\n  );\n}\n\nexport function BeamSplit({\n  title = \"Ship the story\",\n  inner = \"with motion you own\",\n  accent = \"#3B5BFD\",\n  theme = \"dark\",\n  speed = 1,\n}: BeamSplitProps) {\n  const t = useCurrentFrame() * speed;\n  const { width: W, height: H } = useVideoConfig();\n  const u = H / 720;\n  const c = STAGES[theme];\n\n  const s = Math.min(168 * u, (0.8 * W) / widthEm(title, BRICO_500, TRACK));\n  const si = Math.min(\n    96 * u,\n    (0.7 * W) / widthEm(inner, SERIF_ITALIC, SERIF_TRACK),\n  );\n  const cut = H / 2;\n  const yB = cut + (CAP * s) / 2;\n  const lw = Math.max(1.5, 2 * u);\n  const fall = 11 * u;\n\n  const rise = OUT(interpolate(t, [RISE_AT, RISE_END], [0, 1], CLAMP));\n  const draw = DRAW(interpolate(t, [BEAM_AT, BEAM_END], [0, 1], CLAMP));\n  const open = MOVE(interpolate(t, [OPEN_AT, OPEN_END], [0, 1], CLAMP));\n  const close = MOVE(interpolate(t, [CLOSE_AT, CLOSE_END], [0, 1], CLAMP));\n\n  const G1 = 0.34 * H;\n  const G2 = 0.15 * H;\n  const gap = open * (G1 + (G2 - G1) * close);\n  const half = gap / 2;\n  const kRes = 0.56;\n  const k = close > 0 ? 1 + (kRes - 1) * close : 1.05 - 0.05 * open;\n\n  const moving =\n    (t >= BEAM_AT && t < OPEN_END + 8) || (t >= CLOSE_AT && t < CLOSE_END + 8);\n  const glowIn = interpolate(t, [BEAM_AT, BEAM_AT + 6], [0, 1], CLAMP);\n  const glowRest = Math.max(\n    interpolate(t, [OPEN_END - 4, OPEN_END + 10], [1, 0], CLAMP),\n    interpolate(\n      t,\n      [CLOSE_AT - 2, CLOSE_AT + 6, CLOSE_END - 2, CLOSE_END + 12],\n      [0, 1, 1, 0],\n      CLAMP,\n    ),\n  );\n  const glow = moving ? 0.3 * glowIn * glowRest : 0;\n  const split = gap > lw;\n  const gapGlow = Math.min(fall, Math.max(0, half - lw));\n\n  // The gap is a slab of beam light: deep indigo at the edges of frame, the\n  // palette's bright core drifting a few percent across the shot.\n  const sway = interpolate(t, [OPEN_AT, CLOSE_END + 30], [-1, 1], CLAMP);\n  const edgeTone = theme === \"light\" ? \"#14104a\" : BEAM[4];\n  const band = [\n    `radial-gradient(38% 160% at ${50 + 6 * sway}% 50%, color-mix(in oklab, ${BEAM[1]} 55%, transparent) 0%, transparent 70%)`,\n    `radial-gradient(70% 220% at ${48 - 4 * sway}% 50%, ${BEAM[2]} 0%, color-mix(in oklab, ${BEAM[2]} 40%, transparent) 45%, transparent 80%)`,\n    `linear-gradient(90deg, ${edgeTone} 0%, ${BEAM[3]} 22%, ${BEAM[3]} 78%, ${edgeTone} 100%)`,\n  ].join(\", \");\n\n  const clip = (top: number, bottom: number) =>\n    `inset(${Math.max(0, top)}px 0px ${Math.max(0, H - bottom)}px 0px)`;\n\n  return (\n    <AbsoluteFill style={{ background: c.bg, overflow: \"hidden\" }}>\n      <AbsoluteFill\n        style={{\n          opacity: rise,\n          transform: `translateY(${(1 - rise) * 14 * u}px)`,\n        }}\n      >\n        <AbsoluteFill\n          style={{\n            clipPath: clip(0, cut),\n            transform: `translateY(${-half}px)`,\n          }}\n        >\n          <Line text={title} baseline={yB} size={s} color={c.fg} />\n        </AbsoluteFill>\n        <AbsoluteFill\n          style={{\n            clipPath: clip(cut, H),\n            transform: `translateY(${half}px)`,\n          }}\n        >\n          <Line text={title} baseline={yB} size={s} color={c.fg} />\n        </AbsoluteFill>\n      </AbsoluteFill>\n\n      {split ? (\n        <AbsoluteFill style={{ clipPath: clip(cut - half, cut + half) }}>\n          <AbsoluteFill style={{ background: band }} />\n          <AbsoluteFill\n            style={{\n              transform: `scale(${k})`,\n              transformOrigin: `50% ${cut}px`,\n            }}\n          >\n            <Line\n              text={inner}\n              baseline={cut + (SERIF_CAP * si) / 2}\n              size={si}\n              color={BEAM[0]}\n              italic\n            />\n          </AbsoluteFill>\n        </AbsoluteFill>\n      ) : null}\n\n      {split ? (\n        <>\n          <Edge\n            y={cut - half}\n            draw={draw}\n            width={W}\n            lw={lw}\n            accent={accent}\n            glowUp={0}\n            glowDown={glow * (gapGlow / fall)}\n            fall={gapGlow}\n          />\n          <Edge\n            y={cut + half}\n            draw={draw}\n            width={W}\n            lw={lw}\n            accent={accent}\n            glowUp={glow * (gapGlow / fall)}\n            glowDown={0}\n            fall={gapGlow}\n          />\n        </>\n      ) : (\n        <Edge\n          y={cut}\n          draw={draw}\n          width={W}\n          lw={lw}\n          accent={accent}\n          glowUp={glow}\n          glowDown={glow}\n          fall={fall}\n        />\n      )}\n\n      <Grain opacity={theme === \"light\" ? 0.04 : 0.05} />\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/beam-split.tsx"
    }
  ],
  "type": "registry:component"
}
