Hero Background

The visual backdrop of the homepage hero — radial gradient, dark vignette, bottom fade, and a canvas-based starfield with shooting meteors (dark mode only).

Gradient + vignette

Combines .hero-gradient — a multi-stop radial gradient blending --accent-deep --accent --hero-glow-magenta → background — with .hero-vignette, a radial dark mask centred on the section to keep text legible.

Stars animation (dark mode)

HeroStars draws a canvas starfield with slow-drifting stars and periodic shooting meteors. Hidden in light mode via [[data-theme=light]_&]:hidden. Uses an IntersectionObserver to pause the animation when off-screen.

Bottom fade

.fade-to-background is a linear-to-bottom gradient that blends the hero into the page background beneath it.

HeroStars props

starVelocity

number (default: 1)

Multiplier for star drift speed. 0 freezes stars; 2 doubles speed.

shootingStarsOpacity

number (default: 1)

Opacity multiplier for meteor trails. Set to 0 to disable meteors.

CSS classes

.hero-gradient

Multi-stop radial gradient from accent-deep → accent → hero-glow-magenta → background.

.hero-vignette

Radial dark mask centred on the section for text legibility.

.fade-to-background

Linear bottom fade from transparent → background. Applied to the bottom 40% of the hero.

Usage

tsx
{/* Background layers — stack order matters */}
<section className="relative overflow-hidden">
  <div className="hero-gradient pointer-events-none absolute inset-0 z-0" />
  <div className="hero-vignette pointer-events-none absolute inset-0 z-0" />

  {/* Stars — dark mode only */}
  <div className="pointer-events-none absolute inset-0 z-[1] [[data-theme=light]_&]:hidden">
    <HeroStars starVelocity={1} shootingStarsOpacity={1} />
  </div>

  {/* Bottom fade */}
  <div className="fade-to-background pointer-events-none absolute inset-x-0 bottom-0 z-[2] h-[40%]" />

  {/* Content above layers */}
  <div className="relative z-10">
    <h1 className="heading-h1 tracking-tight">Title</h1>
  </div>
</section>

Import

tsx
import dynamic from 'next/dynamic'

const HeroStars = dynamic(
  () => import('@/components/ui/HeroStars').then(mod => ({ default: mod.HeroStars })),
  { ssr: false }
)

Related files

src/components/ui/HeroStars.tsxsrc/app/globals.css — .hero-gradient, .hero-vignette, .fade-to-backgroundsrc/components/sections/Hero.tsx