remocn logoremocn

Perspective Marquee

A 3D-tilted infinite marquee with depth-of-field blur on items rolling toward the horizon.

A typography primitive that takes the seamless modulo-based loop from InfiniteMarquee and tilts it in 3D space using CSS perspective and rotateX/Y. Items further from the viewport center receive progressively heavier filter: blur() and lower opacity, mimicking depth of field. Edge vignettes fade the marquee into the background so the loop is invisible.

Installation

$ pnpm dlx shadcn@latest add @remocn/perspective-marquee

Usage

// src/Root.tsx
import { Composition } from "remotion";
import { PerspectiveMarquee } from "@/components/remocn/perspective-marquee";

const PerspectiveMarqueeScene = () => (
  <PerspectiveMarquee
    items={["Vercel", "Linear", "Stripe", "Figma"]}
    rotateY={-28}
    pixelsPerFrame={2}
  />
);

export const RemotionRoot = () => (
  <Composition
    id="PerspectiveMarquee"
    component={PerspectiveMarqueeScene}
    durationInFrames={240}
    fps={30}
    width={1280}
    height={720}
  />
);

Props

PropTypeDefaultDescription
items
string[]["Vercel", "Linear", "Stripe", "Figma", "Notion", "Raycast", "Arc", "Cursor"]Items rendered in the marquee. Repeated three times under the hood for a seamless loop.
fontSize
number84Font size in pixels.
color
string"#fafafa"Text color of each item.
fontWeight
number700CSS font-weight.
pixelsPerFrame
number2Horizontal scroll speed in pixels per frame.
rotateY
number-28Y-axis rotation in degrees applied to the marquee row.
rotateX
number8X-axis rotation in degrees applied to the marquee row.
perspective
number1200CSS perspective in pixels on the parent.
fadeColor
string"#050505"Color used in the edge vignette gradients.
background
string"#050505"Root container background color.
speed
number1Playback speed multiplier.
className
stringOptional className passed to the root container.

Notes

Slow is hypnotic

Keep pixelsPerFrame between 1 and 3. The 3D tilt amplifies perceived speed — anything faster reads as motion sickness.

Match `fadeColor` to `background`

The vignette assumes fadeColor === background. If they differ you will see hard edges where the marquee ends and the background begins.