Rows of bold black-and-white typography wrapped into a rotating cylinder. The camera drifts between reading the folded text wall and staring straight down the vortex, with the far wall ghosting through the gaps. Feed it your own manifesto lines.
import WordTunnel from '@crazygl/hero-word-tunnel';
export default function Page() {
return (
<WordTunnel
phrases={'BUILD THE FUTURE\nSHIP WITH INTENT\nFORM MEETS FUNCTION\nDETAILS DECIDE'}
spinSpeed={1}
cameraCycle
/>
);
}phrases accepts a newline-separated string (as the customizer edits it) or an array of strings from code — each line becomes one ring of the tunnel.
phrases (8–12 short lines look best), headingFontFamily (bold tight sans-serifs read best), italicAlternate for the editorial every-other-row italics.spinSpeed, rowDrift (rows slide against each other), cameraCycle + cycleSeconds for the wall↔vortex journey, ghostOpacity for the mirrored far-wall text showing through the gaps.textColor, bgColor. Monochrome white-on-black is the signature look; try warm paper tones for an editorial variant.npm install @crazygl/hero-word-tunnelThe component takes the same props you see in the live customizer on the right — every default ships poster-quality.
import WordTunnel from '@crazygl/hero-word-tunnel';
export default function Landing() {
return (
<WordTunnel />
);
}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 WordTunnel from '@crazygl/hero-word-tunnel';
export default function Page() {
return (
<section>
<WordTunnel
heading="Say hi."
subheading="Your new hero."
/>
<article>
<h2>Welcome</h2>
<p>Your content keeps its own voice below the hero.</p>
</article>
</section>
);
}