Shimmer Text
Description
**The "AI is thinking" shimmer, and a one-shot reveal wipe - one small component, 60fps, entirely on the UI thread.**
You've seen it everywhere lately: a label like *Thinking…* or *Editing file.ts* with a bright band of light sliding across it. It reads as "something is happening" without a spinner. It's also almost always done badly - with a timer re-rendering colors, or a heavy gradient library animating on the JS thread.
Here it is as one idea:
1. **The text is a mask.** A `MaskedView` uses the glyph shapes as a stencil, so every layer beneath shows *only through the letters*.
2. **A dim base color** fills those letters at rest.
3. **A bright layer, driven by one shared value**, rides above the base:
- **`mode="shimmer"`** - a narrow bright band *translates* across on a loop, lighting each glyph as it passes. Perpetual, for a "working…" indicator.
- **`mode="reveal"`** - a bright fill *grows* from the left with a feathered leading edge and stays lit. Text arriving on a sweep of light.
One driver (a `translateX` or a width on a repeating/one-shot clock), nothing on the JS thread, and it can never desync.
### What you'll learn
- Using `MaskedView` to fill text with anything (a gradient, a video, a sweep) instead of a flat color
- Driving a masked highlight from a single Reanimated shared value, so the effect is a pure function of the clock
- Feathering a band with a 3-stop `transparent → highlight → transparent` gradient so its edges glow instead of hard-cutting
- Measuring the text once (`onLayout`) so the sweep knows exactly where to start and end
### The personality knobs
Everything that defines the feel is a named prop:
- `baseColor` / `highlightColor` (the rest and peak)
- `duration` (sweep speed), `bandWidth` (band width in shimmer, feather size in reveal)
- `gap` (the little pause a thinking indicator takes between sweeps).
Swap `mode` to switch between the perpetual shimmer and the one-shot reveal.
Built with **Reanimated**, **`@react-native-masked-view/masked-view`**, and **`expo-linear-gradient`** - all Expo-friendly, so it drops straight into a Snack. Works on iOS, Android, and web.
Installation
bunx @animatereactnative/cli@latest add shimmer-text
npx @animatereactnative/cli@latest add shimmer-text
yarn @animatereactnative/cli@latest add shimmer-text
pnpm dlx @animatereactnative/cli@latest add shimmer-text