Your main product screenshot sits on top of a stack of secondary UI cards. The front card swoops up and over to the back at a configurable interval, autonomously cycling through every screen. Soft drop shadows, a cyan edge glow on the top card, cursor parallax tilt.
import HeroCardStack from '@crazygl/hero-card-stack';
export default function Hero() {
return (
<HeroCardStack
heading="One product, every module."
subheading="Watch the deck cycle through every screen."
screenshot1="/screens/dashboard.png"
screenshot2="/screens/builder.png"
screenshot3="/screens/editor.png"
cycleInterval={3.5}
/>
);
}heading / subheading, or switch contentType to two-columns / custom for richer copy.screenshot1..5, one image per card. Screenshot 1 is the top (most visible) card, 5 is the bottom. Each card adopts its image's own aspect ratio.cardCount (2–6), stackOffsetX/Y/Z, cardSize, cardCornerRadius, plus groupOffsetX/Y to position the whole deck.flipCycle toggles the auto-cycle; cycleInterval (seconds) sets the pace.cursorTilt for pointer parallax, ambientFloat for a gentle continuous bob.edgeGlowColor / edgeGlowStrength, shadowStrength, keyColor / fillColor, screenBrightness, and bgTop / bgBottom gradient.npm install @crazygl/hero-card-stackThe component takes the same props you see in the live customizer on the right — every default ships poster-quality.
import ScreenshotAsA3DCardStack from '@crazygl/hero-card-stack';
export default function Landing() {
return (
<ScreenshotAsA3DCardStack />
);
}The wrapper renders static HTML on the server and only initialises the canvas after hydration, so search engines see your copy.
// app/page.tsx — works in SSR-first frameworks (Next, Remix, Astro, etc.)
'use client';
import ScreenshotAsA3DCardStack from '@crazygl/hero-card-stack';
export default function Page() {
return (
<section>
<ScreenshotAsA3DCardStack
heading="Say hi."
subheading="Your new hero."
/>
<article>
<h2>Welcome</h2>
<p>Your content keeps its own voice below the hero.</p>
</article>
</section>
);
}