Component

Tsunami Scroll

Full-viewport sticky scroll section — a centered headline sits above a full-width strip of portrait photos that slides through horizontally as the user scrolls. Each card magnifies as it passes the viewport center using GSAP dock physics. Mobile falls back to native horizontal scroll-snap. Dark + light themes.

Preview

TsunamiScroll requires scroll interaction and a full-viewport canvas to animate — open the live preview to see it in action.

Open interactive preview →

How it works

The section takes up (N + 1) × 100vh of scroll height, where N is the number of photos. The inner content is position: sticky, so the viewport stays locked while GSAP translates the strip from off-screen right to off-screen left.

As the strip scrolls, each card's distance from the viewport center is computed each frame. Cards within the dock radius scale up (max 1×) using a cosine curve — cards further away shrink to 60%. The center card receives the deepest shadow; surrounding cards fade progressively.

On mobile (below 768px), GSAP is disabled entirely and the strip renders as a native horizontal flex row with scroll-snap-type: x mandatory.

Themes

theme="dark"

Light That Stays

Dark bg — card shadows use inset highlights

theme="light"

Light That Stays

White bg — layered gray drop shadows

Props

PropTypeDefaultDescription
headerTsunamiScrollHeaderDEMO_HEADEROptional heading block above the strip.
header.eyebrowstringSmall mono-caps label — e.g. "The Work".
header.headlinestringCal Sans display headline.
header.descriptionstringOptional body copy beneath the headline.
itemsTsunamiItem[]DEMO_ITEMSArray of photo items. 6–12 recommended for a good scroll duration.
items[].image.srcstringImage URL. Portrait 2:3 ratio works best.
items[].image.altstring""Alt text for accessibility.
items[].image.blurDataURLstringSanity LQIP — shown as placeholder while image loads.
items[].image.objectPositionstring"center"Sanity hotspot translated to CSS object-position.
theme"dark" | "light""dark"Color scheme. Dark uses inset ring shadows; light uses layered drop shadows.

Sanity fields

Available as tsunamiScrollSection in the Page builder. Add 6–12 photos for best effect.

PropTypeDefaultDescription
eyebrowstringOptional accent label above the headline.
headlinestringDisplay headline above the photo strip.
descriptionstringOptional body copy.
itemsimage[]Array of Sanity image references.
themedark|lightdarkSection color scheme.

Usage

tsx
import { TsunamiScroll } from '@/components/sections/tsunami-scroll'

<TsunamiScroll
  theme="dark"
  header={{
    eyebrow:     'The Work',
    headline:    'Light That Stays',
    description: 'Some light arrives and never really leaves.',
  }}
  items={[
    { image: { src: '/photos/01.jpg', alt: 'Coastal dusk' } },
    { image: { src: '/photos/02.jpg', alt: 'Mountain ridge' } },
    // ... 6–12 items recommended
  ]}
/>
tsx
// Via Sanity BlockRenderer — no extra code needed.
// Add to a Page document in Studio:
// Sections → Add item → Tsunami Scroll Section