Component
HeroParallax
Full-viewport hero with 5 independent depth planes driven by mousemove. Each layer has a distinct transition duration — the lag differential between layers creates the sense of depth. Clip-path wipe reveal on mount with opacity fade-in.
Preview
Documentary Photography
The World Through Glass
View the Work
Move cursor to parallax
No CTA
Documentary Photography
The World Through Glass
Move cursor to parallax
Depth planes
z:1Photo
±40px opposite cursor0.15s ease-outDeepest plane — most movement, fastest response
z:2Vignette
±22px opposite cursor0.28s ease-outRadial gradient — lags behind photo
z:3Film grain
±9px opposite cursor0.45s ease-outSVG noise texture — barely moves, most lag
z:4Bottom scrim
FixedNoneLinear gradient — no parallax
z:5Text
±14px WITH cursor0.12s ease-outForeground — moves forward, snaps fast
Mount animation
clipPathinset(0 100% 0 0) → inset(0 0% 0 0)1.5s[0.22,1,0.36,1] expo-out0.3sopacity0 → 12.0s[0.64,0,0.78,0] expo-in0.3sProps
| Prop | Type | Default | Description |
|---|---|---|---|
| src | string | — | Hero image URL — loaded with next/image priority |
| alt | string | — | Alt text for the hero image |
| eyebrow | string | — | Small uppercase label above the headline |
| headline | ReactNode | — | Headline — typically an <h1> with className="hero-headline" |
| cta | { label, href } | — | Optional CTA button (frosted glass variant) |
| className | string | "hero-section" | Root class — controls sizing via globals.css |
Usage
tsx
import { HeroParallax } from '@/components/hero-parallax'
<HeroParallax
src="https://cdn.sanity.io/images/orbu72vm/production/..."
alt="Columbia River Gorge at golden hour"
eyebrow="Documentary Photography"
headline={
<h1 className="hero-headline">
The World<br />Through Glass
</h1>
}
cta={{ label: 'View the Work', href: '/landscape' }}
/>