babylon.quarks 0.18.0 → 0.19.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.
@@ -1,70 +1,11 @@
1
+ import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture';
2
+ import { Texture } from '@babylonjs/core/Materials/Textures/texture';
1
3
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
2
4
  import { Scene } from '@babylonjs/core/scene';
3
- import { Texture } from '@babylonjs/core/Materials/Textures/texture';
4
- import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture';
5
5
  import { Mesh } from '@babylonjs/core/Meshes/mesh';
6
- import { Node } from '@babylonjs/core/node';
7
6
  import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
8
7
  import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
9
-
10
- declare const WebGLCoordinateSystem = 2000;
11
- declare const WebGPUCoordinateSystem = 2001;
12
- declare class Matrix4 {
13
- elements: number[];
14
- readonly isMatrix4 = true;
15
- constructor(n11?: number, n12?: number, n13?: number, n14?: number, n21?: number, n22?: number, n23?: number, n24?: number, n31?: number, n32?: number, n33?: number, n34?: number, n41?: number, n42?: number, n43?: number, n44?: number);
16
- /**
17
- * @deprecated Use {@link Matrix4#copyPosition .copyPosition()} instead.
18
- */
19
- extractPosition(m: Matrix4): Matrix4;
20
- /**
21
- * Sets this matrix to a x b and stores the result into the flat array r.
22
- * r can be either a regular Array or a TypedArray.
23
- *
24
- * @deprecated This method has been removed completely.
25
- */
26
- multiplyToArray(a: Matrix4, b: Matrix4, r: number[]): Matrix4;
27
- /**
28
- * @deprecated Use {@link Matrix4#makeRotationFromQuaternion .makeRotationFromQuaternion()} instead.
29
- */
30
- setRotationFromQuaternion(q: Quaternion): Matrix4;
31
- set(n11: number, n12: number, n13: number, n14: number, n21: number, n22: number, n23: number, n24: number, n31: number, n32: number, n33: number, n34: number, n41: number, n42: number, n43: number, n44: number): this;
32
- identity(): this;
33
- clone(): Matrix4;
34
- copy(m: Matrix4): this;
35
- copyPosition(m: Matrix4): this;
36
- setFromMatrix3(m: Matrix3): this;
37
- extractBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
38
- makeBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
39
- extractRotation(m: Matrix4): this;
40
- makeRotationFromEuler(euler: Euler): this;
41
- makeRotationFromQuaternion(q: Quaternion): this;
42
- lookAt(eye: Vector3, target: Vector3, up: Vector3): this;
43
- multiply(m: Matrix4): this;
44
- premultiply(m: Matrix4): this;
45
- multiplyMatrices(a: Matrix4, b: Matrix4): this;
46
- multiplyScalar(s: number): this;
47
- determinant(): number;
48
- transpose(): this;
49
- setPosition(x: number | Vector3, y?: number, z?: number): this;
50
- invert(): this;
51
- scale(v: Vector3): this;
52
- getMaxScaleOnAxis(): number;
53
- makeTranslation(x: number | Vector3, y?: number, z?: number): this;
54
- makeRotationX(theta: number): this;
55
- makeRotationY(theta: number): this;
56
- makeRotationZ(theta: number): this;
57
- makeRotationAxis(axis: Vector3, angle: number): this;
58
- makeScale(x: number, y: number, z: number): this;
59
- makeShear(xy: number, xz: number, yx: number, yz: number, zx: number, zy: number): this;
60
- compose(position: Vector3, quaternion: Quaternion, scale: Vector3): this;
61
- decompose(position: Vector3, quaternion: Quaternion, scale: Vector3): this;
62
- makePerspective(left: number, right: number, top: number, bottom: number, near: number, far: number, coordinateSystem?: number): this;
63
- makeOrthographic(left: number, right: number, top: number, bottom: number, near: number, far: number, coordinateSystem?: number): this;
64
- equals(matrix: Matrix4): boolean;
65
- fromArray(array: number[], offset?: number): this;
66
- toArray(array?: number[], offset?: number): number[];
67
- }
8
+ import { Node } from '@babylonjs/core/node';
68
9
 
