Copy URL or Code
Paste to your AI coding assistant and say:
“Add this carousel with my team members”
“Make the cards bigger and less blurry”
“Speed up the animation and use a blue background”
Done. Your AI handles the rest.
/*
================================================================================
AI COMPONENT: Seamless Carousel
================================================================================
SETUP:
1. Run: npm install @paper-design/shaders
2. Create file: components/SeamlessCarousel.tsx
3. Copy this entire code block into that file
4. Import: import SeamlessCarousel from "@/components/SeamlessCarousel"
================================================================================
QUICK CUSTOMIZATION
================================================================================
| Property | Description |
|-------------------|--------------------------------------------|
| cardData | Array of {name, shape} objects for cards |
| cardSpacing | Distance between cards (default: 120px) |
| Background colors | Modify lava bubble rgba values |
| Card size | Change width: "8.4rem" to desired size |
================================================================================
FEATURES
================================================================================
- Glassmorphism cards with blur effect
- Liquid metal WebGL shader border effect
- Animated lava bubble background
- 3D depth perspective (center card larger)
- Smooth CSS transitions
- Infinite loop navigation
================================================================================
COMMON MODIFICATIONS
================================================================================
1. CARD CONTENT — Edit the cardData array:
const cardData = [
{ name: "ALICE", shape: "circle" },
{ name: "BOB", shape: "square" },
];
2. CARD SIZE — Change width value:
width: "8.4rem" → width: "12rem" (larger)
width: "8.4rem" → width: "6rem" (smaller)
3. CARD TEXTURE — Adjust glassmorphism:
background: "rgba(255,255,255,0.08)" → "rgba(255,255,255,0.15)" (more visible)
backdropFilter: "blur(12px)" → "blur(20px)" (more blur)
opacity: 0.2 (noise) → opacity: 0.4 (more texture)
4. ANIMATION SPEED — Change transition duration:
transition: "all 0.5s..." → "all 0.3s..." (faster)
transition: "all 0.5s..." → "all 0.8s..." (slower)
5. BACKGROUND COLOR — Modify lava bubble rgba values:
Yellow/gold: rgba(200, 160, 60, 0.9)
Blue: rgba(60, 100, 200, 0.9)
Purple: rgba(150, 80, 180, 0.9)
Green: rgba(60, 180, 100, 0.9)
================================================================================
SOURCE CODE
================================================================================
*/
"use client";
import { useState, useEffect, useRef } from "react";
import { liquidMetalFragmentShader, ShaderMount } from "@paper-design/shaders";
// Liquid Metal Edge component for card borders
function LiquidMetalEdge({ borderWidth = 3 }: { borderWidth?: number }) {
const containerRef = useRef<HTMLDivElement>(null);
const shaderMountRef = useRef<ShaderMount | null>(null);
useEffect(() => {
if (!containerRef.current) return;
shaderMountRef.current = new ShaderMount(
containerRef.current,
liquidMetalFragmentShader,
{
u_repetition: 2.5,
u_softness: 0.5,
u_shiftRed: 0.4,
u_shiftBlue: 0.3,
u_distortion: 0,
u_contour: 0.1,
u_angle: 90,
u_scale: 2,
u_shape: 0,
u_offsetX: 0,
u_offsetY: 0,
},
undefined,
0.6,
);
return () => {
if (shaderMountRef.current) {
shaderMountRef.current.dispose();
shaderMountRef.current = null;
}
};
}, []);
const maskImage = `linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)`;
return (
<div
style={{
position: "absolute",
inset: 0,
borderRadius: "0.75rem",
padding: borderWidth,
pointerEvents: "none",
WebkitMask: maskImage,
WebkitMaskComposite: "xor",
mask: maskImage,
maskComposite: "exclude",
overflow: "hidden",
}}
>
<div
ref={containerRef}
style={{
position: "absolute",
inset: -borderWidth,
borderRadius: "0.75rem",
}}
/>
</div>
);
}
// Keyframes for lava bubble animation
const lavaKeyframes = `
@keyframes moveInCircle {
0% { transform: rotate(0deg); }
50% { transform: rotate(180deg); }
100% { transform: rotate(360deg); }
}
@keyframes moveVertical {
0% { transform: translateY(-50%); }
50% { transform: translateY(50%); }
100% { transform: translateY(-50%); }
}
@keyframes moveHorizontal {
0% { transform: translateX(-50%) translateY(-10%); }
50% { transform: translateX(50%) translateY(10%); }
100% { transform: translateX(-50%) translateY(-10%); }
}
`;
// Shape SVG components - add more as needed
const shapes = {
circle: <circle cx="15" cy="15" r="12" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
square: <rect x="3" y="3" width="24" height="24" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
triangle: <polygon points="15,3 27,27 3,27" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
diamond: <polygon points="15,2 28,15 15,28 2,15" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
hexagon: <polygon points="15,2 26,8 26,22 15,28 4,22 4,8" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
star: <polygon points="15,2 18,11 28,11 20,17 23,27 15,21 7,27 10,17 2,11 12,11" fill="none" stroke="rgba(255,255,255,0.6)" strokeWidth="1.5" />,
};
// Card data - customize this array
const cardData = [
{ name: "CLAUDE", shape: "circle" },
{ name: "OPENAI", shape: "square" },
{ name: "GEMINI", shape: "triangle" },
{ name: "GROK", shape: "diamond" },
{ name: "LLAMA", shape: "hexagon" },
{ name: "MISTRAL", shape: "star" },
];
// Card content component
const CardContent = ({ name, shape }: { name: string; shape: string }) => (
<svg width="100%" height="100%" viewBox="0 0 100 160" preserveAspectRatio="xMidYMid slice">
<g transform="translate(10, 20)">
<svg width="30" height="30" viewBox="0 0 30 30">
{shapes[shape as keyof typeof shapes]}
</svg>
</g>
<text fill="rgba(255,255,255,0.7)" fontSize="6" fontFamily="monospace" x="10" y="115" letterSpacing="1">
•••• •••• ••••
</text>
<text fill="rgba(255,255,255,0.8)" fontSize="5" fontFamily="sans-serif" fontWeight="500" x="10" y="130">
{name}
</text>
</svg>
);
export default function SeamlessCarousel() {
const [currentIndex, setCurrentIndex] = useState(0);
const goNext = () => setCurrentIndex((prev) => (prev + 1) % cardData.length);
const goPrev = () => setCurrentIndex((prev) => (prev - 1 + cardData.length) % cardData.length);
const cardSpacing = 120;
const getCardStyle = (i: number): React.CSSProperties => {
const diff = i - currentIndex;
const offset = diff > cardData.length / 2 ? diff - cardData.length
: diff < -cardData.length / 2 ? diff + cardData.length : diff;
const absOffset = Math.abs(offset);
if (absOffset === 0) {
return { transform: "translateX(0) scale(1)", opacity: 1, zIndex: 10 };
} else if (absOffset === 1) {
return { transform: `translateX(${offset * cardSpacing}px) scale(0.7)`, opacity: 0.9, zIndex: 8 };
} else if (absOffset === 2) {
return { transform: `translateX(${offset * cardSpacing}px) scale(0.5)`, opacity: 0.7, zIndex: 6 };
} else {
return { transform: `translateX(${offset * cardSpacing}px) scale(0.4)`, opacity: 0, zIndex: 1 };
}
};
return (
<div style={{ position: "relative", width: "100%", height: "100vh", overflow: "hidden", background: "linear-gradient(40deg, rgb(45, 45, 50), rgb(30, 30, 35))" }}>
{/* SVG filter for gooey effect */}
<svg xmlns="http://www.w3.org/2000/svg" style={{ position: "absolute", width: 0, height: 0 }}>
<defs>
<filter id="lava-goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -8" result="goo" />
<feBlend in="SourceGraphic" in2="goo" />
</filter>
</defs>
</svg>
{/* Base gradient background */}
<div style={{ position: "absolute", inset: 0, background: "linear-gradient(40deg, rgb(45, 35, 25), rgb(60, 50, 35))", zIndex: 0 }} />
{/* Lava bubbles layer - modify rgba colors to change appearance */}
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 1, pointerEvents: "none" }}>
<div style={{ width: "100%", height: "100%", filter: "url(#lava-goo) blur(40px)" }}>
<div style={{ position: "absolute", background: "radial-gradient(circle at center, rgba(200, 160, 60, 0.9) 0, rgba(200, 160, 60, 0) 50%)", mixBlendMode: "hard-light", width: "80%", height: "80%", top: "calc(50% - 40%)", left: "calc(50% - 40%)", transformOrigin: "center center", animation: "moveVertical 8s ease infinite" }} />
<div style={{ position: "absolute", background: "radial-gradient(circle at center, rgba(220, 140, 50, 0.9) 0, rgba(220, 140, 50, 0) 50%)", mixBlendMode: "hard-light", width: "80%", height: "80%", top: "calc(50% - 40%)", left: "calc(50% - 40%)", transformOrigin: "calc(50% - 400px)", animation: "moveInCircle 6s reverse infinite" }} />
<div style={{ position: "absolute", background: "radial-gradient(circle at center, rgba(180, 130, 40, 0.9) 0, rgba(180, 130, 40, 0) 50%)", mixBlendMode: "hard-light", width: "80%", height: "80%", top: "calc(50% - 40% + 200px)", left: "calc(50% - 40% - 500px)", transformOrigin: "calc(50% + 400px)", animation: "moveInCircle 10s linear infinite" }} />
<div style={{ position: "absolute", background: "radial-gradient(circle at center, rgba(240, 200, 100, 0.85) 0, rgba(240, 200, 100, 0) 50%)", mixBlendMode: "hard-light", width: "80%", height: "80%", top: "calc(50% - 40%)", left: "calc(50% - 40%)", transformOrigin: "calc(50% - 200px)", animation: "moveHorizontal 10s ease infinite" }} />
</div>
</div>
{/* Keyframes */}
<style dangerouslySetInnerHTML={{ __html: lavaKeyframes }} />
{/* Cards */}
<div style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", width: "8.4rem", height: "14.9rem", zIndex: 5 }}>
{cardData.map((card, i) => (
<div key={i} style={{
position: "absolute", top: 0, left: 0, width: "8.4rem", aspectRatio: "9/16", borderRadius: "0.75rem",
background: "rgba(255,255,255,0.08)", backdropFilter: "blur(12px)", WebkitBackdropFilter: "blur(12px)",
display: "flex", alignItems: "center", justifyContent: "center",
boxShadow: "0 8px 32px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.15)",
overflow: "hidden", transition: "all 0.5s cubic-bezier(0.4, 0, 0.2, 1)", ...getCardStyle(i),
}}>
{/* Noise texture */}
<div style={{ position: "absolute", inset: 0, backgroundImage: "url(https://assets.codepen.io/721952/whiteNoise2.png)", backgroundSize: "100px 100px", opacity: 0.2, pointerEvents: "none" }} />
{/* Glossy highlight */}
<div style={{ position: "absolute", inset: 0, background: "linear-gradient(135deg, rgba(255,255,255,0.2) 0%, rgba(255,255,255,0.05) 40%, rgba(255,255,255,0) 60%)", pointerEvents: "none" }} />
{/* Liquid Metal Edge */}
<LiquidMetalEdge borderWidth={3} />
{/* Content */}
<div style={{ position: "absolute", inset: 8, zIndex: 1 }}>
<CardContent name={card.name} shape={card.shape} />
</div>
</div>
))}
</div>
{/* Navigation */}
<div style={{ position: "absolute", bottom: 40, left: "50%", transform: "translateX(-50%)", display: "flex", gap: "1rem", zIndex: 10 }}>
<button onClick={goPrev} style={{ padding: "0.6rem", background: "rgba(255,255,255,0.1)", border: "1px solid rgba(255,255,255,0.25)", borderRadius: "50%", color: "rgba(255,255,255,0.8)", cursor: "pointer", fontSize: "1rem", backdropFilter: "blur(8px)", width: "2.5rem", height: "2.5rem", display: "flex", alignItems: "center", justifyContent: "center" }}>◀</button>
<button onClick={goNext} style={{ padding: "0.6rem", background: "rgba(255,255,255,0.1)", border: "1px solid rgba(255,255,255,0.25)", borderRadius: "50%", color: "rgba(255,255,255,0.8)", cursor: "pointer", fontSize: "1rem", backdropFilter: "blur(8px)", width: "2.5rem", height: "2.5rem", display: "flex", alignItems: "center", justifyContent: "center" }}>▶</button>
</div>
</div>
);
}import SeamlessCarousel from "@/components/SeamlessCarousel";
// Basic usage - full page carousel
export default function HomePage() {
return <SeamlessCarousel />;
}
// Customize card data by editing the cardData array in the component:
const cardData = [
{ name: "YOUR NAME", shape: "circle" },
{ name: "TEAMMATE", shape: "square" },
{ name: "PARTNER", shape: "triangle" },
];