Licence
MIT
Version
0.1.0
Deps
0
Size
48 kB
Vulns
0
Weekly
0
shimmer-text
A soft-blur front sweeps across your text, then settles into crisp type. One file, zero dependencies, 8 kB gzipped. The text stays selectable.
Install
npm install shimmer-text
Or drop it in — no build step, no JavaScript to write:
<h1 data-shimmer-text>Sound you can feel before you hear it.</h1>
<script type="module" src="https://offbr.co/tools/shimmer-text.js"></script>
Use
import { shimmerText } from "shimmer-text";
const hero = await shimmerText("#hero", { duration: 7200, intensity: 2 });
hero.replay();
hero.destroy();
import { ShimmerText } from "shimmer-text/react";
<ShimmerText as="h1" intensity={2}>
Sound you can feel
</ShimmerText>;
React is an optional peer dependency — only the /react entry point pulls it in.
Options
| Option | Default | Meaning |
|---|---|---|
target |
"[data-shimmer-text]" |
Selector, Element, or iterable of elements |
duration |
5600 |
Sweep length in ms |
delay |
0 |
Wait after the element enters the viewport |
stagger |
0 |
Extra delay per element, in document order |
intensity |
1 |
How pronounced — ~2 for a hero, ~0.7 for body copy |
colors |
none | CSS colours the sweep front cycles through (up to 6) |
Each has a data-shimmer-* twin for the drop-in path, e.g.
data-shimmer-intensity="2". Pair a loud heading with quiet body copy —
everything at one intensity reads as a broken page.
Good to know
- Selectable. The real text sits under the canvas, transparent but live — highlight it, copy it, ⌘F it. Screen readers and crawlers read it normally.
- Cheap. Waits for the viewport, and the animation loop exits once everything has settled.
- Degrades twice. WebGL first, then a Canvas2D renderer, then plain static
text under
prefers-reduced-motion. - Leaf elements only. The text is baked to a canvas, so child markup is
flattened. Parents need
overflow: visible— the blur bleeds past the glyphs.
Anything with <canvas> works; WebGL 1 for the good path.
License
MIT