Recorded on iPhone. Labubu, Expo, Discord, PlayStation and Pizza Hut stickers scattered on a board, peeled up, dragged and stuck back down.
Gesture
Holographic Sticker
Die-cut foil stickers that catch rainbow light as you tilt the phone and peel up off the screen when you hold them.
Features
- Stickers shine with rainbow foil as you tilt the phone
- Hold one and it peels up from under your finger, with a light tap of feedback
- Drag it around, twist it with two fingers, or pinch to zoom
- Let go and it sticks back down, starting from the edge you lifted
- Drop in a list of stickers and the board scatters them for you
- Runs on iOS and Android from the same code
Built with
- Skia mesh and shaders
- Reanimated
- Gesture Handler
- expo-haptics
- expo-image
Installation
Without it nothing errors, but the stickers never respond to a touch.
Usage
The board fills its parent, tosses each sticker on at a random spot and angle, and brings the one you pick up to the front. Try it on a real device: a simulator can't be tilted, so the foil never shows.
Examples
A board in a card, with fixed positions
Give the board a size and place each sticker yourself.
A single sticker
For one sticker, such as a badge, use HolographicSticker inside a FoilLightProvider.
Props
StickerBoard:
| Prop | Type | Default | Description |
|---|---|---|---|
stickers | StickerBoardItem[] | Required | The stickers to lay out. |
style | StyleProp<ViewStyle> | — | Fills its parent by default. Give it a size to embed it. |
onPickUp | (key: string) => void | — | Called as a sticker is picked up. The board brings it to the front. |
Each sticker:
| Field | Type | Default | Description |
|---|---|---|---|
key | string | Required | Unique on the board. Passed to onPickUp. |
source | number | Required | A transparent die-cut PNG, as a require(). |
width | number | Required | Points. The height follows from the image. |
x, y | number | random | Points from the board's top-left. Leave them out and the sticker lands at random. |
rotation | number | random | Degrees, clockwise. Leave it out for a random tilt of up to 25° either way. |
Advanced
Everything most apps never need to touch.
Use it inside one FoilLightProvider, which takes only children.
| Prop | Type | Default | Description |
|---|---|---|---|
source | number | Required | A transparent die-cut PNG. Its outline is the sticker's shape. |
width | number | Required | Points. The height follows from the image. |
initialRotation | number | 0 | Degrees it starts turned, clockwise. Read once; twisting turns it from there. |
style | StyleProp<ViewStyle> | — | For example position and left/top. |
onPickUp | () => void | — | Called as the peel starts. |
There are no presets yet. Every number that shapes the look, such as the peel timing, bend, ripple, shadow and foil, is a named constant in constants.ts, with its unit and what it changes.
- Hold for 150 ms and the sticker peels up from under your finger. Press near the middle and it peels outward in a circle instead.
- Drag while holding to move it. Pull 90 points and it peels the rest of the way at once.
- Twist with a second finger while holding to turn it.
- Pinch any time to zoom, from 0.4× to 4×.
- Let go and it sticks back down from the edge you peeled. Grab it again partway and it lifts from that same edge.
- Put one
FoilLightProviderabove everyHolographicStickeron screen. It runs the single tilt sensor they all share.StickerBoardbrings its own. - Random spots are rolled once per
key, so stickers never reshuffle on a re-render and stay on the board when it resizes. - Dragged stickers can leave the board. Add
overflow: 'hidden'to itsstyleto clip them. - The foil fades in only as the phone tilts. Once the phone lies flat, nothing redraws.
- A sticker sets no accessibility label of its own. If one carries meaning, such as a badge, wrap it in a view with
accessibleand anaccessibilityLabel. - With Reduce Motion on, the wobble after the peel is turned off. The peel itself still plays, since it shows the sticker has been picked up.
How it works
Each sticker is drawn with Skia as a 16 × 16 mesh. Holding it starts a bend at your finger that sweeps to the far side, and each point rises the further the bend has passed it, with perspective so the lifted part grows toward you. The same mesh, blurred and flattened, is the shadow. One shader rides the bend with a bright crest and a dark trough so the crease reads as a crease; another adds the rainbow foil, clipped to the art's outline and driven by the phone's rotation sensor on the UI thread.