A photograph made of a couple of hundred thousand grains of colored dust in WebGL. At the start the grains drift as a fine cloud carried by a slow curl wind; as progress rises they settle into place from the bottom up along a soft noise field, each one lifting a little before it lands, until the picture is whole and the real photo fades in for full detail. The cursor blows the settled grains aside as it passes. Progress takes a number or a live scroll source without re-rendering, or autoplay gathers and scatters on a loop. Density, wind, grain, ground color and crop focus are props. It pauses offscreen, adapts its resolution, and shows the plain photo for reduced motion.
The import and the props worth knowing about, in one place.
import { PhotoDust } from "@/components/beste/component/photo-dust";
// Gathers and scatters on its own
<PhotoDust className="aspect-[4/5] w-full max-w-md" />
// Driven by scroll: 0 is loose dust, 1 is the finished photo
<PhotoDust
className="aspect-[4/5] w-full"
imageSrc="https://images.unsplash.com/photo-1622618991746-fe6004db3a47?w=1600&q=80"
imageAlt="A glass perfume bottle on warm paper"
progress={0.6} // or a scroll MotionValue, read every frame without re-rendering
autoplay={false}
density={0.7}
wind={0.4}
/>Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
imageSrc | string | — | The photograph the dust settles into. Its host must allow cross-origin loading (Unsplash does). |
imageAlt | string | — | |
density | number | — | Number of grains, 0 to 1 (about 60 to 250 thousand on a large screen). |
wind | number | — | Strength of the wind that carries the loose dust, 0 to 1. |
grain | number | — | Film grain on the settled photo, 0 to 1. |
groundColor | string | — | Surface behind the dust. Any CSS color, tokens included (e.g. "var(--background)"). |
progress | number | ProgressSource | — | 0 is a drifting cloud of dust, 1 is the finished photograph. A number, or a live source such as a scroll MotionValue. Leave it out to let autoplay run. |
autoplay | boolean | — | Gather and scatter on a loop when no progress is given. |
speed | number | — | Pace of the drift and of autoplay. |
interactive | boolean | — | The cursor blows the grains aside as it passes over the settled photo. |
focusX | number | — | Focal point of the crop, 0 to 1 on each axis. |
focusY | number | — | |
paused | boolean | — | Freeze the dust where it is. |
className | string | — | |
children | ReactNode | — |