@cyberluke/three-particles 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/index.d.ts +2970 -0
- package/dist/index.js +3138 -0
- package/dist/index.js.map +1 -0
- package/dist/three-particles.min.js +1 -0
- package/dist/three-particles.min.js.map +1 -0
- package/dist/webgpu.js +2522 -0
- package/dist/webgpu.js.map +1 -0
- package/llms-full.txt +1005 -0
- package/llms.txt +339 -0
- package/package.json +111 -0
- package/webgpu.d.ts +98 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 CyberLuke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/images/logo-colorful.png" alt="THREE Particles Logo" width="150" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# THREE Particles
|
|
6
|
+
|
|
7
|
+
Best-in-class particle framework for Three.js. Unity-style effects with a GPU-compute backbone: Three.js TSL kernels run gravity, orbital motion, Bézier over-lifetime curves, force fields and 3D simplex noise for 350K+ particles per system at full framerate.
|
|
8
|
+
|
|
9
|
+
Author: **CyberLuke** — the single maintained line since v4.
|
|
10
|
+
|
|
11
|
+
# Features
|
|
12
|
+
|
|
13
|
+
* Easy integration with Three.js.
|
|
14
|
+
* Visual editor for fine-tuning and exporting effect configs (`@cyberluke/three-particles-editor`).
|
|
15
|
+
* Highly customizable particle properties (position, velocity, size, color, alpha, rotation, etc.).
|
|
16
|
+
* Support for various emitter shapes and parameters.
|
|
17
|
+
* Force fields and attractors for dynamic particle behavior (point attraction/repulsion, directional wind) — up to 16 per system.
|
|
18
|
+
* Collision planes — kill, clamp, or bounce particles off infinite planes (e.g., water surfaces, floors, walls). Part of the compute pass.
|
|
19
|
+
* Sub-emitters triggered on particle birth or death events (GPU ping-pong event buffers).
|
|
20
|
+
* Baked Bézier over-lifetime curves — 256-sample lookup arrays (`curve-bake.ts`), <0.4% max interpolation error.
|
|
21
|
+
* Four renderer types (`RendererType`): `POINTS` (billboard quads), `INSTANCED` (GPU instancing, no `gl_PointSize` limit), `TRAIL` (ribbon trails with width/opacity/color tapering), `MESH` (instanced 3D meshes with full rotation and lighting).
|
|
22
|
+
* Soft particles — depth-based alpha fade near opaque geometry.
|
|
23
|
+
* **WebGPU compute** — all per-particle physics runs in TSL compute kernels (`SimulationBackend.GPU`); `AUTO` uses the registered WebGPU path, `CPU` maps to the identical GPU path in this GPU-only build.
|
|
24
|
+
* TypeScript definitions shipped (`dist/index.d.ts`, `webgpu.d.ts`).
|
|
25
|
+
|
|
26
|
+
# Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @cyberluke/three-particles
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Both entry points are plain ESM (no separate CDN files; the package ships `dist/index.js`, `dist/webgpu.js` and a minified `dist/three-particles.min.js`).
|
|
33
|
+
|
|
34
|
+
# Usage
|
|
35
|
+
|
|
36
|
+
The engine is **GPU-only** (v4): a WebGPU backend is required before creating any system.
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import * as THREE from "three/webgpu";
|
|
40
|
+
import {
|
|
41
|
+
createParticleSystem,
|
|
42
|
+
updateParticleSystems,
|
|
43
|
+
Shape,
|
|
44
|
+
} from "@cyberluke/three-particles";
|
|
45
|
+
import { enableWebGPU } from "@cyberluke/three-particles/webgpu";
|
|
46
|
+
|
|
47
|
+
// 1. WebGPU renderer, then register the library with it (once)
|
|
48
|
+
const renderer = new THREE.WebGPURenderer({ antialias: true });
|
|
49
|
+
await renderer.init();
|
|
50
|
+
enableWebGPU(renderer); // false + warning if the backend lacks compute
|
|
51
|
+
|
|
52
|
+
// 2. Create a system (same config shape the editor exports)
|
|
53
|
+
const system = createParticleSystem({
|
|
54
|
+
maxParticles: 100000,
|
|
55
|
+
gravity: -9.8,
|
|
56
|
+
emission: { rateOverTime: 50 },
|
|
57
|
+
shape: { shape: Shape.CONE, cone: { angle: 0.2, radius: 0.3 } },
|
|
58
|
+
forceFields: [
|
|
59
|
+
{ type: "DIRECTIONAL", direction: { x: 1, y: 0, z: 0 }, strength: 5 },
|
|
60
|
+
],
|
|
61
|
+
collisionPlanes: [
|
|
62
|
+
{ position: { x: 0, y: 5, z: 0 }, normal: { x: 0, y: -1, z: 0 }, mode: "KILL" },
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
scene.add(system.instance);
|
|
66
|
+
|
|
67
|
+
// 3. Render loop — dispatch compute, then render
|
|
68
|
+
renderer.setAnimationLoop(() => {
|
|
69
|
+
const delta = clock.getDelta();
|
|
70
|
+
system.update({ now: performance.now(), delta, elapsed: clock.elapsedTime });
|
|
71
|
+
if (system.computeNode) renderer.compute(system.computeNode);
|
|
72
|
+
renderer.render(scene, camera);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// or drive every created system at once:
|
|
76
|
+
updateParticleSystems({ now: performance.now(), delta, elapsed });
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`updateParticleSystems(cycleData)` and per-system `system.update(cycleData)` take the same `CycleData` object: `{ now, delta, elapsed }` (see `types.ts`). `system.updateConfig(...)` applies on the next compute dispatch; `system.dispose()` releases buffers.
|
|
80
|
+
|
|
81
|
+
Note on `rendererType`: `POINTS` is the billboard-quad path (a unit quad per particle sampled with a computed point UV — there is no point-sprite mode on the GPU backend because WGSL has no `gl_PointCoord`), `INSTANCED`/`MESH` use `InstancedBufferGeometry`, `TRAIL` fills a GPU history ring (`StorageBufferAttribute`) that the ribbon material reads.
|
|
82
|
+
|
|
83
|
+
# Usage with Three.js
|
|
84
|
+
|
|
85
|
+
- **Three.js r186+** (`"three": "^0.186.0"` — the exact peer version pinned in `package.json`) with the WebGPU build (`three/webgpu`).
|
|
86
|
+
- A browser with [WebGPU support](https://caniuse.com/webgpu) (Chrome 113+, Edge 113+, Firefox 186+ / Nightly).
|
|
87
|
+
- The v4 engine ships a single WebGPU code path (`SimulationBackend.GPU`); config objects are otherwise identical to older 3.x configs.
|
|
88
|
+
|
|
89
|
+
# Usage with React Three Fiber
|
|
90
|
+
|
|
91
|
+
As of now we **do not recommend** using react-three-fiber with this engine: with react 19.3 the fiber integration is breaking (tracked upstream in [pmndrs/react-three-fiber#3915](https://github.com/pmndrs/react-three-fiber/issues/3915)). Use **three.js r186+ directly** — `WebGPURenderer` + the loop shown above is all you need:
|
|
92
|
+
|
|
93
|
+
```javascript
|
|
94
|
+
import * as THREE from "three/webgpu";
|
|
95
|
+
import { createParticleSystem } from "@cyberluke/three-particles";
|
|
96
|
+
|
|
97
|
+
const renderer = new THREE.WebGPURenderer({ antialias: true });
|
|
98
|
+
await renderer.init();
|
|
99
|
+
|
|
100
|
+
const scene = new THREE.Scene();
|
|
101
|
+
const camera = new THREE.PerspectiveCamera(50, 1, 0.1, 100);
|
|
102
|
+
// ... system = createParticleSystem(config); scene.add(system.instance);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
# WebGPU Compute Support
|
|
106
|
+
|
|
107
|
+
Optional GPU-accelerated particle simulation via Three.js WebGPU renderer and TSL (Three Shading Language). Offloads all per-particle physics and modifiers to GPU compute shaders, enabling **50K-350K+ particles** at interactive frame rates.
|
|
108
|
+
|
|
109
|
+
The CPU path used to be the bottleneck for real 350K+ particle counts, so the whole pipeline was reworked around TSL compute kernels. Current split (grounded in `src/js/effects/three-particles/webgpu/`):
|
|
110
|
+
|
|
111
|
+
## What Runs on GPU (TSL compute kernels)
|
|
112
|
+
|
|
113
|
+
- **Core physics** (`compute-particle-update.ts`): gravity, velocity integration, position update, lifetime tracking
|
|
114
|
+
- **All 7 modifiers** (`compute-modifiers.ts`): size/opacity/color over lifetime, rotation, linear velocity, orbital velocity, noise (3D simplex FBM)
|
|
115
|
+
- **Force fields** (`compute-force-fields.ts`): point attractors/repulsors and directional forces with falloff — `MAX_FORCE_FIELDS = 16`
|
|
116
|
+
- **Collision planes** (`compute-collision-planes.ts`): kill/clamp/bounce evaluated inside the compute pass
|
|
117
|
+
- **Curves** (`curve-bake.ts`): baked into `CURVE_RESOLUTION = 256`-sample lookup arrays for fast GPU evaluation (<0.4% error)
|
|
118
|
+
|
|
119
|
+
The same kernel also fills the `TRAIL` history ring, ping-pong sub-emitter birth/death buffers and the free-list allocator — all as `StorageBufferAttribute`s read directly by the materials.
|
|
120
|
+
|
|
121
|
+
## What Stays on CPU
|
|
122
|
+
|
|
123
|
+
- **Emission** — particle activation, burst scheduling, rate-over-distance
|
|
124
|
+
- **Sub-emitters** — birth/death trigger spawning
|
|
125
|
+
- **Configuration changes** — `updateConfig()` applies on the next frame
|
|
126
|
+
- **Trail renderer** — TRAIL type always uses CPU simulation (other renderer types work with GPU)
|
|
127
|
+
|
|
128
|
+
# Important Notes
|
|
129
|
+
|
|
130
|
+
## Color Conventions
|
|
131
|
+
|
|
132
|
+
All RGB values in particle configs (`startColor`, `backgroundColor`) are
|
|
133
|
+
**sRGB** — the same convention used everywhere else in three.js. Pass the
|
|
134
|
+
value a color picker gives you (e.g. `{ r: 1, g: 0, b: 0 }` for pure red)
|
|
135
|
+
and the renderer will display it correctly.
|
|
136
|
+
|
|
137
|
+
Internally the library decodes these to linear for shader math and relies
|
|
138
|
+
on the renderer's standard output pass to convert back to sRGB on the way
|
|
139
|
+
to the framebuffer. No special `outputColorSpace` setup is required; the
|
|
140
|
+
three.js default (`SRGBColorSpace`) works.
|
|
141
|
+
|
|
142
|
+
User-supplied color map textures should also be tagged as sRGB
|
|
143
|
+
(`texture.colorSpace = THREE.SRGBColorSpace`) — this is also the
|
|
144
|
+
three.js default for color textures loaded via `TextureLoader`.
|
|
145
|
+
|
|
146
|
+
## Color Over Lifetime
|
|
147
|
+
|
|
148
|
+
The `colorOverLifetime` feature uses a **multiplier-based approach** (similar to Unity's particle system), where each RGB channel curve acts as a multiplier applied to the particle's `startColor`.
|
|
149
|
+
|
|
150
|
+
**Formula:** `finalColor = startColor * colorOverLifetime`
|
|
151
|
+
|
|
152
|
+
> [!IMPORTANT]
|
|
153
|
+
> To achieve full color transitions, set `startColor` to white `{ r: 1, g: 1, b: 1 }`. If any channel in `startColor` is set to 0, that channel cannot be modified by `colorOverLifetime`.
|
|
154
|
+
|
|
155
|
+
**Example - Rainbow effect:**
|
|
156
|
+
```javascript
|
|
157
|
+
{
|
|
158
|
+
startColor: {
|
|
159
|
+
min: { r: 1, g: 1, b: 1 }, // White - allows full color range
|
|
160
|
+
max: { r: 1, g: 1, b: 1 }
|
|
161
|
+
},
|
|
162
|
+
colorOverLifetime: {
|
|
163
|
+
isActive: true,
|
|
164
|
+
r: { // Red: full → half → off
|
|
165
|
+
type: 'BEZIER',
|
|
166
|
+
scale: 1,
|
|
167
|
+
bezierPoints: [
|
|
168
|
+
{ x: 0, y: 1, percentage: 0 },
|
|
169
|
+
{ x: 0.5, y: 0.5, percentage: 0.5 },
|
|
170
|
+
{ x: 1, y: 0, percentage: 1 }
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
g: { // Green: off → full → off
|
|
174
|
+
type: 'BEZIER',
|
|
175
|
+
scale: 1,
|
|
176
|
+
bezierPoints: [
|
|
177
|
+
{ x: 0, y: 0, percentage: 0 },
|
|
178
|
+
{ x: 0.5, y: 1, percentage: 0.5 },
|
|
179
|
+
{ x: 1, y: 0, percentage: 1 }
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
b: { // Blue: off → half → full
|
|
183
|
+
type: 'BEZIER',
|
|
184
|
+
scale: 1,
|
|
185
|
+
bezierPoints: [
|
|
186
|
+
{ x: 0, y: 0, percentage: 0 },
|
|
187
|
+
{ x: 0.5, y: 0.5, percentage: 0.5 },
|
|
188
|
+
{ x: 1, y: 1, percentage: 1 }
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Documentation
|
|
196
|
+
|
|
197
|
+
Full API types ship with the package: `dist/index.d.ts` and `webgpu.d.ts`. A machine-readable overview is included as `llms.txt` / `llms-full.txt` in the package.
|