@frapx/react-particles
react-* — framework binding Wraps @frapx/fx-particles for React.
A thin lifecycle adapter around @frapx/fx-particles — the simulation and
render loop stay in the runtime, and the package ships no CSS. Needs WebGL2.
pnpm add @frapx/fx-particles @frapx/react-particlesComponent
Section titled “Component”import { Particles } from "@frapx/react-particles";
export function Hero() { return ( <section style={{ position: "relative", minHeight: "100vh" }}> <Particles preset="snow" rate={60} style={{ position: "absolute", inset: 0 }} /> <h1>Winter sale</h1> </section> );}Props are the createParticles() options (except target, onReady and
onError) plus regular div attributes. The canvas is transparent, so stack
it over other content — a <ShaderBackground /> from
@frapx/react-canvas, for example — with CSS.
What changes in place
Section titled “What changes in place”Options are compared by value, so inline arrays and objects are fine.
- In place:
rate,opacity,twinkle,perspective, the force values (forces.gravity,forces.drag,forces.curl.*,forces.pointer.*),color,palette,blend,clock,timeSourceandresolution. AtimeSourceis called through a stable wrapper, so an inline arrow function is fine. - Recreated: any other change (
preset,lifetime,size,sprite, which forces are present…), removing an in-place value, andrecreateKey. - Without
maxParticles, raisingratebeyond what the automatic pool holds recreates the instance with a larger pool; withmaxParticles,ratealways changes in place.
Timelines
Section titled “Timelines”uniformSources binds sources such as keyframes() in array order (a later
one wins for the same uniform). Sources are compared by identity, and a
recreated instance is bound again.
import { keyframes } from "@frapx/fx-particles";
const fadeIn = keyframes({ opacity: [[0, 0], [3, 1]] }, { ease: "smooth" });
<Particles preset="fireflies" uniformSources={[fadeIn]} />;Hook and handle
Section titled “Hook and handle”useParticles(options, recreateDeps?) returns { ref, instance, status, error }
with the same comparison rules. status follows the instance live through
onStatusChange ("paused" while offscreen, hidden or under reduced motion,
"context-lost"), and an onStatusChange prop is still called with every
change. The component’s ref exposes the instance’s methods — setTime, setClock, captureFrame, reset, setUniform,
bindUniforms, setColor and the rest:
const ref = useRef<ParticlesHandle>(null);
<Particles ref={ref} preset="confetti" clock="manual" resolution={[1920, 1080]} />;
ref.current?.setTime(2);const png = await ref.current?.captureFrame();- React 18+ is supported. Safe to import during SSR — WebGL work starts only after mount.
- An invalid config reaches
error/onParticlesErrorinstead of throwing. - Use
onParticlesReady/onParticlesErrorinstead of the runtime’sonReady/onError(avoids a DOM prop naming conflict).
Full prop and hook reference: package README on GitHub.