@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 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.