particle-field
v0.1.1
Published
A reactive WebGL particle field for React. Arrange thousands of particles into random, grid, content-aware, or SVG-based layouts, then animate smoothly between them.
Readme
Particle Field
A reactive WebGL particle field for React. Arrange thousands of particles into random, grid, content-aware, or SVG-based layouts, then animate smoothly between them.
Install
npm install @maxvdec/particle-fieldUsage
import { useMemo, useState } from "react";
import {
ParticleField,
gridLayout,
randomLayout,
type ParticleState,
} from "@maxvdec/particle-field";
const chaos = randomLayout({ margin: 8 });
const grid = gridLayout({ jitter: 0.08 });
export function Background() {
const [state, setState] = useState("chaos");
const states = useMemo<Record<string, ParticleState>>(
() => ({ chaos: { layout: chaos }, grid: { layout: grid } }),
[],
);
return (
<div style={{ position: "relative", width: "100%", height: "100vh" }}>
<ParticleField
count={6500}
state={state}
states={states}
pointer={{ radius: 160, strength: 3600 }}
/>
<button onClick={() => setState(state === "chaos" ? "grid" : "chaos")}>
Change layout
</button>
</div>
);
}The canvas fills its parent, so give the parent an explicit size.
Layouts
randomLayout({ margin })distributes particles across the field.gridLayout({ jitter })creates an evenly spaced grid.contentLayout({ width, padding })leaves a clear centered column. Set the state'scontentWidthto the same width so pointer and flow motion respect it.await svgLayout(svgText, { scatter, scale })samples visible SVG fills and strokes. Use a self-contained SVG; external resources are not loaded.blendLayouts(from, to, progress)creates a layout between two others.
For a continuous transition, pass transition={{ from, to, progress }}. Progress is clamped from 0 to 1 and can be driven by scroll position, animation, or application state.
Customization
ParticleField accepts palette, physics, pointer, and appearance options. Positive pointer strength repels particles. Flow physics also supports inwardStrength, signed twist, normalized centerX and centerY, and a pixel-based captureRadius.
<ParticleField
state="flow"
states={{ flow: { layout: randomLayout() } }}
palette={["#dffcff", "#7ad7df", "#f4f7f2", "#d9956f"]}
physics={{ inwardStrength: 160, twist: 100 }}
appearance={{ minSize: 0.35, maxSize: 4 }}
/>Requirements
- React 18 or newer
- A browser with WebGL support
License
No license has been specified yet.
