{ "$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 background?: 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 background = \"#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