{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "perspective-marquee",
  "title": "Perspective Marquee",
  "description": "A 3D-tilted infinite marquee with depth-of-field blur on items rolling toward the horizon.",
  "dependencies": ["remotion"],
  "files": [
    {
      "path": "registry/remocn/perspective-marquee/index.tsx",
      "content": "\"use client\";\n\nimport { useCurrentFrame } from \"remotion\";\n\nexport interface PerspectiveMarqueeProps {\n  items?: string[];\n  fontSize?: number;\n  color?: string;\n  fontWeight?: number;\n  pixelsPerFrame?: number;\n  rotateY?: number;\n  rotateX?: number;\n  perspective?: number;\n  fadeColor?: string;\n  speed?: number;\n  className?: string;\n}\n\nconst FONT_FAMILY =\n  \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\";\n\nconst DEFAULT_ITEMS = [\n  \"Vercel\",\n  \"Linear\",\n  \"Stripe\",\n  \"Figma\",\n  \"Notion\",\n  \"Raycast\",\n  \"Arc\",\n  \"Cursor\",\n];\n\nexport function PerspectiveMarquee({\n  items = DEFAULT_ITEMS,\n  fontSize = 84,\n  color = \"#fafafa\",\n  fontWeight = 700,\n  pixelsPerFrame = 2,\n  rotateY = -28,\n  rotateX = 8,\n  perspective = 1200,\n  fadeColor = \"#050505\",\n  speed = 1,\n  className,\n}: PerspectiveMarqueeProps) {\n  const frame = useCurrentFrame() * speed;\n\n  // Approximate width of one full item set so the modulo wraps cleanly.\n  const itemPadding = fontSize * 0.9;\n  const approxItemWidth = items.reduce(\n    (acc, item) => acc + item.length * fontSize * 0.6 + itemPadding,\n    0,\n  );\n\n  const offset = -((frame * pixelsPerFrame) % approxItemWidth);\n\n  // Render the row 3x so the loop is seamless even when rotated in 3D.\n  const rendered = [...items, ...items, ...items];\n\n  return (\n    <div\n      className={className}\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        display: \"flex\",\n        alignItems: \"center\",\n        justifyContent: \"center\",\n        overflow: \"hidden\",\n        perspective: `${perspective}px`,\n      }}\n    >\n      <div\n        style={{\n          width: \"100%\",\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"flex-start\",\n          transform: `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`,\n          transformStyle: \"preserve-3d\",\n        }}\n      >\n        <div\n          style={{\n            display: \"flex\",\n            whiteSpace: \"nowrap\",\n            translate: `${offset}px`,\n          }}\n        >\n          {rendered.map((item, i) => {\n            // Approximate this item's center X (relative to the marquee row,\n            // including the rolling offset). Used to dial in depth-of-field blur\n            // and opacity by horizontal position on screen.\n            const itemCenter =\n              i * (approxItemWidth / items.length) +\n              approxItemWidth / items.length / 2 +\n              offset;\n            // Normalize roughly to [-1, 1] across a 1280px viewport.\n            const norm = (itemCenter - 640) / 640;\n            const distance = Math.min(1, Math.abs(norm));\n            const blurPx = distance * 6;\n            const opacity = 1 - distance * 0.4;\n\n            return (\n              <span\n                key={i}\n                style={{\n                  display: \"inline-block\",\n                  fontFamily: FONT_FAMILY,\n                  fontSize,\n                  fontWeight,\n                  color,\n                  letterSpacing: \"-0.03em\",\n                  paddingRight: itemPadding,\n                  filter: `blur(${blurPx}px)`,\n                  opacity,\n                }}\n              >\n                {item}\n              </span>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Vignette to fade marquee edges into background */}\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          pointerEvents: \"none\",\n          background: `linear-gradient(90deg, ${fadeColor} 0%, transparent 18%, transparent 82%, ${fadeColor} 100%)`,\n        }}\n      />\n      <div\n        style={{\n          position: \"absolute\",\n          inset: 0,\n          pointerEvents: \"none\",\n          background: `linear-gradient(180deg, ${fadeColor} 0%, transparent 25%, transparent 75%, ${fadeColor} 100%)`,\n        }}\n      />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/perspective-marquee.tsx"
    }
  ],
  "type": "registry:component"
}
