About this animation
A full-screen story pager with slower-moving photography, gesture-linked staggered headlines, pausable autoplay, and circular progress.
How it works
- The component measures its container, then lays every story over the same full-screen stage.
- One continuous
positionshared value drives page travel, image parallax, headline separation, fading, and the settled page index. - A horizontal pan updates that value directly and springs from its current position toward a velocity-aware destination.
- A second UI-thread value runs the story timer, fills the top segment, and lights the action button's progress ring.
- Touching pauses autoplay; releasing resumes it, while short taps on either half navigate backward or forward.
Why this one
Unlike a typical story viewer, every headline line remains tied to the finger with a different travel factor. The words separate naturally during a drag, fade around the midpoint, and reunite if the gesture reverses. The same progress is visible both in the familiar story bars and as a precise halo around the action.
Install
npx expo install expo-image expo-linear-gradient react-native-gesture-handler react-native-reanimated react-native-workletsUsage
import ParallaxStoryPager from './ParallaxStoryPager';
export function StoriesScreen() {
return (
<ParallaxStoryPager
pages={[
{
image: require('./forest.jpg'),
title: 'Breathe with\nthe forest',
caption: 'A quiet twenty-minute reset.',
meta: '20 MIN',
},
]}
/>
);
}Use the personality knobs and imperative controls when the screen needs custom behavior:
import { useRef } from 'react';
import ParallaxStoryPager, { type ParallaxStoryPagerRef } from './ParallaxStoryPager';
export function GuidedStories() {
const pagerRef = useRef<ParallaxStoryPagerRef>(null);
return (
<ParallaxStoryPager
ref={pagerRef}
pages={stories}
duration={6}
accentColor="#7DE2C4"
fontFamily="YourSansFont"
titleFontFamily="YourDisplayFont"
onPageChange={(index) => trackStory(index)}
onCtaPress={(index) => openSession(index)}
/>
);
}The forwarded ref exposes next(), prev(), pause(), and resume().
Props
| Prop | Type | Default | Description |
|---|---|---|---|
pages | StoryPage[] | Required | Images, titles, and optional captions and metadata. Use newlines to control the two- or three-line title. |
duration | number | 5 | Seconds per story; 0 disables autoplay. |
accentColor | string | '#FF6A2B' | Action fill, glow, and circular progress color. |
fontFamily | string | System font | Metadata, caption, and control font. |
titleFontFamily | string | System font | Headline font. |
onPageChange | (index: number) => void | — | Called after the active page changes. |
onCtaPress | (index: number) => void | — | Called with the current page when the round action is pressed. |
style | StyleProp<ViewStyle> | — | Outer-container style. |
testID | string | — | Test identifier for the outer container. |
Compatibility
- Expo SDK 57
- React Native 0.86
- Reanimated 4.5 and Worklets 0.10
- iOS: supported, not yet verified on a device
- Android: supported, not yet verified on a device
- Web: supported, pending gate verification
- Works in Expo Go because all native dependencies are bundled with the SDK
Accessibility
The pager exposes adjustable increment and decrement actions to screen readers, and the action is a labeled button. Tapping either side is an alternative to swiping. With reduced motion enabled, parallax and line travel are removed and page changes use a short crossfade.



