Several mobile screenshots float inside transparent neon phone frames, fanned out in a translucent stack. Outlines pulse left-to-right in a swipe-like wave and the whole stack bends gently with the cursor.
import NeonPhoneStack from '@crazygl/hero-neon-phone-stack';
export default function Page() {
return (
<NeonPhoneStack
heading="Built for the feed."
screenshot1="https://crazygl.com/samples/screenshot-phone-dark-A.avif"
phoneSpread={2.85}
outlineColor1="#56e3ff"
/>
);
}contentType (heading / two-columns / custom) with heading + subheading or your own nodes.screenshot1–screenshot5 (image or short video; vertical 9:19.5 crops fit best, others cover-fit).phoneSpread, mainScale, phoneSizeReduction, depthOffset shape the fan.outlineColor1–5, outlineIntensity, outlineWidth, bodyTransmission (screen transparency), screenEmissive.swipeEnabled, swipePeriod, swipeBoost drive the swipe pulse.gridEnabled / gridColor / gridIntensity, haloStrength, bgTop / bgBottom, transparentBackground.parallaxStrength and bendStrength for pointer response.npm install @crazygl/hero-neon-phone-stackThe component takes the same props you see in the live customizer on the right — every default ships poster-quality.
import NeonGlassPhoneStack from '@crazygl/hero-neon-phone-stack';
export default function Landing() {
return (
<NeonGlassPhoneStack />
);
}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 NeonGlassPhoneStack from '@crazygl/hero-neon-phone-stack';
export default function Page() {
return (
<section>
<NeonGlassPhoneStack
heading="Say hi."
subheading="Your new hero."
/>
<article>
<h2>Welcome</h2>
<p>Your content keeps its own voice below the hero.</p>
</article>
</section>
);
}