@cazala/party 0.0.0

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.
Files changed (73) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +598 -0
  3. package/dist/engine.d.ts +113 -0
  4. package/dist/engine.d.ts.map +1 -0
  5. package/dist/index.d.ts +8 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +9628 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/interfaces.d.ts +223 -0
  10. package/dist/interfaces.d.ts.map +1 -0
  11. package/dist/module.d.ts +259 -0
  12. package/dist/module.d.ts.map +1 -0
  13. package/dist/modules/forces/behavior.d.ts +78 -0
  14. package/dist/modules/forces/behavior.d.ts.map +1 -0
  15. package/dist/modules/forces/boundary.d.ts +58 -0
  16. package/dist/modules/forces/boundary.d.ts.map +1 -0
  17. package/dist/modules/forces/collisions.d.ts +34 -0
  18. package/dist/modules/forces/collisions.d.ts.map +1 -0
  19. package/dist/modules/forces/environment.d.ts +62 -0
  20. package/dist/modules/forces/environment.d.ts.map +1 -0
  21. package/dist/modules/forces/fluids.d.ts +73 -0
  22. package/dist/modules/forces/fluids.d.ts.map +1 -0
  23. package/dist/modules/forces/grab.d.ts +56 -0
  24. package/dist/modules/forces/grab.d.ts.map +1 -0
  25. package/dist/modules/forces/interaction.d.ts +59 -0
  26. package/dist/modules/forces/interaction.d.ts.map +1 -0
  27. package/dist/modules/forces/joints.d.ts +87 -0
  28. package/dist/modules/forces/joints.d.ts.map +1 -0
  29. package/dist/modules/forces/sensors.d.ts +81 -0
  30. package/dist/modules/forces/sensors.d.ts.map +1 -0
  31. package/dist/modules/index.d.ts +13 -0
  32. package/dist/modules/index.d.ts.map +1 -0
  33. package/dist/modules/render/lines.d.ts +55 -0
  34. package/dist/modules/render/lines.d.ts.map +1 -0
  35. package/dist/modules/render/particles.d.ts +53 -0
  36. package/dist/modules/render/particles.d.ts.map +1 -0
  37. package/dist/modules/render/trails.d.ts +36 -0
  38. package/dist/modules/render/trails.d.ts.map +1 -0
  39. package/dist/oscillators.d.ts +66 -0
  40. package/dist/oscillators.d.ts.map +1 -0
  41. package/dist/particle.d.ts +19 -0
  42. package/dist/particle.d.ts.map +1 -0
  43. package/dist/runtimes/cpu/engine.d.ts +60 -0
  44. package/dist/runtimes/cpu/engine.d.ts.map +1 -0
  45. package/dist/runtimes/cpu/spatial-grid.d.ts +56 -0
  46. package/dist/runtimes/cpu/spatial-grid.d.ts.map +1 -0
  47. package/dist/runtimes/webgpu/builders/program.d.ts +56 -0
  48. package/dist/runtimes/webgpu/builders/program.d.ts.map +1 -0
  49. package/dist/runtimes/webgpu/builders/render-pass.d.ts +26 -0
  50. package/dist/runtimes/webgpu/builders/render-pass.d.ts.map +1 -0
  51. package/dist/runtimes/webgpu/engine.d.ts +73 -0
  52. package/dist/runtimes/webgpu/engine.d.ts.map +1 -0
  53. package/dist/runtimes/webgpu/gpu-resources.d.ts +141 -0
  54. package/dist/runtimes/webgpu/gpu-resources.d.ts.map +1 -0
  55. package/dist/runtimes/webgpu/module-registry.d.ts +53 -0
  56. package/dist/runtimes/webgpu/module-registry.d.ts.map +1 -0
  57. package/dist/runtimes/webgpu/particle-store.d.ts +43 -0
  58. package/dist/runtimes/webgpu/particle-store.d.ts.map +1 -0
  59. package/dist/runtimes/webgpu/render-pipeline.d.ts +49 -0
  60. package/dist/runtimes/webgpu/render-pipeline.d.ts.map +1 -0
  61. package/dist/runtimes/webgpu/shaders.d.ts +8 -0
  62. package/dist/runtimes/webgpu/shaders.d.ts.map +1 -0
  63. package/dist/runtimes/webgpu/simulation-pipeline.d.ts +22 -0
  64. package/dist/runtimes/webgpu/simulation-pipeline.d.ts.map +1 -0
  65. package/dist/runtimes/webgpu/spacial-grid.d.ts +27 -0
  66. package/dist/runtimes/webgpu/spacial-grid.d.ts.map +1 -0
  67. package/dist/spawner.d.ts +40 -0
  68. package/dist/spawner.d.ts.map +1 -0
  69. package/dist/vector.d.ts +61 -0
  70. package/dist/vector.d.ts.map +1 -0
  71. package/dist/view.d.ts +43 -0
  72. package/dist/view.d.ts.map +1 -0
  73. package/package.json +67 -0
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 cazala
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.
22
+
23
+
package/README.md ADDED
@@ -0,0 +1,598 @@
1
+ # @cazala/party
2
+
3
+ A high-performance TypeScript particle physics engine with dual runtime support (WebGPU compute + CPU fallback), modular architecture, and real-time parameter oscillation.
4
+
5
+ ## Features
6
+
7
+ - **Dual Runtime Architecture**: Automatic WebGPU/CPU runtime selection with seamless fallback
8
+ - **GPU Compute Performance**: WebGPU shaders for parallel particle processing at scale
9
+ - **Modular Force System**: Pluggable physics modules with four-phase lifecycle
10
+ - **Spatial Grid Optimization**: Efficient O(1) neighbor queries for collision detection
11
+ - **Real-time Oscillators**: Animate any module parameter with configurable frequency and bounds
12
+ - **Advanced Rendering**: Trails, particle instancing, line rendering with multiple color modes
13
+ - **Session Management**: Export/import complete simulation configurations
14
+ - **Cross-platform**: Works in all modern browsers with automatic feature detection
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @cazala/party
20
+ ```
21
+
22
+ > **Development Note**: This package is part of a pnpm workspace. For development, clone the full repository and use `npm run setup` from the root.
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import {
28
+ Engine,
29
+ // Force modules
30
+ Environment,
31
+ Boundary,
32
+ Collisions,
33
+ Behavior,
34
+ Fluids,
35
+ // Render modules
36
+ Particles,
37
+ Trails,
38
+ } from "@cazala/party";
39
+
40
+ const canvas = document.querySelector("canvas")!;
41
+
42
+ const forces = [
43
+ new Environment({
44
+ gravityStrength: 600,
45
+ gravityDirection: "down",
46
+ inertia: 0.05,
47
+ friction: 0.01,
48
+ }),
49
+ new Boundary({
50
+ mode: "bounce",
51
+ restitution: 0.9,
52
+ friction: 0.1,
53
+ }),
54
+ new Collisions({ restitution: 0.85 }),
55
+ new Behavior({
56
+ cohesion: 1.5,
57
+ alignment: 1.2,
58
+ separation: 12,
59
+ viewRadius: 100,
60
+ }),
61
+ new Fluids({
62
+ influenceRadius: 80,
63
+ pressureMultiplier: 25,
64
+ viscosity: 0.8,
65
+ }),
66
+ ];
67
+
68
+ const render = [
69
+ new Trails({ trailDecay: 10, trailDiffuse: 4 }),
70
+ new Particles({ colorType: 2, hue: 0.55 }),
71
+ ];
72
+
73
+ const engine = new Engine({
74
+ canvas,
75
+ forces,
76
+ render,
77
+ runtime: "auto", // Auto-selects WebGPU when available
78
+ });
79
+
80
+ await engine.initialize();
81
+
82
+ // Add particles
83
+ for (let i = 0; i < 100; i++) {
84
+ engine.addParticle({
85
+ x: Math.random() * canvas.width,
86
+ y: Math.random() * canvas.height,
87
+ vx: (Math.random() - 0.5) * 4,
88
+ vy: (Math.random() - 0.5) * 4,
89
+ mass: 1 + Math.random() * 2,
90
+ size: 3 + Math.random() * 7,
91
+ });
92
+ }
93
+
94
+ engine.play();
95
+ ```
96
+
97
+ ## Core Concepts
98
+
99
+ ### Engine
100
+
101
+ The `Engine` class provides a unified API that automatically selects the best runtime:
102
+
103
+ ```typescript
104
+ const engine = new Engine({
105
+ canvas: HTMLCanvasElement,
106
+ forces: Module[], // Force modules
107
+ render: Module[], // Render modules
108
+ runtime: "auto", // "auto" | "webgpu" | "cpu"
109
+
110
+ // Optional configuration
111
+ constrainIterations: 50, // Constraint solver iterations
112
+ cellSize: 32, // Spatial grid cell size
113
+ maxNeighbors: 128, // Max neighbors per particle
114
+ maxParticles: 10000, // Particle capacity
115
+ clearColor: "#000000", // Background color
116
+ });
117
+
118
+ // Lifecycle
119
+ await engine.initialize();
120
+ engine.play();
121
+ engine.pause();
122
+ engine.stop();
123
+ engine.destroy();
124
+
125
+ // State
126
+ const isPlaying = engine.isPlaying();
127
+ const fps = engine.getFPS();
128
+ const count = engine.getCount();
129
+
130
+ // Particles
131
+ engine.addParticle({ x, y, vx, vy, mass, size });
132
+ engine.setParticles([...particles]);
133
+ const particles = await engine.getParticles();
134
+ engine.clear();
135
+
136
+ // View
137
+ engine.setSize(width, height);
138
+ engine.setCamera(x, y);
139
+ engine.setZoom(scale);
140
+
141
+ // Configuration
142
+ const config = engine.export();
143
+ engine.import(config);
144
+ ```
145
+
146
+ ### Runtime Selection
147
+
148
+ - **"auto"**: Tries WebGPU first, falls back to CPU if unavailable
149
+ - **"webgpu"**: GPU compute with WGSL shaders (Chrome 113+, Edge 113+)
150
+ - **"cpu"**: JavaScript simulation with Canvas2D rendering (universal compatibility)
151
+
152
+ ```typescript
153
+ // Check which runtime is active
154
+ const runtime = engine.getActualRuntime(); // "webgpu" | "cpu"
155
+
156
+ // Test module support
157
+ const isSupported = engine.isSupported(module);
158
+ ```
159
+
160
+ ### Particles
161
+
162
+ Particles are simple data structures with physics properties:
163
+
164
+ ```typescript
165
+ const particle = {
166
+ x: 100, y: 100, // Position
167
+ vx: 1, vy: -2, // Velocity
168
+ mass: 2.5, // Mass (negative = pinned)
169
+ size: 8, // Visual size
170
+ color: 0xff6b35, // Color (24-bit RGB)
171
+ };
172
+
173
+ // Bulk operations (preferred for performance)
174
+ engine.setParticles(particles);
175
+ const allParticles = await engine.getParticles();
176
+
177
+ // Individual operations
178
+ engine.addParticle(particle);
179
+ const singleParticle = await engine.getParticle(index);
180
+
181
+ // Pin/unpin helpers
182
+ engine.pinParticles([0, 1, 2]);
183
+ engine.unpinParticles([0, 1, 2]);
184
+ engine.unpinAll();
185
+ ```
186
+
187
+ ### Modules
188
+
189
+ Modules are pluggable components that contribute to simulation or rendering:
190
+
191
+ ```typescript
192
+ // Force modules affect particle physics
193
+ const forces = [
194
+ new Environment({ gravityStrength: 1000 }),
195
+ new Boundary({ mode: "bounce" }),
196
+ new Collisions({ restitution: 0.8 }),
197
+ ];
198
+
199
+ // Render modules draw visual effects
200
+ const render = [
201
+ new Particles({ colorType: 2, hue: 0.5 }),
202
+ new Trails({ trailDecay: 10 }),
203
+ ];
204
+
205
+ // Module control
206
+ const module = engine.getModule("environment");
207
+ module.setEnabled(false);
208
+ const isEnabled = module.isEnabled();
209
+
210
+ // Read/write module inputs
211
+ const inputs = module.read();
212
+ module.write({ gravityStrength: 500 });
213
+ ```
214
+
215
+ ## Available Modules
216
+
217
+ ### Force Modules
218
+
219
+ #### Environment
220
+ Global physics: gravity, inertia, friction, damping
221
+
222
+ ```typescript
223
+ new Environment({
224
+ gravityStrength: 600, // Gravity magnitude
225
+ gravityDirection: "down", // "up"|"down"|"left"|"right"|"inwards"|"outwards"|"custom"
226
+ gravityAngle: Math.PI / 4, // Custom angle (when direction = "custom")
227
+ inertia: 0.05, // Momentum preservation (0-1)
228
+ friction: 0.01, // Velocity damping (0-1)
229
+ damping: 0.02, // Direct velocity reduction (0-1)
230
+ })
231
+ ```
232
+
233
+ #### Boundary
234
+ Boundary interactions and containment
235
+
236
+ ```typescript
237
+ new Boundary({
238
+ mode: "bounce", // "bounce"|"warp"|"kill"|"none"
239
+ restitution: 0.9, // Bounce energy retention (0-1)
240
+ friction: 0.1, // Tangential friction (0-1)
241
+ repelDistance: 50, // Distance to start repel force
242
+ repelStrength: 0.5, // Repel force magnitude
243
+ })
244
+ ```
245
+
246
+ #### Collisions
247
+ Particle-particle collision detection and response
248
+
249
+ ```typescript
250
+ new Collisions({
251
+ restitution: 0.8, // Collision elasticity (0-1)
252
+ })
253
+ ```
254
+
255
+ #### Behavior
256
+ Flocking behaviors (boids-style steering)
257
+
258
+ ```typescript
259
+ new Behavior({
260
+ cohesion: 1.5, // Attraction to group center
261
+ alignment: 1.2, // Velocity matching
262
+ repulsion: 2.0, // Separation force
263
+ separation: 12, // Personal space radius
264
+ viewRadius: 100, // Neighbor detection radius
265
+ viewAngle: Math.PI, // Field of view (radians)
266
+ wander: 20, // Random exploration
267
+ chase: 0.5, // Pursue lighter particles
268
+ avoid: 0.3, // Flee heavier particles
269
+ })
270
+ ```
271
+
272
+ #### Fluids
273
+ Smoothed Particle Hydrodynamics (SPH) fluid simulation
274
+
275
+ ```typescript
276
+ new Fluids({
277
+ influenceRadius: 80, // Particle interaction radius
278
+ targetDensity: 1.0, // Rest density
279
+ pressureMultiplier: 25, // Pressure force strength
280
+ viscosity: 0.8, // Internal friction
281
+ nearPressureMultiplier: 40, // Near-field pressure
282
+ nearThreshold: 18, // Near-field distance
283
+ enableNearPressure: true, // Enable near-field forces
284
+ maxAcceleration: 60, // Force clamping for stability
285
+ })
286
+ ```
287
+
288
+ #### Sensors
289
+ Trail-following and color-based steering
290
+
291
+ ```typescript
292
+ new Sensors({
293
+ sensorDistance: 30, // Sensor projection distance
294
+ sensorAngle: Math.PI / 6, // Sensor angle offset (30°)
295
+ sensorRadius: 3, // Sensor detection radius
296
+ sensorThreshold: 0.15, // Minimum detection threshold
297
+ sensorStrength: 800, // Steering force magnitude
298
+ followBehavior: "any", // "any"|"same"|"different"|"none"
299
+ fleeBehavior: "none", // "any"|"same"|"different"|"none"
300
+ colorSimilarityThreshold: 0.5, // Color matching threshold
301
+ fleeAngle: Math.PI / 2, // Flee direction offset (90°)
302
+ })
303
+ ```
304
+
305
+ #### Interaction
306
+ User-controlled attraction and repulsion
307
+
308
+ ```typescript
309
+ const interaction = new Interaction({
310
+ mode: "attract", // "attract"|"repel"
311
+ strength: 12000, // Force magnitude
312
+ radius: 300, // Interaction radius
313
+ active: false, // Initially inactive
314
+ });
315
+
316
+ // Control interaction
317
+ interaction.setPosition(mouseX, mouseY);
318
+ interaction.setActive(true);
319
+ interaction.setMode("repel");
320
+ ```
321
+
322
+ #### Joints
323
+ Distance constraints between particles
324
+
325
+ ```typescript
326
+ const joints = new Joints({
327
+ momentum: 0.7, // Momentum preservation (0-1)
328
+ restitution: 0.9, // Joint elasticity
329
+ separation: 0.5, // Separation force strength
330
+ steps: 2, // Constraint iterations
331
+ friction: 0.02, // Joint friction
332
+ enableParticleCollisions: false, // Particle-joint collisions
333
+ enableJointCollisions: false, // Joint-joint collisions
334
+ });
335
+
336
+ // Manage joints
337
+ joints.setJoints([
338
+ { aIndex: 0, bIndex: 1, restLength: 50 },
339
+ { aIndex: 1, bIndex: 2, restLength: 75 },
340
+ ]);
341
+ joints.add({ aIndex: 2, bIndex: 3, restLength: 100 });
342
+ joints.remove(0, 1);
343
+ joints.removeAll();
344
+ ```
345
+
346
+ #### Grab
347
+ Single-particle mouse/touch dragging
348
+
349
+ ```typescript
350
+ const grab = new Grab();
351
+
352
+ // Grab particle
353
+ grab.grabParticle(particleIndex, { x: mouseX, y: mouseY });
354
+
355
+ // Update position
356
+ grab.updatePosition(newX, newY);
357
+
358
+ // Release
359
+ grab.releaseParticle();
360
+
361
+ // Check state
362
+ const isGrabbing = grab.isGrabbing();
363
+ ```
364
+
365
+ ### Render Modules
366
+
367
+ #### Particles
368
+ Instanced particle rendering with multiple color modes
369
+
370
+ ```typescript
371
+ new Particles({
372
+ colorType: 2, // 0=Default, 1=Custom, 2=Hue
373
+ customColorR: 1.0, // Custom color red (0-1)
374
+ customColorG: 0.4, // Custom color green (0-1)
375
+ customColorB: 0.2, // Custom color blue (0-1)
376
+ hue: 0.55, // Hue value (0-1) when colorType=2
377
+ })
378
+
379
+ // Pinned particles render as rings
380
+ // Particle size and color come from particle data
381
+ ```
382
+
383
+ #### Trails
384
+ Decay and diffusion effects
385
+
386
+ ```typescript
387
+ new Trails({
388
+ trailDecay: 10, // Fade speed (higher = faster fade)
389
+ trailDiffuse: 4, // Blur amount (0-12 typical)
390
+ })
391
+ ```
392
+
393
+ #### Lines
394
+ Line rendering between particle pairs
395
+
396
+ ```typescript
397
+ const lines = new Lines({
398
+ lineWidth: 2.0, // Line thickness
399
+ lineColorR: -1, // Line color (-1 = use particle color)
400
+ lineColorG: -1,
401
+ lineColorB: -1,
402
+ });
403
+
404
+ // Manage lines
405
+ lines.setLines([
406
+ { aIndex: 0, bIndex: 1 },
407
+ { aIndex: 1, bIndex: 2 },
408
+ ]);
409
+ lines.add({ aIndex: 2, bIndex: 3 });
410
+ lines.remove(0, 1);
411
+ lines.setLineColor("#ff0000"); // Or null for particle colors
412
+ ```
413
+
414
+ ## Oscillators
415
+
416
+ Oscillators animate module parameters over time with smooth interpolation:
417
+
418
+ ```typescript
419
+ // Add oscillator to animate boundary restitution
420
+ engine.addOscillator({
421
+ moduleName: "boundary",
422
+ inputName: "restitution",
423
+ min: 0.4, // Minimum value
424
+ max: 0.95, // Maximum value
425
+ speedHz: 0.2, // Frequency (cycles per second)
426
+ });
427
+
428
+ // Update oscillator parameters
429
+ engine.updateOscillatorSpeed("boundary", "restitution", 0.5);
430
+ engine.updateOscillatorBounds("boundary", "restitution", 0.2, 0.8);
431
+
432
+ // Remove oscillators
433
+ engine.removeOscillator("boundary", "restitution");
434
+ engine.clearModuleOscillators("boundary");
435
+ engine.clearOscillators();
436
+ ```
437
+
438
+ ## Configuration Management
439
+
440
+ Export and import complete simulation states:
441
+
442
+ ```typescript
443
+ // Export current configuration
444
+ const config = engine.export();
445
+
446
+ // Configuration format
447
+ const config = {
448
+ environment: {
449
+ enabled: true,
450
+ gravityStrength: 600,
451
+ gravityDirection: "down",
452
+ // ... all module inputs
453
+ },
454
+ boundary: {
455
+ enabled: true,
456
+ mode: "bounce",
457
+ restitution: 0.9,
458
+ // ... all module inputs
459
+ },
460
+ // ... all modules
461
+ };
462
+
463
+ // Import configuration
464
+ engine.import(config);
465
+
466
+ // Partial import (only specified modules)
467
+ engine.import({
468
+ environment: { gravityStrength: 1000 },
469
+ collisions: { restitution: 0.5 },
470
+ });
471
+ ```
472
+
473
+ ## Performance Optimization
474
+
475
+ ### Spatial Grid
476
+
477
+ The engine uses spatial partitioning for efficient neighbor queries:
478
+
479
+ ```typescript
480
+ engine.setCellSize(32); // Smaller = more precise, larger = faster
481
+ engine.setMaxNeighbors(128); // Higher = more accurate, slower
482
+ ```
483
+
484
+ **Cell Size Guidelines:**
485
+ - Dense simulations: 16-32
486
+ - Sparse simulations: 64-128
487
+ - Rule of thumb: 2-4x average particle size
488
+
489
+ ### Constraint Iterations
490
+
491
+ Control physics solver accuracy vs performance:
492
+
493
+ ```typescript
494
+ engine.setConstrainIterations(50); // Higher = more stable, slower
495
+ ```
496
+
497
+ **Typical Values:**
498
+ - CPU: 5-10 iterations
499
+ - WebGPU: 20-100 iterations (GPU can handle more)
500
+
501
+ ### WebGPU Configuration
502
+
503
+ ```typescript
504
+ const engine = new Engine({
505
+ runtime: "webgpu",
506
+ workgroupSize: 64, // 32, 64, 128, or 256
507
+ maxParticles: 10000, // Pre-allocate GPU buffers
508
+ });
509
+ ```
510
+
511
+ ## Advanced Usage
512
+
513
+ ### Custom Modules
514
+
515
+ Create custom force modules by extending the Module class:
516
+
517
+ ```typescript
518
+ import { Module, ModuleRole, DataType } from "@cazala/party";
519
+
520
+ type WindInputs = { strength: number; dirX: number; dirY: number };
521
+
522
+ export class Wind extends Module<"wind", WindInputs> {
523
+ readonly name = "wind" as const;
524
+ readonly role = ModuleRole.Force;
525
+ readonly inputs = {
526
+ strength: DataType.NUMBER,
527
+ dirX: DataType.NUMBER,
528
+ dirY: DataType.NUMBER,
529
+ } as const;
530
+
531
+ constructor() {
532
+ super();
533
+ this.write({ strength: 100, dirX: 1, dirY: 0 });
534
+ }
535
+
536
+ // WebGPU implementation
537
+ webgpu() {
538
+ return {
539
+ apply: ({ particleVar, getUniform }) => `{
540
+ let d = vec2<f32>(${getUniform("dirX")}, ${getUniform("dirY")});
541
+ if (length(d) > 0.0) {
542
+ ${particleVar}.acceleration += normalize(d) * ${getUniform("strength")};
543
+ }
544
+ }`,
545
+ };
546
+ }
547
+
548
+ // CPU implementation
549
+ cpu() {
550
+ return {
551
+ apply: ({ particle, input }) => {
552
+ const len = Math.hypot(input.dirX, input.dirY) || 1;
553
+ particle.acceleration.x += (input.dirX / len) * input.strength;
554
+ particle.acceleration.y += (input.dirY / len) * input.strength;
555
+ },
556
+ };
557
+ }
558
+ }
559
+ ```
560
+
561
+ ### Error Handling
562
+
563
+ ```typescript
564
+ try {
565
+ await engine.initialize();
566
+ } catch (error) {
567
+ if (error.message.includes("WebGPU")) {
568
+ console.log("WebGPU not supported, falling back to CPU");
569
+ // Engine automatically falls back when runtime: "auto"
570
+ }
571
+ }
572
+
573
+ // Check module support
574
+ if (!engine.isSupported(customModule)) {
575
+ console.warn("Custom module not supported in current runtime");
576
+ }
577
+ ```
578
+
579
+ ## Browser Support
580
+
581
+ - **WebGPU**: Chrome 113+, Edge 113+, Firefox Nightly (experimental)
582
+ - **CPU Fallback**: All modern browsers with Canvas2D support
583
+ - **Feature Detection**: Automatic runtime selection with graceful fallback
584
+
585
+ ## TypeScript Support
586
+
587
+ Full TypeScript support with comprehensive type definitions:
588
+
589
+ ```typescript
590
+ import type { IEngine, IParticle, Module } from "@cazala/party";
591
+
592
+ const engine: IEngine = new Engine({ /* ... */ });
593
+ const particle: IParticle = { x: 0, y: 0, vx: 1, vy: 1, mass: 1, size: 5 };
594
+ ```
595
+
596
+ ## License
597
+
598
+ MIT License - see [LICENSE](../../LICENSE) file for details.