A 3D product begins disassembled and clicks together as you scroll the page. Once whole, the camera eases in and benefit labels fade in around it. Cinematic three-point studio lighting with HDRI reflections.
import ScrollAssembleProduct from '@crazygl/hero-scroll-assemble-product';
<ScrollAssembleProduct
productModel="https://crazygl.com/samples/camera.glb"
assembleEnd={0.63}
explodeDistance={1.05}
cameraPathAmount={0.3}
/>;productModel (GLB/GLTF), modelScale, restSpin (the angle the finished product faces). Multi-mesh files assemble per part; single-mesh models slice into fallbackBands clean bands along their longest axis.scrollLength (sticky scroll height, vh), explodeDistance / explodeFromAxis (spread along vs. away from the cut axis), assembleEnd (scroll % at which it's whole), swirlAmount, restBreath.showLabels, benefitLabels (one per line, up to six), accentColor for the connector dot / leader line.cameraDistance, cameraPathAmount (reveal dolly; 0 locks the camera).environmentImage (studio HDRI), envIntensity, exposure, plus key / fill / rim colour + intensity.transparent, bgTopColor, bgBottomColor.npm install @crazygl/hero-scroll-assemble-productThe component takes the same props you see in the live customizer on the right — every default ships poster-quality.
import ScrolltoAssembleProduct from '@crazygl/hero-scroll-assemble-product';
export default function Landing() {
return (
<ScrolltoAssembleProduct />
);
}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 ScrolltoAssembleProduct from '@crazygl/hero-scroll-assemble-product';
export default function Page() {
return (
<section>
<ScrolltoAssembleProduct
heading="Say hi."
subheading="Your new hero."
/>
<article>
<h2>Welcome</h2>
<p>Your content keeps its own voice below the hero.</p>
</article>
</section>
);
}