Six raymarched octahedral crystals drift across the screen, refracting the background through each face with per-channel chromatic dispersion at the rim.
import CrystalRefractionField from '@crazygl/hero-crystal-refraction';
export default function Page() {
return (
<CrystalRefractionField
heading="Refracted."
subheading="Six crystals drifting through space, refracting everything behind them."
backgroundImage="https://crazygl.com/samples/nature4.avif"
crystalCount={6}
refraction={1}
chromatic={1}
/>
);
}contentType (heading / two-columns / custom), heading, subheading, or custom nodes.backgroundImage (cover-fit, refracted through the crystals), or bgFallbackA/B/C for the procedural gradient.centerX, centerY position the cluster in the frame.crystalCount, orbitRadius, orbitTilt, radiusJitter, bobAmount, orbitSpeed, spinSpeed.tint, rimColor, refraction, chromatic, fresnel, crystalSize, speed (master time scale).headingFontFamily.npm install @crazygl/hero-crystal-refractionThe component takes the same props you see in the live customizer on the right — every default ships poster-quality.
import CrystalRefractionField from '@crazygl/hero-crystal-refraction';
export default function Landing() {
return (
<CrystalRefractionField />
);
}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 CrystalRefractionField from '@crazygl/hero-crystal-refraction';
export default function Page() {
return (
<section>
<CrystalRefractionField
heading="Say hi."
subheading="Your new hero."
/>
<article>
<h2>Welcome</h2>
<p>Your content keeps its own voice below the hero.</p>
</article>
</section>
);
}