69
10
  declare class Vector2 {
70
11
  x: number;
@@ -127,41 +68,59 @@ declare class Vector2 {
127
68
  [Symbol.iterator](): Generator<number, void, unknown>;
128
69
  }
129
70
 
130
- declare class Matrix3 {
131
- elements: number[];
132
- constructor(n11?: number, n12?: number, n13?: number, n21?: number, n22?: number, n23?: number, n31?: number, n32?: number, n33?: number);
133
- set(n11: number, n12: number, n13: number, n21: number, n22: number, n23: number, n31: number, n32: number, n33: number): this;
71
+ declare class Quaternion {
72
+ _x: number;
73
+ _y: number;
74
+ _z: number;
75
+ _w: number;
76
+ readonly isQuaternion: boolean;
77
+ constructor(x?: number, y?: number, z?: number, w?: number);
78
+ static slerpFlat(dst: number[], dstOffset: number, src0: number[], srcOffset0: number, src1: number[], srcOffset1: number, t: number): void;
79
+ static multiplyQuaternionsFlat(dst: number[], dstOffset: number, src0: number[], srcOffset0: number, src1: number[], srcOffset1: number): number[];
80
+ get x(): number;
81
+ set x(value: number);
82
+ get y(): number;
83
+ set y(value: number);
84
+ get z(): number;
85
+ set z(value: number);
86
+ get w(): number;
87
+ set w(value: number);
88
+ set(x: number, y: number, z: number, w: number): this;
89
+ clone(): Quaternion;
90
+ copy(quaternion: Quaternion): this;
91
+ setFromEuler(euler: Euler, update?: boolean): this;
92
+ setFromAxisAngle(axis: Vector3, angle: number): this;
93
+ setFromRotationMatrix(m: Matrix4): this;
94
+ setFromUnitVectors(vFrom: Vector3, vTo: Vector3): this;
95
+ angleTo(q: Quaternion): number;
96
+ rotateTowards(q: Quaternion, step: number): this;
134
97
  identity(): this;
135
- copy(m: Matrix3): this;
136
- extractBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
137
- setFromMatrix4(m: Matrix4): this;
138
- multiply(m: Matrix3): this;
139
- premultiply(m: Matrix3): this;
140
- multiplyMatrices(a: Matrix3, b: Matrix3): this;
141
- multiplyScalar(s: number): this;
142
- determinant(): number;
143
98
  invert(): this;
144
- transpose(): this;
145
- getNormalMatrix(matrix4: Matrix4): this;
146
- transposeIntoArray(r: number[]): this;
147
- setUvTransform(tx: number, ty: number, sx: number, sy: number, rotation: number, cx: number, cy: number): this;
148
- scale(sx: number, sy: number): this;
149
- rotate(theta: number): this;
150
- translate(tx: number, ty: number): this;
151
- makeTranslation(x: number | Vector2, y: number): this;
152
- makeRotation(theta: number): this;
153
- makeScale(x: number, y: number): this;
154
- equals(matrix: Matrix3): boolean;
99
+ conjugate(): this;
100
+ dot(v: Quaternion): number;
101
+ lengthSq(): number;
102
+ length(): number;
103
+ normalize(): this;
104
+ multiply(q: Quaternion): this;
105
+ premultiply(q: Quaternion): this;
106
+ multiplyQuaternions(a: Quaternion, b: Quaternion): this;
107
+ slerp(qb: Quaternion, t: number): this;
108
+ slerpQuaternions(qa: Quaternion, qb: Quaternion, t: number): this;
109
+ random(): this;
110
+ equals(quaternion: Quaternion): boolean;
155
111
  fromArray(array: number[], offset?: number): this;
156
112
  toArray(array?: number[], offset?: number): number[];
157
- clone(): Matrix3;
113
+ toJSON(): number[];
114
+ _onChange(callback: () => void): this;
115
+ _onChangeCallback(): void;
116
+ [Symbol.iterator](): Generator<number, void, unknown>;
158
117
  }
159
118
 
160
119
  declare class Vector3 {
161
120
  x: number;
162
121
  y: number;
163
122
  z: number;
164
- readonly isVector3 = true;
123
+ readonly isVector3: boolean;
165
124
  constructor(x?: number, y?: number, z?: number);
166
125
  set(x: number, y: number, z: number): this;
167
126
  setScalar(scalar: number): this;
@@ -234,52 +193,94 @@ declare class Vector3 {
234
193
  [Symbol.iterator](): Generator<number, void, unknown>;
235
194
  }
236
195
 
237
- declare class Quaternion {
238
- _x: number;
239
- _y: number;
240
- _z: number;
241
- _w: number;
242
- isQuaternion: boolean;
243
- constructor(x?: number, y?: number, z?: number, w?: number);
244
- static slerpFlat(dst: number[], dstOffset: number, src0: number[], srcOffset0: number, src1: number[], srcOffset1: number, t: number): void;
245
- static multiplyQuaternionsFlat(dst: number[], dstOffset: number, src0: number[], srcOffset0: number, src1: number[], srcOffset1: number): number[];
246
- get x(): number;
247
- set x(value: number);
248
- get y(): number;
249
- set y(value: number);
250
- get z(): number;
251
- set z(value: number);
252
- get w(): number;
253
- set w(value: number);
254
- set(x: number, y: number, z: number, w: number): this;
255
- clone(): Quaternion;
256
- copy(quaternion: Quaternion): this;
257
- setFromEuler(euler: Euler, update?: boolean): this;
258
- setFromAxisAngle(axis: Vector3, angle: number): this;
259
- setFromRotationMatrix(m: Matrix4): this;
260
- setFromUnitVectors(vFrom: Vector3, vTo: Vector3): this;
261
- angleTo(q: Quaternion): number;
262
- rotateTowards(q: Quaternion, step: number): this;
196
+ declare class Matrix3 {
197
+ elements: number[];
198
+ readonly isMatrix3: boolean;
199
+ constructor(n11?: number, n12?: number, n13?: number, n21?: number, n22?: number, n23?: number, n31?: number, n32?: number, n33?: number);
200
+ set(n11: number, n12: number, n13: number, n21: number, n22: number, n23: number, n31: number, n32: number, n33: number): this;
263
201
  identity(): this;
202
+ copy(m: Matrix3): this;
203
+ extractBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
204
+ setFromMatrix4(m: Matrix4): this;
205
+ multiply(m: Matrix3): this;
206
+ premultiply(m: Matrix3): this;
207
+ multiplyMatrices(a: Matrix3, b: Matrix3): this;
208
+ multiplyScalar(s: number): this;
209
+ determinant(): number;
264
210
  invert(): this;
265
- conjugate(): this;
266
- dot(v: Quaternion): number;
267
- lengthSq(): number;
268
- length(): number;
269
- normalize(): this;
270
- multiply(q: Quaternion): this;
271
- premultiply(q: Quaternion): this;
272
- multiplyQuaternions(a: Quaternion, b: Quaternion): this;
273
- slerp(qb: Quaternion, t: number): this;
274
- slerpQuaternions(qa: Quaternion, qb: Quaternion, t: number): this;
275
- random(): this;
276
- equals(quaternion: Quaternion): boolean;
211
+ transpose(): this;
212
+ getNormalMatrix(matrix4: Matrix4): this;
213
+ transposeIntoArray(r: number[]): this;
214
+ setUvTransform(tx: number, ty: number, sx: number, sy: number, rotation: number, cx: number, cy: number): this;
215
+ scale(sx: number, sy: number): this;
216
+ rotate(theta: number): this;
217
+ translate(tx: number, ty: number): this;
218
+ makeTranslation(x: number | Vector2, y: number): this;
219
+ makeRotation(theta: number): this;
220
+ makeScale(x: number, y: number): this;
221
+ equals(matrix: Matrix3): boolean;
222
+ fromArray(array: number[], offset?: number): this;
223
+ toArray(array?: number[], offset?: number): number[];
224
+ clone(): Matrix3;
225
+ }
226
+
227
+ declare const WebGLCoordinateSystem = 2000;
228
+ declare const WebGPUCoordinateSystem = 2001;
229
+ declare class Matrix4 {
230
+ elements: number[];
231
+ readonly isMatrix4: boolean;
232
+ constructor(n11?: number, n12?: number, n13?: number, n14?: number, n21?: number, n22?: number, n23?: number, n24?: number, n31?: number, n32?: number, n33?: number, n34?: number, n41?: number, n42?: number, n43?: number, n44?: number);
233
+ /**
234
+ * @deprecated Use {@link Matrix4#copyPosition .copyPosition()} instead.
235
+ */
236
+ extractPosition(m: Matrix4): Matrix4;
237
+ /**
238
+ * Sets this matrix to a x b and stores the result into the flat array r.
239
+ * r can be either a regular Array or a TypedArray.
240
+ *
241
+ * @deprecated This method has been removed completely.
242
+ */
243
+ multiplyToArray(a: Matrix4, b: Matrix4, r: number[]): Matrix4;
244
+ /**
245
+ * @deprecated Use {@link Matrix4#makeRotationFromQuaternion .makeRotationFromQuaternion()} instead.
246
+ */
247
+ setRotationFromQuaternion(q: Quaternion): Matrix4;
248
+ set(n11: number, n12: number, n13: number, n14: number, n21: number, n22: number, n23: number, n24: number, n31: number, n32: number, n33: number, n34: number, n41: number, n42: number, n43: number, n44: number): this;
249
+ identity(): this;
250
+ clone(): Matrix4;
251
+ copy(m: Matrix4): this;
252
+ copyPosition(m: Matrix4): this;
253
+ setFromMatrix3(m: Matrix3): this;
254
+ extractBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
255
+ makeBasis(xAxis: Vector3, yAxis: Vector3, zAxis: Vector3): this;
256
+ extractRotation(m: Matrix4): this;
257
+ makeRotationFromEuler(euler: Euler): this;
258
+ makeRotationFromQuaternion(q: Quaternion): this;
259
+ lookAt(eye: Vector3, target: Vector3, up: Vector3): this;
260
+ multiply(m: Matrix4): this;
261
+ premultiply(m: Matrix4): this;
262
+ multiplyMatrices(a: Matrix4, b: Matrix4): this;
263
+ multiplyScalar(s: number): this;
264
+ determinant(): number;
265
+ transpose(): this;
266
+ setPosition(x: number | Vector3, y?: number, z?: number): this;
267
+ invert(): this;
268
+ scale(v: Vector3): this;
269
+ getMaxScaleOnAxis(): number;
270
+ makeTranslation(x: number | Vector3, y?: number, z?: number): this;
271
+ makeRotationX(theta: number): this;
272
+ makeRotationY(theta: number): this;
273
+ makeRotationZ(theta: number): this;
274
+ makeRotationAxis(axis: Vector3, angle: number): this;
275
+ makeScale(x: number, y: number, z: number): this;
276
+ makeShear(xy: number, xz: number, yx: number, yz: number, zx: number, zy: number): this;
277
+ compose(position: Vector3, quaternion: Quaternion, scale: Vector3): this;
278
+ decompose(position: Vector3, quaternion: Quaternion, scale: Vector3): this;
279
+ makePerspective(left: number, right: number, top: number, bottom: number, near: number, far: number, coordinateSystem?: number): this;
280
+ makeOrthographic(left: number, right: number, top: number, bottom: number, near: number, far: number, coordinateSystem?: number): this;
281
+ equals(matrix: Matrix4): boolean;
277
282
  fromArray(array: number[], offset?: number): this;
278
283
  toArray(array?: number[], offset?: number): number[];
279
- toJSON(): number[];
280
- _onChange(callback: () => void): this;
281
- _onChangeCallback(): void;
282
- [Symbol.iterator](): Generator<number, void, unknown>;
283
284
  }
284
285
 
285
286
  type EulerOrder = 'XYZ' | 'YXZ' | 'ZXY' | 'ZYX' | 'YZX' | 'XZY' | 'XYX' | 'YZY' | 'ZXZ' | 'XZX' | 'YXY' | 'ZYZ';
@@ -288,7 +289,7 @@ declare class Euler {
288
289
  _y: number;
289
290
  _z: number;
290
291
  _order: EulerOrder;
291
- isEuler: boolean;
292
+ readonly isEuler: boolean;
292
293
  static DEFAULT_ORDER: EulerOrder;
293
294
  constructor(x?: number, y?: number, z?: number, order?: EulerOrder);
294
295
  get x(): number;
@@ -314,11 +315,87 @@ declare class Euler {
314
315
  [Symbol.iterator](): Generator<number | EulerOrder, void, unknown>;
315
316
  }
316
317
 
317
- declare class Vector4 {
318
- x: number;
319
- y: number;
320
- z: number;
318
+ declare const DEG2RAD: number;
319
+ declare const RAD2DEG: number;
320
+ declare function generateUUID(): string;
321
+ declare function clamp(value: number, min: number, max: number): number;
322
+ declare function euclideanModulo(n: number, m: number): number;
323
+ declare function mapLinear(x: number, a1: number, a2: number, b1: number, b2: number): number;
324
+ declare function inverseLerp(x: number, y: number, value: number): number;
325
+ declare function lerp(x: number, y: number, t: number): number;
326
+ declare function damp(x: number, y: number, lambda: number, dt: number): number;
327
+ declare function pingpong(x: number, length?: number): number;
328
+ declare function smoothstep(x: number, min: number, max: number): number;
329
+ declare function smootherstep(x: number, min: number, max: number): number;
330
+ declare function randInt(low: number, high: number): number;
331
+ declare function randFloat(low: number, high: number): number;
332
+ declare function randFloatSpread(range: number): number;
333
+ declare function seededRandom(s: number): number;
334
+ declare function degToRad(degrees: number): number;
335
+ declare function radToDeg(radians: number): number;
336
+ declare function isPowerOfTwo(value: number): boolean;
337
+ declare function ceilPowerOfTwo(value: number): number;
338
+ declare function floorPowerOfTwo(value: number): number;
339
+ declare function setQuaternionFromProperEuler(q: Quaternion, a: number, b: number, c: number, order: EulerOrder): void;
340
+ declare function denormalize(value: number, array: number[]): number;
341
+ declare function normalize(value: number, array: number[]): number;
342
+ declare const MathUtils: {
343
+ DEG2RAD: number;
344
+ RAD2DEG: number;
345
+ generateUUID: typeof generateUUID;
346
+ clamp: typeof clamp;
347
+ euclideanModulo: typeof euclideanModulo;
348
+ mapLinear: typeof mapLinear;
349
+ inverseLerp: typeof inverseLerp;
350
+ lerp: typeof lerp;
351
+ damp: typeof damp;
352
+ pingpong: typeof pingpong;
353
+ smoothstep: typeof smoothstep;
354
+ smootherstep: typeof smootherstep;
355
+ randInt: typeof randInt;
356
+ randFloat: typeof randFloat;
357
+ randFloatSpread: typeof randFloatSpread;
358
+ seededRandom: typeof seededRandom;
359
+ degToRad: typeof degToRad;
360
+ radToDeg: typeof radToDeg;
361
+ isPowerOfTwo: typeof isPowerOfTwo;
362
+ ceilPowerOfTwo: typeof ceilPowerOfTwo;
363
+ floorPowerOfTwo: typeof floorPowerOfTwo;
364
+ setQuaternionFromProperEuler: typeof setQuaternionFromProperEuler;
365
+ normalize: typeof normalize;
366
+ denormalize: typeof denormalize;
367
+ };
368
+
369
+ /**
370
+ * A `Vector3` whose components live in a shared `Float32Array` at a fixed
371
+ * offset rather than in three own properties.
372
+ *
373
+ * Every `Vector3` method routes through `x` / `y` / `z`, so replacing those
374
+ * with accessors inherits the whole API unchanged — including `clone()`, which
375
+ * still returns a detached plain `Vector3`.
376
+ *
377
+ * The accessors are installed on the prototype below rather than written as
378
+ * `get x()` in the class body, because TypeScript forbids overriding an
379
+ * inherited property with an accessor (TS2611). Runtime behaviour is the same:
380
+ * one shared property descriptor for every instance.
381
+ */
382
+ declare class Vector3View extends Vector3 {
383
+ data: Float32Array;
384
+ offset: number;
385
+ x: number;
386
+ y: number;
387
+ z: number;
388
+ constructor(data: Float32Array, offset: number);
389
+ /** Points the view at a new backing array and row offset. */
390
+ bind(data: Float32Array, offset: number): void;
391
+ }
392
+
393
+ declare class Vector4 {
394
+ x: number;
395
+ y: number;
396
+ z: number;
321
397
  w: number;
398
+ readonly isVector4: boolean;
322
399
  constructor(x?: number, y?: number, z?: number, w?: number);
323
400
  get width(): number;
324
401
  set width(value: number);
@@ -372,83 +449,22 @@ declare class Vector4 {
372
449
  [Symbol.iterator](): Generator<number, void, unknown>;
373
450
  }
374
451
 
375
- declare const DEG2RAD: number;
376
- declare const RAD2DEG: number;
377
- declare function generateUUID(): string;
378
- declare function clamp(value: number, min: number, max: number): number;
379
- declare function euclideanModulo(n: number, m: number): number;
380
- declare function mapLinear(x: number, a1: number, a2: number, b1: number, b2: number): number;
381
- declare function inverseLerp(x: number, y: number, value: number): number;
382
- declare function lerp(x: number, y: number, t: number): number;
383
- declare function damp(x: number, y: number, lambda: number, dt: number): number;
384
- declare function pingpong(x: number, length?: number): number;
385
- declare function smoothstep(x: number, min: number, max: number): number;
386
- declare function smootherstep(x: number, min: number, max: number): number;
387
- declare function randInt(low: number, high: number): number;
388
- declare function randFloat(low: number, high: number): number;
389
- declare function randFloatSpread(range: number): number;
390
- declare function seededRandom(s: number): number;
391
- declare function degToRad(degrees: number): number;
392
- declare function radToDeg(radians: number): number;
393
- declare function isPowerOfTwo(value: number): boolean;
394
- declare function ceilPowerOfTwo(value: number): number;
395
- declare function floorPowerOfTwo(value: number): number;
396
- declare function setQuaternionFromProperEuler(q: Quaternion, a: number, b: number, c: number, order: EulerOrder): void;
397
- declare function denormalize(value: number, array: number[]): number;
398
- declare function normalize(value: number, array: number[]): number;
399
- declare const MathUtils: {
400
- DEG2RAD: number;
401
- RAD2DEG: number;
402
- generateUUID: typeof generateUUID;
403
- clamp: typeof clamp;
404
- euclideanModulo: typeof euclideanModulo;
405
- mapLinear: typeof mapLinear;
406
- inverseLerp: typeof inverseLerp;
407
- lerp: typeof lerp;
408
- damp: typeof damp;
409
- pingpong: typeof pingpong;
410
- smoothstep: typeof smoothstep;
411
- smootherstep: typeof smootherstep;
412
- randInt: typeof randInt;
413
- randFloat: typeof randFloat;
414
- randFloatSpread: typeof randFloatSpread;
415
- seededRandom: typeof seededRandom;
416
- degToRad: typeof degToRad;
417
- radToDeg: typeof radToDeg;
418
- isPowerOfTwo: typeof isPowerOfTwo;
419
- ceilPowerOfTwo: typeof ceilPowerOfTwo;
420
- floorPowerOfTwo: typeof floorPowerOfTwo;
421
- setQuaternionFromProperEuler: typeof setQuaternionFromProperEuler;
422
- normalize: typeof normalize;
423
- denormalize: typeof denormalize;
424
- };
425
-
426
- declare class Bezier {
427
- p: number[];
428
- constructor(p1: number, p2: number, p3: number, p4: number);
429
- genValue(t: number): number;
430
- derivativeCoefficients(points: number[]): number[][];
431
- getSlope(t: number): number;
432
- controlCurve(d0: number, d1: number): void;
433
- hull(t: number): number[];
434
- split(t: number): {
435
- left: Bezier;
436
- right: Bezier;
437
- span: number[];
438
- };
439
- clone(): Bezier;
440
- toJSON(): {
441
- p0: number;
442
- p1: number;
443
- p2: number;
444
- p3: number;
445
- };
446
- static fromJSON(json: {
447
- p0: number;
448
- p1: number;
449
- p2: number;
450
- p3: number;
451
- }): Bezier;
452
+ /**
453
+ * A `Vector4` backed by a shared `Float32Array` at a fixed offset. Replacing
454
+ * the four component accessors inherits every `Vector4` method as-is; they are
455
+ * installed on the prototype because TypeScript forbids overriding an
456
+ * inherited property with an accessor in the class body (TS2611).
457
+ */
458
+ declare class Vector4View extends Vector4 {
459
+ data: Float32Array;
460
+ offset: number;
461
+ x: number;
462
+ y: number;
463
+ z: number;
464
+ w: number;
465
+ constructor(data: Float32Array, offset: number);
466
+ /** Points the view at a new backing array and row offset. */
467
+ bind(data: Float32Array, offset: number): void;
452
468
  }
453
469
 
454
470
  type FunctionJSON = {
@@ -504,16 +520,83 @@ type FunctionJSON = {
504
520
  */
505
521
  type GeneratorMemory = any[];
506
522
 
507
- declare class RandomColor implements ColorGenerator {
508
- a: Vector4;
509
- b: Vector4;
510
- constructor(a: Vector4, b: Vector4);
523
+ interface RotationGenerator {
524
+ type: 'rotation';
511
525
  startGen(memory: GeneratorMemory): void;
512
- genColor(memory: GeneratorMemory, color: Vector4): Vector4;
526
+ genValue(memory: GeneratorMemory, q: Quaternion, delta: number, t: number): Quaternion;
527
+ toJSON(): FunctionJSON;
528
+ clone(): RotationGenerator;
529
+ }
530
+ declare function RotationGeneratorFromJSON(json: FunctionJSON): RotationGenerator;
531
+
532
+ /**
533
+ * `startGen`/`genValue` follow the per-particle slot pattern documented in
534
+ * `GeneratorMemory.ts`: spawn calls `startGen(memory)` once (claim a slot or
535
+ * no-op), then `genValue(memory)` per frame.
536
+ */
537
+ interface ValueGenerator {
513
538
  type: 'value';
539
+ startGen(memory: any): void;
540
+ genValue(memory: any): number;
541
+ /** See FunctionValueGenerator.refreshTable. */
542
+ refreshTable?(): void;
514
543
  toJSON(): FunctionJSON;
515
- static fromJSON(json: FunctionJSON): RandomColor;
516
- clone(): ColorGenerator;
544
+ clone(): ValueGenerator;
545
+ }
546
+ interface FunctionValueGenerator {
547
+ type: 'function';
548
+ startGen(memory: GeneratorMemory): void;
549
+ genValue(memory: GeneratorMemory, t: number): number;
550
+ /**
551
+ * Optional hook for generators that can precompute a sampled table of
552
+ * themselves. Called once per frame by behaviors that evaluate the
553
+ * generator per particle, before any genValue of that frame, so a curve
554
+ * edited between frames is picked up.
555
+ */
556
+ refreshTable?(): void;
557
+ toJSON(): FunctionJSON;
558
+ clone(): FunctionValueGenerator;
559
+ }
560
+ declare function ValueGeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator;
561
+
562
+ declare class AxisAngleGenerator implements RotationGenerator {
563
+ axis: Vector3;
564
+ angle: FunctionValueGenerator | ValueGenerator;
565
+ type: 'rotation';
566
+ constructor(axis: Vector3, angle: FunctionValueGenerator | ValueGenerator);
567
+ startGen(memory: GeneratorMemory): void;
568
+ genValue(memory: GeneratorMemory, quat: Quaternion, delta: number, t?: number): Quaternion;
569
+ toJSON(): FunctionJSON;
570
+ static fromJSON(json: FunctionJSON): AxisAngleGenerator;
571
+ clone(): RotationGenerator;
572
+ }
573
+
574
+ declare class Bezier {
575
+ p: number[];
576
+ constructor(p1: number, p2: number, p3: number, p4: number);
577
+ genValue(t: number): number;
578
+ derivativeCoefficients(points: number[]): number[][];
579
+ getSlope(t: number): number;
580
+ controlCurve(d0: number, d1: number): void;
581
+ hull(t: number): number[];
582
+ split(t: number): {
583
+ left: Bezier;
584
+ right: Bezier;
585
+ span: number[];
586
+ };
587
+ clone(): Bezier;
588
+ toJSON(): {
589
+ p0: number;
590
+ p1: number;
591
+ p2: number;
592
+ p3: number;
593
+ };
594
+ static fromJSON(json: {
595
+ p0: number;
596
+ p1: number;
597
+ p2: number;
598
+ p3: number;
599
+ }): Bezier;
517
600
  }
518
601
 
519
602
  declare class ColorRange implements ColorGenerator {
@@ -553,13 +636,41 @@ declare class Gradient implements FunctionColorGenerator {
553
636
  color: ContinuousLinearFunction<Vector3>;
554
637
  alpha: ContinuousLinearFunction<number>;
555
638
  constructor(color?: Array<[Vector3, number]>, alpha?: Array<[number, number]>);
639
+ /** Sample count of the tables built by {@link refreshTable}. */
640
+ static readonly TABLE_SIZE = 257;
641
+ /** Sampled RGBA copy of the gradient, or null while none has been built. */
642
+ private table;
643
+ /** Keys the tables were built from, used to detect edits. */
644
+ private tableSignature;
645
+ /**
646
+ * Rebuilds the sampled table when the gradient changed, otherwise does
647
+ * nothing. See PiecewiseBezier.refreshTable — same reasoning, and the same
648
+ * signature check so a gradient edited in an editor is picked up.
649
+ */
650
+ refreshTable(): void;
651
+ /** Drops the sampled table, so later reads go back to evaluating the keys. */
652
+ clearTable(): void;
556
653
  genColor(memory: GeneratorMemory, color: Vector4, t: number): Vector4;
654
+ /** Evaluates the gradient keys themselves, ignoring any sampled table. */
655
+ genColorExact(color: Vector4, t: number): Vector4;
557
656
  toJSON(): FunctionJSON;
558
657
  static fromJSON(json: FunctionJSON): Gradient;
559
658
  clone(): FunctionColorGenerator;
560
659
  startGen(memory: GeneratorMemory): void;
561
660
  }
562
661
 
662
+ declare class RandomColor implements ColorGenerator {
663
+ a: Vector4;
664
+ b: Vector4;
665
+ constructor(a: Vector4, b: Vector4);
666
+ startGen(memory: GeneratorMemory): void;
667
+ genColor(memory: GeneratorMemory, color: Vector4): Vector4;
668
+ type: 'value';
669
+ toJSON(): FunctionJSON;
670
+ static fromJSON(json: FunctionJSON): RandomColor;
671
+ clone(): ColorGenerator;
672
+ }
673
+
563
674
  declare class RandomColorBetweenGradient implements FunctionColorGenerator {
564
675
  gradient1: Gradient;
565
676
  gradient2: Gradient;
@@ -584,6 +695,8 @@ interface FunctionColorGenerator {
584
695
  type: 'function';
585
696
  startGen(memory: GeneratorMemory): void;
586
697
  genColor(memory: GeneratorMemory, color: Vector4, t: number): Vector4;
698
+ /** See FunctionValueGenerator.refreshTable. */
699
+ refreshTable?(): void;
587
700
  toJSON(): FunctionJSON;
588
701
  clone(): FunctionColorGenerator;
589
702
  }
@@ -597,28 +710,7 @@ declare class ConstantColor implements ColorGenerator {
597
710
  static fromJSON(json: FunctionJSON): ConstantColor;
598
711
  clone(): ColorGenerator;
599
712
  }
600
- declare function ColorGeneratorFromJSON(json: FunctionJSON): RandomColor | ColorRange | Gradient | RandomColorBetweenGradient | ConstantColor;
601
-
602
- /**
603
- * `startGen`/`genValue` follow the per-particle slot pattern documented in
604
- * `GeneratorMemory.ts`: spawn calls `startGen(memory)` once (claim a slot or
605
- * no-op), then `genValue(memory)` per frame.
606
- */
607
- interface ValueGenerator {
608
- type: 'value';
609
- startGen(memory: any): void;
610
- genValue(memory: any): number;
611
- toJSON(): FunctionJSON;
612
- clone(): ValueGenerator;
613
- }
614
- interface FunctionValueGenerator {
615
- type: 'function';
616
- startGen(memory: GeneratorMemory): void;
617
- genValue(memory: GeneratorMemory, t: number): number;
618
- toJSON(): FunctionJSON;
619
- clone(): FunctionValueGenerator;
620
- }
621
- declare function ValueGeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator;
713
+ declare function ColorGeneratorFromJSON(json: FunctionJSON): ColorRange | Gradient | RandomColor | RandomColorBetweenGradient | ConstantColor;
622
714
 
623
715
  declare class ConstantValue implements ValueGenerator {
624
716
  value: number;
@@ -631,8 +723,35 @@ declare class ConstantValue implements ValueGenerator {
631
723
  clone(): ValueGenerator;
632
724
  }
633
725
 
634
- declare class IntervalValue implements ValueGenerator {
635
- a: number;
726
+ declare class EulerGenerator implements RotationGenerator {
727
+ angleX: FunctionValueGenerator | ValueGenerator;
728
+ angleY: FunctionValueGenerator | ValueGenerator;
729
+ angleZ: FunctionValueGenerator | ValueGenerator;
730
+ type: 'rotation';
731
+ eular: Euler;
732
+ constructor(angleX: FunctionValueGenerator | ValueGenerator, angleY: FunctionValueGenerator | ValueGenerator, angleZ: FunctionValueGenerator | ValueGenerator, eulerOrder?: EulerOrder);
733
+ startGen(memory: GeneratorMemory): void;
734
+ genValue(memory: GeneratorMemory, quat: Quaternion, delta: number, t?: number): Quaternion;
735
+ toJSON(): FunctionJSON;
736
+ static fromJSON(json: FunctionJSON): EulerGenerator;
737
+ clone(): RotationGenerator;
738
+ }
739
+
740
+ interface Vector3Generator {
741
+ type: 'vec3function';
742
+ startGen(memory: GeneratorMemory): void;
743
+ genValue(memory: GeneratorMemory, vec: Vector3, t?: number): Vector3;
744
+ /** See FunctionValueGenerator.refreshTable. */
745
+ refreshTable?(): void;
746
+ toJSON(): FunctionJSON;
747
+ clone(): Vector3Generator;
748
+ }
749
+ declare function Vector3GeneratorFromJSON(json: FunctionJSON): Vector3Generator;
750
+
751
+ declare function GeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator | RotationGenerator | Vector3Generator;
752
+
753
+ declare class IntervalValue implements ValueGenerator {
754
+ a: number;
636
755
  b: number;
637
756
  constructor(a: number, b: number);
638
757
  indexCount: number;
@@ -660,8 +779,36 @@ declare abstract class PiecewiseFunction<T> {
660
779
  }
661
780
 
662
781
  declare class PiecewiseBezier extends PiecewiseFunction<Bezier> implements FunctionValueGenerator {
782
+ /** Sample count of the table built by {@link refreshTable}. */
783
+ static readonly TABLE_SIZE = 257;
663
784
  constructor(curves?: Array<[Bezier, number]>);
785
+ /**
786
+ * Sampled copy of the curve, or null while none has been built.
787
+ * See {@link refreshTable}.
788
+ */
789
+ private table;
790
+ /** Control points the table was built from, used to detect edits. */
791
+ private tableSignature;
792
+ /**
793
+ * Rebuilds the sampled table when the curve changed, otherwise does nothing.
794
+ *
795
+ * Evaluating this curve means a piece lookup plus a cubic; a particle system
796
+ * does that once per particle per frame. Sampling it once and interpolating
797
+ * costs two loads and a lerp instead. Sampling error at
798
+ * {@link PiecewiseBezier.TABLE_SIZE} points stays around 1e-5 for the shapes
799
+ * a curve editor produces — far below what a colour or a size can show.
800
+ *
801
+ * The curve is public and mutable (a curve editor writes straight into
802
+ * `functions` and a Bezier's `p`), so this compares the control points
803
+ * against the ones the table was built from and only resamples on a real
804
+ * change. That is a handful of float compares per frame.
805
+ */
806
+ refreshTable(): void;
807
+ /** Drops the sampled table, so later reads go back to evaluating the curve. */
808
+ clearTable(): void;
664
809
  genValue(memory: GeneratorMemory, t?: number): number;
810
+ /** Evaluates the curve itself, ignoring any sampled table. */
811
+ genValueExact(t: number): number;
665
812
  toSVG(length: number, segments: number): string;
666
813
  type: 'function';
667
814
  toJSON(): FunctionJSON;
@@ -670,15 +817,6 @@ declare class PiecewiseBezier extends PiecewiseFunction<Bezier> implements Funct
670
817
  startGen(memory: GeneratorMemory): void;
671
818
  }
672
819
 
673
- interface RotationGenerator {
674
- type: 'rotation';
675
- startGen(memory: GeneratorMemory): void;
676
- genValue(memory: GeneratorMemory, q: Quaternion, delta: number, t: number): Quaternion;
677
- toJSON(): FunctionJSON;
678
- clone(): RotationGenerator;
679
- }
680
- declare function RotationGeneratorFromJSON(json: FunctionJSON): RotationGenerator;
681
-
682
820
  declare class RandomQuatGenerator implements RotationGenerator {
683
821
  type: 'rotation';
684
822
  constructor();
@@ -690,41 +828,6 @@ declare class RandomQuatGenerator implements RotationGenerator {
690
828
  clone(): RotationGenerator;
691
829
  }
692
830
 
693
- declare class AxisAngleGenerator implements RotationGenerator {
694
- axis: Vector3;
695
- angle: FunctionValueGenerator | ValueGenerator;
696
- type: 'rotation';
697
- constructor(axis: Vector3, angle: FunctionValueGenerator | ValueGenerator);
698
- startGen(memory: GeneratorMemory): void;
699
- genValue(memory: GeneratorMemory, quat: Quaternion, delta: number, t?: number): Quaternion;
700
- toJSON(): FunctionJSON;
701
- static fromJSON(json: FunctionJSON): AxisAngleGenerator;
702
- clone(): RotationGenerator;
703
- }
704
-
705
- declare class EulerGenerator implements RotationGenerator {
706
- angleX: FunctionValueGenerator | ValueGenerator;
707
- angleY: FunctionValueGenerator | ValueGenerator;
708
- angleZ: FunctionValueGenerator | ValueGenerator;
709
- type: 'rotation';
710
- eular: Euler;
711
- constructor(angleX: FunctionValueGenerator | ValueGenerator, angleY: FunctionValueGenerator | ValueGenerator, angleZ: FunctionValueGenerator | ValueGenerator, eulerOrder?: EulerOrder);
712
- startGen(memory: GeneratorMemory): void;
713
- genValue(memory: GeneratorMemory, quat: Quaternion, delta: number, t?: number): Quaternion;
714
- toJSON(): FunctionJSON;
715
- static fromJSON(json: FunctionJSON): EulerGenerator;
716
- clone(): RotationGenerator;
717
- }
718
-
719
- interface Vector3Generator {
720
- type: 'vec3function';
721
- startGen(memory: GeneratorMemory): void;
722
- genValue(memory: GeneratorMemory, vec: Vector3, t?: number): Vector3;
723
- toJSON(): FunctionJSON;
724
- clone(): Vector3Generator;
725
- }
726
- declare function Vector3GeneratorFromJSON(json: FunctionJSON): Vector3Generator;
727
-
728
831
  declare class Vector3Function implements Vector3Generator {
729
832
  x: FunctionValueGenerator | ValueGenerator;
730
833
  y: FunctionValueGenerator | ValueGenerator;
@@ -738,7 +841,103 @@ declare class Vector3Function implements Vector3Generator {
738
841
  clone(): Vector3Generator;
739
842
  }
740
843
 
741
- declare function GeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator | RotationGenerator | Vector3Generator;
844
+ /**
845
+ * Column storage for the vector-valued particle attributes.
846
+ *
847
+ * The three-component and four-component fields of a particle used to be six
848
+ * separate objects per particle, so walking a system meant chasing pointers
849
+ * across the heap. Here each attribute is one flat `Float32Array` shared by
850
+ * every particle in a system, and a particle holds views into its own row. The
851
+ * numbers a simulation step touches are then contiguous and prefetchable, while
852
+ * `particle.position.x` keeps working exactly as before.
853
+ *
854
+ * Scalar attributes (age, life, rotation, …) stay as plain properties on the
855
+ * particle: a monomorphic own property is already a single load, so moving them
856
+ * here would add an indirection rather than remove one.
857
+ */
858
+ declare class ParticleStore {
859
+ private static readonly EMPTY;
860
+ /** Number of particle rows the arrays can hold. */
861
+ capacity: number;
862
+ position: Float32Array;
863
+ /**
864
+ * Where each particle was when the current simulation step began.
865
+ *
866
+ * The step is fixed while frames are not, so a frame is usually drawn some
867
+ * way past the last step. The renderer closes that gap by continuing the
868
+ * motion the last step produced — and the only way to know that motion for
869
+ * every kind of behavior, not just the ones that move a particle by its
870
+ * velocity, is to have kept where it started.
871
+ */
872
+ previousPosition: Float32Array;
873
+ /**
874
+ * Size and colour at the start of the current step, for the same reason as
875
+ * {@link previousPosition}. These are read off a curve at `age / life`
876
+ * rather than integrated, and at the lifetimes an explosion uses — a fifth
877
+ * of a second, a dozen steps in total — a whole step of fade lands on one
878
+ * frame and none on the next.
879
+ */
880
+ previousSize: Float32Array;
881
+ previousColor: Float32Array;
882
+ /**
883
+ * Velocity at the start of the current step. A stretched billboard's shape
884
+ * is its velocity — the streak points along it and is as long as it — so a
885
+ * velocity that only changes on steps makes the sprite's outline pop at the
886
+ * step rate even while its position moves smoothly.
887
+ *
888
+ * Empty until {@link keepPreviousVelocity} asks for it, because only that
889
+ * one render mode reads it and an unused column is not free: it sits
890
+ * between the columns that are hot and costs them their locality.
891
+ */
892
+ previousVelocity: Float32Array;
893
+ velocity: Float32Array;
894
+ size: Float32Array;
895
+ startSize: Float32Array;
896
+ color: Float32Array;
897
+ startColor: Float32Array;
898
+ /**
899
+ * age, life and speedModifier interleaved, {@link SCALAR_STRIDE} per row.
900
+ *
901
+ * Double precision, unlike the vector columns: age accumulates `+= delta`
902
+ * for the particle's whole life and is compared against life to decide
903
+ * death, so rounding it to float32 shifts when particles die and makes
904
+ * tightly balanced emitters flicker.
905
+ */
906
+ scalars: Float64Array;
907
+ /** Values per row in {@link scalars}. */
908
+ static readonly SCALAR_STRIDE = 3;
909
+ /** Offsets within a {@link scalars} row. */
910
+ static readonly AGE = 0;
911
+ static readonly LIFE = 1;
912
+ static readonly SPEED_MODIFIER = 2;
913
+ constructor(capacity?: number);
914
+ /**
915
+ * Grows the arrays so `count` rows fit, preserving the existing contents.
916
+ *
917
+ * @param count - Number of rows that must be addressable.
918
+ * @returns `true` when the arrays were replaced, meaning every particle
919
+ * bound to this store has to be re-bound.
920
+ */
921
+ ensureCapacity(count: number): boolean;
922
+ /**
923
+ * Exchanges the contents of two rows.
924
+ *
925
+ * Used to keep row order aligned with the owning system's particle order, so
926
+ * the live particles stay a contiguous range that a renderer can copy in one
927
+ * go rather than gathering particle by particle.
928
+ */
929
+ /**
930
+ * Starts keeping {@link previousVelocity}. Harmless to call every step;
931
+ * returns true on the call that allocated, which replaces the array and so
932
+ * leaves every particle's view of it pointing at the old one.
933
+ */
934
+ keepPreviousVelocity(): boolean;
935
+ swapRows(a: number, b: number): void;
936
+ private static growDouble;
937
+ private static swap3;
938
+ private static swap4;
939
+ private static grow;
940
+ }
742
941
 
743
942
  interface EmissionState {
744
943
  burstIndex: number;
@@ -823,13 +1022,44 @@ interface IEmitter {
823
1022
  visible: boolean;
824
1023
  matrixWorld: any;
825
1024
  }
826
- type ParticleSystemEventType = "emitEnd" | "finished" | "destroy" | "particleDied";
1025
+ type ParticleSystemEventType = 'emitEnd' | 'finished' | 'destroy' | 'particleDied';
827
1026
  interface ParticleSystemEvent {
828
1027
  type: ParticleSystemEventType;
829
1028
  particleSystem: IParticleSystem;
830
1029
  particle?: IParticle;
831
1030
  }
832
1031
  interface IParticleSystem {
1032
+ /**
1033
+ * Column storage backing the particles' vector attributes, when the
1034
+ * implementation uses one. Rows `[0, particleNum)` hold the live particles
1035
+ * in the same order as `particles`, so a renderer can read them as ranges.
1036
+ * @type {ParticleStore}
1037
+ */
1038
+ store?: ParticleStore;
1039
+ /**
1040
+ * Wall-clock time that has passed since the last simulated step, in
1041
+ * seconds, when the implementation simulates on a fixed timestep. Negative
1042
+ * when that step ran a hair ahead of real time instead (rounded to the
1043
+ * nearest step rather than floored, so this stays small either way). A
1044
+ * renderer uses it to draw where the particles are now rather than where
1045
+ * the last step left them.
1046
+ * @type {number}
1047
+ */
1048
+ simulationResidual?: number;
1049
+ /**
1050
+ * Length of one simulation step, in seconds, when the implementation
1051
+ * simulates on a fixed timestep. Turning is recorded per step rather than
1052
+ * per second, so a renderer needs this to know what fraction of a step
1053
+ * {@link simulationResidual} is.
1054
+ * @type {number}
1055
+ */
1056
+ simulationStep?: number;
1057
+ /**
1058
+ * Whether this system only emits through another system, which is when its
1059
+ * particles carry their own parent transform.
1060
+ * @type {boolean}
1061
+ */
1062
+ onlyUsedByOther?: boolean;
833
1063
  /**
834
1064
  * Whether the ParticleSystem should be automatically disposed when it finishes emitting particles.
835
1065
  * @type {string}
@@ -989,6 +1219,30 @@ interface IParticle {
989
1219
  get died(): boolean;
990
1220
  }
991
1221
  interface Particle extends IParticle {
1222
+ /**
1223
+ * Where the particle was when the current simulation step began, when the
1224
+ * implementation keeps it. A renderer draws between fixed steps and uses
1225
+ * this to continue the motion the last step produced, whatever produced it.
1226
+ * @type {Vector3}
1227
+ */
1228
+ previousPosition?: Vector3;
1229
+ /**
1230
+ * Velocity at the start of the current step, when the implementation keeps
1231
+ * it. A stretched billboard is drawn from its velocity, so a renderer needs
1232
+ * this to keep the sprite's shape moving between steps as its position does.
1233
+ * @type {Vector3}
1234
+ */
1235
+ previousVelocity?: Vector3;
1236
+ /**
1237
+ * How fast the particle is turning, as the behavior that turns it last left
1238
+ * it: a rate in radians per second for a particle that rotates by an angle,
1239
+ * or one simulation step's turn for one that rotates by quaternion.
1240
+ *
1241
+ * Written by the turning behaviors and read by the renderer, which draws
1242
+ * between simulation steps and has no other way to continue the turn.
1243
+ * @type {number | Quaternion}
1244
+ */
1245
+ angularVelocity?: number | Quaternion;
992
1246
  /**
993
1247
  * Speed modifier of the particle.
994
1248
  * @type {number}
@@ -1085,6 +1339,10 @@ declare class NodeParticle implements IParticle {
1085
1339
  * Particle implementation for sprite-based particle.
1086
1340
  */
1087
1341
  declare class SpriteParticle implements Particle {
1342
+ /** Column storage backing this particle's vector attributes. */
1343
+ readonly store: ParticleStore;
1344
+ /** Row this particle occupies in {@link store}. */
1345
+ storeIndex: number;
1088
1346
  /**
1089
1347
  * Parent matrix for transformation.
1090
1348
  * @type {Matrix4}
@@ -1110,31 +1368,49 @@ declare class SpriteParticle implements Particle {
1110
1368
  * @type {Vector3}
1111
1369
  */
1112
1370
  position: Vector3;
1371
+ /**
1372
+ * Where this particle was when the current simulation step began; see
1373
+ * {@link Particle.previousPosition}.
1374
+ * @type {Vector3}
1375
+ */
1376
+ previousPosition: Vector3;
1377
+ /**
1378
+ * Velocity at the start of the current step; see
1379
+ * {@link Particle.previousVelocity}.
1380
+ * @type {Vector3}
1381
+ */
1382
+ previousVelocity: Vector3;
1113
1383
  /**
1114
1384
  * Velocity of the particle.
1115
1385
  * @type {Vector3}
1116
1386
  */
1117
1387
  velocity: Vector3;
1388
+ /**
1389
+ * Size of the particle.
1390
+ * @type {Vector3}
1391
+ */
1392
+ size: Vector3;
1393
+ /** Row of the store's interleaved scalars this particle owns. */
1394
+ protected scalars: Float64Array;
1395
+ protected scalarOffset: number;
1118
1396
  /**
1119
1397
  * Age of the particle.
1120
1398
  * @type {number}
1121
1399
  */
1122
- age: number;
1400
+ get age(): number;
1401
+ set age(value: number);
1123
1402
  /**
1124
1403
  * Life duration of the particle.
1125
1404
  * @type {number}
1126
1405
  */
1127
- life: number;
1128
- /**
1129
- * Size of the particle.
1130
- * @type {Vector3}
1131
- */
1132
- size: Vector3;
1406
+ get life(): number;
1407
+ set life(value: number);
1133
1408
  /**
1134
1409
  * Speed modifier of the particle.
1135
1410
  * @type {number}
1136
1411
  */
1137
- speedModifier: number;
1412
+ get speedModifier(): number;
1413
+ set speedModifier(value: number);
1138
1414
  /**
1139
1415
  * Angular velocity of the particle.
1140
1416
  * @type {number | Quaternion}
@@ -1155,6 +1431,19 @@ declare class SpriteParticle implements Particle {
1155
1431
  * @type {number}
1156
1432
  */
1157
1433
  uvTile: number;
1434
+ /**
1435
+ * @param store - Column storage to bind to. A private single-row store is
1436
+ * created when omitted, so a standalone `new SpriteParticle()` still works.
1437
+ * @param storeIndex - Row this particle owns.
1438
+ */
1439
+ constructor(store?: ParticleStore, storeIndex?: number);
1440
+ /**
1441
+ * Moves this particle onto a different store row. The caller is responsible
1442
+ * for having moved the row contents too.
1443
+ */
1444
+ setStoreIndex(index: number): void;
1445
+ /** Re-points the vector views after the store grew its arrays. */
1446
+ rebind(): void;
1158
1447
  /**
1159
1448
  * Indicates if the particle has died.
1160
1449
  * @type {boolean}
@@ -1179,6 +1468,10 @@ declare class RecordState {
1179
1468
  * Particle implementation for trail-based particles.
1180
1469
  */
1181
1470
  declare class TrailParticle implements Particle {
1471
+ /** Column storage backing this particle's vector attributes. */
1472
+ readonly store: ParticleStore;
1473
+ /** Row this particle occupies in {@link store}. */
1474
+ storeIndex: number;
1182
1475
  /**
1183
1476
  * Parent matrix for transformation.
1184
1477
  * @type {Matrix4}
@@ -1204,6 +1497,18 @@ declare class TrailParticle implements Particle {
1204
1497
  * @type {Vector3}
1205
1498
  */
1206
1499
  position: Vector3;
1500
+ /**
1501
+ * Where this particle was when the current simulation step began; see
1502
+ * {@link Particle.previousPosition}.
1503
+ * @type {Vector3}
1504
+ */
1505
+ previousPosition: Vector3;
1506
+ /**
1507
+ * Velocity at the start of the current step; see
1508
+ * {@link Particle.previousVelocity}.
1509
+ * @type {Vector3}
1510
+ */
1511
+ previousVelocity: Vector3;
1207
1512
  /**
1208
1513
  * Local position of the particle.
1209
1514
  * @type {Vector3}
@@ -1214,31 +1519,37 @@ declare class TrailParticle implements Particle {
1214
1519
  * @type {Vector3}
1215
1520
  */
1216
1521
  velocity: Vector3;
1522
+ /**
1523
+ * Size of the particle.
1524
+ * @type {Vector3}
1525
+ */
1526
+ size: Vector3;
1527
+ /** Row of the store's interleaved scalars this particle owns. */
1528
+ protected scalars: Float64Array;
1529
+ protected scalarOffset: number;
1217
1530
  /**
1218
1531
  * Age of the particle.
1219
1532
  * @type {number}
1220
1533
  */
1221
- age: number;
1534
+ get age(): number;
1535
+ set age(value: number);
1222
1536
  /**
1223
1537
  * Life duration of the particle.
1224
1538
  * @type {number}
1225
1539
  */
1226
- life: number;
1540
+ get life(): number;
1541
+ set life(value: number);
1227
1542
  /**
1228
- * Size of the particle.
1229
- * @type {Vector3}
1543
+ * Speed modifier of the particle.
1544
+ * @type {number}
1230
1545
  */
1231
- size: Vector3;
1546
+ get speedModifier(): number;
1547
+ set speedModifier(value: number);
1232
1548
  /**
1233
1549
  * Length of the trail.
1234
1550
  * @type {number}
1235
1551
  */
1236
1552
  length: number;
1237
- /**
1238
- * Speed modifier of the particle.
1239
- * @type {number}
1240
- */
1241
- speedModifier: number;
1242
1553
  /**
1243
1554
  * Color of the particle.
1244
1555
  * @type {Vector4}
@@ -1246,6 +1557,10 @@ declare class TrailParticle implements Particle {
1246
1557
  color: Vector4;
1247
1558
  /**
1248
1559
  * Previous states of the particle.
1560
+ *
1561
+ * @deprecated The trail history now lives in the flat ring buffer below
1562
+ * (`historyPositions` / `historySizes` / `historyColors`), which records a
1563
+ * sample without allocating. This list is no longer populated or rendered.
1249
1564
  * @type {LinkedList<RecordState>}
1250
1565
  */
1251
1566
  previous: LinkedList<RecordState>;
@@ -1254,8 +1569,46 @@ declare class TrailParticle implements Particle {
1254
1569
  * @type {number}
1255
1570
  */
1256
1571
  uvTile: number;
1572
+ /** Ring buffer of recorded positions, 3 floats per sample. */
1573
+ historyPositions: Float32Array;
1574
+ /** Ring buffer of recorded widths, 1 float per sample. */
1575
+ historySizes: Float32Array;
1576
+ /** Ring buffer of recorded colors, 4 floats per sample. */
1577
+ historyColors: Float32Array;
1578
+ /** Number of samples the ring buffers can hold. */
1579
+ historyCapacity: number;
1580
+ /** Slot the next sample is written to. */
1581
+ historyHead: number;
1582
+ /** Number of valid samples currently held. */
1583
+ historyCount: number;
1584
+ /**
1585
+ * @param store - Column storage to bind to. A private single-row store is
1586
+ * created when omitted, so a standalone `new TrailParticle()` still works.
1587
+ * @param storeIndex - Row this particle owns.
1588
+ */
1589
+ constructor(store?: ParticleStore, storeIndex?: number);
1590
+ /**
1591
+ * Moves this particle onto a different store row. The caller is responsible
1592
+ * for having moved the row contents too.
1593
+ */
1594
+ setStoreIndex(index: number): void;
1595
+ /** Re-points the vector views after the store grew its arrays. */
1596
+ rebind(): void;
1597
+ /**
1598
+ * Allocates the trail ring buffers, reusing them when the capacity is unchanged.
1599
+ * @param {number} capacity - Number of samples to hold.
1600
+ */
1601
+ ensureHistoryCapacity(capacity: number): void;
1602
+ /** Drops every recorded sample without releasing the buffers. */
1603
+ resetHistory(): void;
1604
+ /**
1605
+ * Ring buffer slot of the i-th sample counting from the oldest one.
1606
+ * @param {number} i - Sample offset, `0` being the oldest live sample.
1607
+ */
1608
+ getHistoryIndex(i: number): number;
1257
1609
  /**
1258
- * Updates the particle state.
1610
+ * Records the current state into the trail ring buffer, or retires the
1611
+ * oldest sample once the particle is dead. Allocation free.
1259
1612
  */
1260
1613
  update(): void;
1261
1614
  /**
@@ -1270,473 +1623,186 @@ declare class TrailParticle implements Particle {
1270
1623
  memory: never[];
1271
1624
  }
1272
1625
 
1273
- interface ShapeJSON {
1274
- type: string;
1275
- radius?: number;
1276
- arc?: number;
1277
- thickness?: number;
1278
- donutRadius?: number;
1279
- angle?: number;
1280
- width?: number;
1281
- height?: number;
1282
- column?: number;
1283
- row?: number;
1284
- mesh?: string;
1285
- mode?: number;
1286
- particleSystem?: string;
1287
- spread?: number;
1288
- speed?: any;
1626
+ interface Constructable<T> {
1627
+ new (...args: any): T;
1289
1628
  }
1629
+ type FieldType = 'vec3' | 'value' | 'number' | 'range' | 'colorFunc' | 'valueFunc' | 'rotationFunc' | 'radian' | 'mesh' | 'particleSystem' | 'boolean' | 'string' | 'geometry' | 'emitterMode' | 'vec3Func';
1630
+ type ParameterType = FieldType | 'self';
1631
+ type ParameterPair = [string, Array<ParameterType>];
1632
+
1290
1633
  /**
1291
- * Enum representing the emitter modes for particles.
1634
+ * Interface for particle behaviors.
1635
+ * a behavior is a function that modifies a particle's properties over time.
1292
1636
  */
1293
- declare enum EmitterMode {
1294
- /**
1295
- * Emit particles randomly over the specified duration.
1296
- */
1297
- Random = 0,
1298
- /**
1299
- * Emit particles in a continuous loop.
1300
- */
1301
- Loop = 1,
1302
- /**
1303
- * Emit particles back and forth in a ping-pong manner.
1304
- */
1305
- PingPong = 2,
1637
+ interface Behavior {
1638
+ type: string;
1639
+ initialize(particle: Particle, particleSystem: IParticleSystem): void;
1640
+ update(particle: Particle, delta: number): void;
1306
1641
  /**
1307
- * Emit particles in bursts.
1642
+ * Optional bulk form of {@link update}, applied to `particles[0..count)`.
1643
+ *
1644
+ * The per-particle `update` is reached through one call site shared by every
1645
+ * behavior type, which leaves it megamorphic: V8 can neither inline it nor
1646
+ * specialise the generator calls inside. A behavior that implements this
1647
+ * instead gets one call per frame and a loop it owns, where those calls are
1648
+ * monomorphic. Implementations must skip dead particles exactly as the
1649
+ * per-particle path does, and must produce identical results.
1650
+ *
1651
+ * Behaviors that do not implement it keep working unchanged.
1308
1652
  */
1309
- Burst = 3
1653
+ updateAll?(particles: Array<Particle>, count: number, delta: number): void;
1654
+ frameUpdate(delta: number): void;
1655
+ toJSON(): any;
1656
+ clone(): Behavior;
1657
+ reset(): void;
1310
1658
  }
1311
- declare function getValueFromEmitterMode(mode: EmitterMode, currentValue: number, spread: number, emissionState: EmissionState): number;
1312
- interface EmitterShape {
1659
+ interface BehaviorPlugin {
1313
1660
  type: string;
1314
- initialize(particle: Particle, emissionState: EmissionState): void;
1315
- toJSON(): ShapeJSON;
1316
- update(system: IParticleSystem, delta: number): void;
1317
- clone(): EmitterShape;
1661
+ constructor: Constructable<Behavior>;
1662
+ params: ParameterPair[];
1663
+ loadJSON: (json: any, particleSystem: IParticleSystem) => Behavior;
1318
1664
  }
1665
+ declare const BehaviorTypes: {
1666
+ [key: string]: BehaviorPlugin;
1667
+ };
1668
+ declare function BehaviorFromJSON(json: any, particleSystem: IParticleSystem): Behavior | null;
1319
1669
 
1670
+ interface PhysicsResolver {
1671
+ resolve(pos: Vector3, normal: Vector3): boolean;
1672
+ }
1673
+ declare function setPhysicsResolver(resolver: PhysicsResolver): void;
1674
+ declare function getPhysicsResolver(): PhysicsResolver;
1320
1675
  /**
1321
- * Interface representing the parameters for a cone emitter.
1676
+ * Apply collision to particles from a physics resolver.
1322
1677
  */
1323
- interface ConeEmitterParameters {
1324
- /**
1325
- * The radius of the cone base.
1326
- */
1327
- radius?: number;
1328
- /**
1329
- * The arc of the cone.
1330
- */
1331
- arc?: number;
1332
- /**
1333
- * The thickness of the cone. 1 is a full cone, 0 is a cone with 0 thickness.
1334
- */
1335
- thickness?: number;
1336
- /**
1337
- * The angle of the cone, ranging from 0 to Math.PI / 2.
1338
- */
1339
- angle?: number;
1340
- /**
1341
- * The mode of the emitter.
1342
- * {@link EmitterMode}
1343
- */
1344
- mode?: EmitterMode;
1345
- /**
1346
- * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1347
- * {@link EmitterMode}
1348
- */
1349
- spread?: number;
1350
- /**
1351
- * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
1352
- * {@link EmitterMode}
1353
- */
1354
- speed?: ValueGenerator | FunctionValueGenerator;
1355
- }
1356
- declare class ConeEmitter implements EmitterShape {
1357
- type: string;
1358
- radius: number;
1359
- arc: number;
1360
- thickness: number;
1361
- angle: number;
1362
- mode: EmitterMode;
1363
- spread: number;
1364
- speed: ValueGenerator | FunctionValueGenerator;
1365
- memory: GeneratorMemory;
1366
- private currentValue;
1367
- constructor(parameters?: ConeEmitterParameters);
1368
- update(system: IParticleSystem, delta: number): void;
1369
- initialize(p: Particle, emissionState: EmissionState): void;
1370
- toJSON(): ShapeJSON;
1371
- static fromJSON(json: ShapeJSON): ConeEmitter;
1372
- clone(): EmitterShape;
1373
- }
1374
-
1375
- /**
1376
- * Interface representing the parameters for a circle emitter.
1377
- */
1378
- interface CircleEmitterParameters {
1379
- /**
1380
- * The radius of the circle.
1381
- */
1382
- radius?: number;
1383
- /**
1384
- * The arc of the circle.
1385
- */
1386
- arc?: number;
1387
- /**
1388
- * The thickness of the ring.
1389
- * 1 is a full circle, 0 is a ring with 0 radius.
1390
- */
1391
- thickness?: number;
1392
- /**
1393
- * The mode of the emitter.
1394
- * {@link EmitterMode}
1395
- */
1396
- mode?: EmitterMode;
1397
- /**
1398
- * The length of segment of which emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1399
- * {@link EmitterMode}
1400
- */
1401
- spread?: number;
1402
- /**
1403
- * The speed of the emitter start point travels when mode is EmitterMode.Loop or EmitterMode.PingPong.
1404
- * {@link EmitterMode}
1405
- */
1406
- speed?: ValueGenerator | FunctionValueGenerator;
1407
- }
1408
- /**
1409
- * a particle emitter that emits particles from a circle.
1410
- */
1411
- declare class CircleEmitter implements EmitterShape {
1412
- type: string;
1413
- radius: number;
1414
- arc: number;
1415
- thickness: number;
1416
- mode: EmitterMode;
1417
- spread: number;
1418
- speed: ValueGenerator | FunctionValueGenerator;
1419
- memory: GeneratorMemory;
1420
- private currentValue;
1421
- constructor(parameters?: CircleEmitterParameters);
1422
- update(system: IParticleSystem, delta: number): void;
1423
- initialize(p: Particle, emissionState: EmissionState): void;
1424
- toJSON(): ShapeJSON;
1425
- static fromJSON(json: any): CircleEmitter;
1426
- clone(): EmitterShape;
1427
- }
1428
-
1429
- /**
1430
- * Interface representing the parameters for a donut emitter.
1431
- */
1432
- interface DonutEmitterParameters {
1433
- /**
1434
- * The radius of the donut.
1435
- */
1436
- radius?: number;
1437
- /**
1438
- * The arc of the donut.
1439
- */
1440
- arc?: number;
1441
- /**
1442
- * The thickness of the ring. 1 is a full donut, 0 is a ring with 0 radius.
1443
- */
1444
- thickness?: number;
1445
- /**
1446
- * The radius of the hole in the center of the donut.
1447
- */
1448
- donutRadius?: number;
1449
- /**
1450
- * The mode of the emitter.
1451
- * {@link EmitterMode}
1452
- */
1453
- mode?: EmitterMode;
1454
- /**
1455
- * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1456
- * {@link EmitterMode}
1457
- */
1458
- spread?: number;
1459
- /**
1460
- * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
1461
- * {@link EmitterMode}
1462
- */
1463
- speed?: ValueGenerator | FunctionValueGenerator;
1464
- }
1465
- declare class DonutEmitter implements EmitterShape {
1466
- type: string;
1467
- radius: number;
1468
- donutRadius: number;
1469
- arc: number;
1470
- thickness: number;
1471
- mode: EmitterMode;
1472
- spread: number;
1473
- speed: ValueGenerator | FunctionValueGenerator;
1474
- memory: GeneratorMemory;
1475
- _m1: Matrix4;
1476
- constructor(parameters?: DonutEmitterParameters);
1477
- private currentValue;
1478
- update(system: IParticleSystem, delta: number): void;
1479
- initialize(p: Particle, emissionState: EmissionState): void;
1480
- toJSON(): ShapeJSON;
1481
- static fromJSON(json: any): DonutEmitter;
1482
- clone(): EmitterShape;
1483
- }
1484
-
1485
- /**
1486
- * A point emitter emits particles from a single point.
1487
- */
1488
- declare class PointEmitter implements EmitterShape {
1489
- type: string;
1490
- _m1: Matrix4;
1491
- constructor();
1492
- update(system: IParticleSystem, delta: number): void;
1493
- initialize(p: Particle): void;
1494
- toJSON(): ShapeJSON;
1495
- static fromJSON(json: any): PointEmitter;
1496
- clone(): EmitterShape;
1497
- }
1498
-
1499
- /**
1500
- * Interface representing the parameters for a sphere emitter.
1501
- */
1502
- interface SphereEmitterParameters {
1503
- /**
1504
- * The radius of the sphere.
1505
- */
1506
- radius?: number;
1507
- /**
1508
- * The arc of the sphere.
1509
- */
1510
- arc?: number;
1511
- /**
1512
- * The thickness of the sphere. 1 is a full sphere, 0 is a thin shell.
1513
- */
1514
- thickness?: number;
1515
- /**
1516
- * The mode of the emitter.
1517
- * {@link EmitterMode}
1518
- */
1519
- mode?: EmitterMode;
1520
- /**
1521
- * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1522
- * {@link EmitterMode}
1523
- */
1524
- spread?: number;
1525
- /**
1526
- * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
1527
- * {@link EmitterMode}
1528
- */
1529
- speed?: ValueGenerator | FunctionValueGenerator;
1530
- }
1531
- declare class SphereEmitter implements EmitterShape {
1678
+ declare class ApplyCollision implements Behavior {
1679
+ resolver: PhysicsResolver;
1680
+ bounce: number;
1532
1681
  type: string;
1533
- radius: number;
1534
- arc: number;
1535
- thickness: number;
1536
- mode: EmitterMode;
1537
- spread: number;
1538
- speed: ValueGenerator | FunctionValueGenerator;
1539
- memory: GeneratorMemory;
1540
- _m1: Matrix4;
1541
- constructor(parameters?: SphereEmitterParameters);
1542
- private currentValue;
1543
- update(system: IParticleSystem, delta: number): void;
1544
- initialize(p: Particle, emissionState: EmissionState): void;
1545
- toJSON(): ShapeJSON;
1546
- static fromJSON(json: any): SphereEmitter;
1547
- clone(): EmitterShape;
1682
+ tempV: Vector3;
1683
+ constructor(resolver: PhysicsResolver, bounce: number);
1684
+ initialize(particle: Particle): void;
1685
+ update(particle: Particle, delta: number): void;
1686
+ frameUpdate(delta: number): void;
1687
+ toJSON(): any;
1688
+ static fromJSON(json: any): Behavior;
1689
+ clone(): Behavior;
1690
+ reset(): void;
1548
1691
  }
1549
1692
 
1550
1693
  /**
1551
- * Interface representing the parameters for a hemisphere emitter.
1694
+ * Apply a global force to particles.
1552
1695
  */
1553
- interface HemisphereEmitterParameters {
1554
- /**
1555
- * The radius of the hemisphere.
1556
- */
1557
- radius?: number;
1558
- /**
1559
- * The arc of the hemisphere.
1560
- */
1561
- arc?: number;
1562
- /**
1563
- * The thickness of the hemisphere. 1 is a full hemisphere, 0 is a thin shell.
1564
- */
1565
- thickness?: number;
1566
- /**
1567
- * The mode of the emitter.
1568
- * {@link EmitterMode}
1569
- */
1570
- mode?: EmitterMode;
1571
- /**
1572
- * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1573
- * {@link EmitterMode}
1574
- */
1575
- spread?: number;
1576
- /**
1577
- * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
1578
- * {@link EmitterMode}
1579
- */
1580
- speed?: ValueGenerator | FunctionValueGenerator;
1581
- }
1582
- declare class HemisphereEmitter implements EmitterShape {
1696
+ declare class ApplyForce implements Behavior {
1697
+ direction: Vector3;
1698
+ magnitude: ValueGenerator;
1583
1699
  type: string;
1584
- radius: number;
1585
- arc: number;
1586
- thickness: number;
1587
- mode: EmitterMode;
1588
- spread: number;
1589
- speed: ValueGenerator | FunctionValueGenerator;
1590
- memory: GeneratorMemory;
1591
- _m1: Matrix4;
1592
- constructor(parameters?: HemisphereEmitterParameters);
1593
- private currentValue;
1594
- update(system: IParticleSystem, delta: number): void;
1595
- initialize(p: Particle, emissionState: EmissionState): void;
1596
- toJSON(): ShapeJSON;
1597
- static fromJSON(json: any): HemisphereEmitter;
1598
- clone(): EmitterShape;
1700
+ magnitudeValue: number;
1701
+ memory: {
1702
+ data: never[];
1703
+ dataCount: number;
1704
+ };
1705
+ constructor(direction: Vector3, magnitude: ValueGenerator);
1706
+ initialize(particle: Particle): void;
1707
+ update(particle: Particle, delta: number): void;
1708
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1709
+ frameUpdate(delta: number): void;
1710
+ toJSON(): any;
1711
+ static fromJSON(json: any): Behavior;
1712
+ clone(): Behavior;
1713
+ reset(): void;
1599
1714
  }
1600
1715
 
1601
- /**
1602
- * Interface representing the parameters for a grid emitter.
1603
- */
1604
- interface GridEmitterParameters {
1605
- /**
1606
- * The width of the grid.
1607
- */
1608
- width?: number;
1609
- /**
1610
- * The height of the grid.
1611
- */
1612
- height?: number;
1613
- /**
1614
- * The number of columns in the grid.
1615
- */
1616
- column?: number;
1617
- /**
1618
- * The number of rows in the grid.
1619
- */
1620
- row?: number;
1621
- }
1622
- declare class GridEmitter implements EmitterShape {
1623
- type: string;
1624
- width: number;
1625
- height: number;
1626
- column: number;
1627
- row: number;
1628
- constructor(parameters?: GridEmitterParameters);
1629
- initialize(p: Particle): void;
1630
- toJSON(): ShapeJSON;
1631
- static fromJSON(json: any): GridEmitter;
1632
- clone(): EmitterShape;
1633
- update(system: IParticleSystem, delta: number): void;
1716
+ interface Sequencer {
1717
+ transform(position: Vector3, index: number): void;
1718
+ toJSON(): any;
1719
+ clone(): Sequencer;
1634
1720
  }
1721
+ declare function SequencerFromJSON(json: any): Sequencer;
1635
1722
 
1636
1723
  /**
1637
- * Interface representing the parameters for a rectangle emitter.
1638
- */
1639
- interface RectangleEmitterParameters {
1640
- /**
1641
- * The width of the rectangle.
1642
- */
1643
- width?: number;
1644
- /**
1645
- * The height of the rectangle.
1646
- */
1647
- height?: number;
1648
- /**
1649
- * The thickness of the ring.
1650
- * 1 is a full rectangle, 0 is a ring with 0 radius.
1651
- */
1652
- thickness?: number;
1653
- /**
1654
- * The mode of the emitter.
1655
- * {@link EmitterMode}
1656
- */
1657
- mode?: EmitterMode;
1658
- /**
1659
- * The length of segment of which emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
1660
- * {@link EmitterMode}
1661
- */
1662
- spread?: number;
1663
- /**
1664
- * The speed of the emitter start point travels when mode is EmitterMode.Loop or EmitterMode.PingPong.
1665
- * {@link EmitterMode}
1666
- */
1667
- speed?: ValueGenerator | FunctionValueGenerator;
1668
- }
1669
- /**
1670
- * a particle emitter that emits particles from a rectangle.
1724
+ * Apply sequences to particles.
1725
+ * {@link Sequencer}
1671
1726
  */
1672
- declare class RectangleEmitter implements EmitterShape {
1727
+ declare class ApplySequences implements Behavior {
1728
+ static BEZIER: Bezier;
1673
1729
  type: string;
1674
- width: number;
1675
- height: number;
1676
- thickness: number;
1677
- mode: EmitterMode;
1678
- spread: number;
1679
- speed: ValueGenerator | FunctionValueGenerator;
1680
- memory: GeneratorMemory;
1681
- private currentValue;
1682
- private _m1;
1683
- constructor(parameters?: RectangleEmitterParameters);
1684
- update(system: IParticleSystem, delta: number): void;
1685
- initialize(p: Particle, emissionState: EmissionState): void;
1686
- toJSON(): ShapeJSON;
1687
- static fromJSON(json: any): RectangleEmitter;
1688
- clone(): EmitterShape;
1689
- }
1690
-
1691
- interface Constructable<T> {
1692
- new (...args: any): T;
1730
+ sequencers: Array<[IntervalValue, Sequencer]>;
1731
+ time: number;
1732
+ index: number;
1733
+ pCount: number;
1734
+ delay: number;
1735
+ tempV: Vector3;
1736
+ constructor(delayBetweenParticles: number);
1737
+ initialize(particle: Particle): void;
1738
+ reset(): void;
1739
+ update(particle: Particle, delta: number): void;
1740
+ frameUpdate(delta: number): void;
1741
+ appendSequencer(range: IntervalValue, sequencer: Sequencer): void;
1742
+ toJSON(): any;
1743
+ static fromJSON(json: any): Behavior;
1744
+ clone(): Behavior;
1693
1745
  }
1694
- type FieldType = 'vec3' | 'value' | 'number' | 'range' | 'colorFunc' | 'valueFunc' | 'rotationFunc' | 'radian' | 'mesh' | 'particleSystem' | 'boolean' | 'string' | 'geometry' | 'emitterMode' | 'vec3Func';
1695
- type ParameterType = FieldType | 'self';
1696
- type ParameterPair = [string, Array<ParameterType>];
1697
1746
 
1698
- interface EmitterShapePlugin {
1699
- type: string;
1700
- constructor: Constructable<EmitterShape>;
1701
- params: ParameterPair[];
1702
- loadJSON: (json: any, meta: JsonMetaData) => EmitterShape;
1747
+ /**
1748
+ * Compiles a run of behaviors into a single loop over the particles.
1749
+ *
1750
+ * Each behavior walking the particle array on its own means the array, and
1751
+ * every particle in it, is re-read once per behavior. Merging the ones this
1752
+ * module recognises into one pass reads each particle once — worth roughly
1753
+ * 1.2x at a hundred thousand particles and up to 1.6x at twenty thousand,
1754
+ * where the per-pass overhead weighs most.
1755
+ *
1756
+ * A behavior that is not recognised keeps its own pass, in its original place
1757
+ * in the order, so nothing here depends on the built-in set being complete.
1758
+ */
1759
+ /** Runs the compiled work for `particles[0..count)`. */
1760
+ type FusedPass = (behaviors: Array<Behavior>, particles: Array<Particle>, count: number, delta: number) => void;
1761
+ /** One step of a plan: either a compiled run of behaviors, or a single behavior. */
1762
+ interface FusionStep {
1763
+ /** Behaviors this step covers, in order. */
1764
+ behaviors: Array<Behavior>;
1765
+ /** Compiled pass, or undefined when the behavior runs its own update. */
1766
+ run?: FusedPass;
1703
1767
  }
1704
- declare const EmitterShapes: {
1705
- [key: string]: EmitterShapePlugin;
1706
- };
1707
- declare function EmitterFromJSON(json: ShapeJSON, meta: JsonMetaData): EmitterShape;
1768
+ /**
1769
+ * Splits `behaviors` into steps, merging consecutive recognised ones.
1770
+ *
1771
+ * Only consecutive behaviors are merged: a behavior that stays on its own must
1772
+ * still see the particles exactly where the original order left them.
1773
+ */
1774
+ declare function planBehaviorFusion(behaviors: Array<Behavior>): Array<FusionStep>;
1708
1775
 
1709
1776
  /**
1710
- * Interface for particle behaviors.
1711
- * a behavior is a function that modifies a particle's properties over time.
1777
+ * Change the emit direction of particles.
1712
1778
  */
1713
- interface Behavior {
1779
+ declare class ChangeEmitDirection implements Behavior {
1780
+ angle: ValueGenerator;
1714
1781
  type: string;
1715
- initialize(particle: Particle, particleSystem: IParticleSystem): void;
1782
+ _temp: Vector3;
1783
+ _q: Quaternion;
1784
+ memory: {
1785
+ data: never[];
1786
+ dataCount: number;
1787
+ };
1788
+ constructor(angle: ValueGenerator);
1789
+ initialize(particle: Particle): void;
1716
1790
  update(particle: Particle, delta: number): void;
1717
1791
  frameUpdate(delta: number): void;
1718
1792
  toJSON(): any;
1793
+ static fromJSON(json: any): Behavior;
1719
1794
  clone(): Behavior;
1720
1795
  reset(): void;
1721
1796
  }
1722
- interface BehaviorPlugin {
1723
- type: string;
1724
- constructor: Constructable<Behavior>;
1725
- params: ParameterPair[];
1726
- loadJSON: (json: any, particleSystem: IParticleSystem) => Behavior;
1727
- }
1728
- declare const BehaviorTypes: {
1729
- [key: string]: BehaviorPlugin;
1730
- };
1731
- declare function BehaviorFromJSON(json: any, particleSystem: IParticleSystem): Behavior | null;
1732
1797
 
1733
1798
  /**
1734
- * Color particles by their life.
1799
+ * Color particles by their speed.
1735
1800
  */
1736
- declare class ColorOverLife implements Behavior {
1801
+ declare class ColorBySpeed implements Behavior {
1737
1802
  color: FunctionColorGenerator;
1803
+ speedRange: IntervalValue;
1738
1804
  type: string;
1739
- constructor(color: FunctionColorGenerator);
1805
+ constructor(color: FunctionColorGenerator, speedRange: IntervalValue);
1740
1806
  initialize(particle: Particle): void;
1741
1807
  update(particle: Particle, delta: number): void;
1742
1808
  frameUpdate(delta: number): void;
@@ -1747,37 +1813,51 @@ declare class ColorOverLife implements Behavior {
1747
1813
  }
1748
1814
 
1749
1815
  /**
1750
- * Apply rotation to particles over their life.
1816
+ * Color particles by their life.
1751
1817
  */
1752
- declare class RotationOverLife implements Behavior {
1753
- angularVelocity: ValueGenerator | FunctionValueGenerator;
1818
+ declare class ColorOverLife implements Behavior {
1819
+ color: FunctionColorGenerator;
1754
1820
  type: string;
1755
- constructor(angularVelocity: ValueGenerator | FunctionValueGenerator);
1821
+ constructor(color: FunctionColorGenerator);
1756
1822
  initialize(particle: Particle): void;
1757
1823
  update(particle: Particle, delta: number): void;
1824
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1825
+ frameUpdate(delta: number): void;
1758
1826
  toJSON(): any;
1759
1827
  static fromJSON(json: any): Behavior;
1760
- frameUpdate(delta: number): void;
1761
1828
  clone(): Behavior;
1762
1829
  reset(): void;
1763
1830
  }
1764
1831
 
1832
+ declare enum SubParticleEmitMode {
1833
+ Death = 0,
1834
+ Birth = 1,
1835
+ Frame = 2
1836
+ }
1765
1837
  /**
1766
- * Apply rotation to particles over their life.
1838
+ * Emit a sub particle system from particles.
1767
1839
  */
1768
- declare class Rotation3DOverLife implements Behavior {
1769
- angularVelocity: RotationGenerator;
1840
+ declare class EmitSubParticleSystem implements Behavior {
1841
+ private particleSystem;
1842
+ useVelocityAsBasis: boolean;
1843
+ subParticleSystem: IEmitter | undefined;
1844
+ mode: SubParticleEmitMode;
1845
+ emitProbability: number;
1770
1846
  type: string;
1771
- private tempQuat;
1772
- private tempQuat2;
1773
- constructor(angularVelocity: RotationGenerator);
1847
+ private q_;
1848
+ private v_;
1849
+ private v2_;
1850
+ private subEmissions;
1851
+ constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number);
1774
1852
  initialize(particle: Particle): void;
1775
1853
  update(particle: Particle, delta: number): void;
1776
- toJSON(): any;
1777
- static fromJSON(json: any): Behavior;
1854
+ private emit;
1778
1855
  frameUpdate(delta: number): void;
1856
+ toJSON(): any;
1857
+ static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
1779
1858
  clone(): Behavior;
1780
1859
  reset(): void;
1860
+ private setMatrixFromParticle;
1781
1861
  }
1782
1862
 
1783
1863
  /**
@@ -1789,10 +1869,12 @@ declare class ForceOverLife implements Behavior {
1789
1869
  z: FunctionValueGenerator | ValueGenerator;
1790
1870
  type: string;
1791
1871
  _temp: Vector3;
1792
- ps: IParticleSystem;
1872
+ /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
1873
+ ps?: IParticleSystem;
1793
1874
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
1794
1875
  constructor(x: FunctionValueGenerator | ValueGenerator, y: FunctionValueGenerator | ValueGenerator, z: FunctionValueGenerator | ValueGenerator);
1795
1876
  update(particle: Particle, delta: number): void;
1877
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1796
1878
  toJSON(): any;
1797
1879
  static fromJSON(json: any): Behavior;
1798
1880
  _tempScale: Vector3;
@@ -1802,35 +1884,41 @@ declare class ForceOverLife implements Behavior {
1802
1884
  reset(): void;
1803
1885
  }
1804
1886
 
1805
- type VelocityOverLifeSpace = 'local' | 'world';
1806
1887
  /**
1807
- * Move particles with a direct velocity over their life (Unity's "Velocity over Lifetime").
1808
- * Applied as a positional displacement, so it is not affected by speed modifiers,
1809
- * forces, or speed limits. Orbital speeds rotate particles around the emitter axes.
1888
+ * apply tile number of particle texture by particles' life.
1810
1889
  */
1811
- declare class VelocityOverLife implements Behavior {
1812
- linearX: FunctionValueGenerator | ValueGenerator;
1813
- linearY: FunctionValueGenerator | ValueGenerator;
1814
- linearZ: FunctionValueGenerator | ValueGenerator;
1815
- orbitalX: FunctionValueGenerator | ValueGenerator;
1816
- orbitalY: FunctionValueGenerator | ValueGenerator;
1817
- orbitalZ: FunctionValueGenerator | ValueGenerator;
1818
- space: VelocityOverLifeSpace;
1890
+ declare class FrameOverLife implements Behavior {
1819
1891
  type: string;
1820
- ps: IParticleSystem;
1821
- constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace);
1822
- _temp: Vector3;
1823
- _tempEmitterPos: Vector3;
1824
- _tempQ: Quaternion;
1825
- _tempQInv: Quaternion;
1826
- _tempScale: Vector3;
1827
- _tempScaleInv: Vector3;
1828
- _tempRot: Quaternion;
1829
- _tempAxis: Vector3;
1830
- initialize(particle: Particle, particleSystem: IParticleSystem): void;
1892
+ private _frame;
1893
+ private _frameIsBezier;
1894
+ constructor(frame: FunctionValueGenerator);
1895
+ get frame(): FunctionValueGenerator;
1896
+ set frame(frame: FunctionValueGenerator);
1897
+ initialize(particle: Particle): void;
1898
+ update(particle: Particle, delta: number): void;
1899
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1831
1900
  frameUpdate(delta: number): void;
1901
+ toJSON(): any;
1902
+ static fromJSON(json: any): Behavior;
1903
+ clone(): Behavior;
1904
+ reset(): void;
1905
+ }
1906
+
1907
+ /**
1908
+ * Apply a gravity force to particles.
1909
+ * the gravity force is calculated as:
1910
+ * F = G * m1 * m2 / r^2
1911
+ */
1912
+ declare class GravityForce implements Behavior {
1913
+ center: Vector3;
1914
+ magnitude: number;
1915
+ type: string;
1916
+ temp: Vector3;
1917
+ constructor(center: Vector3, magnitude: number);
1918
+ initialize(particle: Particle): void;
1832
1919
  update(particle: Particle, delta: number): void;
1833
- private orbit;
1920
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1921
+ frameUpdate(delta: number): void;
1834
1922
  toJSON(): any;
1835
1923
  static fromJSON(json: any): Behavior;
1836
1924
  clone(): Behavior;
@@ -1847,7 +1935,8 @@ declare class InheritVelocity implements Behavior {
1847
1935
  multiplier: FunctionValueGenerator | ValueGenerator;
1848
1936
  mode: InheritVelocityMode;
1849
1937
  type: string;
1850
- ps: IParticleSystem;
1938
+ /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
1939
+ ps?: IParticleSystem;
1851
1940
  constructor(multiplier?: FunctionValueGenerator | ValueGenerator, mode?: InheritVelocityMode);
1852
1941
  _temp: Vector3;
1853
1942
  _tempPos: Vector3;
@@ -1855,10 +1944,139 @@ declare class InheritVelocity implements Behavior {
1855
1944
  _tempScaleInv: Vector3;
1856
1945
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
1857
1946
  frameUpdate(delta: number): void;
1858
- update(particle: Particle, delta: number): void;
1859
- private decomposeInverse;
1947
+ update(particle: Particle, delta: number): void;
1948
+ private decomposeInverse;
1949
+ toJSON(): any;
1950
+ static fromJSON(json: any): Behavior;
1951
+ clone(): Behavior;
1952
+ reset(): void;
1953
+ }
1954
+
1955
+ /**
1956
+ * Limit the speed of particles over their life.
1957
+ */
1958
+ declare class LimitSpeedOverLife implements Behavior {
1959
+ speed: FunctionValueGenerator;
1960
+ dampen: number;
1961
+ type: string;
1962
+ initialize(particle: Particle): void;
1963
+ constructor(speed: FunctionValueGenerator, dampen: number);
1964
+ update(particle: Particle, delta: number): void;
1965
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1966
+ toJSON(): any;
1967
+ static fromJSON(json: any): Behavior;
1968
+ frameUpdate(delta: number): void;
1969
+ clone(): Behavior;
1970
+ reset(): void;
1971
+ }
1972
+
1973
+ /**
1974
+ * Apply noise to particles.
1975
+ */
1976
+ declare class Noise implements Behavior {
1977
+ frequency: FunctionValueGenerator | ValueGenerator;
1978
+ power: FunctionValueGenerator | ValueGenerator;
1979
+ positionAmount: FunctionValueGenerator | ValueGenerator;
1980
+ rotationAmount: FunctionValueGenerator | ValueGenerator;
1981
+ type: string;
1982
+ duration: number;
1983
+ constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator);
1984
+ initialize(particle: Particle): void;
1985
+ update(particle: Particle, _: number): void;
1986
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1987
+ toJSON(): any;
1988
+ frameUpdate(delta: number): void;
1989
+ static fromJSON(json: any): Behavior;
1990
+ clone(): Behavior;
1991
+ reset(): void;
1992
+ }
1993
+
1994
+ /**
1995
+ * Orbit particles around an axis over their life.
1996
+ */
1997
+ declare class OrbitOverLife implements Behavior {
1998
+ orbitSpeed: FunctionValueGenerator | ValueGenerator;
1999
+ axis: Vector3;
2000
+ type: string;
2001
+ rotation: Quaternion;
2002
+ temp: Vector3;
2003
+ constructor(orbitSpeed: FunctionValueGenerator | ValueGenerator, axis?: Vector3);
2004
+ initialize(particle: Particle): void;
2005
+ update(particle: Particle, delta: number): void;
2006
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
2007
+ frameUpdate(delta: number): void;
2008
+ toJSON(): any;
2009
+ static fromJSON(json: any): Behavior;
2010
+ clone(): Behavior;
2011
+ reset(): void;
2012
+ }
2013
+
2014
+ /**
2015
+ * Apply rotation to particles over their life.
2016
+ */
2017
+ declare class Rotation3DOverLife implements Behavior {
2018
+ angularVelocity: RotationGenerator;
2019
+ type: string;
2020
+ /** Scratch for the frame's rotation step; also read by the fused pass. */
2021
+ tempQuat: Quaternion;
2022
+ constructor(angularVelocity: RotationGenerator);
2023
+ initialize(particle: Particle): void;
2024
+ update(particle: Particle, delta: number): void;
2025
+ toJSON(): any;
2026
+ static fromJSON(json: any): Behavior;
2027
+ frameUpdate(delta: number): void;
2028
+ clone(): Behavior;
2029
+ reset(): void;
2030
+ }
2031
+
2032
+ /**
2033
+ * Apply rotation to particles based on their speed.
2034
+ */
2035
+ declare class RotationBySpeed implements Behavior {
2036
+ angularVelocity: ValueGenerator | FunctionValueGenerator;
2037
+ speedRange: IntervalValue;
2038
+ type: string;
2039
+ private tempQuat;
2040
+ constructor(angularVelocity: ValueGenerator | FunctionValueGenerator, speedRange: IntervalValue);
2041
+ initialize(particle: Particle): void;
2042
+ update(particle: Particle, delta: number): void;
2043
+ toJSON(): any;
2044
+ static fromJSON(json: any): Behavior;
2045
+ frameUpdate(delta: number): void;
2046
+ clone(): Behavior;
2047
+ reset(): void;
2048
+ }
2049
+
2050
+ /**
2051
+ * Apply rotation to particles over their life.
2052
+ */
2053
+ declare class RotationOverLife implements Behavior {
2054
+ angularVelocity: ValueGenerator | FunctionValueGenerator;
2055
+ type: string;
2056
+ constructor(angularVelocity: ValueGenerator | FunctionValueGenerator);
2057
+ initialize(particle: Particle): void;
2058
+ update(particle: Particle, delta: number): void;
2059
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
2060
+ toJSON(): any;
2061
+ static fromJSON(json: any): Behavior;
2062
+ frameUpdate(delta: number): void;
2063
+ clone(): Behavior;
2064
+ reset(): void;
2065
+ }
2066
+
2067
+ /**
2068
+ * Apply size to particles based on their speed.
2069
+ */
2070
+ declare class SizeBySpeed implements Behavior {
2071
+ size: FunctionValueGenerator | Vector3Generator;
2072
+ speedRange: IntervalValue;
2073
+ type: string;
2074
+ initialize(particle: Particle): void;
2075
+ constructor(size: FunctionValueGenerator | Vector3Generator, speedRange: IntervalValue);
2076
+ update(particle: Particle): void;
1860
2077
  toJSON(): any;
1861
2078
  static fromJSON(json: any): Behavior;
2079
+ frameUpdate(delta: number): void;
1862
2080
  clone(): Behavior;
1863
2081
  reset(): void;
1864
2082
  }
@@ -1867,11 +2085,15 @@ declare class InheritVelocity implements Behavior {
1867
2085
  * Apply size to particles based on their life.
1868
2086
  */
1869
2087
  declare class SizeOverLife implements Behavior {
1870
- size: FunctionValueGenerator | Vector3Generator;
1871
2088
  type: string;
1872
- initialize(particle: Particle): void;
2089
+ private _size;
2090
+ private _sizeIsVector3;
1873
2091
  constructor(size: FunctionValueGenerator | Vector3Generator);
2092
+ get size(): FunctionValueGenerator | Vector3Generator;
2093
+ set size(size: FunctionValueGenerator | Vector3Generator);
2094
+ initialize(particle: Particle): void;
1874
2095
  update(particle: Particle): void;
2096
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1875
2097
  toJSON(): any;
1876
2098
  static fromJSON(json: any): Behavior;
1877
2099
  frameUpdate(delta: number): void;
@@ -1888,6 +2110,7 @@ declare class SpeedOverLife implements Behavior {
1888
2110
  initialize(particle: Particle): void;
1889
2111
  constructor(speed: FunctionValueGenerator);
1890
2112
  update(particle: Particle): void;
2113
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
1891
2114
  toJSON(): any;
1892
2115
  static fromJSON(json: any): Behavior;
1893
2116
  frameUpdate(delta: number): void;
@@ -1896,34 +2119,107 @@ declare class SpeedOverLife implements Behavior {
1896
2119
  }
1897
2120
 
1898
2121
  /**
1899
- * apply tile number of particle texture by particles' life.
2122
+ * A random() function, must return a numer in the interval [0,1), just like Math.random().
1900
2123
  */
1901
- declare class FrameOverLife implements Behavior {
1902
- frame: FunctionValueGenerator;
2124
+ type RandomFn = () => number;
2125
+ /** Deterministic simplex noise generator suitable for 2D, 3D and 4D spaces. */
2126
+ declare class SimplexNoise {
2127
+ private p;
2128
+ private perm;
2129
+ private permMod12;
2130
+ /**
2131
+ * Creates a new `SimplexNoise` instance.
2132
+ * This involves some setup. You can save a few cpu cycles by reusing the same instance.
2133
+ * @param randomOrSeed A random number generator or a seed (string|number).
2134
+ * Defaults to Math.random (random irreproducible initialization).
2135
+ */
2136
+ constructor(randomOrSeed?: RandomFn | string | number);
2137
+ /**
2138
+ * Samples the noise field in 2 dimensions
2139
+ * @param x
2140
+ * @param y
2141
+ * @returns a number in the interval [-1, 1]
2142
+ */
2143
+ noise2D(x: number, y: number): number;
2144
+ /**
2145
+ * Samples the noise field in 3 dimensions
2146
+ * @param x
2147
+ * @param y
2148
+ * @param z
2149
+ * @returns a number in the interval [-1, 1]
2150
+ */
2151
+ noise3D(x: number, y: number, z: number): number;
2152
+ /**
2153
+ * Samples the noise field in 4 dimensions
2154
+ * @param x
2155
+ * @param y
2156
+ * @param z
2157
+ * @returns a number in the interval [-1, 1]
2158
+ */
2159
+ noise4D(x: number, y: number, z: number, w: number): number;
2160
+ }
2161
+
2162
+ /**
2163
+ * Apply turbulence to particles.
2164
+ */
2165
+ declare class TurbulenceField implements Behavior {
2166
+ scale: Vector3;
2167
+ octaves: number;
2168
+ velocityMultiplier: Vector3;
2169
+ timeScale: Vector3;
1903
2170
  type: string;
1904
- constructor(frame: FunctionValueGenerator);
2171
+ generator: SimplexNoise;
2172
+ timeOffset: Vector3;
2173
+ temp: Vector3;
2174
+ temp2: Vector3;
2175
+ constructor(scale: Vector3, octaves: number, velocityMultiplier: Vector3, timeScale: Vector3);
1905
2176
  initialize(particle: Particle): void;
1906
2177
  update(particle: Particle, delta: number): void;
1907
- frameUpdate(delta: number): void;
1908
2178
  toJSON(): any;
2179
+ frameUpdate(delta: number): void;
1909
2180
  static fromJSON(json: any): Behavior;
1910
2181
  clone(): Behavior;
1911
2182
  reset(): void;
1912
2183
  }
1913
2184
 
2185
+ type VelocityOverLifeSpace = 'local' | 'world';
1914
2186
  /**
1915
- * Orbit particles around an axis over their life.
2187
+ * Move particles with a direct velocity over their life (Unity's "Velocity over Lifetime").
2188
+ * Applied as a positional displacement, so it is not affected by speed modifiers,
2189
+ * forces, or speed limits. Orbital speeds rotate particles around the emitter axes.
1916
2190
  */
1917
- declare class OrbitOverLife implements Behavior {
1918
- orbitSpeed: FunctionValueGenerator | ValueGenerator;
1919
- axis: Vector3;
2191
+ declare class VelocityOverLife implements Behavior {
2192
+ linearX: FunctionValueGenerator | ValueGenerator;
2193
+ linearY: FunctionValueGenerator | ValueGenerator;
2194
+ linearZ: FunctionValueGenerator | ValueGenerator;
2195
+ orbitalX: FunctionValueGenerator | ValueGenerator;
2196
+ orbitalY: FunctionValueGenerator | ValueGenerator;
2197
+ orbitalZ: FunctionValueGenerator | ValueGenerator;
2198
+ space: VelocityOverLifeSpace;
1920
2199
  type: string;
1921
- rotation: Quaternion;
1922
- temp: Vector3;
1923
- constructor(orbitSpeed: FunctionValueGenerator | ValueGenerator, axis?: Vector3);
1924
- initialize(particle: Particle): void;
1925
- update(particle: Particle, delta: number): void;
2200
+ /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2201
+ ps?: IParticleSystem;
2202
+ constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace);
2203
+ _temp: Vector3;
2204
+ _tempEmitterPos: Vector3;
2205
+ _tempQ: Quaternion;
2206
+ _tempQInv: Quaternion;
2207
+ _tempScale: Vector3;
2208
+ _tempScaleInv: Vector3;
2209
+ _tempRot: Quaternion;
2210
+ /**
2211
+ * Axes the orbital speeds turn around, refreshed once per frame by
2212
+ * {@link frameUpdate}. In world space they are the emitter's axes, which
2213
+ * only change when the emitter does — so they are hoisted out of the
2214
+ * per-particle work rather than rebuilt for every particle.
2215
+ */
2216
+ _axisX: Vector3;
2217
+ _axisY: Vector3;
2218
+ _axisZ: Vector3;
2219
+ initialize(particle: Particle, particleSystem: IParticleSystem): void;
1926
2220
  frameUpdate(delta: number): void;
2221
+ update(particle: Particle, delta: number): void;
2222
+ private orbit;
1927
2223
  toJSON(): any;
1928
2224
  static fromJSON(json: any): Behavior;
1929
2225
  clone(): Behavior;
@@ -1946,319 +2242,452 @@ declare class WidthOverLength implements Behavior {
1946
2242
  reset(): void;
1947
2243
  }
1948
2244
 
1949
- /**
1950
- * Apply a global force to particles.
1951
- */
1952
- declare class ApplyForce implements Behavior {
1953
- direction: Vector3;
1954
- magnitude: ValueGenerator;
1955
- type: string;
1956
- magnitudeValue: number;
1957
- memory: {
1958
- data: never[];
1959
- dataCount: number;
1960
- };
1961
- constructor(direction: Vector3, magnitude: ValueGenerator);
1962
- initialize(particle: Particle): void;
1963
- update(particle: Particle, delta: number): void;
1964
- frameUpdate(delta: number): void;
1965
- toJSON(): any;
1966
- static fromJSON(json: any): Behavior;
1967
- clone(): Behavior;
1968
- reset(): void;
2245
+ interface IAnimationData {
2246
+ /** Start time in seconds */
2247
+ startTime: number;
2248
+ /** Duration in seconds */
2249
+ duration: number;
2250
+ /** Target object */
2251
+ target: any;
2252
+ }
2253
+ interface IPrefab {
2254
+ /**
2255
+ * The name of the prefab.
2256
+ */
2257
+ name: string;
2258
+ /**
2259
+ * The children of the prefab.
2260
+ */
2261
+ animationData: IAnimationData[];
1969
2262
  }
1970
2263
 
1971
- /**
1972
- * Apply a gravity force to particles.
1973
- * the gravity force is calculated as:
1974
- * F = G * m1 * m2 / r^2
1975
- */
1976
- declare class GravityForce implements Behavior {
1977
- center: Vector3;
1978
- magnitude: number;
2264
+ interface ShapeJSON {
1979
2265
  type: string;
1980
- temp: Vector3;
1981
- constructor(center: Vector3, magnitude: number);
1982
- initialize(particle: Particle): void;
1983
- update(particle: Particle, delta: number): void;
1984
- frameUpdate(delta: number): void;
1985
- toJSON(): any;
1986
- static fromJSON(json: any): Behavior;
1987
- clone(): Behavior;
1988
- reset(): void;
2266
+ radius?: number;
2267
+ arc?: number;
2268
+ thickness?: number;
2269
+ donutRadius?: number;
2270
+ angle?: number;
2271
+ width?: number;
2272
+ height?: number;
2273
+ column?: number;
2274
+ row?: number;
2275
+ mesh?: string;
2276
+ mode?: number;
2277
+ particleSystem?: string;
2278
+ spread?: number;
2279
+ speed?: any;
1989
2280
  }
1990
-
1991
2281
  /**
1992
- * Change the emit direction of particles.
2282
+ * Enum representing the emitter modes for particles.
1993
2283
  */
1994
- declare class ChangeEmitDirection implements Behavior {
1995
- angle: ValueGenerator;
2284
+ declare enum EmitterMode {
2285
+ /**
2286
+ * Emit particles randomly over the specified duration.
2287
+ */
2288
+ Random = 0,
2289
+ /**
2290
+ * Emit particles in a continuous loop.
2291
+ */
2292
+ Loop = 1,
2293
+ /**
2294
+ * Emit particles back and forth in a ping-pong manner.
2295
+ */
2296
+ PingPong = 2,
2297
+ /**
2298
+ * Emit particles in bursts.
2299
+ */
2300
+ Burst = 3
2301
+ }
2302
+ declare function getValueFromEmitterMode(mode: EmitterMode, currentValue: number, spread: number, emissionState: EmissionState): number;
2303
+ interface EmitterShape {
1996
2304
  type: string;
1997
- _temp: Vector3;
1998
- _q: Quaternion;
1999
- memory: {
2000
- data: never[];
2001
- dataCount: number;
2002
- };
2003
- constructor(angle: ValueGenerator);
2004
- initialize(particle: Particle): void;
2005
- update(particle: Particle, delta: number): void;
2006
- frameUpdate(delta: number): void;
2007
- toJSON(): any;
2008
- static fromJSON(json: any): Behavior;
2009
- clone(): Behavior;
2010
- reset(): void;
2305
+ initialize(particle: Particle, emissionState: EmissionState): void;
2306
+ toJSON(): ShapeJSON;
2307
+ update(system: IParticleSystem, delta: number): void;
2308
+ clone(): EmitterShape;
2011
2309
  }
2012
2310
 
2013
- declare enum SubParticleEmitMode {
2014
- Death = 0,
2015
- Birth = 1,
2016
- Frame = 2
2311
+ /**
2312
+ * Interface representing the parameters for a circle emitter.
2313
+ */
2314
+ interface CircleEmitterParameters {
2315
+ /**
2316
+ * The radius of the circle.
2317
+ */
2318
+ radius?: number;
2319
+ /**
2320
+ * The arc of the circle.
2321
+ */
2322
+ arc?: number;
2323
+ /**
2324
+ * The thickness of the ring.
2325
+ * 1 is a full circle, 0 is a ring with 0 radius.
2326
+ */
2327
+ thickness?: number;
2328
+ /**
2329
+ * The mode of the emitter.
2330
+ * {@link EmitterMode}
2331
+ */
2332
+ mode?: EmitterMode;
2333
+ /**
2334
+ * The length of segment of which emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2335
+ * {@link EmitterMode}
2336
+ */
2337
+ spread?: number;
2338
+ /**
2339
+ * The speed of the emitter start point travels when mode is EmitterMode.Loop or EmitterMode.PingPong.
2340
+ * {@link EmitterMode}
2341
+ */
2342
+ speed?: ValueGenerator | FunctionValueGenerator;
2017
2343
  }
2018
2344
  /**
2019
- * Emit a sub particle system from particles.
2345
+ * a particle emitter that emits particles from a circle.
2020
2346
  */
2021
- declare class EmitSubParticleSystem implements Behavior {
2022
- private particleSystem;
2023
- useVelocityAsBasis: boolean;
2024
- subParticleSystem: IEmitter | undefined;
2025
- mode: SubParticleEmitMode;
2026
- emitProbability: number;
2347
+ declare class CircleEmitter implements EmitterShape {
2027
2348
  type: string;
2028
- private q_;
2029
- private v_;
2030
- private v2_;
2031
- private subEmissions;
2032
- constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number);
2033
- initialize(particle: Particle): void;
2034
- update(particle: Particle, delta: number): void;
2035
- private emit;
2036
- frameUpdate(delta: number): void;
2037
- toJSON(): any;
2038
- static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
2039
- clone(): Behavior;
2040
- reset(): void;
2041
- private setMatrixFromParticle;
2349
+ radius: number;
2350
+ arc: number;
2351
+ thickness: number;
2352
+ mode: EmitterMode;
2353
+ spread: number;
2354
+ speed: ValueGenerator | FunctionValueGenerator;
2355
+ memory: GeneratorMemory;
2356
+ private currentValue;
2357
+ constructor(parameters?: CircleEmitterParameters);
2358
+ update(system: IParticleSystem, delta: number): void;
2359
+ initialize(p: Particle, emissionState: EmissionState): void;
2360
+ toJSON(): ShapeJSON;
2361
+ static fromJSON(json: any): CircleEmitter;
2362
+ clone(): EmitterShape;
2042
2363
  }
2043
2364
 
2044
2365
  /**
2045
- * A random() function, must return a numer in the interval [0,1), just like Math.random().
2366
+ * Interface representing the parameters for a cone emitter.
2046
2367
  */
2047
- type RandomFn = () => number;
2048
- /** Deterministic simplex noise generator suitable for 2D, 3D and 4D spaces. */
2049
- declare class SimplexNoise {
2050
- private p;
2051
- private perm;
2052
- private permMod12;
2368
+ interface ConeEmitterParameters {
2053
2369
  /**
2054
- * Creates a new `SimplexNoise` instance.
2055
- * This involves some setup. You can save a few cpu cycles by reusing the same instance.
2056
- * @param randomOrSeed A random number generator or a seed (string|number).
2057
- * Defaults to Math.random (random irreproducible initialization).
2370
+ * The radius of the cone base.
2058
2371
  */
2059
- constructor(randomOrSeed?: RandomFn | string | number);
2372
+ radius?: number;
2060
2373
  /**
2061
- * Samples the noise field in 2 dimensions
2062
- * @param x
2063
- * @param y
2064
- * @returns a number in the interval [-1, 1]
2374
+ * The arc of the cone.
2065
2375
  */
2066
- noise2D(x: number, y: number): number;
2376
+ arc?: number;
2067
2377
  /**
2068
- * Samples the noise field in 3 dimensions
2069
- * @param x
2070
- * @param y
2071
- * @param z
2072
- * @returns a number in the interval [-1, 1]
2378
+ * The thickness of the cone. 1 is a full cone, 0 is a cone with 0 thickness.
2073
2379
  */
2074
- noise3D(x: number, y: number, z: number): number;
2380
+ thickness?: number;
2075
2381
  /**
2076
- * Samples the noise field in 4 dimensions
2077
- * @param x
2078
- * @param y
2079
- * @param z
2080
- * @returns a number in the interval [-1, 1]
2382
+ * The angle of the cone, ranging from 0 to Math.PI / 2.
2081
2383
  */
2082
- noise4D(x: number, y: number, z: number, w: number): number;
2384
+ angle?: number;
2385
+ /**
2386
+ * The mode of the emitter.
2387
+ * {@link EmitterMode}
2388
+ */
2389
+ mode?: EmitterMode;
2390
+ /**
2391
+ * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2392
+ * {@link EmitterMode}
2393
+ */
2394
+ spread?: number;
2395
+ /**
2396
+ * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
2397
+ * {@link EmitterMode}
2398
+ */
2399
+ speed?: ValueGenerator | FunctionValueGenerator;
2083
2400
  }
2084
-
2085
- /**
2086
- * Apply turbulence to particles.
2087
- */
2088
- declare class TurbulenceField implements Behavior {
2089
- scale: Vector3;
2090
- octaves: number;
2091
- velocityMultiplier: Vector3;
2092
- timeScale: Vector3;
2401
+ declare class ConeEmitter implements EmitterShape {
2093
2402
  type: string;
2094
- generator: SimplexNoise;
2095
- timeOffset: Vector3;
2096
- temp: Vector3;
2097
- temp2: Vector3;
2098
- constructor(scale: Vector3, octaves: number, velocityMultiplier: Vector3, timeScale: Vector3);
2099
- initialize(particle: Particle): void;
2100
- update(particle: Particle, delta: number): void;
2101
- toJSON(): any;
2102
- frameUpdate(delta: number): void;
2103
- static fromJSON(json: any): Behavior;
2104
- clone(): Behavior;
2105
- reset(): void;
2403
+ radius: number;
2404
+ arc: number;
2405
+ thickness: number;
2406
+ angle: number;
2407
+ mode: EmitterMode;
2408
+ spread: number;
2409
+ speed: ValueGenerator | FunctionValueGenerator;
2410
+ memory: GeneratorMemory;
2411
+ private currentValue;
2412
+ constructor(parameters?: ConeEmitterParameters);
2413
+ update(system: IParticleSystem, delta: number): void;
2414
+ initialize(p: Particle, emissionState: EmissionState): void;
2415
+ toJSON(): ShapeJSON;
2416
+ static fromJSON(json: ShapeJSON): ConeEmitter;
2417
+ clone(): EmitterShape;
2106
2418
  }
2107
2419
 
2108
2420
  /**
2109
- * Apply noise to particles.
2421
+ * Interface representing the parameters for a donut emitter.
2110
2422
  */
2111
- declare class Noise implements Behavior {
2112
- frequency: FunctionValueGenerator | ValueGenerator;
2113
- power: FunctionValueGenerator | ValueGenerator;
2114
- positionAmount: FunctionValueGenerator | ValueGenerator;
2115
- rotationAmount: FunctionValueGenerator | ValueGenerator;
2423
+ interface DonutEmitterParameters {
2424
+ /**
2425
+ * The radius of the donut.
2426
+ */
2427
+ radius?: number;
2428
+ /**
2429
+ * The arc of the donut.
2430
+ */
2431
+ arc?: number;
2432
+ /**
2433
+ * The thickness of the ring. 1 is a full donut, 0 is a ring with 0 radius.
2434
+ */
2435
+ thickness?: number;
2436
+ /**
2437
+ * The radius of the hole in the center of the donut.
2438
+ */
2439
+ donutRadius?: number;
2440
+ /**
2441
+ * The mode of the emitter.
2442
+ * {@link EmitterMode}
2443
+ */
2444
+ mode?: EmitterMode;
2445
+ /**
2446
+ * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2447
+ * {@link EmitterMode}
2448
+ */
2449
+ spread?: number;
2450
+ /**
2451
+ * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
2452
+ * {@link EmitterMode}
2453
+ */
2454
+ speed?: ValueGenerator | FunctionValueGenerator;
2455
+ }
2456
+ declare class DonutEmitter implements EmitterShape {
2116
2457
  type: string;
2117
- duration: number;
2118
- constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator);
2119
- initialize(particle: Particle): void;
2120
- update(particle: Particle, _: number): void;
2121
- toJSON(): any;
2122
- frameUpdate(delta: number): void;
2123
- static fromJSON(json: any): Behavior;
2124
- clone(): Behavior;
2125
- reset(): void;
2458
+ radius: number;
2459
+ donutRadius: number;
2460
+ arc: number;
2461
+ thickness: number;
2462
+ mode: EmitterMode;
2463
+ spread: number;
2464
+ speed: ValueGenerator | FunctionValueGenerator;
2465
+ memory: GeneratorMemory;
2466
+ _m1: Matrix4;
2467
+ constructor(parameters?: DonutEmitterParameters);
2468
+ private currentValue;
2469
+ update(system: IParticleSystem, delta: number): void;
2470
+ initialize(p: Particle, emissionState: EmissionState): void;
2471
+ toJSON(): ShapeJSON;
2472
+ static fromJSON(json: any): DonutEmitter;
2473
+ clone(): EmitterShape;
2126
2474
  }
2127
2475
 
2128
- interface Sequencer {
2129
- transform(position: Vector3, index: number): void;
2130
- toJSON(): any;
2131
- clone(): Sequencer;
2476
+ interface EmitterShapePlugin {
2477
+ type: string;
2478
+ constructor: Constructable<EmitterShape>;
2479
+ params: ParameterPair[];
2480
+ loadJSON: (json: any, meta: JsonMetaData) => EmitterShape;
2132
2481
  }
2133
- declare function SequencerFromJSON(json: any): Sequencer;
2482
+ declare const EmitterShapes: {
2483
+ [key: string]: EmitterShapePlugin;
2484
+ };
2485
+ declare function EmitterFromJSON(json: ShapeJSON, meta: JsonMetaData): EmitterShape;
2134
2486
 
2135
2487
  /**
2136
- * Apply sequences to particles.
2137
- * {@link Sequencer}
2488
+ * Interface representing the parameters for a grid emitter.
2138
2489
  */
2139
- declare class ApplySequences implements Behavior {
2140
- static BEZIER: Bezier;
2490
+ interface GridEmitterParameters {
2491
+ /**
2492
+ * The width of the grid.
2493
+ */
2494
+ width?: number;
2495
+ /**
2496
+ * The height of the grid.
2497
+ */
2498
+ height?: number;
2499
+ /**
2500
+ * The number of columns in the grid.
2501
+ */
2502
+ column?: number;
2503
+ /**
2504
+ * The number of rows in the grid.
2505
+ */
2506
+ row?: number;
2507
+ }
2508
+ declare class GridEmitter implements EmitterShape {
2141
2509
  type: string;
2142
- sequencers: Array<[IntervalValue, Sequencer]>;
2143
- time: number;
2144
- index: number;
2145
- pCount: number;
2146
- delay: number;
2147
- tempV: Vector3;
2148
- constructor(delayBetweenParticles: number);
2149
- initialize(particle: Particle): void;
2150
- reset(): void;
2151
- update(particle: Particle, delta: number): void;
2152
- frameUpdate(delta: number): void;
2153
- appendSequencer(range: IntervalValue, sequencer: Sequencer): void;
2154
- toJSON(): any;
2155
- static fromJSON(json: any): Behavior;
2156
- clone(): Behavior;
2510
+ width: number;
2511
+ height: number;
2512
+ column: number;
2513
+ row: number;
2514
+ constructor(parameters?: GridEmitterParameters);
2515
+ initialize(p: Particle): void;
2516
+ toJSON(): ShapeJSON;
2517
+ static fromJSON(json: any): GridEmitter;
2518
+ clone(): EmitterShape;
2519
+ update(system: IParticleSystem, delta: number): void;
2157
2520
  }
2158
2521
 
2159
- interface PhysicsResolver {
2160
- resolve(pos: Vector3, normal: Vector3): boolean;
2161
- }
2162
- declare function setPhysicsResolver(resolver: PhysicsResolver): void;
2163
- declare function getPhysicsResolver(): PhysicsResolver;
2164
2522
  /**
2165
- * Apply collision to particles from a physics resolver.
2523
+ * Interface representing the parameters for a hemisphere emitter.
2166
2524
  */
2167
- declare class ApplyCollision implements Behavior {
2168
- resolver: PhysicsResolver;
2169
- bounce: number;
2525
+ interface HemisphereEmitterParameters {
2526
+ /**
2527
+ * The radius of the hemisphere.
2528
+ */
2529
+ radius?: number;
2530
+ /**
2531
+ * The arc of the hemisphere.
2532
+ */
2533
+ arc?: number;
2534
+ /**
2535
+ * The thickness of the hemisphere. 1 is a full hemisphere, 0 is a thin shell.
2536
+ */
2537
+ thickness?: number;
2538
+ /**
2539
+ * The mode of the emitter.
2540
+ * {@link EmitterMode}
2541
+ */
2542
+ mode?: EmitterMode;
2543
+ /**
2544
+ * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2545
+ * {@link EmitterMode}
2546
+ */
2547
+ spread?: number;
2548
+ /**
2549
+ * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
2550
+ * {@link EmitterMode}
2551
+ */
2552
+ speed?: ValueGenerator | FunctionValueGenerator;
2553
+ }
2554
+ declare class HemisphereEmitter implements EmitterShape {
2170
2555
  type: string;
2171
- tempV: Vector3;
2172
- constructor(resolver: PhysicsResolver, bounce: number);
2173
- initialize(particle: Particle): void;
2174
- update(particle: Particle, delta: number): void;
2175
- frameUpdate(delta: number): void;
2176
- toJSON(): any;
2177
- static fromJSON(json: any): Behavior;
2178
- clone(): Behavior;
2179
- reset(): void;
2556
+ radius: number;
2557
+ arc: number;
2558
+ thickness: number;
2559
+ mode: EmitterMode;
2560
+ spread: number;
2561
+ speed: ValueGenerator | FunctionValueGenerator;
2562
+ memory: GeneratorMemory;
2563
+ _m1: Matrix4;
2564
+ constructor(parameters?: HemisphereEmitterParameters);
2565
+ private currentValue;
2566
+ update(system: IParticleSystem, delta: number): void;
2567
+ initialize(p: Particle, emissionState: EmissionState): void;
2568
+ toJSON(): ShapeJSON;
2569
+ static fromJSON(json: any): HemisphereEmitter;
2570
+ clone(): EmitterShape;
2180
2571
  }
2181
2572
 
2182
2573
  /**
2183
- * Color particles by their speed.
2574
+ * A point emitter emits particles from a single point.
2184
2575
  */
2185
- declare class ColorBySpeed implements Behavior {
2186
- color: FunctionColorGenerator;
2187
- speedRange: IntervalValue;
2576
+ declare class PointEmitter implements EmitterShape {
2188
2577
  type: string;
2189
- constructor(color: FunctionColorGenerator, speedRange: IntervalValue);
2190
- initialize(particle: Particle): void;
2191
- update(particle: Particle, delta: number): void;
2192
- frameUpdate(delta: number): void;
2193
- toJSON(): any;
2194
- static fromJSON(json: any): Behavior;
2195
- clone(): Behavior;
2196
- reset(): void;
2578
+ _m1: Matrix4;
2579
+ constructor();
2580
+ update(system: IParticleSystem, delta: number): void;
2581
+ initialize(p: Particle): void;
2582
+ toJSON(): ShapeJSON;
2583
+ static fromJSON(json: any): PointEmitter;
2584
+ clone(): EmitterShape;
2197
2585
  }
2198
2586
 
2199
2587
  /**
2200
- * Apply size to particles based on their speed.
2588
+ * Interface representing the parameters for a rectangle emitter.
2201
2589
  */
2202
- declare class SizeBySpeed implements Behavior {
2203
- size: FunctionValueGenerator | Vector3Generator;
2204
- speedRange: IntervalValue;
2205
- type: string;
2206
- initialize(particle: Particle): void;
2207
- constructor(size: FunctionValueGenerator | Vector3Generator, speedRange: IntervalValue);
2208
- update(particle: Particle): void;
2209
- toJSON(): any;
2210
- static fromJSON(json: any): Behavior;
2211
- frameUpdate(delta: number): void;
2212
- clone(): Behavior;
2213
- reset(): void;
2590
+ interface RectangleEmitterParameters {
2591
+ /**
2592
+ * The width of the rectangle.
2593
+ */
2594
+ width?: number;
2595
+ /**
2596
+ * The height of the rectangle.
2597
+ */
2598
+ height?: number;
2599
+ /**
2600
+ * The thickness of the ring.
2601
+ * 1 is a full rectangle, 0 is a ring with 0 radius.
2602
+ */
2603
+ thickness?: number;
2604
+ /**
2605
+ * The mode of the emitter.
2606
+ * {@link EmitterMode}
2607
+ */
2608
+ mode?: EmitterMode;
2609
+ /**
2610
+ * The length of segment of which emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2611
+ * {@link EmitterMode}
2612
+ */
2613
+ spread?: number;
2614
+ /**
2615
+ * The speed of the emitter start point travels when mode is EmitterMode.Loop or EmitterMode.PingPong.
2616
+ * {@link EmitterMode}
2617
+ */
2618
+ speed?: ValueGenerator | FunctionValueGenerator;
2214
2619
  }
2215
-
2216
2620
  /**
2217
- * Apply rotation to particles based on their speed.
2621
+ * a particle emitter that emits particles from a rectangle.
2218
2622
  */
2219
- declare class RotationBySpeed implements Behavior {
2220
- angularVelocity: ValueGenerator | FunctionValueGenerator;
2221
- speedRange: IntervalValue;
2623
+ declare class RectangleEmitter implements EmitterShape {
2222
2624
  type: string;
2223
- private tempQuat;
2224
- constructor(angularVelocity: ValueGenerator | FunctionValueGenerator, speedRange: IntervalValue);
2225
- initialize(particle: Particle): void;
2226
- update(particle: Particle, delta: number): void;
2227
- toJSON(): any;
2228
- static fromJSON(json: any): Behavior;
2229
- frameUpdate(delta: number): void;
2230
- clone(): Behavior;
2231
- reset(): void;
2625
+ width: number;
2626
+ height: number;
2627
+ thickness: number;
2628
+ mode: EmitterMode;
2629
+ spread: number;
2630
+ speed: ValueGenerator | FunctionValueGenerator;
2631
+ memory: GeneratorMemory;
2632
+ private currentValue;
2633
+ private _m1;
2634
+ constructor(parameters?: RectangleEmitterParameters);
2635
+ update(system: IParticleSystem, delta: number): void;
2636
+ initialize(p: Particle, emissionState: EmissionState): void;
2637
+ toJSON(): ShapeJSON;
2638
+ static fromJSON(json: any): RectangleEmitter;
2639
+ clone(): EmitterShape;
2232
2640
  }
2233
2641
 
2234
2642
  /**
2235
- * Limit the speed of particles over their life.
2643
+ * Interface representing the parameters for a sphere emitter.
2236
2644
  */
2237
- declare class LimitSpeedOverLife implements Behavior {
2238
- speed: FunctionValueGenerator;
2239
- dampen: number;
2240
- type: string;
2241
- initialize(particle: Particle): void;
2242
- constructor(speed: FunctionValueGenerator, dampen: number);
2243
- update(particle: Particle, delta: number): void;
2244
- toJSON(): any;
2245
- static fromJSON(json: any): Behavior;
2246
- frameUpdate(delta: number): void;
2247
- clone(): Behavior;
2248
- reset(): void;
2645
+ interface SphereEmitterParameters {
2646
+ /**
2647
+ * The radius of the sphere.
2648
+ */
2649
+ radius?: number;
2650
+ /**
2651
+ * The arc of the sphere.
2652
+ */
2653
+ arc?: number;
2654
+ /**
2655
+ * The thickness of the sphere. 1 is a full sphere, 0 is a thin shell.
2656
+ */
2657
+ thickness?: number;
2658
+ /**
2659
+ * The mode of the emitter.
2660
+ * {@link EmitterMode}
2661
+ */
2662
+ mode?: EmitterMode;
2663
+ /**
2664
+ * The length of the segment at which the emitter point converges at the start and end, when mode is EmitterMode.Loop or EmitterMode.PingPong.
2665
+ * {@link EmitterMode}
2666
+ */
2667
+ spread?: number;
2668
+ /**
2669
+ * The speed of the emitter start point when mode is EmitterMode.Loop or EmitterMode.PingPong.
2670
+ * {@link EmitterMode}
2671
+ */
2672
+ speed?: ValueGenerator | FunctionValueGenerator;
2249
2673
  }
2250
-
2251
- declare class TextureSequencer implements Sequencer {
2252
- scaleX: number;
2253
- scaleY: number;
2254
- position: Vector3;
2255
- locations: Vector2[];
2256
- constructor(scaleX?: number, scaleY?: number, position?: Vector3);
2257
- transform(position: Vector3, index: number): void;
2258
- static fromJSON(json: any): Sequencer;
2259
- clone(): Sequencer;
2260
- toJSON(): any;
2261
- fromImage(img: CanvasImageSource, threshold: number): void;
2674
+ declare class SphereEmitter implements EmitterShape {
2675
+ type: string;
2676
+ radius: number;
2677
+ arc: number;
2678
+ thickness: number;
2679
+ mode: EmitterMode;
2680
+ spread: number;
2681
+ speed: ValueGenerator | FunctionValueGenerator;
2682
+ memory: GeneratorMemory;
2683
+ _m1: Matrix4;
2684
+ constructor(parameters?: SphereEmitterParameters);
2685
+ private currentValue;
2686
+ update(system: IParticleSystem, delta: number): void;
2687
+ initialize(p: Particle, emissionState: EmissionState): void;
2688
+ toJSON(): ShapeJSON;
2689
+ static fromJSON(json: any): SphereEmitter;
2690
+ clone(): EmitterShape;
2262
2691
  }
2263
2692
 
2264
2693
  interface Plugin {
@@ -2267,28 +2696,22 @@ interface Plugin {
2267
2696
  emitterShapes: Array<EmitterShapePlugin>;
2268
2697
  behaviors: Array<BehaviorPlugin>;
2269
2698
  }
2270
- declare const Plugins: Array<Plugin>;
2271
- declare function loadPlugin(plugin: Plugin): void;
2272
- declare function unloadPlugin(pluginId: string): void;
2273
-
2274
- interface IAnimationData {
2275
- /** Start time in seconds */
2276
- startTime: number;
2277
- /** Duration in seconds */
2278
- duration: number;
2279
- /** Target object */
2280
- target: any;
2281
- }
2282
- interface IPrefab {
2283
- /**
2284
- * The name of the prefab.
2285
- */
2286
- name: string;
2287
- /**
2288
- * The children of the prefab.
2289
- */
2290
- animationData: IAnimationData[];
2291
- }
2699
+ declare const Plugins: Array<Plugin>;
2700
+ declare function loadPlugin(plugin: Plugin): void;
2701
+ declare function unloadPlugin(pluginId: string): void;
2702
+
2703
+ declare class TextureSequencer implements Sequencer {
2704
+ scaleX: number;
2705
+ scaleY: number;
2706
+ position: Vector3;
2707
+ locations: Vector2[];
2708
+ constructor(scaleX?: number, scaleY?: number, position?: Vector3);
2709
+ transform(position: Vector3, index: number): void;
2710
+ static fromJSON(json: any): Sequencer;
2711
+ clone(): Sequencer;
2712
+ toJSON(): any;
2713
+ fromImage(img: CanvasImageSource, threshold: number): void;
2714
+ }
2292
2715
 
2293
2716
  declare enum RenderMode {
2294
2717
  BillBoard = 0,
@@ -2317,6 +2740,10 @@ interface StoredBatchSettings {
2317
2740
  materialDepthWrite: boolean;
2318
2741
  materialAlphaTest: number;
2319
2742
  texture: any;
2743
+ reflectionTexture: BaseTexture | null;
2744
+ reflectionLevel: number;
2745
+ reflectionFaces: BaseTexture[] | null;
2746
+ reflectionAtlas: BaseTexture | null;
2320
2747
  layerMask: number;
2321
2748
  }
2322
2749
  declare abstract class VFXBatch {
@@ -2325,9 +2752,15 @@ declare abstract class VFXBatch {
2325
2752
  settings: StoredBatchSettings;
2326
2753
  protected maxParticles: number;
2327
2754
  protected scene: Scene;
2755
+ private readonly visibleSystems;
2328
2756
  protected constructor(settings: VFXBatchSettings, scene: Scene);
2329
2757
  addSystem(system: IParticleSystem): void;
2330
2758
  removeSystem(system: IParticleSystem): void;
2759
+ /**
2760
+ * Visible systems of this batch, written into a buffer owned by the batch.
2761
+ * Called once per frame per batch, so the result is reused rather than
2762
+ * reallocated; treat it as valid only until the next call.
2763
+ */
2331
2764
  getVisibleSystems(): IParticleSystem[];
2332
2765
  applyDepthTexture(depthTexture: BaseTexture | null): void;
2333
2766
  abstract setupBuffers(): void;
@@ -2356,6 +2789,25 @@ interface VFXBatchSettings {
2356
2789
  materialDepthWrite: boolean;
2357
2790
  materialAlphaTest: number;
2358
2791
  texture: Texture | null;
2792
+ /**
2793
+ * Cubemap (or other reflection texture) harvested from a Babylon material's
2794
+ * `reflectionTexture`. Mesh batches sample it like StandardMaterial cubic
2795
+ * reflection; other render modes ignore it.
2796
+ */
2797
+ reflectionTexture: BaseTexture | null;
2798
+ /** Multiplier for the reflection sample — mirrors `texture.level`. */
2799
+ reflectionLevel: number;
2800
+ /**
2801
+ * Optional six cube-face 2D textures (px,py,pz,nx,ny,nz). Prefer
2802
+ * `reflectionAtlas` on iOS — many simultaneous face samplers still trip
2803
+ * GL_INVALID_OPERATION on WebKit.
2804
+ */
2805
+ reflectionFaces: BaseTexture[] | null;
2806
+ /**
2807
+ * Single 3×2 atlas of cube faces (px py pz / nx ny nz). One sampler2D —
2808
+ * the path that stays valid on iOS WebKit ShaderMaterial draws.
2809
+ */
2810
+ reflectionAtlas: BaseTexture | null;
2359
2811
  layerMask: number;
2360
2812
  }
2361
2813
  interface AdaptivePerformanceOptions {
@@ -2374,22 +2826,66 @@ declare class BatchedRenderer extends TransformNode {
2374
2826
  batches: Array<VFXBatch>;
2375
2827
  systemToBatchIndex: Map<IParticleSystem, number>;
2376
2828
  depthTexture: BaseTexture | null;
2829
+ /** Systems in insertion order — iterated every frame, unlike the map. */
2830
+ private systems;
2831
+ /**
2832
+ * The same systems, ordered so that one emitting into another comes first.
2833
+ *
2834
+ * A sub emitter's particles are created by its parent's behaviors, part way
2835
+ * through the parent's step. A sub system updated before its parent has
2836
+ * already fixed the list of particles it will run behaviors over, so those
2837
+ * new particles are drawn that frame with nothing but their start values —
2838
+ * white where a colour curve would have coloured them, at their start size,
2839
+ * sitting at the point they were born. Rebuilt only when the set of systems
2840
+ * or their behaviors changes, not per frame.
2841
+ */
2842
+ private orderedSystems;
2843
+ private orderedSystemsStale;
2844
+ /** Consecutive frames each batch has held no system, parallel to `batches`. */
2845
+ private batchEmptyFrames;
2846
+ /**
2847
+ * How long an empty batch is kept before it is disposed. Systems that toggle
2848
+ * a setting back and forth reuse the batch within this window instead of
2849
+ * rebuilding a mesh and material every time.
2850
+ */
2851
+ private static readonly EMPTY_BATCH_GRACE_FRAMES;
2377
2852
  private adaptivePerformanceState;
2378
2853
  private lastAppliedQuality;
2379
2854
  constructor(name: string, scene: Scene);
2380
2855
  private static clamp;
2381
2856
  private static equals;
2382
2857
  addSystem(system: IParticleSystem): void;
2383
- deleteSystem(system: IParticleSystem): void;
2858
+ /** Places a system into a compatible batch, creating one when none matches. */
2859
+ private assignToBatch;
2860
+ deleteSystem(system: IParticleSystem): boolean;
2861
+ /** Detaches a system from its batch, leaving the renderer's system list alone. */
2862
+ private removeFromBatch;
2863
+ /**
2864
+ * Re-buckets a system whose render settings changed. The system keeps its
2865
+ * place in the update order, so this is safe to call mid-frame.
2866
+ */
2384
2867
  updateSystem(system: IParticleSystem): void;
2385
2868
  setDepthTexture(depthTexture: BaseTexture | null): void;
2386
2869
  configureAdaptivePerformance(options?: Partial<AdaptivePerformanceOptions>): void;
2387
2870
  disableAdaptivePerformance(resetQuality?: boolean): void;
2388
2871
  getAdaptivePerformanceState(): AdaptivePerformanceState;
2389
2872
  private applyAdaptiveQuality;
2873
+ /** @internal Called when a system's behaviors change, which can add a sub emitter. */
2874
+ _invalidateUpdateOrder(): void;
2875
+ /**
2876
+ * Orders the systems so a system emitting into another runs first.
2877
+ *
2878
+ * Depth first over "emits into" edges, recording each system once all the
2879
+ * systems it feeds have been recorded, then reversed — a system therefore
2880
+ * lands ahead of everything it emits into, however deep the chain. A cycle
2881
+ * cannot be satisfied by any order; it is left as found rather than dropped.
2882
+ */
2883
+ private orderSystems;
2390
2884
  update(delta: number): void;
2391
2885
  /** Rebuild instance buffers from current particle state without advancing simulation. */
2392
2886
  refreshBatches(): void;
2887
+ /** Disposes the batch at `index` and repairs the system→batch mapping. */
2888
+ private removeBatch;
2393
2889
  /** Per-batch particle vs GPU instance counts — for diagnosing stale render state. */
2394
2890
  getBatchRenderStats(): Array<{
2395
2891
  batchIndex: number;
@@ -2403,69 +2899,61 @@ declare class BatchedRenderer extends TransformNode {
2403
2899
 
2404
2900
  declare const BatchedParticleRenderer: typeof BatchedRenderer;
2405
2901
 
2406
- declare class SpriteBatch extends VFXBatch {
2407
- private offsetBuffer;
2408
- private rotationBuffer;
2409
- private sizeBuffer;
2410
- private colorBuffer;
2411
- private uvTileBuffer;
2412
- private velocityBuffer?;
2413
- private offsetVB;
2414
- private rotationVB;
2415
- private sizeVB;
2416
- private colorVB;
2417
- private uvTileVB;
2418
- private velocityVB?;
2419
- constructor(settings: VFXBatchSettings, scene: Scene);
2420
- setupBuffers(): void;
2421
- private buildExpandableBuffers;
2422
- expandBuffers(target: number): void;
2423
- rebuildMaterial(): void;
2424
- private vector_;
2425
- private vector2_;
2426
- private vector3_;
2427
- private quaternion_;
2428
- private quaternion2_;
2429
- private quaternion3_;
2430
- private rotationMat_;
2431
- private rotationMat2_;
2432
- private lastStretchedSpeedFactor;
2433
- update(): void;
2434
- /** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
2435
- private uploadClearedInstance;
2436
- dispose(): void;
2902
+ /** Reads the six face URLs from a Babylon CubeTexture (px py pz nx ny nz). */
2903
+ declare function cubeFaceUrls(reflection: BaseTexture | null | undefined): string[] | null;
2904
+ /** Returns a previously built atlas for this cube, if any. */
2905
+ declare function getCachedEnvAtlas(cube: BaseTexture): Texture | null;
2906
+ /** Stores an atlas for a cube source (tests / prebuilt atlases). */
2907
+ declare function cacheEnvAtlas(cube: BaseTexture, atlas: Texture): void;
2908
+ /**
2909
+ * Packs six cube-face images into one 3×2 atlas Texture (px py pz / nx ny nz).
2910
+ * Uses invertY:false so UV cellY=0 maps to the +faces row matching the shader.
2911
+ */
2912
+ declare function createEnvAtlasFromFaceUrls(urls: string[], scene: Scene): Promise<Texture>;
2913
+ /**
2914
+ * Ensures a 3×2 env atlas exists for a CubeTexture. Returns a cached atlas
2915
+ * synchronously when available; otherwise starts (or joins) an async build and
2916
+ * invokes onReady when the atlas is usable.
2917
+ */
2918
+ declare function ensureEnvAtlasFromCube(cube: BaseTexture, scene: Scene, onReady: (atlas: Texture) => void): Texture | null;
2919
+
2920
+ type BabylonParticleMaterialParameters = Record<string, any>;
2921
+ declare class ParticleMeshStandardMaterial extends StandardMaterial {
2922
+ readonly isParticleMeshStandardMaterial = true;
2923
+ constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
2924
+ }
2925
+ declare class ParticleMeshPhysicsMaterial extends PBRMaterial {
2926
+ readonly isParticleMeshPhysicsMaterial = true;
2927
+ constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
2437
2928
  }
2438
2929
 
2439
- declare class TrailBatch extends VFXBatch {
2440
- private positionBuffer;
2441
- private previousBuffer;
2442
- private nextBuffer;
2443
- private uvBuffer;
2444
- private sideBuffer;
2445
- private widthBuffer;
2446
- private colorBuffer;
2447
- private indexBuffer;
2448
- private previousVB;
2449
- private nextVB;
2450
- private sideVB;
2451
- private widthVB;
2452
- private getTrailHistoryCount;
2453
- constructor(settings: VFXBatchSettings, scene: Scene);
2454
- setupBuffers(): void;
2455
- private buildGeometryBuffers;
2456
- expandBuffers(target: number): void;
2457
- rebuildMaterial(): void;
2458
- private vector_;
2459
- private vector2_;
2460
- private vector3_;
2461
- private quaternion_;
2462
- update(): void;
2463
- dispose(): void;
2930
+ declare class MeshSurfaceEmitter implements EmitterShape {
2931
+ type: string;
2932
+ private _triangleIndexToArea;
2933
+ private _mesh?;
2934
+ private _positions?;
2935
+ private _indices?;
2936
+ private _meshReferenceId?;
2937
+ get mesh(): Mesh | undefined;
2938
+ set mesh(mesh: Mesh | undefined);
2939
+ constructor(mesh?: Mesh, meshReferenceId?: string);
2940
+ initialize(p: Particle): void;
2941
+ toJSON(): ShapeJSON;
2942
+ static fromJSON(json: any): MeshSurfaceEmitter;
2943
+ clone(): EmitterShape;
2944
+ update(_system: IParticleSystem, _delta: number): void;
2464
2945
  }
2946
+ declare const MeshSurfaceEmitterPlugin: Plugin;
2465
2947
 
2466
2948
  declare class ParticleEmitter extends TransformNode {
2467
2949
  system: IParticleSystem;
2468
2950
  private _matrixWorld;
2951
+ private _matrixWorldFlag;
2952
+ /**
2953
+ * The node's world matrix in quarks.core form. Mirrored from Babylon's
2954
+ * matrix only when that matrix actually changed (tracked by its
2955
+ * `updateFlag`), so repeated reads inside a frame are free.
2956
+ */
2469
2957
  get matrixWorld(): Matrix4;
2470
2958
  get visible(): boolean;
2471
2959
  set visible(value: boolean);
@@ -2623,6 +3111,8 @@ declare class ParticleSystem implements IParticleSystem {
2623
3111
  particleNum: number;
2624
3112
  paused: boolean;
2625
3113
  particles: Array<Particle>;
3114
+ /** Column storage shared by this system's particles. */
3115
+ readonly store: ParticleStore;
2626
3116
  emitterShape: EmitterShape;
2627
3117
  emitter: ParticleEmitter;
2628
3118
  rendererSettings: VFXBatchSettings;
@@ -2643,8 +3133,13 @@ declare class ParticleSystem implements IParticleSystem {
2643
3133
  private listeners;
2644
3134
  private readonly layerMaskProxy;
2645
3135
  private materialRef;
3136
+ private sceneRef;
2646
3137
  private qualityFactor;
2647
- private useFastTrailHistory;
3138
+ private simulationAccumulator;
3139
+ private destroyed;
3140
+ /** Behaviors the cached plan was built from, compared by identity. */
3141
+ private fusionPlan?;
3142
+ private fusionSteps;
2648
3143
  /** @internal **/
2649
3144
  _renderer?: BatchedRenderer;
2650
3145
  set time(time: number);
@@ -2686,12 +3181,16 @@ declare class ParticleSystem implements IParticleSystem {
2686
3181
  pause(): void;
2687
3182
  play(): void;
2688
3183
  stop(): void;
2689
- private refreshTrailHistoryMode;
2690
- private ensureTrailHistoryCapacity;
2691
- private resetTrailHistory;
2692
- private getTrailHistoryCount;
2693
- private updateFastTrailHistory;
2694
3184
  setQualityFactor(qualityFactor: number): void;
3185
+ /**
3186
+ * Appends one particle to the pool, giving it the next row of the store.
3187
+ *
3188
+ * Growing the store replaces its arrays, so every particle already bound to
3189
+ * it has to be re-pointed at the new ones.
3190
+ */
3191
+ /** Points every particle at the store's columns again, after any were replaced. */
3192
+ private rebindParticles;
3193
+ private growParticlePool;
2695
3194
  private spawn;
2696
3195
  endEmit(): void;
2697
3196
  dispose(): void;
@@ -2699,6 +3198,47 @@ declare class ParticleSystem implements IParticleSystem {
2699
3198
  private firstTimeUpdate;
2700
3199
  /** @internal */
2701
3200
  update(delta: number): void;
3201
+ /**
3202
+ * Time the display is ahead of (positive) or still ahead of the simulation
3203
+ * (negative — the simulation ran a hair early), in seconds. Magnitude never
3204
+ * exceeds one step.
3205
+ *
3206
+ * The simulation runs on a fixed 1/60 step so that emission and lifetimes
3207
+ * stay in phase — without it a slow emitter flickers when the frame rate
3208
+ * wobbles. But frames do not arrive on that grid: a display running at
3209
+ * anything other than exactly 60Hz leaves some frames with no step at all
3210
+ * (half of them at 120Hz, three in five at 144Hz) and others with two, so
3211
+ * the particles are drawn stuttering even while the frame rate is perfect.
3212
+ *
3213
+ * The steps-per-frame count below is chosen by *rounding* the accumulated
3214
+ * time to the nearest step, not flooring it. Flooring always leaves the
3215
+ * accumulator positive, and when the real frame rate sits very close to
3216
+ * 60Hz (as most displays do) that leftover creeps toward a full step for
3217
+ * many consecutive frames before tipping over into a frame that runs two
3218
+ * steps at once and resets it to near zero — a visible lurch, every particle
3219
+ * in the system at once, with a perfectly steady frame rate the whole time.
3220
+ * Rounding lets the leftover go negative instead, which keeps it centered
3221
+ * near zero and stops it from ever building up toward that reset.
3222
+ *
3223
+ * Renderers close the gap by advancing what they draw along each particle's
3224
+ * velocity by this much. That reproduces the straight-line part of the
3225
+ * motion exactly — it is the same term the next step would integrate — so
3226
+ * the simulation stays fixed-step while the picture moves continuously.
3227
+ */
3228
+ /** Length of one simulation step, in seconds. See {@link simulationResidual}. */
3229
+ get simulationStep(): number;
3230
+ get simulationResidual(): number;
3231
+ /**
3232
+ * Execution plan for this system's behaviors, rebuilt when the list changes.
3233
+ *
3234
+ * Consecutive behaviors that can be compiled into one loop are merged, so
3235
+ * the particles are walked once instead of once per behavior. The plan is
3236
+ * keyed on the behavior instances, not their types: swapping one out has to
3237
+ * change the generated code's indices.
3238
+ */
3239
+ private behaviorSteps;
3240
+ /** Advances emission, behaviors, motion and culling by one fixed timestep. */
3241
+ private simulateStep;
2702
3242
  private notifyFinished;
2703
3243
  emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4): void;
2704
3244
  toJSON(metaData?: BabylonMetaData | string, _options?: SerializationOptions): ParticleSystemJSONParameters;
@@ -2716,24 +3256,12 @@ declare class ParticleSystem implements IParticleSystem {
2716
3256
  addEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
2717
3257
  removeAllEventListeners(event: ParticleSystemEventType): void;
2718
3258
  removeEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
3259
+ /** True when at least one callback is registered for the event type. */
3260
+ private hasListeners;
2719
3261
  private fire;
2720
3262
  clone(): ParticleSystem;
2721
3263
  }
2722
3264
 
2723
- declare class QuarksUtil {
2724
- static runOnAllParticleEmitters(root: Node, callback: (emitter: ParticleEmitter) => void): void;
2725
- static addToBatchRenderer(root: Node, batchRenderer: BatchedRenderer): void;
2726
- static play(root: Node): void;
2727
- static stop(root: Node): void;
2728
- static pause(root: Node): void;
2729
- static restart(root: Node): void;
2730
- static setAutoDestroy(root: Node, autoDestroy: boolean): void;
2731
- static endEmit(root: Node): void;
2732
- /** True when every emitter under `root` is a finished non-looping system (or looping). */
2733
- static isEffectFinished(root: Node): boolean;
2734
- private static traverseNode;
2735
- }
2736
-
2737
3265
  interface QuarksLoaderOptions {
2738
3266
  baseUrl?: string;
2739
3267
  }
@@ -2749,6 +3277,23 @@ declare class QuarksLoader {
2749
3277
  private extractInterleavedAttribute;
2750
3278
  private int32ArrayToFloat32;
2751
3279
  private parseImages;
3280
+ /**
3281
+ * Flags an image entry that is plainly not an image, which otherwise only
3282
+ * shows up as a texture that silently fails to load.
3283
+ *
3284
+ * The case worth naming: an exporter that could not embed a texture falls
3285
+ * back to writing the source asset's path, and a Unity built-in texture
3286
+ * reports a virtual path such as `Resources/unity_builtin_extra` that no
3287
+ * file backs.
3288
+ */
3289
+ private static warnIfNotAnImageUrl;
3290
+ /**
3291
+ * `img.url` is already absolute for data/blob URIs and full http(s) URLs — common for
3292
+ * "portable" exports that embed textures as base64 (see ensurePortableTextureUrl in
3293
+ * babylon.quarks-editor). Prepending baseUrl to those turns e.g.
3294
+ * "data:image/png;base64,AAAA" into an invalid path like "/some/dir/data:image/png;base64,AAAA".
3295
+ */
3296
+ private resolveImageUrl;
2752
3297
  private parseTextures;
2753
3298
  private mapWrapMode;
2754
3299
  private parseMaterials;
@@ -2804,53 +3349,172 @@ declare class QuarksPrefab extends TransformNode implements IPrefab {
2804
3349
  private updateDuration;
2805
3350
  }
2806
3351
 
2807
- declare class MeshSurfaceEmitter implements EmitterShape {
2808
- type: string;
2809
- private _triangleIndexToArea;
2810
- private _mesh?;
2811
- private _positions?;
2812
- private _indices?;
2813
- private _meshReferenceId?;
2814
- get mesh(): Mesh | undefined;
2815
- set mesh(mesh: Mesh | undefined);
2816
- constructor(mesh?: Mesh, meshReferenceId?: string);
2817
- initialize(p: Particle): void;
2818
- toJSON(): ShapeJSON;
2819
- static fromJSON(json: any): MeshSurfaceEmitter;
2820
- clone(): EmitterShape;
2821
- update(_system: IParticleSystem, _delta: number): void;
3352
+ declare class QuarksUtil {
3353
+ static runOnAllParticleEmitters(root: Node, callback: (emitter: ParticleEmitter) => void): void;
3354
+ static addToBatchRenderer(root: Node, batchRenderer: BatchedRenderer): void;
3355
+ static play(root: Node): void;
3356
+ static stop(root: Node): void;
3357
+ static pause(root: Node): void;
3358
+ static restart(root: Node): void;
3359
+ static setAutoDestroy(root: Node, autoDestroy: boolean): void;
3360
+ static endEmit(root: Node): void;
3361
+ /** True when every emitter under `root` is a finished non-looping system (or looping). */
3362
+ static isEffectFinished(root: Node): boolean;
3363
+ private static traverseNode;
2822
3364
  }
2823
- declare const MeshSurfaceEmitterPlugin: Plugin;
2824
3365
 
2825
3366
  declare function registerShaderChunks(): void;
2826
3367
  declare function getShaderChunk(chunkName: string): string | undefined;
2827
3368
  declare function getRegisteredShaderChunks(): Readonly<Record<string, string>>;
2828
3369
 
2829
- declare const _default$7: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float c = cos(rotation);\n float s = sin(rotation);\n\n vec2 alignedPosition = position.xy * size.xy;\n vec2 rotatedPosition;\n rotatedPosition.x = c * alignedPosition.x - s * alignedPosition.y;\n rotatedPosition.y = s * alignedPosition.x + c * alignedPosition.y;\n\n#ifdef HORIZONTAL\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.x += rotatedPosition.x;\n mvPosition.z -= rotatedPosition.y;\n mvPosition = view * mvPosition;\n#elif defined(VERTICAL)\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.y += rotatedPosition.y;\n mvPosition = view * mvPosition;\n mvPosition.x += rotatedPosition.x;\n#else\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n mvPosition.xy += rotatedPosition;\n#endif\n\n gl_Position = projection * mvPosition;\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
3370
+ declare const _default$7: "\nattribute vec3 position;\nattribute vec2 uv;\nattribute vec3 normal;\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 scaledPosition = position * size;\n vec3 rotatedPosition = applyQuaternion(scaledPosition, rotation);\n vec3 rotatedNormal = normalize(applyQuaternion(normal, rotation));\n vec3 localPos = rotatedPosition + offset;\n\n vec4 worldPos = world * vec4(localPos, 1.0);\n vec4 viewPos = view * worldPos;\n gl_Position = projection * viewPos;\n\n vWorldPos = worldPos.xyz;\n vNormal = normalize((world * vec4(rotatedNormal, 0.0)).xyz);\n\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -viewPos.z;\n#endif\n\n#ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n#else\n vUV = uv;\n#endif\n\n vColor = color;\n}\n";
2830
3371
 
2831
- declare const _default$6: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_COLOR_AS_ALPHA\n baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n gl_FragColor = baseColor;\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
3372
+ declare const _default$6: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 rotatedPosition = applyQuaternion(position * size, rotation);\n vec3 worldPos = rotatedPosition + offset;\n\n gl_Position = worldViewProjection * vec4(worldPos, 1.0);\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
2832
3373
 
2833
- declare const _default$5: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 rotatedPosition = applyQuaternion(position * size, rotation);\n vec3 worldPos = rotatedPosition + offset;\n\n gl_Position = worldViewProjection * vec4(worldPos, 1.0);\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
3374
+ declare const _default$5: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_COLOR_AS_ALPHA\n baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n gl_FragColor = baseColor;\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
2834
3375
 
2835
- declare const _default$4: "\nattribute vec3 position;\nattribute vec2 uv;\nattribute vec3 normal;\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 scaledPosition = position * size;\n vec3 rotatedPosition = applyQuaternion(scaledPosition, rotation);\n vec3 rotatedNormal = normalize(applyQuaternion(normal, rotation));\n vec3 localPos = rotatedPosition + offset;\n\n vec4 worldPos = world * vec4(localPos, 1.0);\n vec4 viewPos = view * worldPos;\n gl_Position = projection * viewPos;\n\n vWorldPos = worldPos.xyz;\n vNormal = normalize((world * vec4(rotatedNormal, 0.0)).xyz);\n\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -viewPos.z;\n#endif\n\n#ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n#else\n vUV = uv;\n#endif\n\n vColor = color;\n}\n";
3376
+ declare const _default$4: "\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\nuniform vec3 lightDirection;\nuniform vec3 lightColor;\nuniform vec3 ambientColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n// One 3\u00D72 atlas (px py pz / nx ny nz). Avoids samplerCube and multi-face\n// sampler bindings that raise GL_INVALID_OPERATION on iOS WebKit.\n#ifdef USE_ENVMAP_ATLAS\nuniform sampler2D envAtlas;\nuniform vec3 eyePosition;\nuniform float reflectionLevel;\n\nvec3 sampleEnvAtlas(vec3 r) {\n vec3 a = abs(r);\n vec2 localUV;\n float cellX;\n float cellY;\n // Atlas layout: +X +Y +Z on row 0, -X -Y -Z on row 1.\n if (a.x >= a.y && a.x >= a.z) {\n cellX = 0.0;\n if (r.x >= 0.0) {\n cellY = 0.0;\n localUV = vec2(-r.z, -r.y) / a.x * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.z, -r.y) / a.x * 0.5 + 0.5;\n }\n } else if (a.y >= a.z) {\n cellX = 1.0;\n if (r.y >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, r.z) / a.y * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.x, -r.z) / a.y * 0.5 + 0.5;\n }\n } else {\n cellX = 2.0;\n if (r.z >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, -r.y) / a.z * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(-r.x, -r.y) / a.z * 0.5 + 0.5;\n }\n }\n vec2 uv = (vec2(cellX, cellY) + clamp(localUV, 0.0, 1.0)) / vec2(3.0, 2.0);\n return texture2D(envAtlas, uv).rgb;\n}\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n vec3 N = normalize(vNormal);\n vec3 L = normalize(-lightDirection);\n float NdotL = max(dot(N, L), 0.0);\n vec3 litColor = ambientColor + lightColor * NdotL;\n\n vec3 color = baseColor.rgb * litColor;\n\n#ifdef USE_ENVMAP_ATLAS\n vec3 viewDir = normalize(vWorldPos - eyePosition);\n vec3 reflectionCoords = reflect(viewDir, N);\n color += sampleEnvAtlas(reflectionCoords) * reflectionLevel;\n#endif\n\n gl_FragColor = vec4(color, baseColor.a);\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
2836
3377
 
2837
- declare const _default$3: "\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\n\nuniform vec3 lightDirection;\nuniform vec3 lightColor;\nuniform vec3 ambientColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n vec3 N = normalize(vNormal);\n vec3 L = normalize(-lightDirection);\n float NdotL = max(dot(N, L), 0.0);\n vec3 litColor = ambientColor + lightColor * NdotL;\n\n gl_FragColor = vec4(baseColor.rgb * litColor, baseColor.a);\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
3378
+ declare const _default$3: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float c = cos(rotation);\n float s = sin(rotation);\n\n vec2 alignedPosition = position.xy * size.xy;\n vec2 rotatedPosition;\n rotatedPosition.x = c * alignedPosition.x - s * alignedPosition.y;\n rotatedPosition.y = s * alignedPosition.x + c * alignedPosition.y;\n\n#ifdef HORIZONTAL\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.x += rotatedPosition.x;\n mvPosition.z -= rotatedPosition.y;\n mvPosition = view * mvPosition;\n#elif defined(VERTICAL)\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.y += rotatedPosition.y;\n mvPosition = view * mvPosition;\n mvPosition.x += rotatedPosition.x;\n#else\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n mvPosition.xy += rotatedPosition;\n#endif\n\n gl_Position = projection * mvPosition;\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
2838
3379
 
2839
3380
  declare const _default$2: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\nattribute vec4 velocity;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform float speedFactor;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float lengthFactor = velocity.w;\n float avgSize = (size.x + size.y) * 0.5;\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n vec3 viewVelocity = mat3(view * world) * velocity.xyz;\n float vlength = length(viewVelocity);\n // Stretch direction is the velocity direction; only a genuinely motionless particle has none.\n // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0\n // (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.\n vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);\n mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, vdir)) * avgSize;\n // Equivalent to viewVelocity * (1.0 + lengthFactor / vlength) for moving particles, but the\n // size-based term (vdir * lengthFactor) survives when the velocity contribution vanishes.\n mvPosition.xyz -= (position.x + 0.5) * (viewVelocity + vdir * lengthFactor) * avgSize;\n gl_Position = projection * mvPosition;\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
2840
3381
 
2841
- declare const _default$1: "\nattribute vec3 position;\nattribute vec3 previous;\nattribute vec3 next;\nattribute float side;\nattribute float width;\nattribute vec2 uv;\nattribute vec4 color;\n\nuniform mat4 view;\nuniform mat4 projection;\nuniform float lineWidth;\nuniform vec2 resolution;\nuniform float sizeAttenuation;\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec2 fix(vec4 i, float aspect) {\n vec2 res = i.xy / i.w;\n res.x *= aspect;\n return res;\n}\n\nvoid main() {\n float aspect = resolution.x / resolution.y;\n vec4 finalPosition = projection * view * vec4(position, 1.0);\n vec4 prevPos = projection * view * vec4(previous, 1.0);\n vec4 nextPos = projection * view * vec4(next, 1.0);\n\n vec2 currentP = fix(finalPosition, aspect);\n vec2 prevP = fix(prevPos, aspect);\n vec2 nextP = fix(nextPos, aspect);\n\n float w = lineWidth * width;\n vec2 dir;\n if (distance(nextP, currentP) < 0.0001) {\n dir = normalize(currentP - prevP);\n } else if (distance(prevP, currentP) < 0.0001) {\n dir = normalize(nextP - currentP);\n } else {\n vec2 dir1 = normalize(currentP - prevP);\n vec2 dir2 = normalize(nextP - currentP);\n dir = normalize(dir1 + dir2);\n }\n vec4 normal = vec4(-dir.y, dir.x, 0.0, 1.0);\n normal.xy *= 0.5 * w;\n normal *= projection;\n if (sizeAttenuation == 0.0) {\n normal.xy *= finalPosition.w;\n normal.xy /= (vec4(resolution, 0.0, 1.0) * projection).xy;\n }\n finalPosition.xy += normal.xy * side;\n gl_Position = finalPosition;\n vUV = uv;\n vColor = color;\n}\n";
3382
+ declare const _default$1: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n baseColor *= texColor;\n#endif\n\n if (baseColor.a < 0.01) discard;\n\n gl_FragColor = baseColor;\n}\n";
2842
3383
 
2843
- declare const _default: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n baseColor *= texColor;\n#endif\n\n if (baseColor.a < 0.01) discard;\n\n gl_FragColor = baseColor;\n}\n";
3384
+ declare const _default: "\nattribute vec3 position;\nattribute vec3 previous;\nattribute vec3 next;\nattribute float side;\nattribute float width;\nattribute vec2 uv;\nattribute vec4 color;\n\nuniform mat4 view;\nuniform mat4 projection;\nuniform float lineWidth;\nuniform vec2 resolution;\nuniform float sizeAttenuation;\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec2 fix(vec4 i, float aspect) {\n vec2 res = i.xy / i.w;\n res.x *= aspect;\n return res;\n}\n\nvoid main() {\n float aspect = resolution.x / resolution.y;\n vec4 finalPosition = projection * view * vec4(position, 1.0);\n vec4 prevPos = projection * view * vec4(previous, 1.0);\n vec4 nextPos = projection * view * vec4(next, 1.0);\n\n vec2 currentP = fix(finalPosition, aspect);\n vec2 prevP = fix(prevPos, aspect);\n vec2 nextP = fix(nextPos, aspect);\n\n float w = lineWidth * width;\n vec2 dir;\n if (distance(nextP, currentP) < 0.0001) {\n dir = normalize(currentP - prevP);\n } else if (distance(prevP, currentP) < 0.0001) {\n dir = normalize(nextP - currentP);\n } else {\n vec2 dir1 = normalize(currentP - prevP);\n vec2 dir2 = normalize(nextP - currentP);\n dir = normalize(dir1 + dir2);\n }\n vec4 normal = vec4(-dir.y, dir.x, 0.0, 1.0);\n normal.xy *= 0.5 * w;\n normal *= projection;\n if (sizeAttenuation == 0.0) {\n normal.xy *= finalPosition.w;\n normal.xy /= (vec4(resolution, 0.0, 1.0) * projection).xy;\n }\n finalPosition.xy += normal.xy * side;\n gl_Position = finalPosition;\n vUV = uv;\n vColor = color;\n}\n";
2844
3385
 
2845
- type BabylonParticleMaterialParameters = Record<string, any>;
2846
- declare class ParticleMeshStandardMaterial extends StandardMaterial {
2847
- readonly isParticleMeshStandardMaterial = true;
2848
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
3386
+ declare class SpriteBatch extends VFXBatch {
3387
+ private static whiteTextureByScene;
3388
+ /** 1×1 white map so mesh batches always have a sampler2D (iOS WebKit). */
3389
+ private static whiteTexture;
3390
+ private offsetBuffer;
3391
+ private rotationBuffer;
3392
+ private sizeBuffer;
3393
+ private colorBuffer;
3394
+ private uvTileBuffer;
3395
+ private velocityBuffer?;
3396
+ /** Concretely typed handle on the batch material, see syncStretchedSpeedFactor. */
3397
+ private shaderMaterial;
3398
+ private offsetVB;
3399
+ private rotationVB;
3400
+ private sizeVB;
3401
+ private colorVB;
3402
+ private uvTileVB;
3403
+ private velocityVB?;
3404
+ constructor(settings: VFXBatchSettings, scene: Scene);
3405
+ setupBuffers(): void;
3406
+ /** Releases the instance vertex buffers so a resize does not leak GPU memory. */
3407
+ private disposeExpandableBuffers;
3408
+ private buildExpandableBuffers;
3409
+ expandBuffers(target: number): void;
3410
+ rebuildMaterial(): void;
3411
+ private vector_;
3412
+ private vector2_;
3413
+ private vector3_;
3414
+ private quaternion_;
3415
+ private quaternion2_;
3416
+ private quaternion3_;
3417
+ private quaternion4_;
3418
+ private quaternion5_;
3419
+ private rotationMat_;
3420
+ private rotationMat2_;
3421
+ private lastStretchedSpeedFactor;
3422
+ update(): void;
3423
+ /**
3424
+ * Pushes the stretched-billboard speed factor to the shader when it changed.
3425
+ *
3426
+ * Deliberately kept out of `update`: touching the loosely typed
3427
+ * `mesh.material` from inside that function gives V8 a generic property
3428
+ * access it has no feedback for, which knocks the whole particle loop out of
3429
+ * optimised code on every frame.
3430
+ */
3431
+ private syncStretchedSpeedFactor;
3432
+ /**
3433
+ * The fraction `f` of a turn, as a normalised lerp from no rotation toward
3434
+ * `step`, written into `out`.
3435
+ *
3436
+ * A true slerp would be exact, but `step` is one simulation step of turning
3437
+ * and `f` is below 1, so the arc being split is small enough that the lerp
3438
+ * is within a rounding error of it and costs a fraction as much.
3439
+ */
3440
+ private static partialTurn;
3441
+ /**
3442
+ * Continues a three-component column by `fraction` of the step it just took,
3443
+ * never below zero.
3444
+ *
3445
+ * Size fades to nothing at the end of a life, so the last step before death
3446
+ * can point past zero; a negative size turns a sprite inside out.
3447
+ */
3448
+ private static continueVector3;
3449
+ /** The same for colour, whose alpha runs out at the end of a life too. */
3450
+ private static continueColor;
3451
+ /**
3452
+ * Writes rows `[0, count)` of the store's positions into `target` at `base`,
3453
+ * each carried on by `fraction` of the step it just took.
3454
+ *
3455
+ * Continuing the measured last step covers every way a particle can move —
3456
+ * velocity integration, an orbit, noise, a plugin's own behavior — because
3457
+ * it reads what happened rather than predicting from one term of it. Over
3458
+ * less than a step it is a straight line through a path that may curve,
3459
+ * which for a sixtieth of a second is well under a pixel.
3460
+ *
3461
+ * A particle born during the step has the same position on both sides and
3462
+ * so does not move at all, which is what puts it at the emitter rather than
3463
+ * a step's travel away from it.
3464
+ */
3465
+ private static extrapolate;
3466
+ /** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
3467
+ private uploadClearedInstance;
3468
+ dispose(): void;
2849
3469
  }
2850
- declare class ParticleMeshPhysicsMaterial extends PBRMaterial {
2851
- readonly isParticleMeshPhysicsMaterial = true;
2852
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
3470
+
3471
+ declare class TrailBatch extends VFXBatch {
3472
+ private positionBuffer;
3473
+ private previousBuffer;
3474
+ private nextBuffer;
3475
+ private uvBuffer;
3476
+ private sideBuffer;
3477
+ private widthBuffer;
3478
+ private colorBuffer;
3479
+ private indexBuffer;
3480
+ /** True while the batch is parked on the degenerate draw, see uploadGeometry. */
3481
+ private drawsNothing;
3482
+ private previousVB;
3483
+ private nextVB;
3484
+ private sideVB;
3485
+ private widthVB;
3486
+ constructor(settings: VFXBatchSettings, scene: Scene);
3487
+ setupBuffers(): void;
3488
+ private buildGeometryBuffers;
3489
+ expandBuffers(target: number): void;
3490
+ rebuildMaterial(): void;
3491
+ private vector_;
3492
+ private vector2_;
3493
+ private vector3_;
3494
+ private quaternion_;
3495
+ /** Forces the emitter's world matrix to be current before sampling it. */
3496
+ private static ensureWorldMatrix;
3497
+ update(): void;
3498
+ /**
3499
+ * Uploads the vertex data written by `update` and resizes the sub mesh.
3500
+ *
3501
+ * Split out of `update` on purpose: the Babylon mesh/sub-mesh plumbing here
3502
+ * runs a handful of times per frame, and folding it into the per-vertex loop
3503
+ * costs that loop its optimised code.
3504
+ */
3505
+ private uploadGeometry;
3506
+ /**
3507
+ * Points every sub mesh at the mesh's own bounds.
3508
+ *
3509
+ * Updating indices rebuilds the sub meshes, and a fresh one computes its
3510
+ * bounds from the vertex data — which this batch keeps deliberately stale
3511
+ * beyond the range it draws. Transparent sorting reads those bounds every
3512
+ * frame, so they have to be replaced again after every index update, not
3513
+ * only when the geometry is built.
3514
+ */
3515
+ private adoptMeshBounds;
3516
+ dispose(): void;
2853
3517
  }
2854
3518
 
2855
- export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EmitSubParticleSystem, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GeneratorFromJSON, Gradient, GravityForce, GridEmitter, HemisphereEmitter, InheritVelocity, IntervalValue, LimitSpeedOverLife, MathUtils, Matrix3, Matrix4, MeshSurfaceEmitter, MeshSurfaceEmitterPlugin, NodeParticle, Noise, OrbitOverLife, ParticleEmitter, ParticleMeshPhysicsMaterial, ParticleMeshStandardMaterial, ParticleSystem, PiecewiseBezier, PiecewiseFunction, Plugins, PointEmitter, QuarksLoader, QuarksPrefab, QuarksUtil, Quaternion, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteBatch, SpriteParticle, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector4, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, ceilPowerOfTwo, clamp, damp, degToRad, denormalize, euclideanModulo, floorPowerOfTwo, generateUUID, getPhysicsResolver, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$4 as localParticlePhysicsVertShader, _default$5 as localParticleVertShader, mapLinear, normalize, _default$6 as particleFragShader, _default$3 as particlePhysicsFragShader, _default$7 as particleVertShader, pingpong, radToDeg, randFloat, randFloatSpread, randInt, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, _default as trailFragShader, _default$1 as trailVertShader, unloadPlugin };
2856
- export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, DonutEmitterParameters, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksLoaderOptions, QuarksTimelineClip, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };
3519
+ export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EmitSubParticleSystem, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GeneratorFromJSON, Gradient, GravityForce, GridEmitter, HemisphereEmitter, InheritVelocity, IntervalValue, LimitSpeedOverLife, MathUtils, Matrix3, Matrix4, MeshSurfaceEmitter, MeshSurfaceEmitterPlugin, NodeParticle, Noise, OrbitOverLife, ParticleEmitter, ParticleMeshPhysicsMaterial, ParticleMeshStandardMaterial, ParticleStore, ParticleSystem, PiecewiseBezier, PiecewiseFunction, Plugins, PointEmitter, QuarksLoader, QuarksPrefab, QuarksUtil, Quaternion, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteBatch, SpriteParticle, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, cubeFaceUrls, damp, degToRad, denormalize, ensureEnvAtlasFromCube, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, normalize, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin };
3520
+ export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, DonutEmitterParameters, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksLoaderOptions, QuarksTimelineClip, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };