Retour au catalogue
Marquee 3D
Marquee avec rotation perspective 3D sur les elements.
marqueesimple Both Responsive a11y
minimaluniversalstacked
Theme
"use client";
import { Sparkles } from "lucide-react";
interface Marquee3DItem {
text: string;
highlight?: boolean;
}
interface Marquee3DProps {
items?: Marquee3DItem[];
speed?: number;
}
const mockItems: Marquee3DItem[] = [
{ text: "Design Systems" },
{ text: "UI Engineering", highlight: true },
{ text: "Creative Dev" },
{ text: "Motion Design", highlight: true },
{ text: "Brand Identity" },
{ text: "Web Performance" },
{ text: "Accessibility", highlight: true },
{ text: "Prototyping" },
{ text: "Design Tokens" },
{ text: "Component Library", highlight: true },
];
export default function Marquee3D({
items = mockItems,
speed = 30,
}: Marquee3DProps) {
const doubled = [...items, ...items];
return (
<section
className="overflow-hidden"
style={{
padding: "5rem 0",
background: "var(--color-background-alt)",
perspective: "600px",
}}
>
<div
className="mb-10 text-center"
style={{ perspectiveOrigin: "center center" }}
>
<p
className="text-xs font-semibold uppercase tracking-widest"
style={{ color: "var(--color-foreground-light)" }}
>
Nos expertises
</p>
</div>
{/* Row 1 - tilted forward */}
<div
className="overflow-hidden mb-4"
style={{
transform: "rotateX(8deg) rotateY(-2deg)",
transformStyle: "preserve-3d",
}}
>
<div
className="flex gap-4 whitespace-nowrap"
style={{ animation: `marquee-3d-left ${speed}s linear infinite` }}
>
{doubled.map((item, i) => (
<div
key={`row1-${i}`}
className="inline-flex items-center gap-2 px-6 py-3 rounded-xl shrink-0 transition-shadow duration-300"
style={{
background: item.highlight ? "var(--color-accent)" : "var(--color-background-card)",
border: `1px solid ${item.highlight ? "var(--color-accent)" : "var(--color-border)"}`,
color: item.highlight ? "var(--color-background)" : "var(--color-foreground)",
boxShadow: "0 4px 16px rgba(0,0,0,0.15)",
}}
>
{item.highlight && <Sparkles size={14} />}
<span className="text-sm font-semibold tracking-wide">
{item.text}
</span>
</div>
))}
</div>
</div>
{/* Row 2 - tilted differently, reverse direction */}
<div
className="overflow-hidden"
style={{
transform: "rotateX(4deg) rotateY(3deg)",
transformStyle: "preserve-3d",
}}
>
<div
className="flex gap-4 whitespace-nowrap"
style={{ animation: `marquee-3d-right ${speed * 1.2}s linear infinite` }}
>
{[...doubled].reverse().map((item, i) => (
<div
key={`row2-${i}`}
className="inline-flex items-center gap-2 px-6 py-3 rounded-xl shrink-0"
style={{
background: "var(--color-background-card)",
border: "1px solid var(--color-border)",
color: "var(--color-foreground-muted)",
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
}}
>
<span className="text-sm font-medium tracking-wide">
{item.text}
</span>
</div>
))}
</div>
</div>
<style>{`
@keyframes marquee-3d-left {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
@keyframes marquee-3d-right {
from { transform: translateX(-50%); }
to { transform: translateX(0); }
}
`}</style>
</section>
);
}