UNPKG

r3f-particle-system

Version:

A declarative particle system for React Three Fiber. It uses an FBO Simulation to provide incremental updates to particles, allowing for an intuitive API with use of forces. **Note**: This package is experimental and may introduce breaking changes in futu

409 lines (329 loc) 11.9 kB
# r3f-particle-system A declarative particle system for React Three Fiber. It uses an FBO Simulation to provide incremental updates to particles, allowing for an intuitive API with use of forces. **Note**: This package is experimental and may introduce breaking changes in future releases. [Check out the demo](https://r3f-particle-system-examples.vercel.app/) to see it in action! This is just one of many possible configurations for this tool. ## Installation This package relies on the following peer dependencies. You need to have them installed in your project: | Package | Required Version | |----------------------|------------------| | `@react-three/drei` | `^9.101.0` | | `@react-three/fiber` | `^8.15.19` | | `react` | `^18` | | `three` | `^0.170.0` | ### Install Peer Dependencies To install all the required peer dependencies for with this package, run the following command: ```bash npm install @react-three/drei@^9.101.0 @react-three/fiber@^8.15.19 react@^18 three@^0.170.0 ``` ### Install Package Once peer dependencies are installed, install the package: ```bash npm install r3f-particle-system ``` ## Usage The particle system consists of four main components: `ParticleSystem`, `Emitters`, `Forces`, and `Particles`. The `ParticleSystem` acts as a context wrapper and must be included for the system to function. Within it, you can use one `Emitter`, one `Particle`, and multiple `Forces` to define and manipulate the behavior of particles. ### Example ```jsx <ParticleSystem> <BoxEmitter speed={[ 0.8, 1 ]} life={[ 1, 10 ]} /> <DirectionalForce direction={[ 0, 1, 0 ]} randomAmt={ 0.1 } strength={ 2 } /> <RotationalForce strength={ 1.5 } /> <PointParticle shape="circle" color={[ "cyan", "magenta" ]} size={[ 5, 25 ]} alphaFade={[ 0.25, 1 ]} /> </ParticleSystem> ``` --- ## Components ### ParticleSystem The core context provider that manages data across the particle system. **Props**: - `simulationSpace`: Determines the coordinate space for particles (`"local"` | `"world"`) - `normalizeForces`: When `true`, normalizes the sum of all forces (useful for maintaining predictable speeds). Example w/ Default Values: ```jsx <ParticleSystem simulationSpace="local" normalizeForces={ false } /> ``` --- ## Emitters Emitters are responsible for spawning particles. Only one emitter can be used per system. ### BoxEmitter Spawns particles from within a box-shaped volume. **Props**: - `size`: Particle buffer size (e.g., `128` = 16,384 particles). - `spawnRate`: Number of particles spawned per second. - `life`: Particle lifespan or min and max life (`life` | `[min, max]`). - `speed`: Particle speed or man and max speed (`speed` | `[min, max]`). - `bounds`: Dimensions of the box `[x, y, z]`. Example w/ Default Values: ```jsx <BoxEmitter size={ 128 } spawnRate={ 500 } life={[ 1.0, 5.0 ]} speed={[ 0.5, 2.0 ]} bounds={[ 1, 1, 1 ]} /> ``` ### CurveEmitter Spawns particles along a curve. **Props**: - `size`: Particle buffer size (e.g., `128` = 16,384 particles). - `spawnRate`: Number of particles spawned per second. - `life`: Particle lifespan or min and max life (`life` | `[min, max]`). - `speed`: Particle speed or man and max speed (`speed` | `[min, max]`). - `points`: Array of control points defining the curve. - `controlOffset`: Smoothness of curve corners. - `curve`: Optional `THREE.Curve` instance (overrides `points`). - `sampleMode`: Distribution mode along the curve (`"random"` | `"sequential"`). - `isLoop`: Whether the curve loops. - `resolution`: How many points make up this curve. - `randomOffset`: Random positional offset for particles. - `debug`: When true shows the curve and control points. Example w/ Default Values: ```jsx <CurveEmitter size={ 128 } spawnRate={ 500 } life={[ 1.0, 5.0 ]} speed={[ 0.5, 2.0 ]} points={[[ 0, 0, 0 ], [ 0, 1, 0 ]]} controlOffset={ 0.1 } curve={ null } sampleMode="random" isLoop={ false } resolution={ 100 } randomOffset={ 0.1 } debug={ false } /> ``` ### CylinderEmitter Spawns particles within a cylindrical volume. **Props**: - `size`: Particle buffer size (e.g., `128` = 16,384 particles). - `spawnRate`: Number of particles spawned per second. - `life`: Particle lifespan or min and max life (`life` | `[min, max]`). - `speed`: Particle speed or man and max speed (`speed` | `[min, max]`). - `innerRadius`: Inner radius of the cylinder (no particles spawn inside). - `outerRadius`: Outer radius of the cylinder. - `height`: Cylinder height. - `arc`: Angular section of the cylinder (in radians). Example w/ Default Values: ```jsx <CylinderEmitter size={ 128 } spawnRate={ 500 } life={[ 1.0, 5.0 ]} speed={[ 0.5, 2.0 ]} innerRadius={ 0.0 }, outerRadius={ 1.0 }, height={ 0.0 }, arc={ Math.PI * 2 } /> ``` ### MeshEmitter Spawns particles from the surface of a mesh. **Props**: - `size`: Particle buffer size (e.g., `128` = 16,384 particles). - `spawnRate`: Number of particles spawned per second. - `life`: Particle lifespan or min and max life (`life` | `[min, max]`). - `speed`: Particle speed or man and max speed (`speed` | `[min, max]`). - `sampleMode`: Determines particle spawn positions (`"random"` | `"sequential"` | `"shuffled"`). - `debug`: If `true`, renders the input mesh for visualization. **Note**: The source mesh must be a child of this emitter. Example w/ Default Values: ```jsx <MeshEmitter size={ 128 } spawnRate={ 500 } life={[ 1.0, 5.0 ]} speed={[ 0.5, 2.0 ]} sampleMode="random", debug={ false } > <mesh> <sphereGeometry> <meshBasicMaterial> </mesh> </MeshEmitter> ``` ### SphereEmitter Spawns particles within a spherical volume. **Props**: - `size`: Particle buffer size (e.g., `128` = 16,384 particles). - `spawnRate`: Number of particles spawned per second. - `life`: Particle lifespan or min and max life (`life` | `[min, max]`). - `speed`: Particle speed or man and max speed (`speed` | `[min, max]`). - `radius`: Radius of the sphere. - `surface`: If `true`, particles conform to the sphere's surface. Example w/ Default Values: ```jsx <SphereEmitter size={ 128 } spawnRate={ 500 } life={[ 1.0, 5.0 ]} speed={[ 0.5, 2.0 ]} radius={ 1 }, surface={ false }, /> ``` --- ## Forces Forces affect the movement and behavior of particles. Multiple forces can be applied simultaneously. ### DirectionalForce Applies a constant directional force. **Props**: - `direction`: Force direction vector (`[x, y, z]`). - `randomAmt`: Random deviation from the base direction. - `strength`: Strength of the force. Example w/ Default Values: ```jsx <DirectionalForce direction={[ 0, 1, 0 ]}, randomAmt={ 0 }, strength={ 1 } /> ``` ### RotationalForce Applies rotational force around a center. **Props**: - `center`: Center point of rotation. - `axis`: Rotation axis (`"xy"` | `"xz"` | `"yz"`). - `strength`: Strength of the force. Example w/ Default Values: ```jsx <RotationalForce axis="xyz", seed="random", period={ 1 }, strength={ 1 } /> ``` ### NoiseForce Applies a curl noise force to particles. **Props**: - `axis`: Which axes are affected by the force (`"xyz"` | `"xy"` | `"xz"` | `"yz"`). - `seed`: Seed position (`[x, y, z]` | `"random"`). - `period`: The period of the noise. - `strength`: Strength of the force. Example w/ Default Values: ```jsx <NoiseForce axis="xyz", seed="random", period={ 1 }, strength={ 1 } /> ``` ### CurveTangentForce Applies a force along the tangent of a curve. Only has Eefect when using CurveEmitter. **Props**: - `direction`: The direction of the force along the curve (`1` | `-1`) - `randomAmt`: Random deviation from the base direction. - `strength`: Strength of the force. Example w/ Default Values: ```jsx <CurveTangentForce direction={ 1 }, randomAmt={ 0.25 }, strength={ 1 } /> ``` ### NormalForce Applies a force perpendicular to a surface. Only has effect when using the MeshEmitter. **Props**: - `strength`: Strength of the rotation. Example w/ Default Values: ```jsx <NormalForce strength={ 1 } /> ``` ### PointForce Dynamically applies a force from a point source up to an effective threshold. **Props**: - `position`: The center positions of the force. - `direction`: The direction of the force relative to the center position (`"towards"` | `"away"`). - `axis`: Which axes are affected by the force (`"xyz"` | `"xy"` | `"xz"` | `"yz"`). - `effectiveDist`: The extents this force affects particles around its center. - `strength`: Strength of the rotation. - `returnForce`: Force particles back to their original position when outside effectiveDist. - `returnForce`: The strength of the return force. Example w/ Default Values: ```jsx <PointForce position={[ 0, 0, 0 ]}, direction="towards", axis="xyz", effectiveDist={ 1 }, strength={ 1 }, returnForce={ true }, returnStrength={ 1 } /> ``` --- ## Particles ### PointParticle Defines individual particles rendered as points. **Props**: - `shape`: Particle shape (`"circle"` | `"square"` | `"softCircle"` | `"point"`). - `color`: Particle color (single value or array for gradients). - `colorMode`: Determines how colors are applied (`"overLife"` | `"random"`). - `size`: Particle size or range (`size` | `[min, max]`). - `alphaFade`: Fade-in and fade-out alpha values. - `depthWrite`: depthWrite value for the particles. - `depthTest`: depthTest value for the particles. - `blending`: blending value for the particles. Example w/ Default Values: ```jsx <PointParticle shape="circle" color="blue" colorMode="overLife", size={ 50 } alphaFade={ 1 } depthWrite={ false }, depthTest={ true }, blending={ THREE.NormalBlending }, /> ``` --- ## Imperative API & Particle Bursts Refs of `ParticleSystem` can be used to expose it's imperative API. Available methods are `stop()`, `start()`, and `createBurst()`. After stopping the system, `createBurst(numParticles)` can be used to create a burst of particles at runtime. ### Example Usage: ```jsx // create ref for particle system const systemRef = useRef(); // pause the spawning of particles useEffect(() => { systemRef.current.pause(); }, []); // create burst of 2000 particles using 'onpointerdown' event useEffect(() => { const burst = () => systemRef.current.createBurst(2000); window.addEventListener('pointerdown', burst); return () => window.removeEventListener('pointerdown', burst); }, []); return ( <ParticleSystem ref={ systemRef }> ... </ParticleSystem> ); ``` --- ## Roadmap Planned features for future releases: - **MeshParticle Component**: Instanced meshes as particles for more advanced visuals. - **Color Sampling**: Allow particles to inherit colors from meshes or textures. - **Lighting**: Allow particles to be affected by scene lighting. - **Scene Collisions**: Allow for particle collisions with scene using depth buffer - **Strength over time**: Option for strength over time to give move control with forces. --- ## License MIT License ---