@zylem/behaviors 0.2.0 → 0.3.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.
@@ -1,15 +1,12 @@
1
1
  import {
2
- createParticleMaterial,
3
- createRangeValue,
4
- createTextureSystemOptions,
2
+ Particles,
5
3
  electricityPresets,
6
4
  firePresets,
7
5
  gasPresets,
8
6
  magicPresets,
9
7
  particleEffect,
10
- toColorVector,
11
8
  waterPresets
12
- } from "./chunk-GYURWCIQ.js";
9
+ } from "./chunk-7JJEIADR.js";
13
10
  import {
14
11
  VEC3_ZERO,
15
12
  normalizeVec3,
@@ -21,9 +18,6 @@ import {
21
18
 
22
19
  // src/lib/behaviors/particle-emitter/particle-emitter.descriptor.ts
23
20
  import { Group, Quaternion, Vector3 } from "three";
24
- import {
25
- BatchedRenderer
26
- } from "three.quarks";
27
21
  function getRefGlobals(ref) {
28
22
  return ref.__getGlobals ?? null;
29
23
  }
@@ -48,28 +42,26 @@ var defaultOptions = {
48
42
  var ParticleRendererService = class {
49
43
  constructor(sceneRoot) {
50
44
  this.sceneRoot = sceneRoot;
51
- this.renderer.name = "zylem-particle-batch-renderer";
52
- this.sceneRoot.add(this.renderer);
53
45
  }
54
46
  sceneRoot;
55
- renderer = new BatchedRenderer();
56
47
  systems = /* @__PURE__ */ new Set();
48
+ /** Scene node that emitter anchors are parented to. */
49
+ get root() {
50
+ return this.sceneRoot;
51
+ }
57
52
  register(system) {
58
- if (this.systems.has(system)) {
59
- return;
60
- }
61
- this.renderer.addSystem(system);
62
53
  this.systems.add(system);
63
54
  }
64
55
  forget(system) {
65
56
  this.systems.delete(system);
66
57
  }
67
58
  update(delta) {
68
- this.renderer.update(delta);
59
+ for (const system of this.systems) {
60
+ system.update(delta);
61
+ }
69
62
  }
70
63
  destroy() {
71
64
  this.systems.clear();
72
- this.renderer.removeFromParent();
73
65
  }
74
66
  };
75
67
  function getParticleControlState(ref) {
@@ -146,7 +138,15 @@ function applyRuntimeState(ref) {
146
138
  }
147
139
  if (state.pendingRestart) {
148
140
  runtime.system.restart();
141
+ runtime.started = true;
149
142
  state.pendingRestart = false;
143
+ if (state.desiredState === "paused") {
144
+ runtime.system.pause();
145
+ } else if (state.desiredState === "stopped") {
146
+ runtime.system.stop();
147
+ runtime.started = false;
148
+ }
149
+ return;
150
150
  }
151
151
  if (state.desiredState === "paused") {
152
152
  runtime.system.pause();
@@ -154,9 +154,15 @@ function applyRuntimeState(ref) {
154
154
  }
155
155
  if (state.desiredState === "stopped") {
156
156
  runtime.system.stop();
157
+ runtime.started = false;
157
158
  return;
158
159
  }
159
- runtime.system.play();
160
+ if (!runtime.started) {
161
+ runtime.system.start();
162
+ runtime.started = true;
163
+ } else {
164
+ runtime.system.resume();
165
+ }
160
166
  }
161
167
  function releaseRuntime(ref, reason) {
162
168
  const state = getParticleControlState(ref);
@@ -166,7 +172,6 @@ function releaseRuntime(ref, reason) {
166
172
  }
167
173
  state.runtime = null;
168
174
  state.pendingRestart = false;
169
- runtime.system.removeEventListener("destroy", runtime.onDestroy);
170
175
  runtime.service.forget(runtime.system);
171
176
  if (reason === "manual") {
172
177
  runtime.system.dispose();
@@ -191,14 +196,12 @@ function createRuntime(entity, ref, service) {
191
196
  service,
192
197
  initialPosition: initialTransform.position.clone(),
193
198
  initialQuaternion: initialTransform.quaternion.clone(),
194
- onDestroy: () => handleSystemDestroyed(entity, ref)
199
+ started: false
195
200
  };
196
201
  anchor.name = `${entity.name || entity.uuid}:particle-anchor`;
197
- system.autoDestroy = ref.options.autoDestroy;
198
- anchor.add(system.emitter);
202
+ anchor.add(system);
199
203
  service.register(system);
200
- service.renderer.parent?.add(anchor);
201
- system.addEventListener("destroy", runtime.onDestroy);
204
+ service.root.add(anchor);
202
205
  syncRuntimeTransform(entity, ref, runtime);
203
206
  return runtime;
204
207
  }
@@ -237,7 +240,7 @@ function createParticleEmitterHandle(ref) {
237
240
  if (!runtime) {
238
241
  return getParticleControlState(ref).desiredState === "playing";
239
242
  }
240
- return !runtime.system.paused;
243
+ return runtime.system.running;
241
244
  },
242
245
  getSystem: () => getParticleControlState(ref).runtime?.system ?? null
243
246
  };
@@ -287,6 +290,9 @@ var ParticleEmitterBehaviorSystem = class {
287
290
  hasRuntime = true;
288
291
  syncRuntimeTransform(entity, ref, state.runtime);
289
292
  applyRuntimeState(ref);
293
+ if (ref.options.autoDestroy && state.runtime.started && state.desiredState === "playing" && state.runtime.system.isComplete()) {
294
+ handleSystemDestroyed(entity, ref);
295
+ }
290
296
  }
291
297
  if (hasRuntime && rendererService) {
292
298
  rendererService.update(delta);
@@ -320,78 +326,78 @@ var ParticleEmitterBehavior = defineBehavior({
320
326
  });
321
327
 
322
328
  // src/lib/behaviors/particle-emitter/particle-effect.ts
323
- import {
324
- ConstantColor,
325
- ConstantValue,
326
- ParticleSystem as ParticleSystem2,
327
- PointEmitter,
328
- RenderMode
329
- } from "three.quarks";
329
+ import { AdditiveBlending, Color } from "three";
330
+ function toRange(value, fallback) {
331
+ if (value === void 0) return fallback;
332
+ if (Array.isArray(value)) {
333
+ return [value[0] ?? fallback[0], value[1] ?? fallback[1]];
334
+ }
335
+ const single = value;
336
+ return [single, single];
337
+ }
338
+ function toHexColor(color) {
339
+ return `#${new Color(color).getHexString()}`;
340
+ }
341
+ function makeBurstConfig(options, defaults) {
342
+ const count = Math.max(1, Math.round(options.count ?? defaults.count));
343
+ const color = toHexColor(options.color ?? defaults.color);
344
+ const blending = options.blending ?? AdditiveBlending;
345
+ const particles = {
346
+ count,
347
+ intensity: options.opacity ?? defaults.intensity,
348
+ colors: [
349
+ [
350
+ { color, stop: 0 },
351
+ { color, stop: 1 }
352
+ ]
353
+ ],
354
+ fadeAlpha: [0.05, 0.7],
355
+ fadeSize: [0.1, 0.85]
356
+ };
357
+ if (options.texture) {
358
+ particles.alphaMapsStart = [options.texture];
359
+ }
360
+ return {
361
+ particles,
362
+ emitter: {
363
+ duration: options.duration ?? defaults.duration,
364
+ loop: false,
365
+ spawnMode: "burst",
366
+ rate: count,
367
+ static: 0,
368
+ lifetime: toRange(options.life, defaults.life),
369
+ speed: toRange(options.speed, defaults.speed),
370
+ size: toRange(options.size, defaults.size),
371
+ directionMin: [-1, -1, -1],
372
+ directionMax: [1, 1, 1]
373
+ },
374
+ render: { blendingMode: blending }
375
+ };
376
+ }
330
377
  var particlePresets = {
331
378
  burst(options = {}) {
332
- return particleEffect(
333
- () => new ParticleSystem2({
334
- duration: options.duration ?? 0.25,
335
- looping: false,
336
- worldSpace: options.worldSpace ?? false,
337
- startLife: createRangeValue(options.life ?? [0.3, 0.7], [0.3, 0.7]),
338
- startSpeed: createRangeValue(options.speed ?? [1.5, 4], [1.5, 4]),
339
- startSize: createRangeValue(options.size ?? [0.08, 0.18], [0.08, 0.18]),
340
- startColor: new ConstantColor(
341
- toColorVector(options.color ?? "#ffffff")
342
- ),
343
- emissionOverTime: new ConstantValue(0),
344
- emissionBursts: [
345
- {
346
- time: 0,
347
- count: new ConstantValue(options.count ?? 18),
348
- cycle: 1,
349
- interval: 0,
350
- probability: 1
351
- }
352
- ],
353
- shape: new PointEmitter(),
354
- material: createParticleMaterial(
355
- options.color ?? "#ffffff",
356
- options
357
- ),
358
- ...createTextureSystemOptions(options),
359
- renderMode: RenderMode.BillBoard
360
- })
361
- );
379
+ const config = makeBurstConfig(options, {
380
+ duration: 0.25,
381
+ life: [0.3, 0.7],
382
+ speed: [1.5, 4],
383
+ size: [0.08, 0.18],
384
+ color: "#ffffff",
385
+ count: 18,
386
+ intensity: 1
387
+ });
388
+ return particleEffect(() => new Particles(config));
362
389
  },
363
390
  smoke(options = {}) {
364
- return particleEffect(
365
- () => new ParticleSystem2({
366
- duration: options.duration ?? 1.1,
367
- looping: false,
368
- worldSpace: options.worldSpace ?? false,
369
- startLife: createRangeValue(options.life ?? [0.8, 1.6], [0.8, 1.6]),
370
- startSpeed: createRangeValue(options.speed ?? [0.2, 0.8], [0.2, 0.8]),
371
- startSize: createRangeValue(options.size ?? [0.2, 0.5], [0.2, 0.5]),
372
- startColor: new ConstantColor(
373
- toColorVector(options.color ?? "#999999")
374
- ),
375
- emissionOverTime: new ConstantValue(0),
376
- emissionBursts: [
377
- {
378
- time: 0,
379
- count: new ConstantValue(options.count ?? 10),
380
- cycle: 1,
381
- interval: 0,
382
- probability: 1
383
- }
384
- ],
385
- shape: new PointEmitter(),
386
- material: createParticleMaterial(
387
- options.color ?? "#999999",
388
- options,
389
- 0.85
390
- ),
391
- ...createTextureSystemOptions(options),
392
- renderMode: RenderMode.BillBoard
393
- })
394
- );
391
+ const config = makeBurstConfig(options, {
392
+ duration: 1.1,
393
+ life: [0.8, 1.6],
394
+ speed: [0.2, 0.8],
395
+ size: [0.2, 0.5],
396
+ color: "#999999",
397
+ count: 10,
398
+ intensity: 0.85
399
+ });
400
+ return particleEffect(() => new Particles(config));
395
401
  },
396
402
  fire: firePresets,
397
403
  water: waterPresets,
@@ -404,4 +410,4 @@ export {
404
410
  ParticleEmitterBehavior,
405
411
  particlePresets
406
412
  };
407
- //# sourceMappingURL=chunk-POZER3MQ.js.map
413
+ //# sourceMappingURL=chunk-ZPSAXX73.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/particle-emitter/particle-emitter.descriptor.ts","../src/lib/behaviors/particle-emitter/particle-effect.ts"],"sourcesContent":["import { Group, Object3D, Quaternion, Vector3 } from 'three';\n\nimport { Particles } from './gpu';\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { VEC3_ZERO, type Vec3Input, normalizeVec3, toThreeVector3 } from '../../core/vector';\nfunction getRefGlobals(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\nimport type { ParticleEffectDefinition } from './particle-effect';\n\nexport interface ParticleEmitterBehaviorOptions {\n\teffect: ParticleEffectDefinition;\n\tautoplay: boolean;\n\tlocalOffset?: Vec3Input;\n\tfollowPosition: boolean;\n\tfollowRotation: boolean;\n\tautoDestroy: boolean;\n}\n\nexport interface ParticleEmitterHandle {\n\tplay(): void;\n\tstop(): void;\n\tpause(): void;\n\trestart(): void;\n\tburst(): void;\n\tisPlaying(): boolean;\n\tgetSystem(): Particles | null;\n}\n\ntype DesiredParticleState = 'playing' | 'paused' | 'stopped';\n\ninterface ParticleEmitterControlState {\n\tdesiredState: DesiredParticleState;\n\tpendingRestart: boolean;\n\truntime: ParticleEmitterRuntime | null;\n}\n\ninterface ParticleEmitterRuntime {\n\tsystem: Particles;\n\tanchor: Group;\n\tservice: ParticleRendererService;\n\tinitialPosition: Vector3;\n\tinitialQuaternion: Quaternion;\n\t/** Whether the system has been started at least once in this lifecycle. */\n\tstarted: boolean;\n}\n\ninterface ParticleEmitterHostEntity {\n\tuuid: string;\n\tname?: string;\n\tbody?: {\n\t\ttranslation(): { x: number; y: number; z: number };\n\t\trotation?(): { x: number; y: number; z: number; w: number };\n\t} | null;\n\tgroup?: Object3D | null;\n\tmesh?: Object3D | null;\n\toptions?: {\n\t\tposition?: Vec3Input;\n\t};\n\tmarkedForRemoval?: boolean;\n\tnodeDestroy?(params: { me: unknown; globals: unknown }): void;\n\t__zylemParticleSystemEntity?: boolean;\n}\n\nconst PARTICLE_EMITTER_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:particle-emitter',\n);\n\nconst DEFAULT_PARTICLE_EFFECT: ParticleEffectDefinition = {\n\tcreate() {\n\t\tthrow new Error(\n\t\t\t'ParticleEmitterBehavior requires an effect definition created with particleEffect(...).',\n\t\t);\n\t},\n};\n\nconst defaultOptions: ParticleEmitterBehaviorOptions = {\n\teffect: DEFAULT_PARTICLE_EFFECT,\n\tautoplay: true,\n\tlocalOffset: undefined,\n\tfollowPosition: true,\n\tfollowRotation: true,\n\tautoDestroy: false,\n};\n\n/**\n * Ticks the GPU particle systems each frame.\n *\n * The previous backend (three.quarks) required a `BatchedRenderer` Object3D in\n * the scene graph; the WebGPU engine instead exposes `Particles` Object3Ds that\n * self-render and only need `update(delta)` called for CPU-side emission.\n */\nclass ParticleRendererService {\n\tprivate readonly systems = new Set<Particles>();\n\n\tconstructor(private readonly sceneRoot: Object3D) {}\n\n\t/** Scene node that emitter anchors are parented to. */\n\tget root(): Object3D {\n\t\treturn this.sceneRoot;\n\t}\n\n\tregister(system: Particles): void {\n\t\tthis.systems.add(system);\n\t}\n\n\tforget(system: Particles): void {\n\t\tthis.systems.delete(system);\n\t}\n\n\tupdate(delta: number): void {\n\t\tfor (const system of this.systems) {\n\t\t\tsystem.update(delta);\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tthis.systems.clear();\n\t}\n}\n\nfunction getParticleControlState(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): ParticleEmitterControlState {\n\tconst runtimeState = (ref as any).__particleEmitterControlState as\n\t\t| ParticleEmitterControlState\n\t\t| undefined;\n\tif (runtimeState) {\n\t\treturn runtimeState;\n\t}\n\n\tconst nextState: ParticleEmitterControlState = {\n\t\tdesiredState: ref.options.autoplay ? 'playing' : 'stopped',\n\t\tpendingRestart: false,\n\t\truntime: null,\n\t};\n\t(ref as any).__particleEmitterControlState = nextState;\n\treturn nextState;\n}\n\nfunction shouldCreateRuntime(\n\tstate: ParticleEmitterControlState,\n): boolean {\n\treturn state.runtime == null\n\t\t&& (state.desiredState !== 'stopped' || state.pendingRestart);\n}\n\nfunction getLocalOffset(options: ParticleEmitterBehaviorOptions): Vector3 {\n\treturn toThreeVector3(options.localOffset, VEC3_ZERO);\n}\n\nfunction readHostTransform(entity: ParticleEmitterHostEntity): {\n\tposition: Vector3;\n\tquaternion: Quaternion;\n} {\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\treturn {\n\t\t\tposition: new Vector3(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z),\n\t\t\tquaternion: new Quaternion(\n\t\t\t\twasmPose.rotation.x,\n\t\t\t\twasmPose.rotation.y,\n\t\t\t\twasmPose.rotation.z,\n\t\t\t\twasmPose.rotation.w,\n\t\t\t),\n\t\t};\n\t}\n\n\tif (entity.body?.translation) {\n\t\tconst position = entity.body.translation();\n\t\tconst rotation = entity.body.rotation?.() ?? { x: 0, y: 0, z: 0, w: 1 };\n\t\treturn {\n\t\t\tposition: new Vector3(position.x, position.y, position.z),\n\t\t\tquaternion: new Quaternion(rotation.x, rotation.y, rotation.z, rotation.w),\n\t\t};\n\t}\n\n\tconst visualRoot = entity.group ?? entity.mesh;\n\tif (visualRoot) {\n\t\tconst position = new Vector3();\n\t\tconst quaternion = new Quaternion();\n\t\tvisualRoot.getWorldPosition(position);\n\t\tvisualRoot.getWorldQuaternion(quaternion);\n\t\treturn { position, quaternion };\n\t}\n\n\tconst position = normalizeVec3(entity.options?.position, VEC3_ZERO);\n\treturn {\n\t\tposition: new Vector3(position.x, position.y, position.z),\n\t\tquaternion: new Quaternion(),\n\t};\n}\n\nfunction syncRuntimeTransform(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\truntime: ParticleEmitterRuntime,\n): void {\n\tconst current = readHostTransform(entity);\n\tconst options = ref.options;\n\tconst basePosition = options.followPosition\n\t\t? current.position\n\t\t: runtime.initialPosition;\n\tconst baseQuaternion = options.followRotation\n\t\t? current.quaternion\n\t\t: runtime.initialQuaternion;\n\tconst offset = getLocalOffset(options);\n\n\tif (options.followRotation) {\n\t\toffset.applyQuaternion(baseQuaternion);\n\t}\n\n\truntime.anchor.position.copy(basePosition).add(offset);\n\truntime.anchor.quaternion.copy(baseQuaternion);\n}\n\nfunction applyRuntimeState(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): void {\n\tconst state = getParticleControlState(ref);\n\tconst runtime = state.runtime;\n\tif (!runtime) {\n\t\treturn;\n\t}\n\n\tif (state.pendingRestart) {\n\t\truntime.system.restart();\n\t\truntime.started = true;\n\t\tstate.pendingRestart = false;\n\n\t\tif (state.desiredState === 'paused') {\n\t\t\truntime.system.pause();\n\t\t} else if (state.desiredState === 'stopped') {\n\t\t\truntime.system.stop();\n\t\t\truntime.started = false;\n\t\t}\n\t\treturn;\n\t}\n\n\tif (state.desiredState === 'paused') {\n\t\truntime.system.pause();\n\t\treturn;\n\t}\n\n\tif (state.desiredState === 'stopped') {\n\t\truntime.system.stop();\n\t\truntime.started = false;\n\t\treturn;\n\t}\n\n\t// playing\n\tif (!runtime.started) {\n\t\truntime.system.start();\n\t\truntime.started = true;\n\t} else {\n\t\truntime.system.resume();\n\t}\n}\n\nfunction releaseRuntime(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\treason: 'manual' | 'system-destroyed',\n): void {\n\tconst state = getParticleControlState(ref);\n\tconst runtime = state.runtime;\n\tif (!runtime) {\n\t\treturn;\n\t}\n\n\tstate.runtime = null;\n\tstate.pendingRestart = false;\n\n\truntime.service.forget(runtime.system);\n\n\tif (reason === 'manual') {\n\t\truntime.system.dispose();\n\t}\n\n\truntime.anchor.removeFromParent();\n}\n\nfunction handleSystemDestroyed(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): void {\n\treleaseRuntime(ref, 'system-destroyed');\n\tconst state = getParticleControlState(ref);\n\tstate.desiredState = 'stopped';\n\n\tif (\n\t\tref.options.autoDestroy\n\t\t&& entity.__zylemParticleSystemEntity\n\t\t&& !entity.markedForRemoval\n\t) {\n\t\tentity.nodeDestroy?.({ me: entity, globals: getRefGlobals(ref)?.() ?? {} });\n\t}\n}\n\nfunction createRuntime(\n\tentity: ParticleEmitterHostEntity,\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n\tservice: ParticleRendererService,\n): ParticleEmitterRuntime {\n\tconst system = ref.options.effect.create();\n\tconst anchor = new Group();\n\tconst initialTransform = readHostTransform(entity);\n\tconst runtime: ParticleEmitterRuntime = {\n\t\tsystem,\n\t\tanchor,\n\t\tservice,\n\t\tinitialPosition: initialTransform.position.clone(),\n\t\tinitialQuaternion: initialTransform.quaternion.clone(),\n\t\tstarted: false,\n\t};\n\n\tanchor.name = `${entity.name || entity.uuid}:particle-anchor`;\n\tanchor.add(system);\n\tservice.register(system);\n\tservice.root.add(anchor);\n\n\tsyncRuntimeTransform(entity, ref, runtime);\n\treturn runtime;\n}\n\nfunction createParticleEmitterHandle(\n\tref: BehaviorRef<ParticleEmitterBehaviorOptions>,\n): ParticleEmitterHandle {\n\treturn {\n\t\tplay: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tstop: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'stopped';\n\t\t\tstate.pendingRestart = false;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tpause: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'paused';\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\trestart: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tstate.pendingRestart = true;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tburst: () => {\n\t\t\tconst state = getParticleControlState(ref);\n\t\t\tstate.desiredState = 'playing';\n\t\t\tstate.pendingRestart = true;\n\t\t\tapplyRuntimeState(ref);\n\t\t},\n\t\tisPlaying: () => {\n\t\t\tconst runtime = getParticleControlState(ref).runtime;\n\t\t\tif (!runtime) {\n\t\t\t\treturn getParticleControlState(ref).desiredState === 'playing';\n\t\t\t}\n\t\t\treturn runtime.system.running;\n\t\t},\n\t\tgetSystem: () => getParticleControlState(ref).runtime?.system ?? null,\n\t};\n}\n\nclass ParticleEmitterBehaviorSystem implements BehaviorSystem {\n\tprivate rendererService: ParticleRendererService | null = null;\n\n\tconstructor(\n\t\tprivate readonly scene: { scene: Object3D },\n\t\tprivate readonly getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate readonly getGlobals?: () => any,\n\t) {}\n\n\tprivate getRendererService(): ParticleRendererService {\n\t\tif (!this.rendererService) {\n\t\t\tthis.rendererService = new ParticleRendererService(this.scene.scene);\n\t\t}\n\t\treturn this.rendererService;\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(PARTICLE_EMITTER_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet hasRuntime = false;\n\t\tlet rendererService = this.rendererService;\n\n\t\tfor (const link of links) {\n\t\t\tconst entity = link.entity as ParticleEmitterHostEntity;\n\t\t\tconst ref = link.ref as BehaviorRef<ParticleEmitterBehaviorOptions>;\n\t\t\t(ref as any).__getGlobals = this.getGlobals;\n\t\t\tconst state = getParticleControlState(ref);\n\n\t\t\tif (shouldCreateRuntime(state)) {\n\t\t\t\ttry {\n\t\t\t\t\trendererService ??= this.getRendererService();\n\t\t\t\t\tstate.runtime = createRuntime(entity, ref, rendererService);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tstate.desiredState = 'stopped';\n\t\t\t\t\tstate.pendingRestart = false;\n\t\t\t\t\tconsole.error('Failed to create particle runtime:', error);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!state.runtime) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\thasRuntime = true;\n\t\t\tsyncRuntimeTransform(entity, ref, state.runtime);\n\t\t\tapplyRuntimeState(ref);\n\n\t\t\tif (\n\t\t\t\tref.options.autoDestroy\n\t\t\t\t&& state.runtime.started\n\t\t\t\t&& state.desiredState === 'playing'\n\t\t\t\t&& state.runtime.system.isComplete()\n\t\t\t) {\n\t\t\t\thandleSystemDestroyed(entity, ref);\n\t\t\t}\n\t\t}\n\n\t\tif (hasRuntime && rendererService) {\n\t\t\trendererService.update(delta);\n\t\t}\n\t}\n\n\tdetach(link: BehaviorEntityLink): void {\n\t\treleaseRuntime(\n\t\t\tlink.ref as BehaviorRef<ParticleEmitterBehaviorOptions>,\n\t\t\t'manual',\n\t\t);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(PARTICLE_EMITTER_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\treleaseRuntime(\n\t\t\t\t\tlink.ref as BehaviorRef<ParticleEmitterBehaviorOptions>,\n\t\t\t\t\t'manual',\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.rendererService?.destroy();\n\t\tthis.rendererService = null;\n\t}\n}\n\nexport const ParticleEmitterBehavior = defineBehavior<\n\tParticleEmitterBehaviorOptions,\n\tParticleEmitterHandle\n>({\n\tname: 'particle-emitter',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ParticleEmitterBehaviorSystem(ctx.scene, ctx.getBehaviorLinks, ctx.getGlobals),\n\tcreateHandle: createParticleEmitterHandle,\n});\n","import { AdditiveBlending, Color, type ColorRepresentation } from 'three';\n\nimport { Particles } from './gpu';\nimport type { ParticleSettings, ParticlesConfig, RenderSettings } from './gpu';\nimport {\n\tparticleEffect,\n\ttype ParticleEffectDefinition,\n\ttype ParticlePresetMaterialOptions,\n} from './preset-builder';\nimport { electricityPresets, firePresets, gasPresets, magicPresets, waterPresets } from './presets';\n\nexport type {\n\tParticleEffectDefinition,\n\tParticleMagicAgency,\n\tParticleMagicAlignment,\n\tParticleMagicModifierInput,\n\tParticleMagicModifierOptions,\n\tParticleMagicOrder,\n\tParticleMagicRealityEffect,\n\tParticleMagicTemperament,\n\tParticlePresetMaterialOptions,\n\tSemanticParticlePresetOptions,\n} from './preset-builder';\n\nexport interface BurstParticlePresetOptions extends ParticlePresetMaterialOptions {\n\tcolor?: ColorRepresentation;\n\tcount?: number;\n\tduration?: number;\n\tlife?: number | readonly [number, number];\n\tsize?: number | readonly [number, number];\n\tspeed?: number | readonly [number, number];\n\t/**\n\t * Kept for API compatibility. Emitter follow behavior is controlled by the\n\t * particle-emitter behavior (followPosition/followRotation), so this flag is\n\t * not used by the GPU engine.\n\t */\n\tworldSpace?: boolean;\n}\n\ninterface BurstDefaults {\n\tduration: number;\n\tlife: [number, number];\n\tspeed: [number, number];\n\tsize: [number, number];\n\tcolor: ColorRepresentation;\n\tcount: number;\n\tintensity: number;\n}\n\nfunction toRange(\n\tvalue: number | readonly [number, number] | undefined,\n\tfallback: [number, number],\n): [number, number] {\n\tif (value === undefined) return fallback;\n\tif (Array.isArray(value)) {\n\t\treturn [value[0] ?? fallback[0], value[1] ?? fallback[1]];\n\t}\n\tconst single = value as number;\n\treturn [single, single];\n}\n\nfunction toHexColor(color: ColorRepresentation): string {\n\treturn `#${new Color(color).getHexString()}`;\n}\n\nfunction makeBurstConfig(\n\toptions: BurstParticlePresetOptions,\n\tdefaults: BurstDefaults,\n): ParticlesConfig {\n\tconst count = Math.max(1, Math.round(options.count ?? defaults.count));\n\tconst color = toHexColor(options.color ?? defaults.color);\n\tconst blending = (options.blending ?? AdditiveBlending) as RenderSettings['blendingMode'];\n\n\tconst particles: Partial<ParticleSettings> & Pick<ParticleSettings, 'count'> = {\n\t\tcount,\n\t\tintensity: options.opacity ?? defaults.intensity,\n\t\tcolors: [\n\t\t\t[\n\t\t\t\t{ color, stop: 0 },\n\t\t\t\t{ color, stop: 1 },\n\t\t\t],\n\t\t],\n\t\tfadeAlpha: [0.05, 0.7],\n\t\tfadeSize: [0.1, 0.85],\n\t};\n\tif (options.texture) {\n\t\tparticles.alphaMapsStart = [options.texture] as unknown as ParticleSettings['alphaMapsStart'];\n\t}\n\n\treturn {\n\t\tparticles,\n\t\temitter: {\n\t\t\tduration: options.duration ?? defaults.duration,\n\t\t\tloop: false,\n\t\t\tspawnMode: 'burst',\n\t\t\trate: count,\n\t\t\tstatic: 0,\n\t\t\tlifetime: toRange(options.life, defaults.life),\n\t\t\tspeed: toRange(options.speed, defaults.speed),\n\t\t\tsize: toRange(options.size, defaults.size),\n\t\t\tdirectionMin: [-1, -1, -1],\n\t\t\tdirectionMax: [1, 1, 1],\n\t\t},\n\t\trender: { blendingMode: blending },\n\t};\n}\n\nexport const particlePresets = {\n\tburst(options: BurstParticlePresetOptions = {}): ParticleEffectDefinition {\n\t\tconst config = makeBurstConfig(options, {\n\t\t\tduration: 0.25,\n\t\t\tlife: [0.3, 0.7],\n\t\t\tspeed: [1.5, 4],\n\t\t\tsize: [0.08, 0.18],\n\t\t\tcolor: '#ffffff',\n\t\t\tcount: 18,\n\t\t\tintensity: 1,\n\t\t});\n\t\treturn particleEffect(() => new Particles(config));\n\t},\n\tsmoke(options: BurstParticlePresetOptions = {}): ParticleEffectDefinition {\n\t\tconst config = makeBurstConfig(options, {\n\t\t\tduration: 1.1,\n\t\t\tlife: [0.8, 1.6],\n\t\t\tspeed: [0.2, 0.8],\n\t\t\tsize: [0.2, 0.5],\n\t\t\tcolor: '#999999',\n\t\t\tcount: 10,\n\t\t\tintensity: 0.85,\n\t\t});\n\t\treturn particleEffect(() => new Particles(config));\n\t},\n\tfire: firePresets,\n\twater: waterPresets,\n\tgas: gasPresets,\n\telectricity: electricityPresets,\n\tmagic: magicPresets,\n} as const;\n\nexport { particleEffect } from './preset-builder';\n"],"mappings":"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","names":["position"]}
package/dist/index.d.ts CHANGED
@@ -28,7 +28,7 @@ export { BoundaryRicochet3DCoordinator } from './coordinators/boundary-ricochet-
28
28
  export { FirstPersonShooterCoordinator, FirstPersonShooterInput } from './coordinators/first-person-shooter.js';
29
29
  export { TopDownShooterCoordinator, TopDownShooterInput } from './coordinators/top-down-shooter.js';
30
30
  export { MultidirectionalSpaceShooterCoordinator, MultidirectionalSpaceShooterInput } from './coordinators/multidirectional-space-shooter.js';
31
- export { P as ParticleEffectDefinition, a as ParticleMagicAgency, b as ParticleMagicAlignment, c as ParticleMagicModifierInput, d as ParticleMagicModifierOptions, e as ParticleMagicOrder, f as ParticleMagicRealityEffect, g as ParticleMagicTemperament, h as ParticlePresetMaterialOptions, S as SemanticParticlePresetOptions, u as particleEffect } from './spark-DDlIg1nM.js';
31
+ export { P as ParticleEffectDefinition, a as ParticleMagicAgency, b as ParticleMagicAlignment, c as ParticleMagicModifierInput, d as ParticleMagicModifierOptions, e as ParticleMagicOrder, f as ParticleMagicRealityEffect, g as ParticleMagicTemperament, h as ParticlePresetMaterialOptions, S as SemanticParticlePresetOptions, v as particleEffect } from './spark-Dx3cJbTW.js';
32
32
  import '@dimforge/rapier3d-compat';
33
33
  import 'three';
34
34
  import './sync-state-machine-CZyspBpj.js';
@@ -36,5 +36,5 @@ import 'typescript-fsm';
36
36
  import './vector-Bm65-FOG.js';
37
37
  import './entity-types-CmtQ-IBp.js';
38
38
  import './first-person-perspective-C9Mptl0-.js';
39
- import 'three.quarks';
40
39
  import './moveable-BCRpjAQb.js';
40
+ import 'three/webgpu';
package/dist/index.js CHANGED
@@ -67,10 +67,10 @@ import "./chunk-OHCPV2NT.js";
67
67
  import {
68
68
  ParticleEmitterBehavior,
69
69
  particlePresets
70
- } from "./chunk-POZER3MQ.js";
70
+ } from "./chunk-ZPSAXX73.js";
71
71
  import {
72
72
  particleEffect
73
- } from "./chunk-GYURWCIQ.js";
73
+ } from "./chunk-7JJEIADR.js";
74
74
  import {
75
75
  Platformer3DBehavior,
76
76
  Platformer3DBehavior2,
@@ -1,6 +1,6 @@
1
- import { j as arcane, q as holy, l as corrupted, t as nature, I as voidMagic, w as psychic, A as spark, i as arc, F as surge, x as pulse, E as storm, H as vapor, y as smoke, p as haze, v as plume, r as miasma, s as mist, D as spray, C as splash, m as drizzle, G as torrent, B as spark$1, n as ember, o as flamelet, k as blaze, z as smolder } from '../spark-DDlIg1nM.js';
1
+ import { k as arcane, r as holy, m as corrupted, u as nature, J as voidMagic, x as psychic, B as spark, j as arc, G as surge, y as pulse, F as storm, I as vapor, z as smoke, q as haze, w as plume, s as miasma, t as mist, E as spray, D as splash, n as drizzle, H as torrent, C as spark$1, o as ember, p as flamelet, l as blaze, A as smolder } from '../spark-Dx3cJbTW.js';
2
2
  import 'three';
3
- import 'three.quarks';
3
+ import 'three/webgpu';
4
4
 
5
5
  declare const magicPresets: {
6
6
  readonly arcane: typeof arcane;
@@ -4,7 +4,7 @@ import {
4
4
  gasPresets,
5
5
  magicPresets,
6
6
  waterPresets
7
- } from "../chunk-GYURWCIQ.js";
7
+ } from "../chunk-7JJEIADR.js";
8
8
  export {
9
9
  electricityPresets,
10
10
  firePresets,
@@ -1,10 +1,10 @@
1
1
  import { a as BehaviorDescriptor } from './behavior-system-DYbx-x_-.js';
2
2
  import { i as Vec3Input } from './vector-Bm65-FOG.js';
3
- import { ParticleSystem } from 'three.quarks';
4
- import { h as ParticlePresetMaterialOptions, P as ParticleEffectDefinition, B as spark, n as ember, o as flamelet, k as blaze, z as smolder, s as mist, D as spray, C as splash, m as drizzle, G as torrent, H as vapor, y as smoke, p as haze, v as plume, r as miasma, A as spark$1, i as arc, F as surge, x as pulse, E as storm, j as arcane, q as holy, l as corrupted, t as nature, I as voidMagic, w as psychic } from './spark-DDlIg1nM.js';
5
- export { a as ParticleMagicAgency, b as ParticleMagicAlignment, c as ParticleMagicModifierInput, d as ParticleMagicModifierOptions, e as ParticleMagicOrder, f as ParticleMagicRealityEffect, g as ParticleMagicTemperament, S as SemanticParticlePresetOptions, u as particleEffect } from './spark-DDlIg1nM.js';
3
+ import { h as ParticlePresetMaterialOptions, P as ParticleEffectDefinition, C as spark, o as ember, p as flamelet, l as blaze, A as smolder, t as mist, E as spray, D as splash, n as drizzle, H as torrent, I as vapor, z as smoke, q as haze, w as plume, s as miasma, B as spark$1, j as arc, G as surge, y as pulse, F as storm, k as arcane, r as holy, m as corrupted, u as nature, J as voidMagic, x as psychic, i as Particles } from './spark-Dx3cJbTW.js';
4
+ export { a as ParticleMagicAgency, b as ParticleMagicAlignment, c as ParticleMagicModifierInput, d as ParticleMagicModifierOptions, e as ParticleMagicOrder, f as ParticleMagicRealityEffect, g as ParticleMagicTemperament, S as SemanticParticlePresetOptions, v as particleEffect } from './spark-Dx3cJbTW.js';
6
5
  import { ColorRepresentation } from 'three';
7
6
  import '@dimforge/rapier3d-compat';
7
+ import 'three/webgpu';
8
8
 
9
9
  interface BurstParticlePresetOptions extends ParticlePresetMaterialOptions {
10
10
  color?: ColorRepresentation;
@@ -13,6 +13,11 @@ interface BurstParticlePresetOptions extends ParticlePresetMaterialOptions {
13
13
  life?: number | readonly [number, number];
14
14
  size?: number | readonly [number, number];
15
15
  speed?: number | readonly [number, number];
16
+ /**
17
+ * Kept for API compatibility. Emitter follow behavior is controlled by the
18
+ * particle-emitter behavior (followPosition/followRotation), so this flag is
19
+ * not used by the GPU engine.
20
+ */
16
21
  worldSpace?: boolean;
17
22
  }
18
23
  declare const particlePresets: {
@@ -71,7 +76,7 @@ interface ParticleEmitterHandle {
71
76
  restart(): void;
72
77
  burst(): void;
73
78
  isPlaying(): boolean;
74
- getSystem(): ParticleSystem | null;
79
+ getSystem(): Particles | null;
75
80
  }
76
81
  declare const ParticleEmitterBehavior: BehaviorDescriptor<ParticleEmitterBehaviorOptions, ParticleEmitterHandle, unknown>;
77
82
 
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ParticleEmitterBehavior,
3
3
  particlePresets
4
- } from "./chunk-POZER3MQ.js";
4
+ } from "./chunk-ZPSAXX73.js";
5
5
  import {
6
6
  particleEffect
7
- } from "./chunk-GYURWCIQ.js";
7
+ } from "./chunk-7JJEIADR.js";
8
8
  import "./chunk-WWVD5DR5.js";
9
9
  import "./chunk-EZNCCO4L.js";
10
10
  export {