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
| Prop | Type | Default | Description |
|---|---|---|---|
| header | TsunamiScrollHeader | DEMO_HEADER | Optional heading block above the strip. |
| header.eyebrow | string | — | Small mono-caps label — e.g. "The Work". |
| header.headline | string | — | Cal Sans display headline. |
| header.description | string | — | Optional body copy beneath the headline. |
| items | TsunamiItem[] | DEMO_ITEMS | Array of photo items. 6–12 recommended for a good scroll duration. |
| items[].image.src | string | — | Image URL. Portrait 2:3 ratio works best. |
| items[].image.alt | string | "" | Alt text for accessibility. |
| items[].image.blurDataURL | string | — | Sanity LQIP — shown as placeholder while image loads. |
| items[].image.objectPosition | string | "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.
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | string | — | Optional accent label above the headline. |
| headline | string | — | Display headline above the photo strip. |
| description | string | — | Optional body copy. |
| items | image[] | — | Array of Sanity image references. |
| theme | dark|light | dark | Section color scheme. |
Usage
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
]}
/>// Via Sanity BlockRenderer — no extra code needed.
// Add to a Page document in Studio:
// Sections → Add item → Tsunami Scroll Section