component
Full-viewport sticky scroll slider with GSAP-driven strip-mask transitions and animated title swaps.
Dependencies
Installation
ScrollGallery is a client component that uses GSAP ScrollTrigger to pin the section while the user scrolls through slides. Each transition uses a 20-strip CSS mask-image wipe and a scale effect (1.25 → 1.0). The title band swaps with a GSAP slide animation at 30% through each transition.
Usage
Basic
import { ScrollGallery } from "@/components/sora-ui/effects/scroll-gallery";
const slides = [
{ title: "Room 14B", image: "/images/slide-1.jpg", url: "/project/1" },
{ title: "Subject Identified", image: "/images/slide-2.jpg", url: "/project/2" },
];
export default function Page() {
return <ScrollGallery slides={slides} />;
}Studio preset
Deadlock Studios featured-work typography and layout — import SCROLL_GALLERY_STUDIO_CLASSES and spread into *ClassName props:
import {
SCROLL_GALLERY_STUDIO_CLASSES as studio,
ScrollGallery,
} from "@/components/sora-ui/effects/scroll-gallery";
<ScrollGallery
className={studio.root}
imagesClassName={studio.images}
imageClassName={studio.image}
imageFrameClassName={studio.imageFrame}
infoClassName={studio.info}
infoInnerClassName={studio.infoInner}
prefixClassName={studio.prefix}
prefixTextClassName={studio.prefixText}
titleClassName={studio.title}
titleTextClassName={studio.titleText}
linkClassName={studio.link}
linkTextClassName={studio.linkText}
slides={slides}
prefixLabel="Featured"
linkLabel="Explore"
/>;Custom labels & timing
<ScrollGallery
slides={slides}
prefixLabel="Projects"
linkLabel="View case study"
showPrefix={false}
scrollPerTransition={800}
timing={{
titleChangeThreshold: 0.25,
scaleFrom: 1.15,
stripRevealSpeed: 2.5,
}}
/>Place ScrollGallery at the root scroll level of the page. GSAP pin requires the section to scroll within window — it will not work correctly inside a custom scroll container unless you pass scroller.
Use high-quality full-bleed images (at least 1920 × 1080). The component crops to object-fit: cover so landscape images work best.
Props
| Prop | Type | Default |
|---|---|---|
slides? | ScrollGallerySlide[] | - |
prefixLabel? | string | Featured |
linkLabel? | string | Explore |
showPrefix? | boolean | true |
showLink? | boolean | true |
showInfoBand? | boolean | true |
stripsCount? | number | 20 |
scrollPerTransition? | number | 1000 |
scrub? | number | 1 |
pinStart? | string | top top |
scroller? | Element | Window | - |
timing? | ScrollGalleryTiming | - |
className? | string | - |
imagesClassName? | string | - |
imageClassName? | string | - |
infoClassName? | string | - |
prefixTextClassName? | string | - |
titleTextClassName? | string | - |
linkTextClassName? | string | - |
ScrollGallerySlide
| Prop | Type | Default |
|---|---|---|
title? | string | - |
image? | string | - |
url? | string | - |
linkLabel? | string | - |
ScrollGalleryTiming
| Prop | Type | Default |
|---|---|---|
initialDelay? | number | 300 |
finalDelay? | number | 300 |
titleChangeThreshold? | number | 0.3 |
titleDuration? | number | 0.3 |
titleEase? | string | power2.out |
titleOffset? | string | 120% |
scaleFrom? | number | 1.25 |
scaleTo? | number | 1 |
stripRevealSpeed? | number | 2 |
When to Use
Use ScrollGallery for creative agency home pages, portfolio showcases, or editorial sections where each project or item deserves a dedicated full-screen moment. The pinned scroll pattern forces a deliberate, focused presentation — the user can only advance by scrolling, which creates a chapter-by-chapter rhythm.
Provide at least 3 slides for the scroll distance to feel earned. With fewer than 3, the section feels short and the pin may disorient users.
Accessibility
The title element stays in the DOM for screen readers while GSAP animates it. Images use alt from slide title. The CTA link updates href (and label when using per-slide linkLabel) on each title change. When prefers-reduced-motion: reduce is set, scroll pinning is skipped and the first slide is shown statically.