About this animation
A scroll-driven water-cycle descent with configurable chapter content, action label, fonts, and parallax strength.
Why this one
An origin infographic usually asks people to read a static cross section. This piece lets them descend through it. A translucent drop deforms at layer crossings, collects three mineral traces in limestone, and merges into water with an expanding ripple. Noise-driven caustics live inside the aquifer material. The scene uses original procedural artwork rather than stock photography.
How it works
- Measure the component with
onLayout; five viewport-height chapters create a real scroll range of four screen heights. useAnimatedScrollHandlerderives one continuous chapter progresspfromscrollY / height. The camera, drop, mineral collection, measurements, and editorial windows all derive from it on the UI thread.- Draw an approximately five-screen cross section in one Skia canvas: a cloudy ridge, rooted soil, clay veins, limestone fossils, cracked granite, and shader-lit water. The foreground travels 12% faster than the camera.
- Hold the drop's poses and measurement keyframes within 20% of each chapter; interpolate the remaining 60% with smoothstep. Per-digit rollers move only at their own carry and fade by distance.
- Apply the prescribed title windows: enter at
(p - (c - 0.52)) / 0.4; exit at(p - (c + 0.14)) / 0.28. Top and bottom veils support readable text. The final chapter stays visible at the end. - Animate real scroll offsets through the ref. The demo clock advances every 2,600 ms with 1,800 ms travel using
(0.77, 0, 0.175, 1). Touch, wheel, keyboard scrolling, and navigation stop the clock. Reset fades to black before returning to the surface.
Install
npx expo install @shopify/react-native-skia@2.14.0 react-native-reanimated@4.7.1 react-native-worklets@0.13.0Use SDK-compatible versions when adapting this piece to another Expo SDK. Skia and Reanimated are included in this project's Expo Go runtime. For web, install CanvasKit using the setup supplied by the installed Skia package and load this component after CanvasKit is ready, for example through Skia's WithSkiaWeb. The catalog integrator must register this demo with the existing lazy Skia loader. No network artwork or additional assets are needed.
Usage
import DepthDescentScroll from './depth-descent-scroll';
export function SourceStory() {
return <DepthDescentScroll onCtaPress={() => openSourceDetails()} />;
}With fonts, motion controls, and an imperative ref:
import { useRef } from 'react';
import {
DepthDescentScroll,
type DepthDescentScrollRef,
} from './depth-descent-scroll';
export function CustomStory() {
const story = useRef<DepthDescentScrollRef>(null);
return (
<DepthDescentScroll
ref={story}
brandName="Your source"
tagline="Follow the water"
fontFamily="YourLoadedSans"
titleFontFamily="YourLoadedSerif"
italicFontFamily="YourLoadedSerifItalic"
monoFontFamily="YourLoadedMono"
parallaxStrength={0.08}
causticsIntensity={1.3}
ctaLabel="Explore the spring"
onCtaPress={() => openSourceDetails()}
/>
);
}Provide five DepthChapter objects through chapters to replace the editorial content and accents. Keep statements brief; headings can wrap naturally. The exported demo supplies the Tidewell kit identity, the five specified geological facts, loaded catalog fonts, autoplay, and a visible selection response on the final action. Demo water ages and mineral amounts are fictional editorial content.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
chapters | DepthChapters | Five neutral source chapters | Five objects with eyebrow, title, detail, body, and accent. |
brandName | string | Source | Wordmark beside the water tile. |
tagline | string | Follow the water | Small brand descriptor. |
ctaLabel | string | Explore the source | Final button text and accessible label. |
onCtaPress | () => void | — | Final action callback. |
onChapterChange | (chapter: number) => void | — | Nearest chapter, indexed 0–4. |
onInteraction | () => void | — | Stops an external demo clock on user interaction. |
fontFamily | string | Platform font | Body and controls. |
titleFontFamily | string | Platform font | Editorial headings and wordmark. |
italicFontFamily | string | titleFontFamily | Accent line. |
monoFontFamily | string | Platform font | Counter and rolling measurements. |
parallaxStrength | number | 0.12 | Foreground speed boost, clamped to 0–0.3. |
causticsIntensity | number | 1 | Water light intensity, clamped to 0–2. |
snapToChapters | boolean | true | Chapter snap on iOS and Android; web always scrolls freely. |
style | StyleProp<ViewStyle> | — | Root style; root defaults to flex: 1. |
testID | string | — | Root identifier. |
The ref exposes scrollToChapter(chapter, duration = 1800), stop(), and reset(). The component has no autoplay prop; the demo owns its timer and cleans it up on unmount.
Compatibility
Targets Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, worklets 0.13.0, and Skia 2.14.0. iOS, Android, and web are supported by the implementation.
Accessibility
Every chapter has a semantic header and a complete accessible description within the scroll content. Decorative Skia canvases and visual heading duplicates are hidden from screen readers. Measurements have chapter-level spoken labels. The first four chapters offer labeled next-chapter buttons, all at least 44 pt tall. The final button has a button role, a customizable label, and a 0.97 press scale with a near-critical return spring.
useReducedMotion() replaces camera travel with stationary material layers that fade in over 200 ms. Parallax, the cloud fall, ripple expansion, ambient animation, and press motion are disabled. Programmatic navigation jumps to a chapter with 200 ms heading fades; the scroll remains directly controlled by the user. There are no speed trails or camera zoom in either mode.
Icons: Lucide (ISC), copied from the repository kit. The demo tile uses the kit's Tidewell droplet and teal gradient.
Implementation notes
The layout reserves the upper-right viewer-close area. Editorial copy sits above the central drop; the gauges occupy opposite edges at 56.5% of the viewport; the final CTA starts at 79%. Typography scales with measured width for 390×844 and 320×694 containers. The first 1,100 ms drop fall crosses the grass before the first 1,800 ms descent finishes at 2,900 ms. The material glow uses radial gradients and the water light uses a clipped shader, rather than solid overlay blocks.
Customization notes
Set chapters[].accent to theme the chapter highlights.




