Continuous autonomous looping · Stop on hover · Edge alpha gradient masks · 60fps GPU transforms
Premium homes in the most desirable locations.
To loop infinitely without visual jitter or frame jumps, the container renders two identical track children. The CSS transform shifts exactly 100% of the track width PLUS the gap value:
When Track 1 reaches -100% - var(--gap), Track 2 has occupied the exact subpixel coordinates where Track 1 started. The animation instantly resets to 0% with 0px visual discrepancy.
transform: translateX() and will-change: transform ensures the entire marquee runs on the compositor thread without triggering layout reflows or repaints.
animation-play-state: paused. Unlike JS-based tick cancellations, the browser retains exact animation timing so movement resumes fluidly without rewinding.
mask-image. This creates an optical vignette that avoids harsh window clipping on wide displays.
import { cn } from "@/lib/utils";
interface MarqueeProps {
className?: string;
reverse?: boolean;
pauseOnHover?: boolean;
children?: React.ReactNode;
vertical?: boolean;
repeat?: number;
[key: string]: any;
}
export function Marquee({
className,
reverse = false,
pauseOnHover = false,
children,
vertical = false,
repeat = 4,
...props
}: MarqueeProps) {
return (
<div
{...props}
className={cn(
"group flex overflow-hidden p-2 [--duration:40s] [--gap:1rem] [gap:var(--gap)]",
{
"flex-row": !vertical,
"flex-col": vertical,
},
className
)}
>
{Array(repeat)
.fill(0)
.map((_, i) => (
<div
key={i}
className={cn("flex shrink-0 justify-around [gap:var(--gap)]", {
"animate-marquee flex-row": !vertical,
"animate-marquee-vertical flex-col": vertical,
"group-hover:[animation-play-state:paused]": pauseOnHover,
"[animation-direction:reverse]": reverse,
})}
>
{children}
</div>
))}
</div>
);
}
Detailed luxury property description...