@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/llms.txt
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# @cyberluke/three-particles
|
|
2
|
+
|
|
3
|
+
> Three.js-based high-performance particle system library for creating visually stunning particle effects. Perfect for game developers and 3D applications.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @cyberluke/three-particles three
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import * as THREE from "three";
|
|
13
|
+
import { createParticleSystem, updateParticleSystems } from "@cyberluke/three-particles";
|
|
14
|
+
|
|
15
|
+
const scene = new THREE.Scene();
|
|
16
|
+
|
|
17
|
+
const { instance } = createParticleSystem({
|
|
18
|
+
duration: 5,
|
|
19
|
+
looping: true,
|
|
20
|
+
maxParticles: 100,
|
|
21
|
+
startLifetime: 2,
|
|
22
|
+
startSpeed: 3,
|
|
23
|
+
startSize: 0.5,
|
|
24
|
+
startColor: { min: { r: 1, g: 0.5, b: 0 }, max: { r: 1, g: 1, b: 0 } },
|
|
25
|
+
emission: { rateOverTime: 20 },
|
|
26
|
+
shape: { shape: Shape.CONE, cone: { angle: 0.4, radius: 0.5 } },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
scene.add(instance);
|
|
30
|
+
|
|
31
|
+
// In your animation loop:
|
|
32
|
+
function animate() {
|
|
33
|
+
updateParticleSystems({
|
|
34
|
+
now: performance.now(),
|
|
35
|
+
delta: clock.getDelta(),
|
|
36
|
+
elapsed: clock.getElapsedTime(),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Main API
|
|
42
|
+
|
|
43
|
+
- `createParticleSystem(config: ParticleSystemConfig): ParticleSystem` ??? Create a particle system
|
|
44
|
+
- `updateParticleSystems(cycleData: CycleData)` ??? Update all active particle systems
|
|
45
|
+
|
|
46
|
+
### ParticleSystem Methods
|
|
47
|
+
|
|
48
|
+
- `instance` ??? The Three.js Points or Mesh object (add to scene)
|
|
49
|
+
- `pauseEmitter()` ??? Pause particle emission
|
|
50
|
+
- `resumeEmitter()` ??? Resume particle emission
|
|
51
|
+
- `dispose()` ??? Clean up and free resources
|
|
52
|
+
- `update(cycleData)` ??? Update this specific system only
|
|
53
|
+
- `updateConfig(config)` ??? Update configuration at runtime without recreating the system
|
|
54
|
+
- `getActiveParticleCount()` ??? Number of currently alive particles (O(1))
|
|
55
|
+
|
|
56
|
+
## Key Configuration Properties
|
|
57
|
+
|
|
58
|
+
| Property | Type | Default | Description |
|
|
59
|
+
|----------|------|---------|-------------|
|
|
60
|
+
| duration | number | 5.0 | Duration in seconds |
|
|
61
|
+
| looping | boolean | true | Whether to loop |
|
|
62
|
+
| maxParticles | number | 100 | Maximum active particles |
|
|
63
|
+
| startLifetime | number / {min,max} / Curve | 5.0 | Particle lifetime |
|
|
64
|
+
| startSpeed | number / {min,max} / Curve | 1.0 | Initial speed |
|
|
65
|
+
| startSize | number / {min,max} / Curve | 1.0 | Initial size |
|
|
66
|
+
| startOpacity | number / {min,max} / Curve | 1.0 | Initial opacity |
|
|
67
|
+
| startRotation | number / {min,max} / Curve | 0.0 | Initial rotation (degrees) |
|
|
68
|
+
| startColor | MinMaxColor | white | Color range |
|
|
69
|
+
| gravity | number | 0.0 | Gravity strength |
|
|
70
|
+
| simulationSpace | LOCAL / WORLD | LOCAL | Coordinate space |
|
|
71
|
+
| simulationBackend | AUTO / CPU / GPU | AUTO | Simulation backend (AUTO: GPU if WebGPU, else CPU) |
|
|
72
|
+
| emission | Emission | rateOverTime: 10 | Emission config |
|
|
73
|
+
| shape | ShapeConfig | ??? | Emitter shape |
|
|
74
|
+
| map | THREE.Texture | undefined | Particle texture |
|
|
75
|
+
| renderer | Renderer | ??? | Renderer settings (blending, rendererType, etc.) |
|
|
76
|
+
|
|
77
|
+
## Renderer Types
|
|
78
|
+
|
|
79
|
+
- `RendererType.POINTS` (default) ??? Classic point sprites via `THREE.Points`
|
|
80
|
+
- `RendererType.INSTANCED` ??? Camera-facing quads via `InstancedBufferGeometry`, removes `gl_PointSize` hardware limit
|
|
81
|
+
- `RendererType.TRAIL` ??? Ribbon trails behind particles with configurable width, opacity, and color tapering
|
|
82
|
+
- `RendererType.MESH` ??? Render each particle as a 3D mesh (cubes, spheres, custom geometry) via GPU instancing with quaternion-based 3D rotation and directional lighting. Uses solid white default texture (not circle) to preserve mesh shape. Sub-emitters do not inherit MESH or TRAIL rendererType from parent
|
|
83
|
+
|
|
84
|
+
## Mesh Particle Renderer
|
|
85
|
+
|
|
86
|
+
Configure via `renderer.mesh`:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
renderer: {
|
|
90
|
+
rendererType: RendererType.MESH,
|
|
91
|
+
blending: THREE.NormalBlending,
|
|
92
|
+
transparent: true,
|
|
93
|
+
depthTest: true,
|
|
94
|
+
depthWrite: true,
|
|
95
|
+
mesh: {
|
|
96
|
+
geometry: new THREE.BoxGeometry(1, 1, 1), // Any THREE.BufferGeometry
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Mesh particles use GPU instancing (`InstancedBufferGeometry`). Each particle is a full 3D mesh with quaternion rotation, normals, and UVs preserved. All modifiers (sizeOverLifetime, colorOverLifetime, noise, force fields, sub-emitters) work with mesh particles.
|
|
102
|
+
|
|
103
|
+
## Trail / Ribbon Renderer
|
|
104
|
+
|
|
105
|
+
Configure via `renderer.trail`:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
renderer: {
|
|
109
|
+
rendererType: RendererType.TRAIL,
|
|
110
|
+
blending: THREE.AdditiveBlending,
|
|
111
|
+
transparent: true,
|
|
112
|
+
trail: {
|
|
113
|
+
length: 40, // History samples per particle (default: 20)
|
|
114
|
+
width: 0.5, // Ribbon width in world units (default: 1.0)
|
|
115
|
+
widthOverTrail: { ... }, // LifetimeCurve: width taper (0=head, 1=tail)
|
|
116
|
+
opacityOverTrail: { ... }, // LifetimeCurve: opacity taper
|
|
117
|
+
colorOverTrail: { // Optional per-channel color multipliers
|
|
118
|
+
isActive: true,
|
|
119
|
+
r: { type: LifeTimeCurve.BEZIER, bezierPoints: [...] },
|
|
120
|
+
g: { type: LifeTimeCurve.BEZIER, bezierPoints: [...] },
|
|
121
|
+
b: { type: LifeTimeCurve.BEZIER, bezierPoints: [...] },
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Trails use GPU billboard rendering (vertex shader). Supports optional textures and soft-edge fade.
|
|
128
|
+
|
|
129
|
+
## Emitter Shapes
|
|
130
|
+
|
|
131
|
+
- `Shape.SPHERE` ??? Spherical emission (radius, arc, radiusThickness)
|
|
132
|
+
- `Shape.CONE` ??? Conical emission (angle, radius, arc)
|
|
133
|
+
- `Shape.CIRCLE` ??? Circular flat emission (radius, arc)
|
|
134
|
+
- `Shape.RECTANGLE` ??? Rectangular flat emission (scale, rotation)
|
|
135
|
+
- `Shape.BOX` ??? Box volume emission (scale, emitFrom: VOLUME/SHELL/EDGE)
|
|
136
|
+
|
|
137
|
+
## Lifetime Modifiers
|
|
138
|
+
|
|
139
|
+
- `velocityOverLifetime` ??? Linear & orbital velocity changes
|
|
140
|
+
- `sizeOverLifetime` ??? Size curve over lifetime
|
|
141
|
+
- `opacityOverLifetime` ??? Opacity curve over lifetime
|
|
142
|
+
- `colorOverLifetime` ??? RGB curves (multipliers on startColor)
|
|
143
|
+
- `rotationOverLifetime` ??? Rotation speed range
|
|
144
|
+
- `noise` ??? FBM noise affecting position, rotation, size
|
|
145
|
+
|
|
146
|
+
## Burst Emission
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
emission: {
|
|
150
|
+
rateOverTime: 0,
|
|
151
|
+
bursts: [
|
|
152
|
+
{ time: 0, count: 50 },
|
|
153
|
+
{ time: 1, count: { min: 10, max: 30 }, probability: 0.8 },
|
|
154
|
+
{ time: 0.5, count: 10, cycles: 3, interval: 0.2 },
|
|
155
|
+
],
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Curves
|
|
160
|
+
|
|
161
|
+
Values support: constant `number`, random `{ min, max }`, or curves:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Bezier curve
|
|
165
|
+
{ type: LifeTimeCurve.BEZIER, bezierPoints: [...], scale: 1 }
|
|
166
|
+
|
|
167
|
+
// Easing function
|
|
168
|
+
{ type: LifeTimeCurve.EASING, curveFunction: (t) => t * t, scale: 1 }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Sub-Emitters
|
|
172
|
+
|
|
173
|
+
Trigger child particle systems on particle birth or death:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
subEmitters: [
|
|
177
|
+
{ trigger: SubEmitterTrigger.BIRTH, config: sparkConfig },
|
|
178
|
+
{ trigger: SubEmitterTrigger.DEATH, config: explosionConfig },
|
|
179
|
+
]
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Force Fields
|
|
183
|
+
|
|
184
|
+
Point attractors/repulsors and directional wind forces:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
forceFields: [
|
|
188
|
+
{
|
|
189
|
+
type: ForceFieldType.POINT,
|
|
190
|
+
position: { x: 0, y: 2, z: 0 },
|
|
191
|
+
strength: 5,
|
|
192
|
+
radius: 3,
|
|
193
|
+
falloff: ForceFieldFalloff.LINEAR,
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
type: ForceFieldType.DIRECTIONAL,
|
|
197
|
+
direction: { x: 1, y: 0, z: 0 },
|
|
198
|
+
strength: 2,
|
|
199
|
+
},
|
|
200
|
+
]
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Collision Planes
|
|
204
|
+
|
|
205
|
+
Infinite planes that constrain particles with three response modes: kill, clamp, or bounce.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
collisionPlanes: [
|
|
209
|
+
{ position: { x: 0, y: 0, z: 0 }, normal: { x: 0, y: 1, z: 0 }, mode: CollisionPlaneMode.BOUNCE, dampen: 0.6 },
|
|
210
|
+
{ position: { x: 0, y: 5, z: 0 }, normal: { x: 0, y: -1, z: 0 }, mode: CollisionPlaneMode.KILL },
|
|
211
|
+
]
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## WebGPU Compute Support
|
|
215
|
+
|
|
216
|
+
Optional GPU-accelerated particle simulation via Three.js WebGPU renderer and TSL (Three Shading Language). Enables **50K-350K+ particles** with full physics on the GPU.
|
|
217
|
+
|
|
218
|
+
**Requirements:** Three.js r182+ with WebGPU build (`three/webgpu`), browser with WebGPU support (Chrome 113+, Edge 113+). No breaking changes ??? all existing WebGL code works unchanged.
|
|
219
|
+
|
|
220
|
+
### Setup
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// 1. Enable WebGPU support (once, before creating any particle system)
|
|
224
|
+
import { enableWebGPU } from "@cyberluke/three-particles/webgpu";
|
|
225
|
+
enableWebGPU();
|
|
226
|
+
|
|
227
|
+
// 2. Create a WebGPU renderer
|
|
228
|
+
import * as THREE from "three/webgpu";
|
|
229
|
+
const renderer = new THREE.WebGPURenderer({ antialias: true });
|
|
230
|
+
await renderer.init();
|
|
231
|
+
// No outputColorSpace override needed ??? the library uses the standard
|
|
232
|
+
// three.js linear workflow and works with the default (SRGBColorSpace).
|
|
233
|
+
|
|
234
|
+
// 3. Create a GPU-accelerated particle system
|
|
235
|
+
import { createParticleSystem, SimulationBackend } from "@cyberluke/three-particles";
|
|
236
|
+
const system = createParticleSystem({
|
|
237
|
+
simulationBackend: SimulationBackend.AUTO, // GPU if WebGPU available, else CPU
|
|
238
|
+
maxParticles: 100000,
|
|
239
|
+
// ... rest of config (same API as CPU)
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
scene.add(system.instance);
|
|
243
|
+
|
|
244
|
+
// 4. In your render loop ??? dispatch compute before rendering
|
|
245
|
+
system.update({ now: performance.now(), delta, elapsed });
|
|
246
|
+
if (system.computeNode) {
|
|
247
|
+
renderer.compute(system.computeNode);
|
|
248
|
+
}
|
|
249
|
+
renderer.render(scene, camera);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
For fine-grained control, you can also use `registerTSLMaterialFactory()` to selectively register individual WebGPU functions ??? see the full API reference.
|
|
253
|
+
|
|
254
|
+
### SimulationBackend
|
|
255
|
+
|
|
256
|
+
| Value | WebGPU path registered (`enableWebGPU()`) | Not registered |
|
|
257
|
+
|-------|------------------------------------------|----------------|
|
|
258
|
+
| `AUTO` (default) | GPU compute | CPU (JavaScript) |
|
|
259
|
+
| `CPU` | CPU (JavaScript) | CPU (JavaScript) |
|
|
260
|
+
| `GPU` | GPU compute | CPU (JavaScript) |
|
|
261
|
+
|
|
262
|
+
Note: the library never inspects the renderer on its own ??? the decision is
|
|
263
|
+
based on whether `enableWebGPU()` registered the WebGPU path. Call
|
|
264
|
+
`enableWebGPU(renderer)` (returns boolean) to skip registration automatically
|
|
265
|
+
when the renderer cannot dispatch compute shaders (e.g. `WebGLRenderer`).
|
|
266
|
+
|
|
267
|
+
### What runs on GPU
|
|
268
|
+
|
|
269
|
+
- Core physics: gravity, velocity integration, position update, lifetime tracking
|
|
270
|
+
- All 7 modifiers: size/opacity/color over lifetime, rotation, linear/orbital velocity, noise (3D simplex FBM)
|
|
271
|
+
- Force fields: point/directional with falloff (up to 16 per system)
|
|
272
|
+
- Collision planes: kill/clamp/bounce with dampen and lifetime loss
|
|
273
|
+
- Curves: baked into 256-sample Float32Array lookup tables (<0.4% error)
|
|
274
|
+
|
|
275
|
+
### What stays on CPU
|
|
276
|
+
|
|
277
|
+
- Emission (particle activation, burst scheduling, rate-over-distance)
|
|
278
|
+
- Sub-emitter spawning (birth/death triggers; sub-emitters are forced to CPU backend)
|
|
279
|
+
- Configuration changes (`updateConfig`) ??? note: on the GPU backend, modifier
|
|
280
|
+
flags and lifetime curves (sizeOverLifetime, opacityOverLifetime,
|
|
281
|
+
colorOverLifetime, rotationOverLifetime, velocityOverLifetime,
|
|
282
|
+
noise.isActive) are baked into the compute kernel at creation and cannot be
|
|
283
|
+
changed live (a console warning is logged); recreate the system instead.
|
|
284
|
+
On the CPU backend all of these update live.
|
|
285
|
+
- Trail renderer (`RendererType.TRAIL` always uses CPU simulation)
|
|
286
|
+
|
|
287
|
+
### Compute dispatch
|
|
288
|
+
|
|
289
|
+
The returned `ParticleSystem` exposes `computeNode` (non-null when GPU compute is active). This must be dispatched every frame **before** `renderer.render()`:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
if (system.computeNode) {
|
|
293
|
+
renderer.compute(system.computeNode);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Fallback behavior
|
|
298
|
+
|
|
299
|
+
- If `enableWebGPU()` not called (or no TSL factory registered): uses GLSL shaders (WebGL path) and CPU simulation
|
|
300
|
+
- If `enableWebGPU(renderer)` is called with a renderer that lacks compute support: registration is skipped with a console warning; everything stays on the CPU/GLSL path
|
|
301
|
+
- Same `ParticleSystemConfig` works on both backends ??? but see the `updateConfig` GPU limitation above
|
|
302
|
+
|
|
303
|
+
## Usage with React Three Fiber
|
|
304
|
+
|
|
305
|
+
No wrapper package needed ??? use hooks directly:
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import { useRef, useEffect } from "react";
|
|
309
|
+
import { useFrame } from "@react-three/fiber";
|
|
310
|
+
import { createParticleSystem, type ParticleSystem } from "@cyberluke/three-particles";
|
|
311
|
+
|
|
312
|
+
function ParticleEffect({ config }) {
|
|
313
|
+
const groupRef = useRef(null);
|
|
314
|
+
const systemRef = useRef(null);
|
|
315
|
+
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
const system = createParticleSystem(config);
|
|
318
|
+
systemRef.current = system;
|
|
319
|
+
groupRef.current?.add(system.instance);
|
|
320
|
+
return () => system.dispose();
|
|
321
|
+
}, [config]);
|
|
322
|
+
|
|
323
|
+
useFrame((_, delta) => {
|
|
324
|
+
systemRef.current?.update({ now: performance.now(), delta, elapsed: 0 });
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return <group ref={groupRef} />;
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Key: `useEffect` for create/dispose, `useFrame` for per-frame updates, `system.update()` for individual system control.
|
|
332
|
+
|
|
333
|
+
## Links
|
|
334
|
+
|
|
335
|
+
- Repository: https://github.com/cyberluke/three-particles
|
|
336
|
+
- API docs: shipped TypeScript definitions (`dist/index.d.ts`, `webgpu.d.ts`)
|
|
337
|
+
- Visual Editor: https://github.com/cyberluke/three-particles-editor
|
|
338
|
+
- Editor: `@cyberluke/three-particles-editor`
|
|
339
|
+
- Full LLM reference: `llms-full.txt` included in the npm package.
|
package/package.json
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cyberluke/three-particles",
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Three.js-based high-performance particle system library designed for creating visually stunning particle effects with ease. Perfect for game developers and 3D applications.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"webgpu.d.ts",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"llms.txt",
|
|
15
|
+
"llms-full.txt"
|
|
16
|
+
],
|
|
17
|
+
"llms": "https://newkrok.github.io/three-particles/llms.txt",
|
|
18
|
+
"llmsFull": "https://newkrok.github.io/three-particles/llms-full.txt",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./webgpu": {
|
|
25
|
+
"import": "./dist/webgpu.js",
|
|
26
|
+
"types": "./webgpu.d.ts"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/cyberluke/three-particles.git"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"three",
|
|
35
|
+
"three.js",
|
|
36
|
+
"particles",
|
|
37
|
+
"particle system",
|
|
38
|
+
"webgl",
|
|
39
|
+
"3d",
|
|
40
|
+
"visual effects",
|
|
41
|
+
"game development",
|
|
42
|
+
"3d applications",
|
|
43
|
+
"high performance",
|
|
44
|
+
"javascript",
|
|
45
|
+
"typescript",
|
|
46
|
+
"three-particles",
|
|
47
|
+
"threejs effects"
|
|
48
|
+
],
|
|
49
|
+
"author": "CyberLuke",
|
|
50
|
+
"license": "MIT",
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/cyberluke/three-particles/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/cyberluke/three-particles#readme",
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"prepublishOnly": "npm run build",
|
|
64
|
+
"test": "jest",
|
|
65
|
+
"test:watch": "jest --watch",
|
|
66
|
+
"lint": "eslint src",
|
|
67
|
+
"benchmark": "npm run build && node --experimental-vm-modules benchmarks/run.js",
|
|
68
|
+
"benchmark:json": "npm run build && node --experimental-vm-modules benchmarks/run.js --json",
|
|
69
|
+
"benchmark:compare": "node --experimental-vm-modules benchmarks/run.js --compare",
|
|
70
|
+
"benchmark:save-baseline": "npm run benchmark:json > benchmarks/baseline.json",
|
|
71
|
+
"build:examples": "tsup && webpack --config webpack.docs.config.js",
|
|
72
|
+
"examples:dev": "npm run build:examples && npx http-server examples -p 8081 -o",
|
|
73
|
+
"prepare": "husky"
|
|
74
|
+
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"@newkrok/three-utils": "^2.0.2",
|
|
77
|
+
"easing-functions": "1.3.0",
|
|
78
|
+
"three-noise": "1.1.2"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"three": "^0.186.0"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@babel/preset-env": "^7.29.2",
|
|
85
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
86
|
+
"@commitlint/cli": "^20.5.0",
|
|
87
|
+
"@commitlint/config-conventional": "^20.5.0",
|
|
88
|
+
"@types/jest": "^30.0.0",
|
|
89
|
+
"@types/node": "^25.6.0",
|
|
90
|
+
"@types/three": "^0.183.1",
|
|
91
|
+
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
|
92
|
+
"@typescript-eslint/parser": "^8.58.2",
|
|
93
|
+
"babel-jest": "^30.3.0",
|
|
94
|
+
"eslint": "^9.39.2",
|
|
95
|
+
"eslint-config-prettier": "^10.1.8",
|
|
96
|
+
"eslint-plugin-import": "^2.32.0",
|
|
97
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
98
|
+
"husky": "^9.1.7",
|
|
99
|
+
"jest": "^30.3.0",
|
|
100
|
+
"madge": "^8.0.0",
|
|
101
|
+
"prettier": "^3.8.3",
|
|
102
|
+
"rimraf": "^6.1.3",
|
|
103
|
+
"ts-jest": "^29.4.9",
|
|
104
|
+
"ts-node": "^10.9.2",
|
|
105
|
+
"tsup": "^8.5.1",
|
|
106
|
+
"typedoc": "^0.28.19",
|
|
107
|
+
"typescript": "^5.9.3",
|
|
108
|
+
"webpack": "^5.106.2",
|
|
109
|
+
"webpack-cli": "^7.0.2"
|
|
110
|
+
}
|
|
111
|
+
}
|
package/webgpu.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebGPU entry point type declarations for @cyberluke/three-particles/webgpu.
|
|
3
|
+
*
|
|
4
|
+
* Hand-written because automatic DTS generation fails on TSL node types
|
|
5
|
+
* (Three.js TSL Fn return types resolve to `unknown` in the type system).
|
|
6
|
+
*/
|
|
7
|
+
import type { Material, Blending } from 'three';
|
|
8
|
+
import type { RendererType } from '@cyberluke/three-particles';
|
|
9
|
+
|
|
10
|
+
/** Renderer configuration for material creation. */
|
|
11
|
+
export interface RendererConfig {
|
|
12
|
+
transparent: boolean;
|
|
13
|
+
blending: Blending;
|
|
14
|
+
depthTest: boolean;
|
|
15
|
+
depthWrite: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Creates a TSL NodeMaterial for the main particle system (non-trail). */
|
|
19
|
+
export declare function createTSLParticleMaterial(
|
|
20
|
+
rendererType: RendererType,
|
|
21
|
+
sharedUniforms: Record<string, { value: unknown }>,
|
|
22
|
+
rendererConfig: RendererConfig,
|
|
23
|
+
gpuCompute?: boolean
|
|
24
|
+
): Material;
|
|
25
|
+
|
|
26
|
+
/** Creates a TSL NodeMaterial for the trail ribbon renderer. */
|
|
27
|
+
export declare function createTSLTrailMaterial(
|
|
28
|
+
trailUniforms: Record<string, { value: unknown }>,
|
|
29
|
+
rendererConfig: RendererConfig
|
|
30
|
+
): Material;
|
|
31
|
+
|
|
32
|
+
/** Creates the GPU compute pipeline for particle simulation. */
|
|
33
|
+
export declare function createComputePipeline(
|
|
34
|
+
maxParticles: number,
|
|
35
|
+
instanced: boolean,
|
|
36
|
+
normalizedConfig: unknown,
|
|
37
|
+
particleSystemId: number,
|
|
38
|
+
forceFieldCount: number,
|
|
39
|
+
collisionPlaneCount?: number
|
|
40
|
+
): unknown;
|
|
41
|
+
|
|
42
|
+
/** Writes init data for a newly emitted particle into modifier storage buffers. */
|
|
43
|
+
export declare function writeParticleToModifierBuffers(
|
|
44
|
+
buffers: unknown,
|
|
45
|
+
index: number,
|
|
46
|
+
data: Record<string, unknown>
|
|
47
|
+
): void;
|
|
48
|
+
|
|
49
|
+
/** Deactivates a particle in the modifier storage buffers. */
|
|
50
|
+
export declare function deactivateParticleInModifierBuffers(
|
|
51
|
+
buffers: unknown,
|
|
52
|
+
index: number
|
|
53
|
+
): void;
|
|
54
|
+
|
|
55
|
+
/** Flushes pending init data to the GPU. Call once per frame before compute dispatch. */
|
|
56
|
+
export declare function flushEmitQueue(buffers: unknown): number;
|
|
57
|
+
|
|
58
|
+
/** Registers the curve data length for a buffer. Called once during pipeline creation. */
|
|
59
|
+
export declare function registerCurveDataLength(
|
|
60
|
+
buffers: unknown,
|
|
61
|
+
curveDataLength: number
|
|
62
|
+
): void;
|
|
63
|
+
|
|
64
|
+
/** Packs force field configs into a flat Float32Array for GPU upload. */
|
|
65
|
+
export declare function encodeForceFieldsForGPU(
|
|
66
|
+
forceFields: ReadonlyArray<unknown>,
|
|
67
|
+
particleSystemId: number,
|
|
68
|
+
systemLifetimePercentage: number
|
|
69
|
+
): Float32Array;
|
|
70
|
+
|
|
71
|
+
/** Packs collision plane configs into a flat Float32Array for GPU upload. */
|
|
72
|
+
export declare function encodeCollisionPlanesForGPU(
|
|
73
|
+
planes: ReadonlyArray<unknown>
|
|
74
|
+
): Float32Array;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Convenience function that registers all WebGPU TSL material factories
|
|
78
|
+
* and GPU compute helpers in a single call.
|
|
79
|
+
*
|
|
80
|
+
* Call this **once** before creating any particle systems that use WebGPU rendering.
|
|
81
|
+
*
|
|
82
|
+
* Pass your renderer to get automatic capability detection: when the
|
|
83
|
+
* renderer cannot dispatch compute shaders (e.g. `THREE.WebGLRenderer`),
|
|
84
|
+
* registration is skipped with a console warning and all particle systems
|
|
85
|
+
* keep using the CPU/GLSL path.
|
|
86
|
+
*
|
|
87
|
+
* @param renderer - Optional Three.js renderer used for capability detection.
|
|
88
|
+
* @returns `true` when the WebGPU path was registered, `false` when the
|
|
89
|
+
* provided renderer is not compute-capable and registration was skipped.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { enableWebGPU } from '@cyberluke/three-particles/webgpu';
|
|
94
|
+
* const renderer = new THREE.WebGPURenderer();
|
|
95
|
+
* const gpuEnabled = enableWebGPU(renderer);
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function enableWebGPU(renderer?: unknown): boolean;
|