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'}
spinEven={0.6}
spinOdd={-0.6}
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, tiled to infinity in both directions.
phrases (8–12 short lines look best), headingFontFamily (bold tight sans-serifs read best), italicAlternate for the editorial every-other-row italics.spinEven / spinOdd (independent speed and direction per row parity), ringRepeat (how many times the row set tiles down the tunnel), cameraCycle + cycleSeconds for the endless journey (vortex → wall → opposite vortex → other wall → …), ghostOpacity for the mirrored far-wall text.cameraFov (wide = dramatic vortex, narrow = flat editorial), tunnelRadius, fogDistance (how deep you can see before the rings die into black).textColor, bgColor. Monochrome white-on-black is the signature look.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>
);
}