Skip to content
Native Animation
Stacking cards on scroll animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add stacking-cards-scroll

Stacking cards on scroll

A scroll-driven chapter deck that retains earlier cards in a recessed stack, with configurable chapters, title, accent color, and fonts.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

A scroll-driven chapter deck that retains earlier cards in a recessed stack, with configurable chapters, title, accent color, and fonts.

Why this one

A weekly program usually disappears into a list. Here, each completed chapter stays in the deck: its photo softens to a 6-point blur and its surface recedes to 92% scale. A continuous progress ring connects the stack to the program, making both the next chapter and the path behind it visible.

How it works

  1. Measure the container with onLayout; each card occupies 90% of its width and 66% of its height.
  2. Convert the actual ScrollView offset into one chapter progress, p, using useAnimatedScrollHandler. No React state updates occur per frame.
  3. Use smoothstep transitions with resting poses. Anchor cards at 14% of the container height plus 12 points per index. Derive photo blur, dimming, and recession from the arrival of the next card.
  4. Spring the small arrival tilt with damping 43 and stiffness 180 (effective mass 4). Editorial copy enters over (p - (c - 0.52)) / 0.4 and leaves over (p - (c + 0.14)) / 0.28, keeping headlines separate.
  5. Stack chapter backgrounds with entry opacity only. Gradient veils protect text. Draw the ring as a single trimmed Skia path; the web graphics module loads Skia lazily.
  6. Place the closing action in the scroll content. Native platforms may snap to chapters; web scroll remains continuous. The demo scrolls on a 2.6-second chapter clock, pauses at the close, fades to black, and resets. Touch or wheel input stops playback.

Install

Copy this folder without demo/ into your project.

npx expo install react-native-reanimated@4.7.1 react-native-worklets@0.13.0 expo-image@~58.0.17 expo-linear-gradient@~58.0.3 @shopify/react-native-skia@2.14.0

Configure Reanimated/worklets for your Expo project. For web, make Skia's canvaskit.wasm available using the installed Skia package's web setup (npx setup-skia-web). Graphics.web.tsx waits for LoadSkiaWeb before evaluating the drawing module. Load your chosen fonts in the host app; the component falls back to system fonts.

Usage

import { StackingCardsScroll } from './stacking-cards-scroll';

const chapters = [
  {
    id: 'morning',
    image: require('./morning.jpg'),
    eyebrow: 'WEEK 01',
    title: 'Wake',
    subtitle: 'slower.',
    description: 'Spend 6 minutes arriving before the day begins.',
    sessions: ['Morning arrival · 6 min', 'A softer start · 6 min', 'Meet the light · 6 min'],
  },
];

export function Program() {
  return <StackingCardsScroll chapters={chapters} onStart={() => openFirstSession()} />;
}

Customize the material and control chapters through a ref:

const deck = useRef<StackingCardsScrollRef>(null);

<StackingCardsScroll
  ref={deck}
  chapters={chapters}
  accentColor="#BEDAC9"
  title="A little room to breathe"
  stackSpacing={10}
  blurRadius={4}
  fontFamily="MySans"
  titleFontFamily="MySerif"
  italicFontFamily="MySerifItalic"
  monoFontFamily="MyMono"
  onChapterChange={(index) => saveReadingPosition(index)}
/>;
// From an event handler:
deck.current?.goTo(1);

Props

PropTypeDefaultDescription
chaptersreadonly StackingChapter[]RequiredOrdered cards; images remain outside the reusable component.
titlestring'Your program'Fixed heading.
headerReactNodeundefinedOptional brand or other leading header content.
closingTitlestring'Make a little time for yourself.'Closing statement.
closingCopystring'One small practice. Every day.'Closing supporting copy.
actionLabelstring'Get started'Action label.
actionAccessibilityLabelstringactionLabelAccessible action label, defaulting to actionLabel.
onStart() => voidundefinedCalled when the final action is pressed.
onChapterChange( index: number, ) => voidundefinedCalled once per active chapter change.
onInteraction() => voidundefinedCalled on touch, drag, or wheel interaction to stop demo playback.
fontFamily, titleFontFamily, italicFontFamily, monoFontFamilystringSystem fontBody, headline, italic, and counter fonts.
accentColorstring'#A78BFA'Primary highlight.
backgroundColorstring'#0E0B1F'Base surface.
cardHeightRationumber0.66Card height relative to measured container.
stackSpacingnumber12Spacing between pinned card tops in points.
blurRadiusnumber6Maximum photo blur of a covered card.
snapToChaptersbooleantrueEnable chapter snapping on native platforms.
styleStyleProp<ViewStyle>undefinedRoot style override.
testIDstringundefinedRoot test identifier.
durationnumber850Scroll hint half-cycle in milliseconds. Spring physics and reduced-motion timing are unchanged.
fontFamilystringundefinedBody typeface; system font when omitted.
titleFontFamilystringundefinedEditorial headline typeface.
italicFontFamilystringundefinedItalic headline typeface.
monoFontFamilystringundefinedChapter counter typeface.

Ref methods: goTo(index) and next() spring to a chapter, reset() returns to the top, and scrollToProgress(p) immediately sets the physical scroll for an external clock. Index chapters.length opens the close.

Compatibility

Targets Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, worklets 0.13.0, and Skia 2.14.0. Works with the installed Expo Go modules. Supports iOS, Android, and web. No additional native library is required.

Accessibility

Reduced motion removes zoom, tilt, blur, and arrival translation; chapter changes use 200 ms fades. Only the selected chapter is exposed to screen readers, with a heading role and readable session text. The 44-point progress-ring button provides a tap alternative to scrolling. The closing action has a configurable spoken label and a 56-point target. The decorative scroll hint cannot capture touches. All photos are local in the demo; caller-provided sources remain caller controlled.

Icons: Lucide (ISC). Aurora's demo glyph and gradient come from the project brand kit.

Review notes

Layout calculations reserve the upper-right viewer close area. At 390×844 and 320×694, the 90%-width cards leave horizontal margins and the 66%-height cards fit the two-line headline, supporting copy, and three session rows. The second card reaches its pinned position before 3 seconds of autoplay. Photo blur is applied to the image itself; only the specified dimming veil and loop blackout use covering surfaces.