Recorded on iPhone. Six artworks tide in one after another from the centre of the screen, then loop back to the first.
Shader
Tideline Reveal
The next image washes in like a tide, along a ragged, noise-shaped edge with a warm glow.
Features
- Each new image washes in like a wave running up a beach
- Smooth from start to finish, with no flicker
- Starts wherever you tap, or from a spot you choose
- A soft glow outlines the wave as it moves
- Three ready-made styles: default, calm and stormy
- A gentle vibration you can feel as each image arrives
Built with
- Skia runtime shader
- Baked fBm noise
- Reanimated
- Pulsar haptics
Installation
Usage
Tap anywhere on the image to reveal the next one.
Examples
Presets
Change the character of the edge, then override any single value.
From the centre, without the glow
Every reveal starts in the middle, with no warm edge and no dark overlay.
Driven from outside
Your own buttons, with tapping turned off.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
images | DataSourceParam[] | Required | require() or URLs. Keep the array stable between renders. |
preset | "default" | "calm" | "stormy" | "default" | The edge's character: fingered and ragged, soft and round with a slower swell, or torn into tendrils. |
origin | "touch" | "center" | { x, y } | "touch" | Where each reveal starts: where the image was tapped, the centre, or a fixed point you give. With "touch", ref calls start from the centre. |
glowIntensity | number | 0.18 | Brightness of the glow along the edge, 0–1. 0 removes it. |
overlayOpacity | number | 0.4 | Dark overlay on the new image, which fades as it lands. 0 removes it. |
loop | boolean | true | After the last image comes the first. |
onIndexChange | (index: number) => void | — | Called as each reveal starts. |
children | ReactNode | — | Views laid over the image. They stay put while it changes. |
config | Partial<TidelineRevealConfig> | — | Fine tuning. See Advanced. |
style | StyleProp<ViewStyle> | — | Fills its parent unless you give it a height or flex. |
Advanced
Everything most apps never need to touch.
Every field is optional and overrides the preset. Lengths are in points.
| Field | Default | Description |
|---|---|---|
duration | 900 | Milliseconds one reveal takes. |
raggedness | 0.35 | How far the edge wanders. 0 is a circle. |
raggedFloor | 45 | How ragged it is right at the start, so it never opens as a circle. |
noiseScale | 40 | Size of the edge's lobes. Higher is broader. |
warp | 2.5 | Swirl. 0 gives round blobs, 2.5 fingers, 4 tendrils. |
feather | 10 | Softness across the edge. |
glowWidth | 26 | Width of the glow along the edge. |
glowColor | "#FFFCF0" | Glow colour. |
fit | "cover" | "cover" crops to fill; "contain" letterboxes. |
| Method | Description |
|---|---|
next() | Reveals the next image. |
previous() | Reveals the previous image. |
revealTo(index) | Reveals that image, wrapped with loop or clamped without it. |
| Prop | Default | Description |
|---|---|---|
initialIndex | 0 | Image shown first. Read once; use the ref to move later. |
interactive | true | Off, tapping does nothing; the ref and screen readers still move it. |
haptics | true | A soft vibration that swells with each reveal. |
paintOverlay | — | (canvas, size, index) => void. Draws with Skia into each image before it is revealed, so text dissolves with the photo. Use fonts loaded through Skia, and keep the function stable: a new one replays the reveal. |
onReady | — | Called once the first image is on screen. |
onRevealComplete | — | Called when a reveal lands, with the index now shown. |
accessibilityLabel | "Gallery" | Read before "2 of 4". |
ref | — | A TidelineRevealHandle. See Ref methods. |
- Taps during a reveal are ignored, so a double tap never cuts one short.
- Buttons among the
childrenstill work alongside tapping the image. - Haptics need a physical device.
- Nothing runs while it sits still: no clock, no redraw.
- Screen readers read it as "Gallery, 2 of 4", and swiping up or down moves between images.
- With Reduce Motion on, images simply crossfade: no wave, glow or vibration.
How it works
A Skia shader draws the edge as a line on a noise-warped map of distances from where the reveal starts. During a reveal only that line moves outward, so a pixel can never flip back, which is why the edge never flickers. The noise is baked into a texture once, so each frame costs a single texture read per pixel.