Sand Cursor
v1.0.1FreeInteractivityWebGL
An interactive WebGL sand canvas particle field that deforms dynamically on pointer movement using React Three Fiber.
Sand Cursor
Pointer
Installation
Step 1. Initialize ProjectOne-time setup
Run once in your project root to configure paths and dependencies:
npx vectorvesper initStep 2. Add ComponentInstalls source & assets
Downloads and registers the component in your project:
npx vectorvesper add magnetic-sandStep 3. Required DependenciesAuto-installed with CLI
If installing manually or managing your package lock:
npm install three @react-three/fiberPackages:three@react-three/fiber
Usage
Import
Usage
WebGL — render it on the client only
On Next.js, load it with ssr: false from a Client Component, as below. Vite apps need nothing extra.
Props
A field of fine grains that the cursor drags through, leaving a trail that settles slowly behind it. White ground and black grains by default, so it reads as ink on paper rather than a screen effect.
<MagneticSandVisualizer />
The surface. Fills its container, so give the parent a height.
| Prop | Type | Default | Description |
|---|---|---|---|
backgroundColor | string | "#ffffff" | Colour of the ground the grains sit on. |
color1 | string | "#000000" | Colour of an undisturbed grain. |
color2 | string | "#00eeff" | Colour a grain takes at full disturbance, right under the cursor. It blends back toward color1 as the trail settles. |
gridResolution | number | 140.0 | How many grains across the surface. Higher packs them finer — this is the main control over how the field reads. |
particleSize | number | 0.0 | Extra size added to each grain. Zero means the grain fills its cell exactly; raise it to make them overlap and clump. |
trailSpeed | number | 0.05 | How quickly the field settles back after the cursor passes. Lower leaves the trail standing for longer. |
glowIntensity | number | 0.3 | Bloom around disturbed grains. 0 keeps them flat. |
className | string | "" | Applied to the wrapper around the canvas. |
style | React.CSSProperties | {} | Merged onto the wrapper. It already fills its parent, so use this for position or z-index rather than size. |
Examples
As a section background
import MagneticSandVisualizer from "@/components/vv/magnetic-sand/MagneticSand";
<section className="relative h-screen">
<div className="absolute inset-0">
<MagneticSandVisualizer />
</div>
<h1 className="relative z-10">Drag across the sand</h1>
</section>Dark, coarse and slow to settle
<MagneticSandVisualizer
backgroundColor="#050508"
color1="#1a1a22"
color2="#7EACB5"
gridResolution={70}
particleSize={0.4}
trailSpeed={0.015}
glowIntensity={0.6}
/>The field only moves in response to the cursor — it is still when nothing is happening, so there is no ambient motion to suppress. It has no explicit reduced-motion state.
The whole field is one GPU pass, so gridResolution is cheap to raise. It is the clearest control to reach for before anything else.
Client component. It opens a 3D drawing context on mount — import it dynamically with
ssr: false if your route renders on the server.