{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "infinite-bento-pan",
  "title": "Infinite Bento Pan",
  "description": "A camera diagonally drifts across an oversized bento grid behind a soft vignette.",
  "dependencies": [
    "remotion"
  ],
  "files": [
    {
      "path": "registry/bases/editframe/components/infinite-bento-pan/index.tsx",
      "content": "\"use client\";\n\nimport { Timegroup } from \"@editframe/react\";\nimport type { CSSProperties } from \"react\";\n\nconst FONT_FAMILY =\n  \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\nconst SUPER_W = 3500;\nconst SUPER_H = 2500;\n\ntype CardKind =\n  | \"chart\"\n  | \"counter\"\n  | \"gradient\"\n  | \"code\"\n  | \"logo\"\n  | \"stat\"\n  | \"bars\";\n\ninterface CardDef {\n  x: number;\n  y: number;\n  w: number;\n  h: number;\n  kind: CardKind;\n  hue: number;\n  label?: string;\n}\n\nconst CARDS: CardDef[] = [\n  { h: 280, hue: 220, kind: \"chart\", label: \"Revenue\", w: 480, x: 80, y: 80 },\n  { h: 280, hue: 280, kind: \"counter\", label: \"MRR\", w: 280, x: 600, y: 80 },\n  { h: 180, hue: 200, kind: \"gradient\", w: 360, x: 920, y: 80 },\n  { h: 280, hue: 0, kind: \"code\", label: \"deploy.ts\", w: 480, x: 1320, y: 80 },\n  { h: 280, hue: 320, kind: \"logo\", w: 280, x: 1840, y: 80 },\n  { h: 180, hue: 160, kind: \"stat\", label: \"Uptime\", w: 380, x: 2160, y: 80 },\n  { h: 280, hue: 40, kind: \"bars\", label: \"Visits\", w: 360, x: 2580, y: 80 },\n  { h: 200, hue: 180, kind: \"counter\", label: \"Users\", w: 360, x: 920, y: 300 },\n  {\n    h: 200,\n    hue: 100,\n    kind: \"chart\",\n    label: \"Latency\",\n    w: 380,\n    x: 2160,\n    y: 300,\n  },\n  { h: 280, hue: 340, kind: \"gradient\", w: 280, x: 80, y: 400 },\n  { h: 280, hue: 0, kind: \"code\", label: \"api.ts\", w: 480, x: 400, y: 400 },\n  { h: 280, hue: 60, kind: \"stat\", label: \"P95\", w: 280, x: 1320, y: 420 },\n  { h: 280, hue: 260, kind: \"bars\", label: \"Builds\", w: 380, x: 1640, y: 420 },\n  { h: 280, hue: 200, kind: \"logo\", w: 360, x: 2580, y: 420 },\n  { h: 240, hue: 290, kind: \"chart\", label: \"Errors\", w: 480, x: 80, y: 720 },\n  { h: 240, hue: 20, kind: \"stat\", label: \"RPS\", w: 280, x: 600, y: 720 },\n  { h: 220, hue: 240, kind: \"gradient\", w: 380, x: 920, y: 740 },\n  {\n    h: 220,\n    hue: 140,\n    kind: \"counter\",\n    label: \"Active\",\n    w: 360,\n    x: 1320,\n    y: 740,\n  },\n  { h: 220, hue: 0, kind: \"code\", label: \"worker.ts\", w: 480, x: 1720, y: 740 },\n  { h: 220, hue: 320, kind: \"bars\", label: \"Queue\", w: 360, x: 2240, y: 740 },\n  { h: 220, hue: 180, kind: \"logo\", w: 360, x: 80, y: 1000 },\n  { h: 220, hue: 80, kind: \"stat\", label: \"Cache\", w: 380, x: 460, y: 1000 },\n  { h: 220, hue: 200, kind: \"chart\", label: \"CPU\", w: 480, x: 880, y: 1000 },\n  {\n    h: 220,\n    hue: 360,\n    kind: \"counter\",\n    label: \"Jobs\",\n    w: 280,\n    x: 1400,\n    y: 1000,\n  },\n  { h: 220, hue: 120, kind: \"gradient\", w: 360, x: 1720, y: 1020 },\n  { h: 220, hue: 0, kind: \"code\", label: \"db.sql\", w: 380, x: 2120, y: 1020 },\n  { h: 220, hue: 280, kind: \"bars\", label: \"Tasks\", w: 400, x: 2540, y: 1020 },\n  { h: 260, hue: 0, kind: \"code\", label: \"edge.ts\", w: 480, x: 80, y: 1280 },\n  { h: 260, hue: 240, kind: \"chart\", label: \"TTFB\", w: 360, x: 600, y: 1280 },\n  { h: 260, hue: 60, kind: \"logo\", w: 280, x: 1000, y: 1280 },\n  { h: 260, hue: 200, kind: \"stat\", label: \"Hits\", w: 380, x: 1320, y: 1280 },\n  {\n    h: 260,\n    hue: 300,\n    kind: \"counter\",\n    label: \"Bytes\",\n    w: 360,\n    x: 1740,\n    y: 1280,\n  },\n  { h: 260, hue: 160, kind: \"gradient\", w: 380, x: 2140, y: 1280 },\n  { h: 260, hue: 0, kind: \"bars\", label: \"Errors\", w: 380, x: 2560, y: 1280 },\n  { h: 220, hue: 280, kind: \"stat\", label: \"Saved\", w: 380, x: 80, y: 1600 },\n  { h: 220, hue: 40, kind: \"chart\", label: \"Net Out\", w: 480, x: 500, y: 1600 },\n  { h: 220, hue: 0, kind: \"code\", label: \"auth.ts\", w: 360, x: 1020, y: 1600 },\n  { h: 220, hue: 220, kind: \"logo\", w: 280, x: 1420, y: 1600 },\n  {\n    h: 220,\n    hue: 100,\n    kind: \"counter\",\n    label: \"Hooks\",\n    w: 380,\n    x: 1740,\n    y: 1620,\n  },\n  { h: 220, hue: 340, kind: \"bars\", label: \"Runs\", w: 360, x: 2160, y: 1620 },\n  { h: 220, hue: 200, kind: \"gradient\", w: 380, x: 2560, y: 1620 },\n  { h: 240, hue: 180, kind: \"bars\", label: \"Edges\", w: 480, x: 80, y: 1880 },\n  { h: 240, hue: 320, kind: \"gradient\", w: 380, x: 600, y: 1880 },\n  { h: 240, hue: 80, kind: \"logo\", w: 360, x: 1020, y: 1880 },\n  {\n    h: 240,\n    hue: 260,\n    kind: \"chart\",\n    label: \"Tokens\",\n    w: 480,\n    x: 1420,\n    y: 1880,\n  },\n  {\n    h: 240,\n    hue: 20,\n    kind: \"counter\",\n    label: \"Calls\",\n    w: 280,\n    x: 1940,\n    y: 1880,\n  },\n  { h: 240, hue: 140, kind: \"stat\", label: \"Score\", w: 380, x: 2260, y: 1880 },\n  { h: 240, hue: 0, kind: \"code\", label: \"ws.ts\", w: 260, x: 2680, y: 1880 },\n];\n\nconst ChartCard = ({ accent, t }: { accent: string; t: number }) => {\n  const points: string[] = [];\n  for (let i = 0; i < 12; i += 1) {\n    const x = (i / 11) * 100;\n    const y =\n      50 - (Math.sin(i * 0.7 + t) * 18 + Math.cos(i * 0.4 + t * 0.6) * 8);\n    points.push(`${x},${y}`);\n  }\n  return (\n    <svg\n      viewBox=\"0 0 100 60\"\n      preserveAspectRatio=\"none\"\n      style={{ height: \"100%\", width: \"100%\" }}\n    >\n      <polyline\n        points={points.join(\" \")}\n        fill=\"none\"\n        stroke={accent}\n        strokeWidth={1.4}\n        strokeLinecap=\"round\"\n        strokeLinejoin=\"round\"\n      />\n      <polyline\n        points={`${points.join(\" \")} 100,60 0,60`}\n        fill={`${accent}22`}\n        stroke=\"none\"\n      />\n    </svg>\n  );\n};\n\nconst BarsCard = ({ accent, t }: { accent: string; t: number }) => (\n  <div\n    style={{\n      alignItems: \"flex-end\",\n      display: \"flex\",\n      gap: 6,\n      height: \"100%\",\n      width: \"100%\",\n    }}\n  >\n    {Array.from({ length: 10 }).map((_, i) => {\n      const h = 25 + (Math.sin(i * 0.8 + t) * 0.5 + 0.5) * 70;\n      return (\n        <div\n          key={i}\n          style={{\n            background: `linear-gradient(180deg, ${accent} 0%, ${accent}55 100%)`,\n            borderRadius: 4,\n            flex: 1,\n            height: `${h}%`,\n          }}\n        />\n      );\n    })}\n  </div>\n);\n\nconst CodeCard = () => {\n  const lines = [\n    { c: \"#7dd3fc\", indent: 0, w: 60 },\n    { c: \"rgba(255,255,255,0.8)\", indent: 1, w: 80 },\n    { c: \"#f9a8d4\", indent: 1, w: 50 },\n    { c: \"rgba(255,255,255,0.8)\", indent: 2, w: 70 },\n    { c: \"#fde047\", indent: 2, w: 40 },\n    { c: \"rgba(255,255,255,0.6)\", indent: 1, w: 30 },\n    { c: \"rgba(255,255,255,0.6)\", indent: 0, w: 20 },\n  ];\n  return (\n    <div\n      style={{\n        display: \"flex\",\n        flexDirection: \"column\",\n        fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n        gap: 8,\n      }}\n    >\n      {lines.map((l, i) => (\n        <div\n          key={i}\n          style={{\n            background: l.c,\n            borderRadius: 3,\n            height: 8,\n            marginLeft: l.indent * 14,\n            opacity: 0.7,\n            width: `${l.w}%`,\n          }}\n        />\n      ))}\n    </div>\n  );\n};\n\nconst LogoCard = ({ accent, hue }: { accent: string; hue: number }) => (\n  <div\n    style={{\n      alignItems: \"center\",\n      display: \"flex\",\n      height: \"100%\",\n      justifyContent: \"center\",\n      width: \"100%\",\n    }}\n  >\n    <div\n      style={{\n        background: `linear-gradient(135deg, ${accent} 0%, hsl(${hue},70%,55%) 100%)`,\n        borderRadius: 20,\n        boxShadow: `0 10px 30px ${accent}44`,\n        height: 80,\n        width: 80,\n      }}\n    />\n  </div>\n);\n\nconst GradientCard = ({ hue }: { hue: number }) => (\n  <div\n    style={{\n      background: `radial-gradient(circle at 30% 30%, hsl(${hue},80%,60%) 0%, hsl(${(hue + 60) % 360},70%,40%) 50%, #0a0a0a 100%)`,\n      height: \"100%\",\n      width: \"100%\",\n    }}\n  />\n);\n\nconst Card = ({\n  card,\n  accent,\n  index,\n  frame,\n}: {\n  card: CardDef;\n  accent: string;\n  index: number;\n  frame: number;\n}) => {\n  const t = (Math.sin(frame / 30 + index) * 0.5 + 0.5) * 6.28;\n\n  const baseStyle: React.CSSProperties = {\n    background: \"linear-gradient(180deg, #131313 0%, #0a0a0a 100%)\",\n    border: \"1px solid rgba(255,255,255,0.07)\",\n    borderRadius: 18,\n    color: \"white\",\n    display: \"flex\",\n    flexDirection: \"column\",\n    height: card.h,\n    left: card.x,\n    overflow: \"hidden\",\n    padding: 18,\n    position: \"absolute\",\n    top: card.y,\n    width: card.w,\n  };\n\n  const labelEl = card.label ? (\n    <div\n      style={{\n        color: \"rgba(255,255,255,0.55)\",\n        fontSize: 12,\n        fontWeight: 600,\n        letterSpacing: \"0.04em\",\n        marginBottom: 8,\n        textTransform: \"uppercase\",\n      }}\n    >\n      {card.label}\n    </div>\n  ) : null;\n\n  if (card.kind === \"chart\") {\n    return (\n      <div style={baseStyle}>\n        {labelEl}\n        <div style={{ flex: 1 }}>\n          <ChartCard accent={accent} t={t} />\n        </div>\n      </div>\n    );\n  }\n  if (card.kind === \"bars\") {\n    return (\n      <div style={baseStyle}>\n        {labelEl}\n        <div style={{ flex: 1 }}>\n          <BarsCard accent={accent} t={t} />\n        </div>\n      </div>\n    );\n  }\n  if (card.kind === \"counter\") {\n    const v = Math.floor(1200 + Math.sin(index + frame / 30) * 800);\n    return (\n      <div style={baseStyle}>\n        {labelEl}\n        <div\n          style={{\n            alignItems: \"center\",\n            color: \"white\",\n            display: \"flex\",\n            flex: 1,\n            fontSize: 56,\n            fontWeight: 700,\n            justifyContent: \"flex-start\",\n            letterSpacing: \"-0.04em\",\n          }}\n        >\n          {v.toLocaleString()}\n        </div>\n        <div style={{ color: accent, fontSize: 12, fontWeight: 600 }}>\n          +{(Math.sin(index + 1 + frame / 30) * 12).toFixed(1)}%\n        </div>\n      </div>\n    );\n  }\n  if (card.kind === \"stat\") {\n    const v = (95 + Math.sin(index + frame / 30) * 5).toFixed(2);\n    return (\n      <div style={baseStyle}>\n        {labelEl}\n        <div\n          style={{\n            alignItems: \"center\",\n            display: \"flex\",\n            flex: 1,\n            fontSize: 48,\n            fontWeight: 700,\n            letterSpacing: \"-0.03em\",\n          }}\n        >\n          {v}\n          <span\n            style={{\n              color: \"rgba(255,255,255,0.5)\",\n              fontSize: 20,\n              marginLeft: 4,\n            }}\n          >\n            %\n          </span>\n        </div>\n      </div>\n    );\n  }\n  if (card.kind === \"code\") {\n    return (\n      <div style={{ ...baseStyle, padding: 0 }}>\n        <div style={{ alignItems: \"center\", display: \"flex\", flex: 1 }}>\n          <div style={{ width: \"100%\" }}>\n            <CodeCard />\n          </div>\n        </div>\n      </div>\n    );\n  }\n  if (card.kind === \"logo\") {\n    return (\n      <div style={{ ...baseStyle, padding: 0 }}>\n        <LogoCard accent={accent} hue={card.hue} />\n      </div>\n    );\n  }\n  // gradient\n  return (\n    <div style={{ ...baseStyle, padding: 0 }}>\n      <GradientCard hue={card.hue} />\n    </div>\n  );\n};\n\nexport interface InfiniteBentoPanProps {\n  panSpeed?: number;\n  accentColor?: string;\n  speed?: number;\n  fps?: number;\n  durationInFrames?: number;\n  width?: number;\n  height?: number;\n  className?: string;\n}\n\nexport const InfiniteBentoPan = ({\n  panSpeed = 1,\n  accentColor = \"#7c3aed\",\n  speed = 1,\n  fps = 30,\n  durationInFrames = 300,\n  width = 1280,\n  height = 720,\n  className,\n}: InfiniteBentoPanProps) => {\n  const safeSpeed = Math.max(0.01, speed);\n  const panRate = Math.max(0.01, panSpeed);\n  const durationMs = (durationInFrames / fps) * 1000;\n\n  const maxX = SUPER_W - width;\n  const maxY = SUPER_H - height;\n\n  const containerStyle: CSSProperties = {\n    background: \"#050505\",\n    fontFamily: FONT_FAMILY,\n    height,\n    overflow: \"hidden\",\n    position: \"relative\",\n    width,\n  };\n\n  return (\n    <Timegroup\n      className={className}\n      duration={`${durationMs}ms`}\n      mode=\"fixed\"\n      style={containerStyle}\n    >\n      <>\n        <style>{`\n          @keyframes framecn-bento-pan {\n            from { transform: translate(0, 0); }\n            to { transform: translate(${-maxX}px, ${-maxY}px); }\n          }\n        `}</style>\n        <div\n          style={{\n            animation: `framecn-bento-pan ${durationMs / safeSpeed / panRate}ms linear backwards`,\n            height: SUPER_H,\n            left: 0,\n            position: \"absolute\",\n            top: 0,\n            width: SUPER_W,\n            willChange: \"transform\",\n          }}\n        >\n          {CARDS.map((c, i) => (\n            <Card key={i} card={c} accent={accentColor} index={i} frame={0} />\n          ))}\n        </div>\n        <div\n          style={{\n            background:\n              \"radial-gradient(circle at center, transparent 30%, rgba(0,0,0,0.85) 80%, #000 100%)\",\n            inset: 0,\n            pointerEvents: \"none\",\n            position: \"absolute\",\n          }}\n        />\n      </>\n    </Timegroup>\n  );\n};\n",
      "type": "registry:component",
      "target": "components/framecn/infinite-bento-pan.tsx"
    }
  ],
  "type": "registry:component"
}