remocn logoremocn

Infinite Marquee

A continuously scrolling horizontal text strip that loops seamlessly.

A typography primitive that translates a row of duplicated text spans on the X axis at a fixed pixel-per-frame rate. The offset is taken mod the approximate width of one repetition so the loop is seamless and fully deterministic.

Installation

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

Usage

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

const InfiniteMarqueeScene = () => (
  <InfiniteMarquee text="ship · build · animate · " pixelsPerFrame={4} stroke />
);

export const RemotionRoot = () => (
  <Composition
    id="InfiniteMarquee"
    component={InfiniteMarqueeScene}
    durationInFrames={180}
    fps={30}
    width={1280}
    height={720}
  />
);

Props

PropTypeDefaultDescription
text
string"ship · build · animate · "Text repeated across the marquee. Include trailing whitespace or punctuation for spacing.
fontSize
number120Font size in pixels.
color
string"#171717"Text color when `stroke` is false.
fontWeight
number900CSS font-weight.
pixelsPerFrame
number4Horizontal scroll speed in pixels per frame.
stroke
booleanfalseRender outlined text via `-webkit-text-stroke` instead of filled.
strokeColor
string"#171717"Stroke color used when `stroke` is true.
background
string"#fafafa"Background color of the root container.
speed
number1Playback speed multiplier.
className
stringOptional className passed to the translating row.

Notes

Seamless looping

Width is approximated as text.length * fontSize * 0.55. For very wide or very narrow fonts you may see a small jump on loop — tweak the multiplier to match your typeface, or pass a longer text to make any seam imperceptible.

No layout reads

This component intentionally avoids useRef / measurement so it stays render-deterministic. If you need pixel-perfect looping for a specific font, hard-code the repetition width via text length and fontSize.