{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "bracket-focus",
  "title": "Bracket Focus",
  "description": "Camera-viewfinder brackets focus in on a 1.8s render-time value over a dotted grid.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "files": [
    {
      "path": "registry/remocn/bracket-focus/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont as loadDisplay } from \"@remotion/google-fonts/Geist\";\nimport { loadFont as loadMono } from \"@remotion/google-fonts/GeistMono\";\nimport type React from \"react\";\nimport { useId } from \"react\";\nimport {\n  AbsoluteFill,\n  Easing,\n  interpolate,\n  spring,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\n\nconst { fontFamily: display } = loadDisplay(\"normal\", {\n  weights: [\"400\", \"500\"],\n  subsets: [\"latin\"],\n});\nconst { fontFamily: mono } = loadMono(\"normal\", {\n  weights: [\"400\", \"500\"],\n  subsets: [\"latin\"],\n});\n\nexport interface BracketFocusProps {\n  subject?: string;\n  tag?: 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\nconst EASE_IO = Easing.bezier(0.65, 0, 0.35, 1);\nconst EASE_OUT = Easing.bezier(0.22, 1, 0.36, 1);\n\nconst FLY_AT = 10;\nconst FLY_LEN = 22;\nconst SNAP_AT = FLY_AT + FLY_LEN;\nconst TAG_AT = SNAP_AT + 6;\nconst DIM_AT = SNAP_AT + 8;\n\nconst THEMES = {\n  dark: {\n    bg: \"#0A0A0B\",\n    fg: \"#F3F2EF\",\n    rest: \"#6E6D73\",\n    dot: \"rgba(255,255,255,0.2)\",\n    tick: \"rgba(255,255,255,0.4)\",\n    readout: \"rgba(243,242,239,0.5)\",\n    // gradients.sh \"beam\": #f4f7ff → #8fb4ff → #3d5bff\n    hero: [\"#F4F7FF\", \"#C4D5FF\", \"#8FB4FF\", \"#5C78FF\"],\n    grain: 0.055,\n  },\n  light: {\n    bg: \"#F5F4F0\",\n    fg: \"#121214\",\n    rest: \"#A3A19B\",\n    dot: \"rgba(18,18,20,0.2)\",\n    tick: \"rgba(18,18,20,0.4)\",\n    readout: \"rgba(18,18,20,0.5)\",\n    // gradients.sh \"beam\", deep end first so it reads on off-white\n    hero: [\"#1A1660\", \"#2B32B8\", \"#3D5BFF\", \"#6F8FFF\"],\n    grain: 0.04,\n  },\n} as const;\n\nconst CORNERS = [\n  { sx: -1, sy: -1, delay: 0 },\n  { sx: 1, sy: -1, delay: 2 },\n  { sx: 1, sy: 1, delay: 3 },\n  { sx: -1, sy: 1, delay: 5 },\n] as const;\n\nfunction widthEm(text: string) {\n  let w = 0;\n  for (const ch of text) {\n    if (ch === \" \") w += 0.26;\n    else if (\".,:;'!|\".includes(ch)) w += 0.27;\n    else if (ch >= \"0\" && ch <= \"9\") w += 0.6;\n    else if (\"ijlI\".includes(ch)) w += 0.25;\n    else if (\"ftr\".includes(ch)) w += 0.36;\n    else if (\"mwMW%\".includes(ch)) w += 0.84;\n    else if (ch >= \"A\" && ch <= \"Z\") w += 0.66;\n    else w += 0.54;\n    w -= 0.035;\n  }\n  return Math.max(w, 0.6);\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={17}\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 bracketPath(x: number, y: number, sx: number, sy: number, L: number) {\n  return `M ${x} ${y - sy * L} L ${x} ${y} L ${x - sx * L} ${y}`;\n}\n\nexport function BracketFocus({\n  subject = \"1.8s\",\n  tag = \"Render time\",\n  accent = \"#3B5BFD\",\n  theme = \"dark\",\n  speed = 1,\n}: BracketFocusProps) {\n  const t = useCurrentFrame() * speed;\n  const { width: W, height: H, fps } = useVideoConfig();\n  const u = Math.min(W / 1280, H / 720);\n  const p = THEMES[theme];\n  const maskId = `m${useId().replace(/[^a-zA-Z0-9_-]/g, \"\")}`;\n\n  const cx = W / 2;\n  const cy = H / 2;\n  const size = Math.min(272 * u, (0.6 * W) / widthEm(subject));\n  const textW = widthEm(subject) * size;\n  const capH = 0.74 * size;\n  const pad = 46 * u;\n  const tight = { hw: textW / 2 + pad * 1.05, hh: capH / 2 + pad * 0.9 };\n  const loose = { hw: tight.hw + 46 * u, hh: tight.hh + 36 * u };\n  const margin = 0.07 * W;\n  const far = { hw: W / 2 - margin, hh: H / 2 - margin };\n\n  const arm = 46 * u;\n  const stroke = 3 * u;\n\n  const corner = (sx: number, sy: number, delay: number, at: number) => {\n    const fly = EASE_IO(\n      interpolate(at, [FLY_AT + delay, SNAP_AT + delay], [0, 1], CLAMP),\n    );\n    const snap = spring({\n      frame: at - SNAP_AT - delay,\n      fps,\n      config: { damping: 13, stiffness: 320, mass: 0.55 },\n    });\n    const hw =\n      far.hw + (loose.hw - far.hw) * fly + (tight.hw - loose.hw) * snap;\n    const hh =\n      far.hh + (loose.hh - far.hh) * fly + (tight.hh - loose.hh) * snap;\n    return { x: cx + sx * hw, y: cy + sy * hh };\n  };\n\n  const appear = interpolate(t, [0, 8], [0.35, 1], CLAMP);\n  const dim = EASE_IO(interpolate(t, [DIM_AT, DIM_AT + 22], [0, 1], CLAMP));\n  const tagIn = EASE_OUT(interpolate(t, [TAG_AT, TAG_AT + 14], [0, 1], CLAMP));\n  const tagText = EASE_OUT(\n    interpolate(t, [TAG_AT + 4, TAG_AT + 16], [0, 1], CLAMP),\n  );\n  const subjectIn = EASE_OUT(interpolate(t, [0, 16], [0.25, 1], CLAMP));\n  const lift = EASE_OUT(\n    interpolate(t, [DIM_AT - 2, DIM_AT + 18], [0, 1], CLAMP),\n  );\n  const push = EASE_IO(interpolate(t, [0, DIM_AT + 50], [0, 1], CLAMP));\n\n  const tl = corner(-1, -1, 0, t);\n  const tagH = 32 * u;\n  const tagFont = 14 * u;\n  const tagW = tag.length * 0.6 * tagFont * 1.06 + 26 * u;\n  const br = corner(1, 1, 3, t);\n  const readIn = EASE_OUT(\n    interpolate(t, [TAG_AT + 8, TAG_AT + 22], [0, 1], CLAMP),\n  );\n  const boxW = Math.round((tight.hw * 2) / u);\n  const boxH = Math.round((tight.hh * 2) / u);\n  const drift = interpolate(t, [0, 150], [0, 1], CLAMP);\n  const heroGradient = `linear-gradient(${112 + 10 * drift}deg, ${p.hero[0]} ${-8 + 10 * drift}%, ${p.hero[1]} ${30 + 6 * drift}%, ${p.hero[2]} ${62 + 4 * drift}%, ${p.hero[3]} 104%)`;\n\n  const gap = 32 * u;\n  const cols = Math.floor((W - 2 * margin) / gap);\n  const rows = Math.floor((H - 2 * margin) / gap);\n  const ox = (W - cols * gap) / 2;\n  const oy = (H - rows * gap) / 2;\n  const dots: React.ReactNode[] = [];\n  for (let r = 0; r <= rows; r++) {\n    for (let c = 0; c <= cols; c++) {\n      const x = ox + c * gap;\n      const y = oy + r * gap;\n      const d = Math.hypot((x - cx) / W, (y - cy) / H);\n      const wave = interpolate(t, [d * 18, d * 18 + 10], [0, 1], CLAMP);\n      dots.push(\n        <circle\n          key={`${r}-${c}`}\n          cx={x}\n          cy={y}\n          r={1.4 * u}\n          fill={p.dot}\n          opacity={wave}\n        />,\n      );\n    }\n  }\n\n  const ticks: React.ReactNode[] = [];\n  const tickN = 24;\n  for (let i = 0; i <= tickN; i++) {\n    const x = margin + ((W - 2 * margin) * i) / tickN;\n    const long = i % 6 === 0;\n    const len = (long ? 12 : 6) * u;\n    for (const yEdge of [margin - 22 * u, H - margin + 22 * u]) {\n      const dir = yEdge < cy ? 1 : -1;\n      ticks.push(\n        <line\n          key={`${i}-${yEdge}`}\n          x1={x}\n          x2={x}\n          y1={yEdge}\n          y2={yEdge + dir * len}\n          stroke={p.tick}\n          strokeWidth={Math.max(1, u)}\n        />,\n      );\n    }\n  }\n\n  return (\n    <AbsoluteFill style={{ background: p.bg, overflow: \"hidden\" }}>\n      <AbsoluteFill\n        style={{\n          opacity: appear * (1 - 0.6 * dim),\n          transform: `scale(${1.02 - 0.02 * push})`,\n        }}\n      >\n        <svg width={W} height={H} style={{ position: \"absolute\", inset: 0 }}>\n          <defs>\n            <mask id={maskId}>\n              <rect width={W} height={H} fill=\"white\" />\n              <rect\n                x={cx - loose.hw}\n                y={cy - loose.hh}\n                width={loose.hw * 2}\n                height={loose.hh * 2}\n                fill=\"black\"\n              />\n            </mask>\n          </defs>\n          <g mask={`url(#${maskId})`}>{dots}</g>\n          {ticks}\n        </svg>\n      </AbsoluteFill>\n\n      <AbsoluteFill\n        style={{\n          alignItems: \"center\",\n          justifyContent: \"center\",\n        }}\n      >\n        <div\n          style={{\n            position: \"relative\",\n            fontFamily: display,\n            fontWeight: 500,\n            fontSize: size,\n            lineHeight: 1,\n            letterSpacing: \"-0.035em\",\n            whiteSpace: \"nowrap\",\n            fontVariantNumeric: \"tabular-nums\",\n            opacity: subjectIn,\n            transform: `translate(${-0.02 * size}px, ${(1 - subjectIn) * 10 * u}px) scale(${0.985 + 0.015 * lift + 0.012 * push})`,\n          }}\n        >\n          <span style={{ color: p.rest, opacity: 1 - lift }}>{subject}</span>\n          <span\n            style={{\n              position: \"absolute\",\n              left: 0,\n              top: 0,\n              backgroundImage: heroGradient,\n              WebkitBackgroundClip: \"text\",\n              backgroundClip: \"text\",\n              color: \"transparent\",\n              opacity: lift,\n            }}\n          >\n            {subject}\n          </span>\n        </div>\n      </AbsoluteFill>\n\n      <svg\n        width={W}\n        height={H}\n        style={{ position: \"absolute\", inset: 0, opacity: appear }}\n      >\n        {CORNERS.map(({ sx, sy, delay }) =>\n          [2.4, 1.2, 0].map((lag) => {\n            const c = corner(sx, sy, delay, t - lag);\n            const now = corner(sx, sy, delay, t);\n            const moved = Math.hypot(c.x - now.x, c.y - now.y);\n            const o = lag === 0 ? 1 : lag > 2 ? 0.12 : 0.26;\n            if (lag > 0 && moved < 2 * u) return null;\n            return (\n              <path\n                key={`${sx}${sy}${lag}`}\n                d={bracketPath(c.x, c.y, sx, sy, arm)}\n                fill=\"none\"\n                stroke={accent}\n                strokeWidth={stroke}\n                strokeLinecap=\"square\"\n                opacity={o}\n              />\n            );\n          }),\n        )}\n      </svg>\n\n      <div\n        style={{\n          position: \"absolute\",\n          left: tl.x - stroke / 2,\n          top: tl.y - stroke / 2 - tagH,\n          height: tagH,\n          width: tagW,\n          background: accent,\n          borderRadius: `${4 * u}px ${4 * u}px ${4 * u}px 0`,\n          clipPath: `inset(${(1 - tagIn) * 100}% ${(1 - tagIn) * 100}% 0 0)`,\n          display: \"flex\",\n          alignItems: \"center\",\n          paddingLeft: 12 * u,\n          boxSizing: \"border-box\",\n        }}\n      >\n        <span\n          style={{\n            fontFamily: mono,\n            fontWeight: 500,\n            fontSize: tagFont,\n            letterSpacing: \"0.06em\",\n            textTransform: \"uppercase\",\n            color: \"#FFFFFF\",\n            whiteSpace: \"nowrap\",\n            opacity: tagText,\n            transform: `translateX(${(1 - tagText) * -6 * u}px)`,\n          }}\n        >\n          {tag}\n        </span>\n      </div>\n\n      <div\n        style={{\n          position: \"absolute\",\n          right: W - br.x - stroke / 2,\n          top: br.y + 14 * u,\n          fontFamily: mono,\n          fontWeight: 400,\n          fontSize: 13 * u,\n          letterSpacing: \"0.04em\",\n          fontVariantNumeric: \"tabular-nums\",\n          color: p.readout,\n          whiteSpace: \"pre\",\n          opacity: readIn,\n          transform: `translateY(${(1 - readIn) * 6 * u}px)`,\n        }}\n      >\n        {`W ${boxW}  ×  H ${boxH}`}\n      </div>\n\n      <Grain opacity={p.grain} />\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/bracket-focus.tsx"
    }
  ],
  "type": "registry:component"
}
