{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "opencode",
  "title": "OpenCode",
  "description": "Animated OpenCode TUI welcome screen — two-tone wordmark, an input box with a blue accent bar that types a query, a model status line, and command hints. Dark/light themes.",
  "dependencies": ["remotion", "@remotion/google-fonts"],
  "registryDependencies": ["@remocn/caret", "@remocn/remocn-ui"],
  "files": [
    {
      "path": "registry/remocn/opencode/index.tsx",
      "content": "\"use client\";\n\nimport { loadFont } from \"@remotion/google-fonts/JetBrainsMono\";\nimport {\n  AbsoluteFill,\n  interpolate,\n  spring,\n  useCurrentFrame,\n  useVideoConfig,\n} from \"remotion\";\nimport { Caret } from \"@/components/remocn/caret\";\nimport { useTypewriter } from \"@/lib/remocn-ui\";\n\nconst { fontFamily: MONO_FAMILY } = loadFont();\n\nexport interface OpenCodeProps {\n  placeholder?: string;\n  query?: string;\n  agentName?: string;\n  modelName?: string;\n  provider?: string;\n  accentColor?: string;\n  speed?: number;\n}\n\ninterface Theme {\n  page: string;\n  boxBg: string;\n  fg: string;\n  fgMuted: string;\n  fgQuery: string;\n  logoOpen: string;\n  logoCode: string;\n}\n\nexport const THEMES: Record<\"light\" | \"dark\", Theme> = {\n  light: {\n    page: \"#FFFFFF\",\n    boxBg: \"#F2F2F2\",\n    fg: \"#111111\",\n    fgMuted: \"#888888\",\n    fgQuery: \"#555555\",\n    logoOpen: \"#999999\",\n    logoCode: \"#111111\",\n  },\n  dark: {\n    page: \"#000000\",\n    boxBg: \"#161616\",\n    fg: \"#EDEDED\",\n    fgMuted: \"#6B6B6B\",\n    fgQuery: \"#9A9A9A\",\n    logoOpen: \"#6B6B6B\",\n    logoCode: \"#EDEDED\",\n  },\n};\n\nexport const TYPING_START_FRAME = 48;\n\nexport const TYPING_CPS = 20;\n\nfunction introBounceIn(\n  frame: number,\n  fps: number,\n): { translateY: number; scale: number } {\n  const s = spring({\n    fps,\n    frame,\n    config: { damping: 14, stiffness: 110, mass: 0.7 },\n  });\n  const translateY = interpolate(s, [0, 1], [28, 0]);\n  const scale = interpolate(s, [0, 1], [0.97, 1]);\n  return { translateY, scale };\n}\n\nfunction fadeUpAt(\n  frame: number,\n  range: [number, number],\n): { opacity: number; translateY: number } {\n  const opts = {\n    extrapolateLeft: \"clamp\" as const,\n    extrapolateRight: \"clamp\" as const,\n  };\n  return {\n    opacity: interpolate(frame, range, [0, 1], opts),\n    translateY: interpolate(frame, range, [12, 0], opts),\n  };\n}\n\nexport function OpenCode({\n  placeholder = \"Ask anything... \",\n  query = '\"What is the tech stack of this project?\"',\n  agentName = \"Build\",\n  modelName = \"Kimi K2.5\",\n  provider = \"Moonshot AI\",\n  accentColor = \"#2B7FFF\",\n  speed = 1,\n}: OpenCodeProps) {\n  const frame = useCurrentFrame();\n  const { width, height, fps } = useVideoConfig();\n  const t = THEMES.dark;\n\n  const refW = 1280;\n  const refH = 720;\n  const stageScale = Math.min(width / refW, height / refH);\n\n  const tw = useTypewriter(query, {\n    cps: TYPING_CPS,\n    speed,\n    startFrame: TYPING_START_FRAME,\n  });\n\n  const intro = introBounceIn(frame * speed, fps);\n  const logoFade = fadeUpAt(frame * speed, [4, 22]);\n  const boxFade = fadeUpAt(frame * speed, [12, 30]);\n  const hintsFade = fadeUpAt(frame * speed, [20, 38]);\n\n  const boxWidth = 1000;\n\n  return (\n    <AbsoluteFill style={{ background: \"transparent\" }}>\n      <div\n        style={{\n          position: \"absolute\",\n          left: \"50%\",\n          top: \"50%\",\n          width: refW,\n          height: refH,\n          translate: \"-50% -50%\",\n          scale: `${stageScale}`,\n          display: \"flex\",\n          flexDirection: \"column\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n        }}\n      >\n        <div\n          style={{\n            lineHeight: 0,\n            opacity: logoFade.opacity,\n            translate: `0 ${logoFade.translateY + intro.translateY * 0.4}px`,\n          }}\n        >\n          <svg\n            width={468}\n            height={84}\n            viewBox=\"0 0 234 42\"\n            fill=\"none\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <title>opencode</title>\n            <clipPath id=\"opencode-wordmark-clip\">\n              <rect width={234} height={42} fill=\"#ffffff\" />\n            </clipPath>\n            <g clipPath=\"url(#opencode-wordmark-clip)\">\n              <path d=\"M18 30H6V18H18V30Z\" fill=\"#4B4646\" />\n              <path d=\"M18 12H6V30H18V12ZM24 36H0V6H24V36Z\" fill=\"#B7B1B1\" />\n              <path d=\"M48 30H36V18H48V30Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M36 30H48V12H36V30ZM54 36H36V42H30V6H54V36Z\"\n                fill=\"#B7B1B1\"\n              />\n              <path d=\"M84 24V30H66V24H84Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M84 24H66V30H84V36H60V6H84V24ZM66 18H78V12H66V18Z\"\n                fill=\"#B7B1B1\"\n              />\n              <path d=\"M108 36H96V18H108V36Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M108 12H96V36H90V6H108V12ZM114 36H108V12H114V36Z\"\n                fill=\"#B7B1B1\"\n              />\n              <path d=\"M144 30H126V18H144V30Z\" fill=\"#4B4646\" />\n              <path d=\"M144 12H126V30H144V36H120V6H144V12Z\" fill=\"#F1ECEC\" />\n              <path d=\"M168 30H156V18H168V30Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M168 12H156V30H168V12ZM174 36H150V6H174V36Z\"\n                fill=\"#F1ECEC\"\n              />\n              <path d=\"M198 30H186V18H198V30Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M198 12H186V30H198V12ZM204 36H180V6H198V0H204V36Z\"\n                fill=\"#F1ECEC\"\n              />\n              <path d=\"M234 24V30H216V24H234Z\" fill=\"#4B4646\" />\n              <path\n                d=\"M216 12V18H228V12H216ZM234 24H216V30H234V36H210V6H234V24Z\"\n                fill=\"#F1ECEC\"\n              />\n            </g>\n          </svg>\n        </div>\n\n        <div\n          style={{\n            width: boxWidth,\n            marginTop: 40,\n            minHeight: 150,\n            background: t.boxBg,\n            borderLeft: `4px solid ${accentColor}`,\n            padding: \"26px 28px\",\n            boxSizing: \"border-box\",\n            display: \"flex\",\n            flexDirection: \"column\",\n            justifyContent: \"center\",\n            gap: 26,\n            opacity: boxFade.opacity,\n            translate: `0 ${boxFade.translateY + intro.translateY * 0.6}px`,\n            scale: `${intro.scale}`,\n            transformOrigin: \"center top\",\n          }}\n        >\n          <div\n            style={{\n              display: \"inline-flex\",\n              alignItems: \"center\",\n              fontFamily: MONO_FAMILY,\n              fontSize: 22,\n            }}\n          >\n            <span style={{ color: t.fgMuted }}>{placeholder}</span>\n            {tw.count > 0 ? (\n              <span style={{ color: t.fgQuery }}>{tw.text}</span>\n            ) : null}\n            <span style={{ opacity: 0.6, display: \"inline-flex\" }}>\n              <Caret\n                width={12}\n                height={24}\n                color={t.fg}\n                blink={!tw.typing}\n                speed={speed}\n                marginLeft={2}\n              />\n            </span>\n          </div>\n\n          <div\n            style={{\n              display: \"flex\",\n              flexDirection: \"row\",\n              alignItems: \"center\",\n              gap: 16,\n              fontFamily: MONO_FAMILY,\n              fontSize: 20,\n            }}\n          >\n            <span style={{ color: accentColor, fontWeight: 600 }}>\n              {agentName}\n            </span>\n            <span style={{ color: t.fg }}>{modelName}</span>\n            <span style={{ color: t.fgMuted }}>{provider}</span>\n          </div>\n        </div>\n\n        <div\n          style={{\n            width: boxWidth,\n            marginTop: 18,\n            display: \"flex\",\n            justifyContent: \"flex-end\",\n            gap: 22,\n            fontFamily: MONO_FAMILY,\n            fontSize: 18,\n            opacity: hintsFade.opacity,\n            translate: `0 ${hintsFade.translateY}px`,\n          }}\n        >\n          <span style={{ display: \"inline-flex\", gap: 8 }}>\n            <span style={{ color: t.fg, fontWeight: 700 }}>tab</span>\n            <span style={{ color: t.fgMuted }}>agents</span>\n          </span>\n          <span style={{ display: \"inline-flex\", gap: 8 }}>\n            <span style={{ color: t.fg, fontWeight: 700 }}>ctrl+p</span>\n            <span style={{ color: t.fgMuted }}>commands</span>\n          </span>\n        </div>\n      </div>\n    </AbsoluteFill>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/opencode.tsx"
    }
  ],
  "type": "registry:component"
}
