Displacement
An image or painted canvas that bends around the pointer like wet glass, with a colour split and grain.
Behaviour
- Reduced motion: the plain image, no bending.
- A trail point follows the pointer on a spring; the gap between them drags nearby pixels, the colour channels split along the drag and grain shows while it moves.
- Draws only while the trail moves and pauses off screen: a still page costs nothing. Props are read live.
- WebGL2 with one full-screen triangle and no dependencies. Without WebGL2, or if the context is lost, the plain image or canvas shows.
Props
| Prop | Type | Description |
|---|---|---|
| src | string | The image to distort. Same-origin or CORS-enabled, or the plain image shows instead. |
| alt | stringdefault "" | Accessible name. Empty marks it decorative. |
| paint | (ctx, width, height) => void | Draw the content on a 2D canvas instead, in CSS pixels. Called on mount and every resize. |
| radius | numberdefault 0.22 | Size of the bending area, as a share of the shorter side. |
| strength | numberdefault 0.6 | How far pixels are dragged with the pointer. 0 turns it off. |
| aberration | numberdefault 0.5 | How far the red and blue channels split along the drag, 0 to 1. |
| grain | numberdefault 0.08 | Film grain over the moving area, 0 to 1. |
| className | string | Size it here: it fills its box. |
Installation
npx shadcn@latest add https://purrfectui.com/r/displacement.jsonHow to use
import { Displacement } from "@/components/ui/displacement";
<Displacement src="/hero.jpg" alt="Mountains at dusk" className="h-96 rounded-3xl" />
// or paint it yourself
<Displacement className="h-64" paint={(ctx, w, h) => { ctx.font = "600 96px sans-serif"; ctx.fillText("Hello", 24, h / 2); }} />Source code
Loading…
License
MIT. Copy it into your project and change it as you like.