Scroll / Canvas / COMPONENT

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.

Live preview
Slide 1 of 5: Mountain peak above clouds at golden hour

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.

Package manager
$ npx @istmx/ui add scroll-canvas-cards

Copies the install command for your selected package manager.

Dependencies

ReactMotionTailwind CSSclsxtailwind-mergegsap@gsap/react

Usage

Import the component from the file you copied it to, then use it like any other React component.

Usage
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

Composition
Tall scroll track section establishing progress height
Sticky viewport container maintaining center alignment
Double-bordered card frame with high-DPI HTML canvas
Dual narrative side panels (eyebrow, heading, body)
GSAP ScrollTrigger scrub timeline

API reference

slidesScrollCanvasSlide[]

Array of slide objects containing image URLs, alts, and left/right narrative text.

backgroundColorstring

Background color for the entire scroll section. Defaults to cream #faf7f2.

cardMaxWidthnumber

Maximum width of the center canvas card in pixels. Defaults to 320.

cardHeightnumber

Height of the center canvas card in pixels. Defaults to 220.

cardRadiusnumber

Border radius of the center card and canvas clip in pixels. Defaults to 16.

scrollLengthnumber

Scroll duration multiplier in viewports. Defaults to 4.

onSlideChange(index: number) => void

Callback 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