This component no longer exists. It was in remotionui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-11 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
perspective-marquee
remotionui/perspective-marqueeRemovedComponent
Marquee tilted in 3D with depth fade
Live preview
live · rendered by the registry
Rendered by remotionui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://remotionui.com/r/perspective-marquee.jsonSource
1import { measureText } from "@remotion/layout-utils";2import { useMemo } from "react";3import { useCurrentFrame, useVideoConfig } from "remotion";4import { scaleFont } from "@/remotion/lib/layout";56export type PerspectiveMarqueeProps = {7 text: string;8 /** Scroll speed in px per frame along the floor plane. */9 speed?: number;10 fontSize?: number;11 color?: string;12 fontWeight?: number;13 fontFamily?: string;14 gap?: number;15 /** Floor plane tilt in degrees — higher values exaggerate depth. */16 floorTilt?: number;17 /** Perspective distance in px — lower values exaggerate depth. */18 perspective?: number;19 showFloorGrid?: boolean;20};2122function getItemWidth(23 text: string,24 fontSize: number,25 fontWeight: number,26 fontFamily?: string,27) {28 const family = fontFamily ?? "system-ui";2930 if (typeof document !== "undefined") {31 return measureText({32 text,33 fontFamily: family,34 fontSize,35 fontWeight: String(fontWeight),36 }).width;37 }3839 return text.length * fontSize * 0.55;40}4142export const PerspectiveMarquee: React.FC<PerspectiveMarqueeProps> = ({43 text,44 speed = 10,45 fontSize: fontSizeProp,46 color = "#f4f4f5",47 fontWeight = 600,48 fontFamily,49 gap = 72,50 floorTilt = 70,51 perspective = 640,52 showFloorGrid = true,53}) => {54 const frame = useCurrentFrame();55 const { width, height } = useVideoConfig();56 const fontSize = fontSizeProp ?? scaleFont(56, width);57 const farFontSize = Math.round(fontSize * 0.58);58 const farGap = Math.round(gap * 1.1);59 const displayText = text.toUpperCase();6061 const { repetitions, nearLoopWidth, loopPeriodFrames } = useMemo(() => {62 const nearItemWidth = getItemWidth(63 displayText,64 fontSize,65 fontWeight,66 fontFamily,67 );68 const count = Math.max(4, Math.ceil(width / nearItemWidth) + 2);69 const nearLoop =70 count * nearItemWidth + count * gap;7172 return {73 repetitions: count,74 nearLoopWidth: nearLoop,75 loopPeriodFrames: Math.max(1, Math.round(nearLoop / speed)),76 };77 }, [displayText, fontFamily, fontSize, fontWeight, gap, speed, width]);7879 const progress = (frame % loopPeriodFrames) / loopPeriodFrames;80 const scrollX = -progress * 50;8182 const items = useMemo(83 () =>84 Array.from({ length: repetitions * 2 }, (_, i) => (85 <span key={i}>{text}</span>86 )),87 [repetitions, text],88 );8990 const horizonTop = Math.round(height * 0.34);91 const planeHeight = Math.round(height * 0.9);92// … truncated
