Scroll Canvas Cards
A pinned scroll component with continuous canvas image crossfading, a compact centered card, and animated narrative text panels powered by GSAP and Motion.
How it works
Pins to the top of the viewport and continuously blends canvas images as you scroll, staying pinned until the final slide and image are fully revealed.
Accessibility
Includes an accessible sr-only status announcer indicating the active slide and image description, with reduced-motion support for instant transitions.
Limitations
Best used with high-quality, preloaded images. The section requires vertical scroll height to progress through slides before releasing.
Features
- Continuous smooth image crossfading on HTML canvas
- Sticky viewport pinning that holds until the last card/image finishes
- Curvy cubic-bezier and spring text entrance and exit transitions
- Compact centered card layout with concentric borders and subtle shadows
- Interactive spring-animated progress dots
- Reduced-motion awareness for accessible browsing
Installation
Choose the CLI command or install the component manually.
$ npx @istmx/ui add scroll-canvas-cardsCopies the install command for your selected package manager.
Dependencies
Usage
Import the component from the file you copied it to, then use it like any other React component.
import ScrollCanvasCards, { type ScrollCanvasSlide } from '@/components/ui/scroll-canvas-cards' const slides: ScrollCanvasSlide[] = [ { image: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=900&q=80', imageAlt: 'Mountain peak rising above clouds', leftEyebrow: 'Chapter 01', leftHeading: 'Into the Peaks', leftBody: 'Where granite meets sky, every ridge tells a story.', rightEyebrow: 'Elevation', rightHeading: '4,478 m', rightBody: 'A pyramid of rock and snow.', }, { image: 'https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=900&q=80', imageAlt: 'Misty forest valley', leftEyebrow: 'Chapter 02', leftHeading: 'The Hidden Valley', leftBody: 'Dawn light filters through ancient canopy.', rightEyebrow: 'Ecosystem', rightHeading: 'Old Growth', rightBody: 'Thrived undisturbed for centuries.', },] export function Demo() { return ( <ScrollCanvasCards slides={slides} backgroundColor="#faf7f2" cardMaxWidth={320} cardHeight={220} /> )}Composition
Tall scroll track section establishing progress heightSticky viewport container maintaining center alignmentDouble-bordered card frame with high-DPI HTML canvasDual narrative side panels (eyebrow, heading, body)GSAP ScrollTrigger scrub timelineAPI reference
slidesScrollCanvasSlide[]Array of slide objects containing image URLs, alts, and left/right narrative text.
backgroundColorstringBackground color for the entire scroll section. Defaults to cream #faf7f2.
cardMaxWidthnumberMaximum width of the center canvas card in pixels. Defaults to 320.
cardHeightnumberHeight of the center canvas card in pixels. Defaults to 220.
cardRadiusnumberBorder radius of the center card and canvas clip in pixels. Defaults to 16.
scrollLengthnumberScroll duration multiplier in viewports. Defaults to 4.
onSlideChange(index: number) => voidCallback invoked whenever the active slide index changes.
The listed props match the current component implementation.
Data attributes
Scroll Canvas Cards does not expose custom data attributes.
Examples
ScrollCanvasCards pins in the viewport and continuously dissolves between canvas images while animating side narrative text with curvy transitions. It remains pinned until the last slide finishes.
Credits & inspiration
Created by Aryan (istmX) for ISTMX. The source-first, copy-and-own philosophy is inspired by shadcn/ui. About the creator