babylon.quarks 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +769 -8
  2. package/README.md +10 -8
  3. package/dist/babylon.quarks.cjs +1 -1
  4. package/dist/babylon.quarks.cjs.map +1 -1
  5. package/dist/babylon.quarks.esm.js +1 -1
  6. package/dist/babylon.quarks.esm.js.map +1 -1
  7. package/dist/babylon.quarks.umd.min.js +1 -1
  8. package/dist/babylon.quarks.umd.min.js.map +1 -1
  9. package/dist/types/index.d.cts +6683 -0
  10. package/dist/types/index.d.ts +1959 -588
  11. package/package.json +12 -6
  12. package/src/BatchedRenderer.ts +204 -101
  13. package/src/EffectPool.ts +4 -1
  14. package/src/MeshSurfaceEmitter.ts +29 -4
  15. package/src/ParticleEmitter.ts +45 -15
  16. package/src/ParticleSystem.ts +909 -2061
  17. package/src/QuarksLoader.ts +421 -67
  18. package/src/QuarksPrefab.ts +91 -4
  19. package/src/QuarksSerializer.ts +484 -0
  20. package/src/QuarksUtil.ts +15 -0
  21. package/src/SpriteBatch.ts +106 -246
  22. package/src/TrailBatch.ts +533 -342
  23. package/src/VFXBatch.ts +236 -136
  24. package/src/batchKey.ts +237 -0
  25. package/src/effectResources.ts +79 -0
  26. package/src/envAtlas.ts +119 -17
  27. package/src/index.ts +32 -33
  28. package/src/nodeId.ts +13 -0
  29. package/src/shaderProgram.ts +325 -0
  30. package/src/shaderVariants.ts +225 -0
  31. package/src/shaders/chunks/fog.ts +4 -2
  32. package/src/shaders/chunks/sheet.ts +111 -0
  33. package/src/shaders/chunks/soft.ts +84 -0
  34. package/src/shaders/chunks/surface.ts +10 -0
  35. package/src/shaders/local_particle_physics_vert.glsl.ts +14 -28
  36. package/src/shaders/local_particle_physics_vert.wgsl.ts +16 -29
  37. package/src/shaders/particle_frag.glsl.ts +3 -22
  38. package/src/shaders/particle_frag.wgsl.ts +3 -23
  39. package/src/shaders/particle_physics_frag.glsl.ts +12 -25
  40. package/src/shaders/particle_physics_frag.wgsl.ts +12 -26
  41. package/src/shaders/particle_vert.glsl.ts +5 -27
  42. package/src/shaders/particle_vert.wgsl.ts +5 -26
  43. package/src/shaders/stretched_bb_particle_vert.glsl.ts +7 -33
  44. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +7 -33
  45. package/src/shaders/trail_frag.glsl.ts +11 -1
  46. package/src/shaders/trail_frag.wgsl.ts +11 -0
  47. package/src/shaders/trail_vert.glsl.ts +45 -36
  48. package/src/shaders/trail_vert.wgsl.ts +46 -40
  49. package/src/softDepth.ts +136 -0
  50. package/src/system/BehaviorPlan.ts +85 -0
  51. package/src/system/BoundsTracker.ts +181 -0
  52. package/src/system/EmissionController.ts +360 -0
  53. package/src/system/EventDispatcher.ts +44 -0
  54. package/src/system/ParticleSpawner.ts +274 -0
  55. package/src/system/SimulationClock.ts +130 -0
  56. package/src/system/geometry.ts +111 -0
  57. package/src/system/integrate.ts +428 -0
  58. package/src/system/materialResolve.ts +116 -0
  59. package/src/system/normalize.ts +95 -0
  60. package/src/system/serialization.ts +401 -0
  61. package/src/system/settingsSchema.ts +317 -0
  62. package/src/system/types.ts +410 -0
  63. package/src/textureSource.ts +30 -0
  64. package/src/trailSettings.ts +51 -0
  65. package/src/BatchedParticleRenderer.ts +0 -3
  66. package/src/materials/ParticleMaterials.ts +0 -23
  67. package/src/materials/index.ts +0 -1
  68. package/src/shaders/chunks/index.ts +0 -1
  69. package/src/shaders/chunks/register-shader-chunks.ts +0 -32
  70. package/src/shaders/chunks/soft_fragment.glsl.ts +0 -13
  71. package/src/shaders/chunks/soft_pars_fragment.glsl.ts +0 -20
  72. package/src/shaders/chunks/soft_pars_vertex.glsl.ts +0 -6
  73. package/src/shaders/chunks/soft_vertex.glsl.ts +0 -6
  74. package/src/shaders/chunks/tile_fragment.glsl.ts +0 -9
  75. package/src/shaders/chunks/tile_pars_fragment.glsl.ts +0 -9
  76. package/src/shaders/chunks/tile_pars_vertex.glsl.ts +0 -28
  77. package/src/shaders/chunks/tile_vertex.glsl.ts +0 -18
  78. package/src/shaders/index.ts +0 -9
  79. package/src/shaders/local_particle_vert.glsl.ts +0 -50
@@ -1,14 +1,15 @@
1
- import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture';
2
- import { Texture } from '@babylonjs/core/Materials/Textures/texture';
3
- import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
4
- import { Scene } from '@babylonjs/core/scene';
5
- import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial';
6
- import { Color3 } from '@babylonjs/core/Maths/math.color';
7
- import { Vector3 as Vector3$1 } from '@babylonjs/core/Maths/math.vector';
8
- import { Mesh } from '@babylonjs/core/Meshes/mesh';
9
- import { Node } from '@babylonjs/core/node';
10
- import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
11
- import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
1
+ import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture.js';
2
+ import { Texture } from '@babylonjs/core/Materials/Textures/texture.js';
3
+ import { TransformNode } from '@babylonjs/core/Meshes/transformNode.js';
4
+ import { DepthRenderer } from '@babylonjs/core/Rendering/depthRenderer.js';
5
+ import { Scene } from '@babylonjs/core/scene.js';
6
+ import { Camera } from '@babylonjs/core/Cameras/camera.js';
7
+ import { Vector4 as Vector4$1, Vector3 as Vector3$1 } from '@babylonjs/core/Maths/math.vector.js';
8
+ import { Effect } from '@babylonjs/core/Materials/effect.js';
9
+ import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial.js';
10
+ import { Color3 } from '@babylonjs/core/Maths/math.color.js';
11
+ import { Mesh } from '@babylonjs/core/Meshes/mesh.js';
12
+ import { Node } from '@babylonjs/core/node.js';
12
13
 
13
14
  declare class Vector2 {
14
15
  x: number;
@@ -549,6 +550,7 @@ interface RotationGenerator {
549
550
  toJSON(): FunctionJSON;
550
551
  clone(): RotationGenerator;
551
552
  }
553
+ /** Reads a rotation generator; an unknown or missing type warns and gives a random rotation. */
552
554
  declare function RotationGeneratorFromJSON(json: FunctionJSON): RotationGenerator;
553
555
 
554
556
  /**
@@ -579,6 +581,7 @@ interface FunctionValueGenerator {
579
581
  toJSON(): FunctionJSON;
580
582
  clone(): FunctionValueGenerator;
581
583
  }
584
+ /** Reads a value generator; an unknown or missing type warns and gives 0. */
582
585
  declare function ValueGeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator;
583
586
 
584
587
  declare class AxisAngleGenerator implements RotationGenerator {
@@ -644,6 +647,10 @@ declare class ContinuousLinearFunction<T extends ObjectValueType<T> | number> {
644
647
  type: 'function';
645
648
  subType: 'Number' | 'Vector3' | 'Vector4' | 'Color';
646
649
  constructor(keys: Array<[T, number]>, subType: 'Number' | 'Vector3' | 'Vector4' | 'Color');
650
+ /**
651
+ * The key whose span holds `t`: -1 before the first key, the last key from its position on
652
+ * (so a `t` past 1 holds the final value, as the sampled table does).
653
+ */
647
654
  findKey(t: number): number;
648
655
  getStartX(index: number): number;
649
656
  getEndX(index: number): number;
@@ -738,6 +745,7 @@ declare class ConstantColor implements ColorGenerator {
738
745
  static fromJSON(json: FunctionJSON): ConstantColor;
739
746
  clone(): ColorGenerator;
740
747
  }
748
+ /** Reads a colour generator; an unknown or missing type warns and gives opaque white. */
741
749
  declare function ColorGeneratorFromJSON(json: FunctionJSON): ColorRange | Gradient | RandomColor | RandomColorBetweenGradient | ConstantColor;
742
750
 
743
751
  declare class ConstantValue implements ValueGenerator {
@@ -774,8 +782,10 @@ interface Vector3Generator {
774
782
  toJSON(): FunctionJSON;
775
783
  clone(): Vector3Generator;
776
784
  }
785
+ /** Reads a vector generator; an unknown or missing type warns and gives a zero vector. */
777
786
  declare function Vector3GeneratorFromJSON(json: FunctionJSON): Vector3Generator;
778
787
 
788
+ /** Reads a value, rotation or vector generator; an unknown or missing type warns and gives 0. */
779
789
  declare function GeneratorFromJSON(json: FunctionJSON): FunctionValueGenerator | ValueGenerator | RotationGenerator | Vector3Generator;
780
790
 
781
791
  declare class IntervalValue implements ValueGenerator {
@@ -1004,7 +1014,7 @@ declare class ParticleStore {
1004
1014
  keepPreviousVelocity(): boolean;
1005
1015
  /**
1006
1016
  * Mirrors a freshly spawned particle's generator memory into the
1007
- * {@link memory} column, widening the column when this spawn used more
1017
+ * {@link ParticleStore.memory | memory} column, widening the column when this spawn used more
1008
1018
  * slots than any before it.
1009
1019
  */
1010
1020
  recordMemory(row: number, memory: ReadonlyArray<unknown>): void;
@@ -1087,12 +1097,16 @@ interface BillBoardSettings {
1087
1097
  }
1088
1098
  interface TrailSettings {
1089
1099
  /**
1090
- * Start length of the trail.
1100
+ * How many samples the trail keeps, rolled per particle at emission. The particle records one
1101
+ * sample per simulation step, so in babylon.quarks, which steps at 60 Hz, 30 samples is half a
1102
+ * second of travel. Defaults to 30 in babylon.quarks.
1091
1103
  * @type {ValueGenerator | FunctionValueGenerator}
1092
1104
  */
1093
1105
  startLength: ValueGenerator | FunctionValueGenerator;
1094
1106
  /**
1095
- * Whether to follow the local origin.
1107
+ * Keep each particle where it was emitted relative to the emitter, carried by the emitter's
1108
+ * transform instead of its own velocity, so the trail draws the emitter's motion (a weapon
1109
+ * tip) rather than the particle's travel. Defaults to false.
1096
1110
  * @type {boolean}
1097
1111
  */
1098
1112
  followLocalOrigin: boolean;
@@ -1133,13 +1147,70 @@ interface TrailSettings {
1133
1147
  * @type {Vector3}
1134
1148
  */
1135
1149
  sideAxis?: Vector3;
1136
- }
1137
- interface MeshSettings {
1138
1150
  /**
1139
- * Rotation axis.
1140
- * @type {Vector3}
1151
+ * Draw each segment between two recorded samples as this many more
1152
+ * segments, along a curve through the samples (Niagara's ribbon
1153
+ * tessellation), so a fast or sharply turning trail stays round instead
1154
+ * of showing the corners between frames. A whole number from 0 (the
1155
+ * default: straight segments) to 16. The curve passes through every
1156
+ * sample: it smooths the trail without moving it.
1157
+ * @type {number}
1158
+ */
1159
+ tessellation?: number;
1160
+ /**
1161
+ * How tightly a tessellated trail's curve is drawn between its samples
1162
+ * (Niagara's curve tension): 0 (the default) a Catmull-Rom spline, rising
1163
+ * toward 1 for straight segments.
1164
+ * @type {number}
1165
+ */
1166
+ curveTension?: number;
1167
+ /**
1168
+ * How the texture's U runs along the ribbon (Unity's Texture Mode):
1169
+ * - `'stretch'` (the default): once along the ribbon, by distance, so a fast stretch of the
1170
+ * trail shows more of the texture than a slow one.
1171
+ * - `'distributePerSegment'`: once along the ribbon, each recorded segment an equal share
1172
+ * whatever its length (Niagara's Scaled Uniformly).
1173
+ * - `'tile'`: repeated every world unit along the ribbon, scaled by `textureScale`
1174
+ * (Niagara's Tiling Distance). A sample keeps its U for as long as it lives, so the texture
1175
+ * stays put on the trail as the trail grows. The unit is the space the trail is recorded
1176
+ * in, scaled by the emitter for a local-space trail (as the width is).
1177
+ * - `'repeatPerSegment'`: once per recorded segment.
1178
+ *
1179
+ * `uvFromHead` runs any of them from the particle back. The sprite sheet's cell is the
1180
+ * texture's U range, so the repeating modes want a sheet of 1×1 (the default); on a larger
1181
+ * sheet they run into the next cell.
1182
+ * @type {TrailTextureMode}
1183
+ */
1184
+ textureMode?: TrailTextureMode;
1185
+ /**
1186
+ * Repeats of the texture along the ribbon (Unity's Texture Scale, Niagara's UV Scale): per
1187
+ * world unit in `'tile'`, per recorded segment in `'repeatPerSegment'` and over the whole
1188
+ * ribbon in the other modes. Finite and above 0; the default is 1. For repeats across the
1189
+ * ribbon use the texture's own UV layout (`mapUV.tiling`).
1190
+ * @type {number}
1191
+ */
1192
+ textureScale?: number;
1193
+ /**
1194
+ * A new sample is only recorded once the particle has moved this far from the last one, in
1195
+ * the space the trail is recorded in; until then the last sample follows the particle
1196
+ * (Unity's Min Vertex Distance). Keeps a slow or standing particle from filling its history
1197
+ * with points on one spot, so the trail keeps its length in distance rather than in steps.
1198
+ * 0, the default: a sample every simulation step.
1199
+ * @type {number}
1200
+ */
1201
+ minVertexDistance?: number;
1202
+ /**
1203
+ * How long each recorded sample of the trail is kept, in seconds (Unity's Time): the ribbon
1204
+ * reaches that far back in time, however many samples that is, up to `startLength`. Unset or
1205
+ * 0, the default: samples are kept until the history is full, `startLength` samples. The
1206
+ * `WidthOverLength` curve spans the samples kept.
1207
+ * @type {number}
1141
1208
  */
1142
- rotationAxis?: Vector3;
1209
+ lifetime?: number;
1210
+ }
1211
+ /** How a trail's texture runs along the ribbon, see {@link TrailSettings.textureMode}. */
1212
+ type TrailTextureMode = 'stretch' | 'tile' | 'distributePerSegment' | 'repeatPerSegment';
1213
+ interface MeshSettings {
1143
1214
  /**
1144
1215
  * Initial rotation around the X-axis.
1145
1216
  * @type {ValueGenerator | FunctionValueGenerator}
@@ -1208,6 +1279,12 @@ interface IParticleSystem {
1208
1279
  * @type {boolean}
1209
1280
  */
1210
1281
  onlyUsedByOther?: boolean;
1282
+ /**
1283
+ * Whether the system has been disposed. A disposed system takes no more particles, so a sub
1284
+ * emitter aimed at it emits nothing.
1285
+ * @type {boolean}
1286
+ */
1287
+ readonly isDisposed?: boolean;
1211
1288
  /**
1212
1289
  * Whether the ParticleSystem should be automatically disposed when it finishes emitting particles.
1213
1290
  * @type {string}
@@ -1427,6 +1504,14 @@ interface Particle extends IParticle {
1427
1504
  * @type {Vector3}
1428
1505
  */
1429
1506
  startSize: Vector3;
1507
+ /**
1508
+ * Counts the particles this object has held, when the implementation reuses particle objects:
1509
+ * the system bumps it at every spawn. Something that keeps a reference to a particle, such as
1510
+ * a sub emission following its parent, compares it to tell the particle it saw from a later
1511
+ * one that took over the same object.
1512
+ * @type {number}
1513
+ */
1514
+ serial?: number;
1430
1515
  reset(): void;
1431
1516
  }
1432
1517
  /**
@@ -1502,6 +1587,8 @@ declare class SpriteParticle implements Particle {
1502
1587
  * @type {Matrix4}
1503
1588
  */
1504
1589
  parentMatrix?: Matrix4;
1590
+ /** See {@link Particle.serial}. */
1591
+ serial?: number;
1505
1592
  /**
1506
1593
  * Initial speed of the particle, kept in the store's `startSpeed` column.
1507
1594
  * @type {number}
@@ -1658,6 +1745,8 @@ declare class TrailParticle implements Particle {
1658
1745
  * @type {Matrix4}
1659
1746
  */
1660
1747
  parentMatrix?: Matrix4;
1748
+ /** See {@link Particle.serial}. */
1749
+ serial?: number;
1661
1750
  /**
1662
1751
  * Initial speed of the particle, kept in the store's `startSpeed` column.
1663
1752
  * @type {number}
@@ -1728,7 +1817,8 @@ declare class TrailParticle implements Particle {
1728
1817
  get speedModifier(): number;
1729
1818
  set speedModifier(value: number);
1730
1819
  /**
1731
- * Length of the trail.
1820
+ * How many samples the trail keeps, the capacity of the history below; `TrailSettings.startLength`
1821
+ * rolls it at emission. 30, babylon.quarks's default, until then.
1732
1822
  * @type {number}
1733
1823
  */
1734
1824
  length: number;
@@ -1778,7 +1868,15 @@ declare class TrailParticle implements Particle {
1778
1868
  * axis (`TrailSettings.sideAxis`); see {@link ensureSideHistory}.
1779
1869
  */
1780
1870
  historySides: Float32Array;
1781
- /** Number of samples the ring buffers can hold. */
1871
+ /** Ring buffer of the particle's age when each sample was recorded, 1 float per sample. */
1872
+ historyAges: Float32Array;
1873
+ /**
1874
+ * Ring buffer of each sample's distance along the trail, 1 float per sample: the straight
1875
+ * distances between the samples added up from the particle's first sample, in the space the
1876
+ * positions are recorded in. See {@link measureHeadDistance}.
1877
+ */
1878
+ historyDistances: Float32Array;
1879
+ /** Number of samples the ring buffers hold; the buffers themselves may be longer. */
1782
1880
  historyCapacity: number;
1783
1881
  /** Slot the next sample is written to. */
1784
1882
  historyHead: number;
@@ -1798,7 +1896,9 @@ declare class TrailParticle implements Particle {
1798
1896
  /** Re-points the vector views after the store grew its arrays. */
1799
1897
  rebind(): void;
1800
1898
  /**
1801
- * Allocates the trail ring buffers, reusing them when the capacity is unchanged.
1899
+ * Sets how many samples the history holds and empties it. The ring buffers are only
1900
+ * allocated when they are too short, so a particle re-emitted with a shorter or a random
1901
+ * length keeps the buffers it has.
1802
1902
  * @param {number} capacity - Number of samples to hold.
1803
1903
  */
1804
1904
  ensureHistoryCapacity(capacity: number): void;
@@ -1812,10 +1912,25 @@ declare class TrailParticle implements Particle {
1812
1912
  */
1813
1913
  getHistoryIndex(i: number): number;
1814
1914
  /**
1815
- * Records the current state into the trail ring buffer, or retires the
1816
- * oldest sample once the particle is dead. Allocation free.
1915
+ * Records the current state into the trail ring buffer as a new sample, or over the newest
1916
+ * one with `replaceHead` (the head following the particle until it has moved far enough for
1917
+ * a sample of its own, see `TrailSettings.minVertexDistance`). Once the particle is dead
1918
+ * (`age >= life`) it drops the oldest sample instead, so the trail fades from the tail.
1919
+ * Allocation free.
1920
+ * @param replaceHead - Overwrite the newest sample rather than append one; appends when there is none.
1921
+ * @param measureDistance - Set the sample's distance along the trail; a host that moves the sample
1922
+ * after recording it passes false and calls {@link measureHeadDistance} itself.
1923
+ */
1924
+ update(replaceHead?: boolean, measureDistance?: boolean): void;
1925
+ /**
1926
+ * Sets the newest sample's distance along the trail: the sample before it plus the straight
1927
+ * distance between the two, in the space the positions are recorded in; 0 for a trail's
1928
+ * first sample. {@link update} does this; a host that moves the sample after recording it
1929
+ * (babylon.quarks's world-space recording) calls it again.
1817
1930
  */
1818
- update(): void;
1931
+ measureHeadDistance(): void;
1932
+ /** Drops the oldest sample, the one the tail is drawn from, keeping the rest. */
1933
+ dropOldest(): void;
1819
1934
  /**
1820
1935
  * Indicates if the particle has died.
1821
1936
  * @type {boolean}
@@ -1836,12 +1951,42 @@ type ParameterType = FieldType | 'self';
1836
1951
  type ParameterPair = [string, Array<ParameterType>];
1837
1952
 
1838
1953
  /**
1839
- * Interface for particle behaviors.
1840
- * a behavior is a function that modifies a particle's properties over time.
1954
+ * A behavior changes particles over time; a particle system runs a list of
1955
+ * them every simulation step. Each method is called by the host (the system
1956
+ * that owns the behavior), in this order:
1957
+ *
1958
+ * 1. {@link initialize} once per particle, when it is emitted. The particle is
1959
+ * already in the system's pool, placed and given its start values by the
1960
+ * emitter shape, and converted to the simulation space; `particleSystem` is
1961
+ * the system it belongs to. A behavior that reads a per-particle random
1962
+ * sample starts its generators on `particle.memory` here.
1963
+ * 2. {@link frameUpdate} once per step, before any particle is updated that
1964
+ * step, with the step's length. Per-step work (decomposing the emitter's
1965
+ * transform, advancing a time offset) belongs here.
1966
+ * 3. {@link update} once per live particle, or {@link updateAll} once for the
1967
+ * whole pool when it is implemented. The particle's `age` is the age at the
1968
+ * start of the step; the host adds `delta` and integrates the velocity
1969
+ * after every behavior has run.
1970
+ * 4. {@link reset} when the system restarts, before it emits again: state
1971
+ * accumulated across steps goes back to how it was before the first one.
1972
+ *
1973
+ * Randomness is drawn through `random()` from `quarks.core`'s `util/random`,
1974
+ * never `Math.random`, so a host that runs its steps inside `setRandomSource`
1975
+ * (or `withRandomSource`) with a seeded generator replays the same effect, as
1976
+ * babylon.quarks does for a system with a `seed`. Any other state a behavior
1977
+ * keeps must be derived from its settings, so a `clone()` or a saved and
1978
+ * reloaded copy behaves the same.
1979
+ *
1980
+ * {@link toJSON} writes the behavior's settings as plain data, the `type` and
1981
+ * every non-default field; `BehaviorTypes[type].loadJSON` reads it back. The
1982
+ * `params` of that entry list the fields an editor shows.
1841
1983
  */
1842
1984
  interface Behavior {
1985
+ /** The name the behavior is registered under in {@link BehaviorTypes}. */
1843
1986
  type: string;
1987
+ /** Called once per particle when it is emitted; see the interface's description for when. */
1844
1988
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
1989
+ /** Called once per live particle per step, with the step's length in seconds. */
1845
1990
  update(particle: Particle, delta: number): void;
1846
1991
  /**
1847
1992
  * Optional bulk form of {@link update}, applied to `particles[0..count)`.
@@ -1850,15 +1995,19 @@ interface Behavior {
1850
1995
  * behavior type, which leaves it megamorphic: V8 can neither inline it nor
1851
1996
  * specialise the generator calls inside. A behavior that implements this
1852
1997
  * instead gets one call per frame and a loop it owns, where those calls are
1853
- * monomorphic. Implementations must skip dead particles exactly as the
1854
- * per-particle path does, and must produce identical results.
1998
+ * monomorphic. Implementations must skip dead particles (`age >= life`)
1999
+ * exactly as the per-particle path does, and must produce identical results.
1855
2000
  *
1856
2001
  * Behaviors that do not implement it keep working unchanged.
1857
2002
  */
1858
2003
  updateAll?(particles: Array<Particle>, count: number, delta: number): void;
2004
+ /** Called once per step before the particles are updated, with the step's length in seconds. */
1859
2005
  frameUpdate(delta: number): void;
2006
+ /** The behavior's settings as plain data, with its `type`; see the interface's description. */
1860
2007
  toJSON(): any;
2008
+ /** A copy with the same settings that shares nothing mutable with this one. */
1861
2009
  clone(): Behavior;
2010
+ /** Called when the system restarts: forget state accumulated across steps. */
1862
2011
  reset(): void;
1863
2012
  }
1864
2013
  interface BehaviorPlugin {
@@ -1870,22 +2019,63 @@ interface BehaviorPlugin {
1870
2019
  declare const BehaviorTypes: {
1871
2020
  [key: string]: BehaviorPlugin;
1872
2021
  };
2022
+ /**
2023
+ * Reads a behavior. A type no plugin registered warns and gives `null`; the system loads without
2024
+ * that behavior.
2025
+ */
1873
2026
  declare function BehaviorFromJSON(json: any, particleSystem: IParticleSystem): Behavior | null;
1874
2027
 
2028
+ /**
2029
+ * What {@link ApplyCollision} asks about the world: whether a particle at
2030
+ * `position` has hit something, and if so which way the surface faces.
2031
+ */
1875
2032
  interface PhysicsResolver {
1876
- resolve(pos: Vector3, normal: Vector3): boolean;
2033
+ /**
2034
+ * Tests `position`, in the simulation space of the system asking. Returns
2035
+ * true when it is inside or on a collider, with the surface's unit normal
2036
+ * written to `normal`; false otherwise, leaving `normal` alone.
2037
+ */
2038
+ resolve(position: Vector3, normal: Vector3): boolean;
1877
2039
  }
1878
- declare function setPhysicsResolver(resolver: PhysicsResolver): void;
1879
- declare function getPhysicsResolver(): PhysicsResolver;
1880
2040
  /**
1881
- * Apply collision to particles from a physics resolver.
2041
+ * Registers the resolver every {@link ApplyCollision} without one of its own
2042
+ * uses, from the next step on; `undefined` unregisters it. The host owns the
2043
+ * colliders, so quarks.core registers nothing itself.
2044
+ */
2045
+ declare function setPhysicsResolver(resolver: PhysicsResolver | undefined): void;
2046
+ /** The resolver registered with {@link setPhysicsResolver}, or undefined when there is none. */
2047
+ declare function getPhysicsResolver(): PhysicsResolver | undefined;
2048
+ /**
2049
+ * Bounce particles off the host's colliders (Unity's Collision module in its
2050
+ * World mode, with a host-provided world).
2051
+ *
2052
+ * Every step each particle's position is handed to a {@link PhysicsResolver}:
2053
+ * the behavior's own when it was given one, otherwise whatever is registered
2054
+ * with {@link setPhysicsResolver} at that moment, so a resolver registered
2055
+ * after the effect loaded still takes effect. A hit reflects the velocity
2056
+ * about the surface normal and scales it by `bounce`. Without any resolver
2057
+ * the behavior does nothing, so a collision-bearing effect loads and plays
2058
+ * anywhere. Only `bounce` is saved; the resolver belongs to the host. Applies
2059
+ * in every render mode.
1882
2060
  */
1883
2061
  declare class ApplyCollision implements Behavior {
1884
- resolver: PhysicsResolver;
2062
+ /**
2063
+ * The resolver this behavior asks, or undefined to ask the one
2064
+ * registered with {@link setPhysicsResolver} when a particle is tested.
2065
+ */
2066
+ resolver: PhysicsResolver | undefined;
2067
+ /** How much speed a particle keeps after a hit: 1 bounces back at full speed, 0 stops it. */
1885
2068
  bounce: number;
1886
2069
  type: string;
1887
2070
  tempV: Vector3;
1888
- constructor(resolver: PhysicsResolver, bounce: number);
2071
+ constructor(
2072
+ /**
2073
+ * The resolver this behavior asks, or undefined to ask the one
2074
+ * registered with {@link setPhysicsResolver} when a particle is tested.
2075
+ */
2076
+ resolver: PhysicsResolver | undefined,
2077
+ /** How much speed a particle keeps after a hit: 1 bounces back at full speed, 0 stops it. */
2078
+ bounce: number);
1889
2079
  initialize(particle: Particle): void;
1890
2080
  update(particle: Particle, delta: number): void;
1891
2081
  frameUpdate(delta: number): void;
@@ -1896,19 +2086,98 @@ declare class ApplyCollision implements Behavior {
1896
2086
  }
1897
2087
 
1898
2088
  /**
1899
- * Apply a global force to particles.
2089
+ * The space a behavior's vectors are authored in, as Unity's Space setting on
2090
+ * Velocity over Lifetime and Force over Lifetime:
2091
+ *
2092
+ * - `'local'`: the emitter's own axes and units, so the vector turns and
2093
+ * scales with the emitter;
2094
+ * - `'world'`: the world's axes, however the emitter is placed.
2095
+ *
2096
+ * The behavior converts the vector into the space the system simulates in
2097
+ * (`IParticleSystem.worldSpace`), so a setting means the same thing in a local
2098
+ * and in a world-space system.
2099
+ */
2100
+ type BehaviorSpace = 'local' | 'world';
2101
+ /** Reads a space from JSON: `'local'` or `'world'` as written, `fallback` for anything else. */
2102
+ declare function readBehaviorSpace(value: unknown, fallback: BehaviorSpace): BehaviorSpace;
2103
+ /**
2104
+ * The emitter's world transform, decomposed once per frame, with the
2105
+ * conversions a behavior needs to move a vector or a point between the space
2106
+ * it was authored in and the space the particles simulate in.
2107
+ *
2108
+ * Call {@link refresh} from `frameUpdate`. Before the first refresh the frame
2109
+ * is the identity, so a conversion is a no-op. The transform read is the
2110
+ * emitter's matrix as the host set it for the frame; a host that runs several
2111
+ * simulation steps per frame interpolates the emitter's motion for emission,
2112
+ * but the behaviors see the frame's end position.
2113
+ */
2114
+ declare class EmitterFrame {
2115
+ /** The emitter's world position. */
2116
+ readonly position: Vector3;
2117
+ /** The emitter's world rotation. */
2118
+ readonly quaternion: Quaternion;
2119
+ /** The emitter's world scale per axis. */
2120
+ readonly scale: Vector3;
2121
+ /** Inverse of {@link quaternion}. */
2122
+ readonly quaternionInverse: Quaternion;
2123
+ /** Reciprocal of {@link scale} per axis, 0 where the scale is 0. */
2124
+ readonly scaleInverse: Vector3;
2125
+ /** Decomposes the emitter's current world matrix. */
2126
+ refresh(particleSystem: IParticleSystem): void;
2127
+ /**
2128
+ * Converts the direction `vector`, authored in `space`, into the simulation
2129
+ * space of a system that simulates in world space when `worldSpace` is
2130
+ * true. A vector already in the simulation space is left as it is.
2131
+ */
2132
+ toSimulation(vector: Vector3, space: BehaviorSpace, worldSpace: boolean): Vector3;
2133
+ /**
2134
+ * Converts the point `point`, authored in `space`, into the simulation
2135
+ * space, as {@link toSimulation} does for a direction but with the
2136
+ * emitter's position taken into account.
2137
+ */
2138
+ pointToSimulation(point: Vector3, space: BehaviorSpace, worldSpace: boolean): Vector3;
2139
+ }
2140
+
2141
+ /**
2142
+ * Apply a constant force along one direction to every particle, like gravity or wind.
2143
+ *
2144
+ * `magnitude` is rolled per particle when it is emitted: a {@link ConstantValue} pushes every
2145
+ * particle equally, an {@link IntervalValue} gives each particle its own strength for its whole
2146
+ * life, as Unity's Force over Lifetime does with Random Between Two Constants.
2147
+ *
2148
+ * The direction is authored in {@link space}: world axes by default, so gravity stays down
2149
+ * however the emitter is turned, or the emitter's own axes with `'local'`. In a world-space
2150
+ * system a world force is also multiplied by the system's `motionScale`, as every world-space
2151
+ * force is. Applies in every render mode.
1900
2152
  */
1901
2153
  declare class ApplyForce implements Behavior {
2154
+ /** The direction of the force; its length scales it. */
1902
2155
  direction: Vector3;
2156
+ /** The force's strength, in units per second squared, rolled per particle. */
1903
2157
  magnitude: ValueGenerator;
2158
+ /** The space the direction is authored in; `'world'` by default. */
2159
+ space: BehaviorSpace;
1904
2160
  type: string;
1905
- magnitudeValue: number;
1906
- memory: {
1907
- data: never[];
1908
- dataCount: number;
1909
- };
1910
- constructor(direction: Vector3, magnitude: ValueGenerator);
1911
- initialize(particle: Particle): void;
2161
+ /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2162
+ ps?: IParticleSystem;
2163
+ /** The emitter's transform this frame, refreshed by {@link frameUpdate}. */
2164
+ readonly _frame: EmitterFrame;
2165
+ /** {@link direction} in the simulation space, refreshed by {@link frameUpdate}. */
2166
+ readonly _direction: Vector3;
2167
+ constructor(
2168
+ /** The direction of the force; its length scales it. */
2169
+ direction: Vector3,
2170
+ /** The force's strength, in units per second squared, rolled per particle. */
2171
+ magnitude: ValueGenerator,
2172
+ /** The space the direction is authored in; `'world'` by default. */
2173
+ space?: BehaviorSpace);
2174
+ initialize(particle: Particle, particleSystem: IParticleSystem): void;
2175
+ /**
2176
+ * What the magnitude is multiplied by before it reaches the velocity: the
2177
+ * step, and the system's `motionScale` for a world force in a world-space
2178
+ * system. An unknown system (before {@link initialize}) counts as world space.
2179
+ */
2180
+ _step(delta: number): number;
1912
2181
  update(particle: Particle, delta: number): void;
1913
2182
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
1914
2183
  frameUpdate(delta: number): void;
@@ -1923,7 +2192,11 @@ interface Sequencer {
1923
2192
  toJSON(): any;
1924
2193
  clone(): Sequencer;
1925
2194
  }
1926
- declare function SequencerFromJSON(json: any): Sequencer;
2195
+ /**
2196
+ * Reads a sequencer. A type this version does not know warns and gives `undefined`, so the
2197
+ * caller can skip that sequence and keep the rest of the behavior.
2198
+ */
2199
+ declare function SequencerFromJSON(json: any): Sequencer | undefined;
1927
2200
 
1928
2201
  /**
1929
2202
  * Apply sequences to particles.
@@ -1996,17 +2269,17 @@ interface FusionStep {
1996
2269
  declare function planBehaviorFusion(behaviors: Array<Behavior>): Array<FusionStep>;
1997
2270
 
1998
2271
  /**
1999
- * Change the emit direction of particles.
2272
+ * Turns each new particle's velocity away from its emit direction by `angle` (radians), about
2273
+ * a random axis perpendicular to it, keeping its speed. `angle` may be a constant or a
2274
+ * random range; it is rolled once per particle.
2000
2275
  */
2001
2276
  declare class ChangeEmitDirection implements Behavior {
2002
2277
  angle: ValueGenerator;
2003
2278
  type: string;
2004
2279
  _temp: Vector3;
2005
2280
  _q: Quaternion;
2006
- memory: {
2007
- data: never[];
2008
- dataCount: number;
2009
- };
2281
+ /** Scratch for the angle generator's per-spawn sample; cleared before every spawn. */
2282
+ memory: GeneratorMemory;
2010
2283
  constructor(angle: ValueGenerator);
2011
2284
  initialize(particle: Particle): void;
2012
2285
  update(particle: Particle, delta: number): void;
@@ -2018,7 +2291,9 @@ declare class ChangeEmitDirection implements Behavior {
2018
2291
  }
2019
2292
 
2020
2293
  /**
2021
- * Color particles by their speed.
2294
+ * Colors particles by their current speed, like Unity's Color by Speed: the speed (velocity
2295
+ * length times the speed modifier) is placed in `speedRange`, clamped to 0..1, and the gradient is
2296
+ * read there and multiplied by the start colour.
2022
2297
  */
2023
2298
  declare class ColorBySpeed implements Behavior {
2024
2299
  color: FunctionColorGenerator;
@@ -2079,14 +2354,16 @@ declare class EmitSubParticleSystem implements Behavior {
2079
2354
  /**
2080
2355
  * Which of the parent particle's properties the sub particles start
2081
2356
  * from: its current colour and size multiply theirs, its rotation adds
2082
- * to theirs, and its remaining lifetime fraction scales theirs (so
2083
- * lifetime suits birth sub emitters, not death ones).
2357
+ * to theirs, and its remaining lifetime fraction scales theirs. A Death
2358
+ * sub emitter ignores lifetime, since the parent has none left; Unity
2359
+ * would give its particles no life at all.
2084
2360
  */
2085
2361
  inherit: SubEmitterInheritance[];
2086
2362
  type: string;
2087
2363
  private q_;
2088
2364
  private v_;
2089
2365
  private v2_;
2366
+ private v3_;
2090
2367
  private subEmissions;
2091
2368
  /** Finished emission states, kept for reuse: a burst of deaths would otherwise allocate one plus a matrix each. */
2092
2369
  private spareEmissions;
@@ -2094,8 +2371,9 @@ declare class EmitSubParticleSystem implements Behavior {
2094
2371
  /**
2095
2372
  * Which of the parent particle's properties the sub particles start
2096
2373
  * from: its current colour and size multiply theirs, its rotation adds
2097
- * to theirs, and its remaining lifetime fraction scales theirs (so
2098
- * lifetime suits birth sub emitters, not death ones).
2374
+ * to theirs, and its remaining lifetime fraction scales theirs. A Death
2375
+ * sub emitter ignores lifetime, since the parent has none left; Unity
2376
+ * would give its particles no life at all.
2099
2377
  */
2100
2378
  inherit?: SubEmitterInheritance[]);
2101
2379
  initialize(particle: Particle): void;
@@ -2103,8 +2381,8 @@ declare class EmitSubParticleSystem implements Behavior {
2103
2381
  /**
2104
2382
  * The system to emit into, or undefined when `subParticleSystem` does not
2105
2383
  * hold a resolved emitter — unset, or a uuid string a loader could not
2106
- * link. Every use goes through here, so a bad value is skipped rather
2107
- * than thrown on.
2384
+ * link — or when that system was disposed. Every use goes through here,
2385
+ * so a bad value is skipped rather than thrown on.
2108
2386
  */
2109
2387
  private get target();
2110
2388
  private emit;
@@ -2113,29 +2391,62 @@ declare class EmitSubParticleSystem implements Behavior {
2113
2391
  static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
2114
2392
  clone(): Behavior;
2115
2393
  reset(): void;
2394
+ /**
2395
+ * Drops the emissions still running, as when the parent system restarts or stops: a Death
2396
+ * emission would otherwise keep emitting where a particle of the last play died.
2397
+ */
2398
+ clearEmissions(): void;
2399
+ /** Copies what a sub emission reads from its parent: where it is, how it moves and what it inherits. */
2400
+ private static copyInto;
2116
2401
  private static validInherit;
2117
2402
  private setMatrixFromParticle;
2118
2403
  }
2119
2404
 
2120
2405
  /**
2121
- * Apply a force to particles over their life.
2406
+ * Accelerate particles by a force that changes over their life, one curve per
2407
+ * axis (Unity's Force over Lifetime).
2408
+ *
2409
+ * The force is in units per second squared, authored in {@link space}: world
2410
+ * axes by default, or the emitter's own axes with `'local'`, in which case it
2411
+ * turns and scales with the emitter. In a world-space system a world force is
2412
+ * also multiplied by the system's `motionScale`, as every world-space force is.
2413
+ * Applies in every render mode.
2122
2414
  */
2123
2415
  declare class ForceOverLife implements Behavior {
2416
+ /** Force along X over the particle's life, in units per second squared. */
2124
2417
  x: FunctionValueGenerator | ValueGenerator;
2418
+ /** Force along Y over the particle's life, in units per second squared. */
2125
2419
  y: FunctionValueGenerator | ValueGenerator;
2420
+ /** Force along Z over the particle's life, in units per second squared. */
2126
2421
  z: FunctionValueGenerator | ValueGenerator;
2422
+ /** The space the force is authored in; `'world'` by default. */
2423
+ space: BehaviorSpace;
2127
2424
  type: string;
2128
2425
  _temp: Vector3;
2129
2426
  /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2130
2427
  ps?: IParticleSystem;
2428
+ /** The emitter's transform this frame, refreshed by {@link frameUpdate}. */
2429
+ readonly _frame: EmitterFrame;
2131
2430
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
2132
- constructor(x: FunctionValueGenerator | ValueGenerator, y: FunctionValueGenerator | ValueGenerator, z: FunctionValueGenerator | ValueGenerator);
2431
+ constructor(
2432
+ /** Force along X over the particle's life, in units per second squared. */
2433
+ x: FunctionValueGenerator | ValueGenerator,
2434
+ /** Force along Y over the particle's life, in units per second squared. */
2435
+ y: FunctionValueGenerator | ValueGenerator,
2436
+ /** Force along Z over the particle's life, in units per second squared. */
2437
+ z: FunctionValueGenerator | ValueGenerator,
2438
+ /** The space the force is authored in; `'world'` by default. */
2439
+ space?: BehaviorSpace);
2440
+ /**
2441
+ * What the force is multiplied by before it reaches the velocity: the
2442
+ * step, and the system's `motionScale` for a world force in a world-space
2443
+ * system. An unknown system (before {@link initialize}) counts as world space.
2444
+ */
2445
+ _step(delta: number): number;
2133
2446
  update(particle: Particle, delta: number): void;
2134
2447
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2135
2448
  toJSON(): any;
2136
2449
  static fromJSON(json: any): Behavior;
2137
- _tempScale: Vector3;
2138
- _tempQ: Quaternion;
2139
2450
  frameUpdate(delta: number): void;
2140
2451
  clone(): Behavior;
2141
2452
  reset(): void;
@@ -2227,16 +2538,26 @@ declare class FrameOverLife implements Behavior {
2227
2538
  }
2228
2539
 
2229
2540
  /**
2230
- * Apply a gravity force to particles.
2231
- * the gravity force is calculated as:
2232
- * F = G * m1 * m2 / r^2
2541
+ * Pull particles toward a point with an inverse-square force, F = magnitude / r²
2542
+ * (Niagara's Point Attraction Force).
2543
+ *
2544
+ * `center` is a point in the space the system simulates in: the emitter's own
2545
+ * space for a local-space system, the world for a world-space one. A particle
2546
+ * exactly on the centre is left alone rather than given an infinite pull.
2547
+ * Applies in every render mode.
2233
2548
  */
2234
2549
  declare class GravityForce implements Behavior {
2550
+ /** The point pulled toward, in the simulation space. */
2235
2551
  center: Vector3;
2552
+ /** Strength of the pull at distance 1, in units per second squared. */
2236
2553
  magnitude: number;
2237
2554
  type: string;
2238
2555
  temp: Vector3;
2239
- constructor(center: Vector3, magnitude: number);
2556
+ constructor(
2557
+ /** The point pulled toward, in the simulation space. */
2558
+ center: Vector3,
2559
+ /** Strength of the pull at distance 1, in units per second squared. */
2560
+ magnitude: number);
2240
2561
  initialize(particle: Particle): void;
2241
2562
  update(particle: Particle, delta: number): void;
2242
2563
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
@@ -2275,10 +2596,18 @@ declare class InheritVelocity implements Behavior {
2275
2596
  }
2276
2597
 
2277
2598
  /**
2278
- * Limit the speed of particles over their life.
2599
+ * Limits the speed of particles over their life, like Unity's Limit Velocity over Lifetime: a
2600
+ * particle faster than `speed` loses part of the excess each step.
2279
2601
  */
2280
2602
  declare class LimitSpeedOverLife implements Behavior {
2603
+ /** The speed limit over the particle's life. */
2281
2604
  speed: FunctionValueGenerator;
2605
+ /**
2606
+ * How much of the excess speed goes, from 0 (none) to 1, clamped. At 60 steps a second each
2607
+ * step removes `dampen / 3` of it; other step lengths remove the share that compounds to the
2608
+ * same loss per second, so the result does not depend on the frame rate. Even at 1 the
2609
+ * limit is approached over a few steps rather than held exactly.
2610
+ */
2282
2611
  dampen: number;
2283
2612
  type: string;
2284
2613
  /** Learned in {@link initialize}; its motion scale multiplies the limit of a world-space system. */
@@ -2286,7 +2615,18 @@ declare class LimitSpeedOverLife implements Behavior {
2286
2615
  initialize(particle: Particle, particleSystem?: IParticleSystem): void;
2287
2616
  /** What the limit is multiplied by: the system's motion scale in world space, else 1. */
2288
2617
  motionScale(): number;
2289
- constructor(speed: FunctionValueGenerator, dampen: number);
2618
+ constructor(
2619
+ /** The speed limit over the particle's life. */
2620
+ speed: FunctionValueGenerator,
2621
+ /**
2622
+ * How much of the excess speed goes, from 0 (none) to 1, clamped. At 60 steps a second each
2623
+ * step removes `dampen / 3` of it; other step lengths remove the share that compounds to the
2624
+ * same loss per second, so the result does not depend on the frame rate. Even at 1 the
2625
+ * limit is approached over a few steps rather than held exactly.
2626
+ */
2627
+ dampen: number);
2628
+ /** The share of the excess speed one step of `delta` seconds removes; see {@link dampen}. */
2629
+ dampenStep(delta: number): number;
2290
2630
  update(particle: Particle, delta: number): void;
2291
2631
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2292
2632
  toJSON(): any;
@@ -2297,7 +2637,18 @@ declare class LimitSpeedOverLife implements Behavior {
2297
2637
  }
2298
2638
 
2299
2639
  /**
2300
- * Apply noise to particles.
2640
+ * Jitter particles with smooth noise over their life (Unity's Noise module).
2641
+ *
2642
+ * Each particle reads its own one-dimensional simplex curves at its age times
2643
+ * `frequency`; `power` scales what they return, `positionAmount` and
2644
+ * `rotationAmount` say how much of it goes into the position and the
2645
+ * rotation. The offset applied last step is removed before this step's is
2646
+ * added, so the noise rides on top of the other behaviors instead of
2647
+ * accumulating. A billboard's angle turns by W noise × π × amount; a mesh
2648
+ * particle turns by the same angle around an axis the X, Y and Z noise choose.
2649
+ * The generators are picked per particle from the random source, so a seeded
2650
+ * system (see the `Behavior` contract) replays the same noise. Applies in
2651
+ * every render mode.
2301
2652
  */
2302
2653
  declare class Noise implements Behavior {
2303
2654
  frequency: FunctionValueGenerator | ValueGenerator;
@@ -2346,6 +2697,13 @@ declare class Noise implements Behavior {
2346
2697
  private _positionAmount;
2347
2698
  private _rotationAmount;
2348
2699
  private static constantOf;
2700
+ /**
2701
+ * Replaces the noise turn applied last step with this step's: an axis-angle
2702
+ * turn whose axis comes from the X, Y and Z generators and whose angle, as
2703
+ * for a billboard's angle, is the W generator's value times π times
2704
+ * `amount`, so `rotationAmount` sets how far a mesh particle wobbles.
2705
+ */
2706
+ private rotateByNoise;
2349
2707
  update(particle: Particle, _: number): void;
2350
2708
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2351
2709
  toJSON(): any;
@@ -2356,16 +2714,52 @@ declare class Noise implements Behavior {
2356
2714
  }
2357
2715
 
2358
2716
  /**
2359
- * Orbit particles around an axis over their life.
2717
+ * Turn particles around an axis over their life, like Unity's Orbital
2718
+ * velocity: each particle keeps its distance from the axis and sweeps around
2719
+ * it at `orbitSpeed` radians per second.
2720
+ *
2721
+ * The axis and the pivot are authored in {@link space}. `'local'`, the default,
2722
+ * is the emitter's: the axis is in the emitter's axes and the pivot is the
2723
+ * emitter's origin, so in a world-space system the orbit follows the emitter
2724
+ * and the effect looks the same whichever space the system simulates in.
2725
+ * `'world'` orbits the world origin about a world axis wherever the emitter
2726
+ * goes (Niagara's Vortex Force with a fixed origin). The axis need not be a
2727
+ * unit vector; only its direction matters, and a zero axis orbits nothing.
2728
+ * Applies in every render mode.
2729
+ *
2730
+ * For an orbit around three axes at once, with a radial speed or an offset
2731
+ * pivot, see `VelocityOverLife`.
2360
2732
  */
2361
2733
  declare class OrbitOverLife implements Behavior {
2734
+ /** Angular speed around the axis over the particle's life, in radians per second. */
2362
2735
  orbitSpeed: FunctionValueGenerator | ValueGenerator;
2736
+ /** The axis orbited, in {@link OrbitOverLife.space | space}; its length is ignored. */
2363
2737
  axis: Vector3;
2738
+ /** The space the axis and the pivot are authored in; `'local'` (the emitter's) by default. */
2739
+ space: BehaviorSpace;
2364
2740
  type: string;
2365
2741
  rotation: Quaternion;
2366
2742
  temp: Vector3;
2367
- constructor(orbitSpeed: FunctionValueGenerator | ValueGenerator, axis?: Vector3);
2368
- initialize(particle: Particle): void;
2743
+ /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2744
+ ps?: IParticleSystem;
2745
+ /** The emitter's transform this frame, refreshed by {@link frameUpdate}. */
2746
+ readonly _frame: EmitterFrame;
2747
+ /** Unit {@link axis} in the simulation space, or zero for a zero axis; refreshed by {@link frameUpdate}. */
2748
+ readonly _axis: Vector3;
2749
+ /** The pivot in the simulation space; refreshed by {@link frameUpdate}. */
2750
+ readonly _center: Vector3;
2751
+ constructor(
2752
+ /** Angular speed around the axis over the particle's life, in radians per second. */
2753
+ orbitSpeed: FunctionValueGenerator | ValueGenerator,
2754
+ /** The axis orbited, in {@link OrbitOverLife.space | space}; its length is ignored. */
2755
+ axis?: Vector3,
2756
+ /** The space the axis and the pivot are authored in; `'local'` (the emitter's) by default. */
2757
+ space?: BehaviorSpace);
2758
+ initialize(particle: Particle, particleSystem: IParticleSystem): void;
2759
+ /** Recomputes the unit axis and pivot in the simulation space from {@link axis} and the emitter's frame. */
2760
+ private refreshAxis;
2761
+ /** Whether the frame is read: only when the authored space differs from the simulation space. */
2762
+ private converts;
2369
2763
  update(particle: Particle, delta: number): void;
2370
2764
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2371
2765
  frameUpdate(delta: number): void;
@@ -2394,7 +2788,9 @@ declare class Rotation3DOverLife implements Behavior {
2394
2788
  }
2395
2789
 
2396
2790
  /**
2397
- * Apply rotation to particles based on their speed.
2791
+ * Turns particles at a rate read off their current speed, like Unity's Rotation by Speed: the
2792
+ * speed (velocity length times the speed modifier) is placed in `speedRange`, clamped to 0..1.
2793
+ * Billboards only; particles rotating by quaternion are left alone.
2398
2794
  */
2399
2795
  declare class RotationBySpeed implements Behavior {
2400
2796
  angularVelocity: ValueGenerator | FunctionValueGenerator;
@@ -2442,7 +2838,9 @@ declare class RotationOverLife implements Behavior {
2442
2838
  }
2443
2839
 
2444
2840
  /**
2445
- * Apply size to particles based on their speed.
2841
+ * Sizes particles by their current speed, like Unity's Size by Speed: the speed (velocity length
2842
+ * times the speed modifier) is placed in `speedRange`, clamped to 0..1, and the curve read there
2843
+ * scales the start size.
2446
2844
  */
2447
2845
  declare class SizeBySpeed implements Behavior {
2448
2846
  size: FunctionValueGenerator | Vector3Generator;
@@ -2478,6 +2876,13 @@ declare class SizeOverLife implements Behavior {
2478
2876
  reset(): void;
2479
2877
  }
2480
2878
 
2879
+ /**
2880
+ * Where a particle's current speed (its velocity's length times its speed modifier) falls in
2881
+ * `range`, clamped to 0..1. An empty range is a step at `a`. Unlike Unity, motion that
2882
+ * `VelocityOverLife` adds moves the particle without changing its velocity, so it does not count.
2883
+ */
2884
+ declare function speedFraction(particle: Particle, range: IntervalValue): number;
2885
+
2481
2886
  /**
2482
2887
  * Apply speed to particles based on their life.
2483
2888
  */
@@ -2537,19 +2942,51 @@ declare class SimplexNoise {
2537
2942
  }
2538
2943
 
2539
2944
  /**
2540
- * Apply turbulence to particles.
2945
+ * Push particles around with a turbulent vector field sampled at their
2946
+ * position (Unity's Noise module in its Position mode, Niagara's Curl Noise
2947
+ * Force): nearby particles are pushed alike, so the system swirls instead of
2948
+ * jittering.
2949
+ *
2950
+ * The field is three channels of four-dimensional simplex noise, `octaves`
2951
+ * layers deep, each layer twice as fine and half as strong as the one before.
2952
+ * `scale` is the size of one noise cell per axis in the simulation space (a
2953
+ * zero component gives no variation along that axis), `velocityMultiplier` the
2954
+ * push per axis in units per second squared, and `timeScale` how fast the
2955
+ * field drifts per axis. The field is built from `seed`, so the same settings
2956
+ * give the same field on every run and a clone or a saved copy swirls
2957
+ * identically; give each system its own seed for different fields. Applies in
2958
+ * every render mode.
2541
2959
  */
2542
2960
  declare class TurbulenceField implements Behavior {
2961
+ /** Size of one noise cell per axis, in the simulation space. */
2543
2962
  scale: Vector3;
2963
+ /** How many layers of noise are summed; more is finer and dearer. */
2544
2964
  octaves: number;
2965
+ /** Push per axis, in units per second squared. */
2545
2966
  velocityMultiplier: Vector3;
2967
+ /** How fast the field drifts per axis, in noise time per second. */
2546
2968
  timeScale: Vector3;
2969
+ /** The seed the field is built from; 0 by default. */
2970
+ seed: number;
2547
2971
  type: string;
2548
2972
  generator: SimplexNoise;
2973
+ /** Where in time the field is sampled now; starts at {@link initialOffset} and drifts by `timeScale`. */
2549
2974
  timeOffset: Vector3;
2975
+ /** The time offset the field starts from, derived from {@link seed}; restored by {@link reset}. */
2976
+ readonly initialOffset: Vector3;
2550
2977
  temp: Vector3;
2551
2978
  temp2: Vector3;
2552
- constructor(scale: Vector3, octaves: number, velocityMultiplier: Vector3, timeScale: Vector3);
2979
+ constructor(
2980
+ /** Size of one noise cell per axis, in the simulation space. */
2981
+ scale: Vector3,
2982
+ /** How many layers of noise are summed; more is finer and dearer. */
2983
+ octaves: number,
2984
+ /** Push per axis, in units per second squared. */
2985
+ velocityMultiplier: Vector3,
2986
+ /** How fast the field drifts per axis, in noise time per second. */
2987
+ timeScale: Vector3,
2988
+ /** The seed the field is built from; 0 by default. */
2989
+ seed?: number);
2553
2990
  initialize(particle: Particle): void;
2554
2991
  update(particle: Particle, delta: number): void;
2555
2992
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
@@ -2557,10 +2994,12 @@ declare class TurbulenceField implements Behavior {
2557
2994
  frameUpdate(delta: number): void;
2558
2995
  static fromJSON(json: any): Behavior;
2559
2996
  clone(): Behavior;
2997
+ /** Rewinds the field's drift to where it started, so a restarted system swirls the same way. */
2560
2998
  reset(): void;
2561
2999
  }
2562
3000
 
2563
- type VelocityOverLifeSpace = 'local' | 'world';
3001
+ /** The space a `VelocityOverLife` is authored in; the same choice as {@link BehaviorSpace}. */
3002
+ type VelocityOverLifeSpace = BehaviorSpace;
2564
3003
  /**
2565
3004
  * Move particles with a direct velocity over their life (Unity's "Velocity over Lifetime").
2566
3005
  * Applied as a positional displacement, so it is not affected by speed modifiers,
@@ -2617,7 +3056,7 @@ declare class VelocityOverLife implements Behavior {
2617
3056
  /**
2618
3057
  * Shapes a trail's width along its length — Unity's Width over Trail.
2619
3058
  *
2620
- * The curve runs from the head (0) to the tail (1) and, by default, is a
3059
+ * The curve runs from the head (0) to the tail (1), the trail's oldest sample, and, by default, is a
2621
3060
  * multiplier on the width each sample was recorded with (the particle's
2622
3061
  * `size.x` at that moment): a curve from 1 to 0 tapers the trail from the
2623
3062
  * particle's size at the head down to nothing at the tail, whatever that size
@@ -2729,23 +3168,24 @@ interface ShapeJSON {
2729
3168
  * Enum representing the emitter modes for particles.
2730
3169
  */
2731
3170
  declare enum EmitterMode {
2732
- /**
2733
- * Emit particles randomly over the specified duration.
2734
- */
3171
+ /** Each particle starts at a random point of the arc. */
2735
3172
  Random = 0,
2736
- /**
2737
- * Emit particles in a continuous loop.
2738
- */
3173
+ /** The start point sweeps the arc at the shape's `speed` (arcs per second) and wraps around. */
2739
3174
  Loop = 1,
2740
- /**
2741
- * Emit particles back and forth in a ping-pong manner.
2742
- */
3175
+ /** The start point sweeps the arc back and forth, starting at the arc's start. */
2743
3176
  PingPong = 2,
2744
- /**
2745
- * Emit particles in bursts.
2746
- */
3177
+ /** A burst's particles are spread evenly over the arc; particles emitted by rate start at random. */
2747
3178
  Burst = 3
2748
3179
  }
3180
+ /**
3181
+ * Where along the shape's arc (0…1) the next particle starts, from the shape's
3182
+ * {@link EmitterMode} (Unity's Arc Mode): random; `Loop` sweeps the arc and wraps
3183
+ * (`currentValue` is the sweep position in arcs, any sign); `PingPong` sweeps back
3184
+ * and forth, starting at the arc's start; `Burst` spreads a burst's particles evenly
3185
+ * over the arc and places rate-emitted particles at random. A `spread` above 0 then
3186
+ * snaps the result to multiples of it (Unity's Spread), so 0.25 emits from four
3187
+ * points. The result is always within 0…1.
3188
+ */
2749
3189
  declare function getValueFromEmitterMode(mode: EmitterMode, currentValue: number, spread: number, emissionState: EmissionState): number;
2750
3190
  interface EmitterShape {
2751
3191
  type: string;
@@ -2758,6 +3198,12 @@ interface EmitterShape {
2758
3198
  * by the shape itself at the end of {@link initialize}.
2759
3199
  */
2760
3200
  transform?: ShapeTransform;
3201
+ /**
3202
+ * Forgets the state the shape built up while emitting (the arc sweep position of
3203
+ * `Loop`/`PingPong` shapes, generator memory), so a restarted system emits from the
3204
+ * start of the arc again. Called by the particle system's `restart()`.
3205
+ */
3206
+ reset?(): void;
2761
3207
  }
2762
3208
 
2763
3209
  /**
@@ -2788,6 +3234,11 @@ interface BoxEmitterParameters {
2788
3234
  * box size: 0 keeps them on the surface, 0.5 reaches the center.
2789
3235
  */
2790
3236
  boxThickness?: [number, number, number];
3237
+ /**
3238
+ * Offset, rotation and scale of the shape within the particle system.
3239
+ * {@link ShapeTransform}
3240
+ */
3241
+ transform?: ShapeTransform;
2791
3242
  }
2792
3243
  /**
2793
3244
  * A particle emitter that emits particles from a box centered on the emitter, all moving along +Z
@@ -2800,6 +3251,7 @@ declare class BoxEmitter implements EmitterShape {
2800
3251
  depth: number;
2801
3252
  emitFrom: BoxEmitFrom;
2802
3253
  boxThickness: [number, number, number];
3254
+ transform?: ShapeTransform;
2803
3255
  private readonly _point;
2804
3256
  constructor(parameters?: BoxEmitterParameters);
2805
3257
  update(_system: IParticleSystem, _delta: number): void;
@@ -2867,6 +3319,7 @@ declare class CircleEmitter implements EmitterShape {
2867
3319
  memory: GeneratorMemory;
2868
3320
  transform?: ShapeTransform;
2869
3321
  private currentValue;
3322
+ reset(): void;
2870
3323
  constructor(parameters?: CircleEmitterParameters);
2871
3324
  update(system: IParticleSystem, delta: number): void;
2872
3325
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -2928,6 +3381,7 @@ declare class ConeEmitter implements EmitterShape {
2928
3381
  memory: GeneratorMemory;
2929
3382
  transform?: ShapeTransform;
2930
3383
  private currentValue;
3384
+ reset(): void;
2931
3385
  constructor(parameters?: ConeEmitterParameters);
2932
3386
  update(system: IParticleSystem, delta: number): void;
2933
3387
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -2991,6 +3445,7 @@ declare class DonutEmitter implements EmitterShape {
2991
3445
  _m1: Matrix4;
2992
3446
  constructor(parameters?: DonutEmitterParameters);
2993
3447
  private currentValue;
3448
+ reset(): void;
2994
3449
  update(system: IParticleSystem, delta: number): void;
2995
3450
  initialize(p: Particle, emissionState: EmissionState): void;
2996
3451
  toJSON(): ShapeJSON;
@@ -3019,6 +3474,11 @@ interface EdgeEmitterParameters {
3019
3474
  * {@link EmitterMode}
3020
3475
  */
3021
3476
  speed?: ValueGenerator | FunctionValueGenerator;
3477
+ /**
3478
+ * Offset, rotation and scale of the shape within the particle system.
3479
+ * {@link ShapeTransform}
3480
+ */
3481
+ transform?: ShapeTransform;
3022
3482
  }
3023
3483
  /**
3024
3484
  * A particle emitter that emits particles from a line along X, all moving along +Y like Unity's
@@ -3031,7 +3491,9 @@ declare class EdgeEmitter implements EmitterShape {
3031
3491
  spread: number;
3032
3492
  speed: ValueGenerator | FunctionValueGenerator;
3033
3493
  memory: GeneratorMemory;
3494
+ transform?: ShapeTransform;
3034
3495
  private currentValue;
3496
+ reset(): void;
3035
3497
  constructor(parameters?: EdgeEmitterParameters);
3036
3498
  update(system: IParticleSystem, delta: number): void;
3037
3499
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -3049,6 +3511,10 @@ interface EmitterShapePlugin {
3049
3511
  declare const EmitterShapes: {
3050
3512
  [key: string]: EmitterShapePlugin;
3051
3513
  };
3514
+ /**
3515
+ * Reads an emitter shape. A type no plugin registered (a custom shape whose plugin is not
3516
+ * loaded, or a typo) warns and gives a point emitter, so the rest of the effect still loads.
3517
+ */
3052
3518
  declare function EmitterFromJSON(json: ShapeJSON, meta: JsonMetaData): EmitterShape;
3053
3519
 
3054
3520
  /**
@@ -3142,6 +3608,7 @@ declare class HemisphereEmitter implements EmitterShape {
3142
3608
  _m1: Matrix4;
3143
3609
  constructor(parameters?: HemisphereEmitterParameters);
3144
3610
  private currentValue;
3611
+ reset(): void;
3145
3612
  update(system: IParticleSystem, delta: number): void;
3146
3613
  initialize(p: Particle, emissionState: EmissionState): void;
3147
3614
  toJSON(): ShapeJSON;
@@ -3220,6 +3687,7 @@ declare class RectangleEmitter implements EmitterShape {
3220
3687
  memory: GeneratorMemory;
3221
3688
  transform?: ShapeTransform;
3222
3689
  private currentValue;
3690
+ reset(): void;
3223
3691
  private _m1;
3224
3692
  constructor(parameters?: RectangleEmitterParameters);
3225
3693
  update(system: IParticleSystem, delta: number): void;
@@ -3279,6 +3747,7 @@ declare class SphereEmitter implements EmitterShape {
3279
3747
  _m1: Matrix4;
3280
3748
  constructor(parameters?: SphereEmitterParameters);
3281
3749
  private currentValue;
3750
+ reset(): void;
3282
3751
  update(system: IParticleSystem, delta: number): void;
3283
3752
  initialize(p: Particle, emissionState: EmissionState): void;
3284
3753
  toJSON(): ShapeJSON;
@@ -3293,7 +3762,12 @@ interface Plugin {
3293
3762
  behaviors: Array<BehaviorPlugin>;
3294
3763
  }
3295
3764
  declare const Plugins: Array<Plugin>;
3765
+ /**
3766
+ * Registers a plugin's emitter shapes and behaviors, so effect files can name them. Loading the
3767
+ * same plugin id again does nothing. A type another plugin registered first keeps that plugin's.
3768
+ */
3296
3769
  declare function loadPlugin(plugin: Plugin): void;
3770
+ /** Removes a plugin and the types it registered; types another plugin registered stay. */
3297
3771
  declare function unloadPlugin(pluginId: string): void;
3298
3772
 
3299
3773
  declare class TextureSequencer implements Sequencer {
@@ -3341,6 +3815,58 @@ declare function createSeededRandom(seed: number): RandomSource;
3341
3815
  /** Runs `fn` with `generator` as the random source, restoring the previous one after. */
3342
3816
  declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3343
3817
 
3818
+ /**
3819
+ * What a soft-particle depth texture stores per pixel, so the shaders can turn it back into the
3820
+ * distance from the camera. These are the three outputs of Babylon's `DepthRenderer`:
3821
+ *
3822
+ * - `'linear'`: Babylon's default depth metric, `scene.enableDepthRenderer()`. Linear in view
3823
+ * depth between the camera's near and far planes.
3824
+ * - `'nonLinear'`: the depth buffer value, `enableDepthRenderer(camera, true)`. This is what
3825
+ * Unity's `_CameraDepthTexture` holds and what `LinearEyeDepth` undoes.
3826
+ * - `'viewZ'`: the view-space Z itself, `enableDepthRenderer(camera, false, true, sampling, true)`.
3827
+ * Exact at any range and with an infinite far plane (`camera.maxZ = 0`), which the other two
3828
+ * cannot represent; this is the closest match to Unreal's SceneDepth.
3829
+ *
3830
+ * Perspective and orthographic cameras, both NDC depth ranges (WebGL, WebGPU) and a reverse
3831
+ * depth buffer are all handled, from the camera drawing the particles. With a reverse depth buffer
3832
+ * and `'nonLinear'`, clear the depth renderer to 0 (`depthRenderer.clearColor.r = 0`): it clears
3833
+ * to 1 by default, which a reverse buffer reads as the near plane, so empty sky would fade every
3834
+ * particle in front of it. A packed `'viewZ'` cannot be decoded.
3835
+ */
3836
+ type SoftDepthEncoding = 'linear' | 'nonLinear' | 'viewZ';
3837
+ /** How a depth texture given to {@link BatchedRenderer.setDepthTexture} is read. */
3838
+ interface DepthTextureOptions {
3839
+ /** What the texture stores. Defaults to the encoding of the `DepthRenderer` given, else `'linear'`. */
3840
+ encoding?: SoftDepthEncoding;
3841
+ /**
3842
+ * The depth is packed into the four 8-bit channels, as a `DepthRenderer` of type
3843
+ * `UNSIGNED_BYTE` writes it. Defaults to the `DepthRenderer`'s `isPacked`, else false.
3844
+ */
3845
+ packed?: boolean;
3846
+ }
3847
+ /** The depth texture a batch's soft particles read, and how. */
3848
+ interface DepthBinding {
3849
+ texture: BaseTexture;
3850
+ encoding: SoftDepthEncoding;
3851
+ packed: boolean;
3852
+ }
3853
+ /**
3854
+ * Writes the four coefficients the soft-particle shaders decode a depth sample `d` with:
3855
+ * view depth = |(x·d + y) / (z·d + w)|. Each encoding is a ratio of linear terms in `d` for
3856
+ * every projection Babylon builds, so one formula covers them all.
3857
+ *
3858
+ * @param camera - The camera the particles are drawn for, normally the one the depth was drawn for.
3859
+ * @param encoding - What the depth texture stores.
3860
+ * @param out - Receives the coefficients.
3861
+ */
3862
+ declare function softDepthParams(camera: Camera, encoding: SoftDepthEncoding, out: Vector4$1): Vector4$1;
3863
+ /**
3864
+ * The view depth the shaders read off a depth sample, for the coefficients of
3865
+ * {@link softDepthParams}. Nothing there (a `'viewZ'` sample of 0, or a sample at an infinite far
3866
+ * plane) reads as infinitely far, so the particle does not fade.
3867
+ */
3868
+ declare function decodeSoftDepth(sample: number, params: Vector4$1): number;
3869
+
3344
3870
  /**
3345
3871
  * The order the particles of a batch are drawn in (Unity's Sort Mode). Alpha
3346
3872
  * blended particles cover what was drawn before them, so the order shows.
@@ -3353,12 +3879,25 @@ declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3353
3879
  * Sorting runs over the whole batch after each fill. Trails are not sorted.
3354
3880
  */
3355
3881
  type SortMode = 'none' | 'distance' | 'oldestInFront' | 'youngestInFront';
3882
+ /** How a system draws its particles (Unity's Render Mode), see {@link ParticleSystem.renderMode}. */
3356
3883
  declare enum RenderMode {
3884
+ /** A quad facing the camera (Unity's Billboard). The default. */
3357
3885
  BillBoard = 0,
3886
+ /**
3887
+ * A quad facing the camera and stretched along the particle's velocity (Unity's Stretched
3888
+ * Billboard), by `speedFactor` and `lengthFactor` in the system's `rendererEmitterSettings`.
3889
+ */
3358
3890
  StretchedBillBoard = 1,
3891
+ /** The system's mesh, one instance per particle (Unity's Mesh), see {@link ParticleSystem.instancingGeometry}. */
3359
3892
  Mesh = 2,
3893
+ /**
3894
+ * A ribbon drawn through the particle's past positions (Unity's Trails module, Niagara's
3895
+ * ribbon), facing the camera; its settings are `TrailSettings` in `rendererEmitterSettings`.
3896
+ */
3360
3897
  Trail = 3,
3898
+ /** A quad lying flat in the world's XZ plane, facing up (Unity's Horizontal Billboard). */
3361
3899
  HorizontalBillBoard = 4,
3900
+ /** A quad standing upright and turning only about the world's Y axis to face the camera (Unity's Vertical Billboard). */
3362
3901
  VerticalBillBoard = 5,
3363
3902
  /**
3364
3903
  * A quad laid from each particle to the system's {@link ParticleSystem.beamEnd}
@@ -3472,8 +4011,9 @@ declare function textureUVToJSON(uv: TextureUV, defaults?: Partial<TextureUV>):
3472
4011
  type GradientMapChannel = 'r' | 'g' | 'b' | 'a' | 'luminance';
3473
4012
  /**
3474
4013
  * A gradient map (colour ramp): the map is recoloured by looking its
3475
- * {@link channel} up along U of {@link ramp}. See
3476
- * {@link VFXBatchSettings.gradientMap}.
4014
+ * {@link channel} up along U of {@link ramp}. Without a map the lookup reads
4015
+ * white, so the ramp's right-hand end tints every particle, in every render
4016
+ * mode alike. See {@link VFXBatchSettings.gradientMap}.
3477
4017
  */
3478
4018
  interface ParticleGradientMap {
3479
4019
  /**
@@ -3522,8 +4062,11 @@ interface ParticleErosion {
3522
4062
  }
3523
4063
  /** {@link ParticleErosion} as given: any field may be left out, the mask's layout too. */
3524
4064
  type ParticleErosionOptions = Partial<Omit<ParticleErosion, 'maskUV'>> & {
4065
+ /** See {@link ParticleErosion.maskUV}; fields left out take their defaults. */
3525
4066
  maskUV?: Partial<TextureUV>;
3526
4067
  };
4068
+ /** The width of the soft band an erosion cut fades over when `softness` is left out, in mask units. */
4069
+ declare const EROSION_DEFAULT_SOFTNESS = 0.05;
3527
4070
  /** A complete erosion from a partial one, every field defaulted, or undefined when `erosion` is unset. */
3528
4071
  declare function normalizeErosion(erosion: ParticleErosionOptions | null | undefined): ParticleErosion | undefined;
3529
4072
  /** True when both describe the same erosion (or both none). */
@@ -3551,8 +4094,11 @@ interface ParticleUVDistortion {
3551
4094
  }
3552
4095
  /** {@link ParticleUVDistortion} as given: any field may be left out, the noise's layout too. */
3553
4096
  type ParticleUVDistortionOptions = Partial<Omit<ParticleUVDistortion, 'mapUV'>> & {
4097
+ /** See {@link ParticleUVDistortion.mapUV}; fields left out take their defaults. */
3554
4098
  mapUV?: Partial<TextureUV>;
3555
4099
  };
4100
+ /** How far a distortion pushes the map's UV at most when `strength` is left out, in UV units. */
4101
+ declare const UV_DISTORTION_DEFAULT_STRENGTH = 0.05;
3556
4102
  /** A complete distortion from a partial one, or undefined when unset or without a map. */
3557
4103
  declare function normalizeUVDistortion(distortion: ParticleUVDistortionOptions | null | undefined): ParticleUVDistortion | undefined;
3558
4104
  /** True when both describe the same distortion (or both none). */
@@ -3574,31 +4120,58 @@ declare function readsUV1(settings: {
3574
4120
  uvDistortion?: ParticleUVDistortion;
3575
4121
  erosion?: ParticleErosion;
3576
4122
  }): boolean;
4123
+ /**
4124
+ * A batch's copy of the {@link VFXBatchSettings} its systems share: every optional field
4125
+ * defaulted, and every field the batch's render mode ignores at its default (an opaque batch's
4126
+ * `materialBlendMode` reads `ALPHA_DISABLE`, a billboard batch's `rim` is unset). The renderer
4127
+ * adds a system to the batch whose settings match its own.
4128
+ */
3577
4129
  interface StoredBatchSettings {
4130
+ /** See {@link VFXBatchSettings.instancingGeometry}. */
3578
4131
  instancingGeometry: Float32Array;
4132
+ /** See {@link VFXBatchSettings.instancingIndices}. */
3579
4133
  instancingIndices: Uint32Array | Uint16Array;
4134
+ /** See {@link VFXBatchSettings.instancingUVs}. */
3580
4135
  instancingUVs?: Float32Array;
3581
4136
  /** The mesh's second UV set, see {@link UVChannel}. */
3582
4137
  instancingUVs2?: Float32Array;
4138
+ /** See {@link VFXBatchSettings.instancingNormals}. */
3583
4139
  instancingNormals?: Float32Array;
4140
+ /** See {@link VFXBatchSettings.renderMode}. */
3584
4141
  renderMode: RenderMode;
4142
+ /** See {@link VFXBatchSettings.renderOrder}. */
3585
4143
  renderOrder: number;
4144
+ /** See {@link VFXBatchSettings.uTileCount}. */
3586
4145
  uTileCount: number;
4146
+ /** See {@link VFXBatchSettings.vTileCount}. */
3587
4147
  vTileCount: number;
4148
+ /** See {@link VFXBatchSettings.blendTiles}. */
3588
4149
  blendTiles: boolean;
4150
+ /** See {@link VFXBatchSettings.softParticles}. */
3589
4151
  softParticles: boolean;
4152
+ /** See {@link VFXBatchSettings.softNearFade}. */
3590
4153
  softNearFade: number;
4154
+ /** See {@link VFXBatchSettings.softFarFade}. */
3591
4155
  softFarFade: number;
4156
+ /** See {@link VFXBatchSettings.materialBlendMode}. */
3592
4157
  materialBlendMode: number;
4158
+ /** See {@link VFXBatchSettings.materialTransparent}. */
3593
4159
  materialTransparent: boolean;
4160
+ /** See {@link VFXBatchSettings.materialDepthTest}. */
3594
4161
  materialDepthTest: boolean;
4162
+ /** See {@link VFXBatchSettings.materialDepthWrite}. */
3595
4163
  materialDepthWrite: boolean;
4164
+ /** See {@link VFXBatchSettings.materialAlphaTest}. */
3596
4165
  materialAlphaTest: number;
3597
- texture: any;
4166
+ /** See {@link VFXBatchSettings.texture}. */
4167
+ texture: BaseTexture | null;
4168
+ /** See {@link VFXBatchSettings.reflectionTexture}. */
3598
4169
  reflectionTexture: BaseTexture | null;
4170
+ /** See {@link VFXBatchSettings.reflectionLevel}. */
3599
4171
  reflectionLevel: number;
3600
- reflectionFaces: BaseTexture[] | null;
4172
+ /** See {@link VFXBatchSettings.reflectionAtlas}. */
3601
4173
  reflectionAtlas: BaseTexture | null;
4174
+ /** See {@link VFXBatchSettings.layerMask}. */
3602
4175
  layerMask: number;
3603
4176
  /** Babylon rendering group the batch mesh draws in, see {@link VFXBatchSettings.renderingGroupId}. */
3604
4177
  renderingGroupId: number;
@@ -3625,14 +4198,32 @@ interface StoredBatchSettings {
3625
4198
  /** Alpha erosion, see {@link VFXBatchSettings.erosion}. */
3626
4199
  erosion?: ParticleErosion;
3627
4200
  }
4201
+ /**
4202
+ * One draw call of a {@link BatchedRenderer}: the systems that share a material, texture and
4203
+ * geometry, drawn together from one instanced mesh. The renderer makes and frees batches as
4204
+ * systems are added and their settings change; read them through `renderer.batches` to inspect
4205
+ * what is drawn, not to change it.
4206
+ */
3628
4207
  declare abstract class VFXBatch {
4208
+ /** The Babylon mesh the batch draws with. */
3629
4209
  mesh: Mesh;
4210
+ /** The systems drawn by this batch. */
3630
4211
  systems: Set<IParticleSystem>;
4212
+ /** The settings every system in the batch shares, with what the render mode ignores at its default. */
3631
4213
  settings: StoredBatchSettings;
4214
+ /** @internal */
3632
4215
  protected maxParticles: number;
4216
+ /** @internal */
3633
4217
  protected scene: Scene;
4218
+ /** @internal */
3634
4219
  protected readonly visibleSystems: IParticleSystem[];
3635
- protected constructor(settings: VFXBatchSettings, scene: Scene);
4220
+ /**
4221
+ * The depth texture soft particles read, from {@link BatchedRenderer.setDepthTexture}.
4222
+ * @internal
4223
+ */
4224
+ protected depth: DepthBinding | null;
4225
+ /** @internal */
4226
+ protected constructor(settings: VFXBatchSettings, scene: Scene, depth?: DepthBinding | null);
3636
4227
  /**
3637
4228
  * Applies the batch-level scene settings to {@link mesh}. Called on every
3638
4229
  * mesh the batch creates, since the buffers rebuild it.
@@ -3654,12 +4245,17 @@ declare abstract class VFXBatch {
3654
4245
  */
3655
4246
  protected refreshBoundingInfo(): void;
3656
4247
  /**
3657
- * Fog defines and uniforms for a material of this batch, and the per-bind
3658
- * upload of the scene's current fog. Mode 0 (none) when the scene has fog
4248
+ * Writes a uniform that changes per bind, such as one read off the active camera, to the
4249
+ * material for the next bind and to its bound effect for this one: ShaderMaterial uploads its
4250
+ * stored values before the bind observers run, so a value written only to the material would
4251
+ * reach the GPU one draw late, and with two cameras it would always be the other camera's.
4252
+ */
4253
+ protected static writeBound(material: ShaderMaterial, write: (target: ShaderMaterial | Effect) => void): void;
4254
+ /**
4255
+ * The per-bind upload of the scene's current fog. Mode 0 (none) when the scene has fog
3659
4256
  * disabled, so toggling fog at runtime needs no recompile.
4257
+ * @internal
3660
4258
  */
3661
- protected static readonly FOG_UNIFORMS: string[];
3662
- protected fogDefines(): string[];
3663
4259
  protected bindFog(material: ShaderMaterial): void;
3664
4260
  /**
3665
4261
  * Seconds of renderer time, set by the renderer before each fill; what UV
@@ -3668,13 +4264,26 @@ declare abstract class VFXBatch {
3668
4264
  time: number;
3669
4265
  /** True when a texture effect of this batch samples UV channel 1, see {@link UVChannel}. */
3670
4266
  protected usesUV1(): boolean;
3671
- /** Defines of the texture effects (see `shaders/chunks/surface.ts`) this batch uses. */
3672
- protected surfaceDefines(): string[];
3673
- /** Adds the uniforms and samplers of the texture effects this batch uses. */
3674
- protected surfaceUniforms(uniforms: string[], samplers: string[]): void;
3675
4267
  /** Sets the texture effects' textures and constants, and advances their scrolling on every bind. */
3676
4268
  protected bindSurface(material: ShaderMaterial): void;
4269
+ /** Writes the texture effects' constants (the uniforms their live parameters set). */
4270
+ private writeSurfaceParams;
4271
+ /**
4272
+ * Takes new live parameters (see {@link BatchedRenderer.updateSystem}): settings with the same
4273
+ * shader key as the batch's, whose uniform values differ. They are copied into the batch's
4274
+ * settings and written to its material, which is kept.
4275
+ * @internal
4276
+ */
4277
+ applyLiveSettings(settings: StoredBatchSettings): void;
4278
+ /**
4279
+ * Writes every uniform a live parameter sets, from the batch's settings. The base writes the
4280
+ * ones every render mode has; a mode adds its own.
4281
+ * @internal
4282
+ */
4283
+ protected writeLiveUniforms(material: ShaderMaterial): void;
4284
+ /** @internal */
3677
4285
  addSystem(system: IParticleSystem): void;
4286
+ /** @internal */
3678
4287
  removeSystem(system: IParticleSystem): void;
3679
4288
  /**
3680
4289
  * Visible systems of this batch, written into a buffer owned by the batch.
@@ -3682,56 +4291,115 @@ declare abstract class VFXBatch {
3682
4291
  * reallocated; treat it as valid only until the next call.
3683
4292
  */
3684
4293
  getVisibleSystems(): IParticleSystem[];
3685
- applyDepthTexture(depthTexture: BaseTexture | null): void;
3686
- /** Sets the light `'fixed'` mesh particles are lit by. Batches that draw no meshes ignore it. */
4294
+ /**
4295
+ * Sets the depth texture soft particles read. Soft particles are compiled in only while there
4296
+ * is one, as Unity turns them off for a camera without a depth texture, so attaching or
4297
+ * removing it, or changing how it is packed, rebuilds a soft batch's material.
4298
+ *
4299
+ * @param depth - The binding, or a bare texture, read as `'linear'` and unpacked.
4300
+ * @internal Use {@link BatchedRenderer.setDepthTexture}.
4301
+ */
4302
+ applyDepthTexture(depth: DepthBinding | BaseTexture | null): void;
4303
+ /**
4304
+ * Sets the soft-particle and alpha-test values on a material, and decodes the depth for the
4305
+ * camera of each draw.
4306
+ */
4307
+ protected bindSoft(material: ShaderMaterial): void;
4308
+ /** Writes the soft-particle fade and the alpha cutoff, the live parameters every mode shares. */
4309
+ private writeSoftParams;
4310
+ /** True when this batch draws soft particles: they are on and a depth texture is attached. */
4311
+ protected drawsSoft(): boolean;
4312
+ /**
4313
+ * Sets the light `'fixed'` mesh particles are lit by. Batches that draw no meshes ignore it.
4314
+ * @internal Use {@link BatchedRenderer.setMeshLighting}.
4315
+ */
3687
4316
  applyMeshLighting(_lighting: MeshLightingSettings): void;
4317
+ /** @internal */
3688
4318
  abstract setupBuffers(): void;
4319
+ /** @internal */
3689
4320
  abstract expandBuffers(target: number): void;
4321
+ /** @internal */
3690
4322
  abstract rebuildMaterial(): void;
4323
+ /** @internal */
3691
4324
  abstract update(): void;
4325
+ /** @internal */
3692
4326
  dispose(): void;
3693
4327
  }
3694
4328
 
4329
+ /**
4330
+ * Everything about a system that decides how it is drawn: {@link ParticleSystem.getRendererSettings}
4331
+ * returns it, and the renderer draws systems whose settings match from one batch. Only the
4332
+ * settings a render mode reads count: two billboards that differ in a mesh-only setting, such as
4333
+ * `rim`, share a batch.
4334
+ *
4335
+ * A batch is one draw with one material, so its settings fall into two groups, as a Unity
4336
+ * material's keywords and texture slots against its MaterialPropertyBlock values, or an Unreal
4337
+ * material against a dynamic material instance's parameters. The shader key (render mode,
4338
+ * geometry, textures, blend and depth state, and which effects are on) decides the material.
4339
+ * The live parameters (the fade distances, alpha cutoff, pivot, size limits, reflection level,
4340
+ * rim colour, each effect's numbers, and each texture's tiling, offset and scroll) are uniforms:
4341
+ * changing one on a system that is alone in its batch writes the material in place, with no new
4342
+ * batch or material. A texture's UV channel is part of the shader key, so changing it rebuilds.
4343
+ *
4344
+ * Prefer the system's own setters, which also move it to a matching batch; after changing a
4345
+ * field directly, set {@link ParticleSystem.neededToUpdateRender}.
4346
+ */
3695
4347
  interface VFXBatchSettings {
4348
+ /** Mesh particles' vertex positions, see {@link ParticleSystem.instancingGeometry}. A quad for other modes. */
3696
4349
  instancingGeometry: Float32Array;
4350
+ /** Triangle indices into {@link instancingGeometry}. */
3697
4351
  instancingIndices: Uint32Array | Uint16Array;
4352
+ /** The mesh's first UV set, two values per vertex. */
3698
4353
  instancingUVs?: Float32Array;
3699
4354
  /** The mesh's second UV set, see {@link UVChannel}. */
3700
4355
  instancingUVs2?: Float32Array;
4356
+ /** The mesh's vertex normals; mesh particles fall back to +Z. */
3701
4357
  instancingNormals?: Float32Array;
4358
+ /** See {@link ParticleSystem.renderMode}. */
3702
4359
  renderMode: RenderMode;
4360
+ /** See {@link ParticleSystem.renderOrder}. */
3703
4361
  renderOrder: number;
4362
+ /** See {@link ParticleSystem.uTileCount}. */
3704
4363
  uTileCount: number;
4364
+ /** See {@link ParticleSystem.vTileCount}. */
3705
4365
  vTileCount: number;
4366
+ /** See {@link ParticleSystem.blendTiles}; read with a sheet, and not by trails. */
3706
4367
  blendTiles: boolean;
4368
+ /** See {@link ParticleSystem.softParticles}. */
3707
4369
  softParticles: boolean;
4370
+ /** See {@link ParticleSystem.softNearFade}. */
3708
4371
  softNearFade: number;
4372
+ /** See {@link ParticleSystem.softFarFade}. */
3709
4373
  softFarFade: number;
4374
+ /** Babylon alpha mode, see {@link ParticleSystem.blending}. */
3710
4375
  materialBlendMode: number;
4376
+ /** Whether the batch draws in the transparent pass. */
3711
4377
  materialTransparent: boolean;
4378
+ /** Whether particles are hidden behind nearer geometry. */
3712
4379
  materialDepthTest: boolean;
4380
+ /** Whether particles write depth. */
3713
4381
  materialDepthWrite: boolean;
4382
+ /** Alpha below which a fragment is discarded; 0 discards nothing. */
3714
4383
  materialAlphaTest: number;
4384
+ /** See {@link ParticleSystem.texture}. */
3715
4385
  texture: Texture | null;
3716
4386
  /**
3717
- * Cubemap (or other reflection texture) harvested from a Babylon material's
3718
- * `reflectionTexture`. Mesh batches sample it like StandardMaterial cubic
3719
- * reflection; other render modes ignore it.
4387
+ * The reflection a mesh particle's material carries (a Babylon material's `reflectionTexture`
4388
+ * or `environmentTexture`). It is not sampled itself: a cube texture is unfolded into
4389
+ * {@link reflectionAtlas} once it has loaded and sampled from there; anything else is kept
4390
+ * only to tell materials apart. Other render modes ignore it.
3720
4391
  */
3721
4392
  reflectionTexture: BaseTexture | null;
3722
4393
  /** Multiplier for the reflection sample — mirrors `texture.level`. */
3723
4394
  reflectionLevel: number;
3724
4395
  /**
3725
- * Optional six cube-face 2D textures (px,py,pz,nx,ny,nz). Prefer
3726
- * `reflectionAtlas` on iOS — many simultaneous face samplers still trip
3727
- * GL_INVALID_OPERATION on WebKit.
3728
- */
3729
- reflectionFaces: BaseTexture[] | null;
3730
- /**
3731
- * Single 3×2 atlas of cube faces (px py pz / nx ny nz). One sampler2D —
3732
- * the path that stays valid on iOS WebKit ShaderMaterial draws.
4396
+ * A 3×2 atlas of cube faces (+X +Y +Z over -X -Y -Z) that mesh particles reflect, through one
4397
+ * `sampler2D`: the path that stays valid on iOS WebKit ShaderMaterial draws, where a
4398
+ * `samplerCube` or six face samplers raise GL_INVALID_OPERATION. Built from
4399
+ * {@link reflectionTexture} when that is a cube texture. Other render modes ignore it.
3733
4400
  */
3734
4401
  reflectionAtlas: BaseTexture | null;
4402
+ /** Camera layer mask of the batch mesh, see {@link ParticleSystem.layers}. */
3735
4403
  layerMask: number;
3736
4404
  /**
3737
4405
  * Babylon rendering group (`mesh.renderingGroupId`) the batch draws in,
@@ -3740,8 +4408,11 @@ interface VFXBatchSettings {
3740
4408
  renderingGroupId: number;
3741
4409
  /**
3742
4410
  * Whether the scene's fog applies to the particles, as it does to any other
3743
- * mesh; true by default. Additive particles fade toward black rather than
3744
- * the fog colour. Systems that differ are batched apart.
4411
+ * mesh; true by default. Particles that add to the frame (`ALPHA_ADD`,
4412
+ * `ALPHA_ONEONE`) fade toward black rather than the fog colour, which would
4413
+ * fog the whole screen; every other blend mode mixes toward the fog colour,
4414
+ * which is right for alpha blending and only approximate for a multiply or
4415
+ * subtract. Systems that differ are batched apart.
3745
4416
  */
3746
4417
  applyFog: boolean;
3747
4418
  /**
@@ -3782,24 +4453,61 @@ interface VFXBatchSettings {
3782
4453
  /** Alpha erosion (dissolve / wipe), see {@link ParticleErosion}. Unset: none. Systems that differ are batched apart. */
3783
4454
  erosion?: ParticleErosion;
3784
4455
  }
4456
+ /**
4457
+ * How {@link BatchedRenderer.configureAdaptivePerformance} trades particles for frame time: each
4458
+ * update that runs over `targetFrameMs` lowers every system's quality factor (see
4459
+ * {@link ParticleSystem.setQualityFactor}) by `decreaseStep`, each one under it raises the factor
4460
+ * by `increaseStep`, within `minQuality` and `maxQuality`.
4461
+ */
3785
4462
  interface AdaptivePerformanceOptions {
4463
+ /** CPU time in milliseconds the renderer's update may take before quality drops. Default 16.7. */
3786
4464
  targetFrameMs: number;
4465
+ /** Lowest quality factor, 0.1 to 1 ({@link ParticleSystem.setQualityFactor} clamps lower values). Default 0.35. */
3787
4466
  minQuality: number;
4467
+ /** Highest quality factor, `minQuality` to 1. Default 1. */
3788
4468
  maxQuality: number;
4469
+ /** Quality lost per update over budget. Default 0.08. */
3789
4470
  decreaseStep: number;
4471
+ /** Quality regained per update within budget. Default 0.02. */
3790
4472
  increaseStep: number;
3791
4473
  }
4474
+ /** A snapshot of the renderer's adaptive performance, from {@link BatchedRenderer.getAdaptivePerformanceState}. */
3792
4475
  interface AdaptivePerformanceState extends AdaptivePerformanceOptions {
4476
+ /** Whether adaptive performance is on. */
3793
4477
  enabled: boolean;
4478
+ /** The quality factor the systems run at now. */
3794
4479
  currentQuality: number;
4480
+ /** CPU time the last measured update took, in milliseconds; kept from the last update while off. */
3795
4481
  lastFrameCpuMs: number;
3796
4482
  }
4483
+ /**
4484
+ * Draws particle systems, batching the ones that draw alike into one instanced mesh each, and
4485
+ * advances them every frame. It is a node in the scene; make one per scene, add each system with
4486
+ * {@link addSystem}, and call {@link update} once per frame:
4487
+ *
4488
+ * ```ts
4489
+ * const renderer = new BatchedRenderer('particles', scene);
4490
+ * renderer.addSystem(system);
4491
+ * scene.onBeforeRenderObservable.add(() => renderer.update(scene.getEngine().getDeltaTime() / 1000));
4492
+ * ```
4493
+ *
4494
+ * Systems step on a fixed 60 Hz clock, so an effect plays out the same at any frame rate.
4495
+ *
4496
+ * The renderer is a node so the batches have a parent to live under; leave it at the origin,
4497
+ * unturned and unscaled. Particles are placed in the world by their emitters, and a transform on
4498
+ * the renderer would move every one of them again (it warns once when it finds one). A system
4499
+ * belongs to one renderer at a time: adding it to another takes it out of the first.
4500
+ */
3797
4501
  declare class BatchedRenderer extends TransformNode {
4502
+ /** Whether the renderer has warned about its own transform; see the class description. */
4503
+ private warnedAboutTransform;
4504
+ /** The batches, one draw each. Read to inspect what is drawn; the renderer owns them. */
3798
4505
  batches: Array<VFXBatch>;
3799
4506
  /** Seconds this renderer has been updated for; the clock UV and erosion scrolling run on. */
3800
4507
  private elapsed;
4508
+ /** Index into {@link batches} of each system's batch. The renderer owns it. */
3801
4509
  systemToBatchIndex: Map<IParticleSystem, number>;
3802
- depthTexture: BaseTexture | null;
4510
+ private depth;
3803
4511
  /** Systems in insertion order — iterated every frame, unlike the map. */
3804
4512
  private systems;
3805
4513
  /**
@@ -3864,19 +4572,47 @@ declare class BatchedRenderer extends TransformNode {
3864
4572
  */
3865
4573
  private isSystemInView;
3866
4574
  private static clamp;
3867
- private static equals;
4575
+ /**
4576
+ * Starts drawing and updating `system`, in the batch whose settings match its own (a new one if
4577
+ * none does). Add each system of an effect, or use `QuarksUtil.addToBatchRenderer` on its root.
4578
+ */
3868
4579
  addSystem(system: IParticleSystem): void;
3869
4580
  /** Places a system into a compatible batch, creating one when none matches. */
3870
4581
  private assignToBatch;
4582
+ /**
4583
+ * Stops drawing and updating `system`; disposing the system calls it. Its particles are left as they are.
4584
+ * @returns Whether the system was in one of this renderer's batches.
4585
+ */
3871
4586
  deleteSystem(system: IParticleSystem): boolean;
3872
4587
  /** Detaches a system from its batch, leaving the renderer's system list alone. */
3873
4588
  private removeFromBatch;
3874
4589
  /**
3875
- * Re-buckets a system whose render settings changed. The system keeps its
3876
- * place in the update order, so this is safe to call mid-frame.
4590
+ * Takes a system's changed render settings. When only live parameters changed (see
4591
+ * {@link VFXBatchSettings}) and the system is alone in its batch, the batch's material is
4592
+ * written in place. Otherwise the system moves to the batch its settings now match. The
4593
+ * system keeps its place in the update order, so this is safe to call mid-frame.
3877
4594
  */
3878
4595
  updateSystem(system: IParticleSystem): void;
3879
- setDepthTexture(depthTexture: BaseTexture | null): void;
4596
+ /**
4597
+ * Sets the scene depth that soft particles fade against. Without one, soft particles are not
4598
+ * compiled in and draw hard, as Unity does for a camera with no depth texture.
4599
+ *
4600
+ * Pass the `DepthRenderer` itself to have its encoding read off it, for example
4601
+ * `renderer.setDepthTexture(scene.enableDepthRenderer(camera))`. A bare texture is read as
4602
+ * Babylon's default `'linear'` metric unless `options.encoding` says otherwise; see
4603
+ * {@link SoftDepthEncoding}. The depth should be drawn by the camera that draws the particles.
4604
+ * The texture is held, not the renderer: set it again if the `DepthRenderer` is disposed or
4605
+ * replaced.
4606
+ *
4607
+ * @param depth - A depth texture, a Babylon `DepthRenderer`, or null to turn soft particles off.
4608
+ * @param options - What the texture stores, when it cannot be read off a `DepthRenderer`.
4609
+ */
4610
+ setDepthTexture(depth: BaseTexture | DepthRenderer | null, options?: DepthTextureOptions): void;
4611
+ /** The depth texture soft particles fade against, see {@link setDepthTexture}. */
4612
+ get depthTexture(): BaseTexture | null;
4613
+ set depthTexture(texture: BaseTexture | null);
4614
+ /** What the depth texture stores, see {@link setDepthTexture}. */
4615
+ get depthEncoding(): SoftDepthEncoding | null;
3880
4616
  /**
3881
4617
  * Sets the light mesh particles with `lighting: 'fixed'` (the default) are
3882
4618
  * lit by, for every mesh batch of this renderer, including ones created
@@ -3891,8 +4627,15 @@ declare class BatchedRenderer extends TransformNode {
3891
4627
  setMeshLighting(lighting: Partial<MeshLightingSettings>): void;
3892
4628
  /** A copy of the light set with {@link setMeshLighting}. */
3893
4629
  getMeshLighting(): MeshLightingSettings;
4630
+ /**
4631
+ * Turns on adaptive performance: the renderer measures its own update and thins every system's
4632
+ * emission while it runs over budget, see {@link AdaptivePerformanceOptions}. Options left out
4633
+ * keep their current values.
4634
+ */
3894
4635
  configureAdaptivePerformance(options?: Partial<AdaptivePerformanceOptions>): void;
4636
+ /** Turns adaptive performance off, and by default puts every system back at `maxQuality`. */
3895
4637
  disableAdaptivePerformance(resetQuality?: boolean): void;
4638
+ /** A copy of the adaptive performance settings and the current quality. */
3896
4639
  getAdaptivePerformanceState(): AdaptivePerformanceState;
3897
4640
  private applyAdaptiveQuality;
3898
4641
  /** @internal Called when a system's behaviors change, which can add a sub emitter. */
@@ -3906,6 +4649,11 @@ declare class BatchedRenderer extends TransformNode {
3906
4649
  * cannot be satisfied by any order; it is left as found rather than dropped.
3907
4650
  */
3908
4651
  private orderSystems;
4652
+ /**
4653
+ * Advances every visible system by `delta` seconds and refills the batches. Call it once per
4654
+ * frame. A system whose emitter is disabled is frozen; one no camera sees pauses if its
4655
+ * {@link ParticleSystem.cullingMode} says so.
4656
+ */
3909
4657
  update(delta: number): void;
3910
4658
  /** Rebuild instance buffers from current particle state without advancing simulation. */
3911
4659
  refreshBatches(): void;
@@ -3913,17 +4661,25 @@ declare class BatchedRenderer extends TransformNode {
3913
4661
  private removeBatch;
3914
4662
  /** Per-batch particle vs GPU instance counts — for diagnosing stale render state. */
3915
4663
  getBatchRenderStats(): Array<{
4664
+ /** Index into {@link batches}. */
3916
4665
  batchIndex: number;
4666
+ /** The batch's render mode. */
3917
4667
  renderMode: RenderMode;
4668
+ /** Instances the batch mesh draws. */
3918
4669
  instanceCount: number;
4670
+ /** Live particles of the batch's systems. */
3919
4671
  particleCount: number;
4672
+ /** The emitter names of the batch's systems. */
3920
4673
  systemNames: string[];
3921
4674
  }>;
4675
+ /**
4676
+ * Disposes the batches and their meshes and materials, and lets the systems go: they keep
4677
+ * their particles and can be added to another renderer. The renderer cannot be used again.
4678
+ */
3922
4679
  dispose(): void;
3923
4680
  }
3924
4681
 
3925
- declare const BatchedParticleRenderer: typeof BatchedRenderer;
3926
-
4682
+ /** Options for a new {@link EffectPool}. */
3927
4683
  interface EffectPoolOptions {
3928
4684
  /** The renderer every copy the pool makes is added to. */
3929
4685
  renderer: BatchedRenderer;
@@ -3983,33 +4739,53 @@ declare class EffectPool {
3983
4739
 
3984
4740
  /** Reads the six face URLs from a Babylon CubeTexture (px py pz nx ny nz). */
3985
4741
  declare function cubeFaceUrls(reflection: BaseTexture | null | undefined): string[] | null;
3986
- /** Returns a previously built atlas for this cube, if any. */
3987
- declare function getCachedEnvAtlas(cube: BaseTexture): Texture | null;
3988
- /** Stores an atlas for a cube source (tests / prebuilt atlases). */
4742
+ /**
4743
+ * Returns the atlas already built or cached for this cube in `scene`, if any.
4744
+ *
4745
+ * @param cube - The cube texture the atlas was made from.
4746
+ * @param scene - The scene the atlas must belong to. Defaults to the cube's own scene.
4747
+ */
4748
+ declare function getCachedEnvAtlas(cube: BaseTexture, scene?: Scene | null): Texture | null;
4749
+ /**
4750
+ * Stores a prebuilt atlas for a cube in the atlas's scene, so systems that use the cube in that
4751
+ * scene take it instead of building one. The atlas stays the caller's: quarks never disposes it,
4752
+ * and drops it from the cache when it, or the cube, is disposed.
4753
+ *
4754
+ * @param cube - The cube texture the atlas stands in for.
4755
+ * @param atlas - A 3×2 atlas in the layout of {@link createEnvAtlasFromFaceUrls}.
4756
+ */
3989
4757
  declare function cacheEnvAtlas(cube: BaseTexture, atlas: Texture): void;
4758
+ /**
4759
+ * Drops the atlases made for `cube` from the cache and disposes the ones quarks built. Runs by
4760
+ * itself when the cube is disposed; call it when an environment is swapped out but the cube is
4761
+ * kept. Systems that use the cube build a new atlas the next time their material is resolved.
4762
+ *
4763
+ * @param cube - The cube texture whose atlases to drop.
4764
+ * @param scene - Only the atlas for this scene. Defaults to every scene.
4765
+ */
4766
+ declare function disposeEnvAtlas(cube: BaseTexture, scene?: Scene): void;
3990
4767
  /**
3991
4768
  * Packs six cube-face images into one 3×2 atlas Texture (px py pz / nx ny nz).
3992
4769
  * Uses invertY:false so UV cellY=0 maps to the +faces row matching the shader.
3993
4770
  */
3994
4771
  declare function createEnvAtlasFromFaceUrls(urls: string[], scene: Scene): Promise<Texture>;
3995
4772
  /**
3996
- * Ensures a 3×2 env atlas exists for a CubeTexture. Returns a cached atlas
3997
- * synchronously when available; otherwise starts (or joins) an async build and
3998
- * invokes onReady when the atlas is usable.
4773
+ * Ensures a 3×2 env atlas exists for a CubeTexture in `scene`. Returns a cached atlas
4774
+ * synchronously when available; otherwise starts (or joins) an async build and invokes onReady
4775
+ * when the atlas is usable. A cube disposed before its build finishes gets no atlas.
3999
4776
  */
4000
4777
  declare function ensureEnvAtlasFromCube(cube: BaseTexture, scene: Scene, onReady: (atlas: Texture) => void): Texture | null;
4001
4778
 
4002
- type BabylonParticleMaterialParameters = Record<string, any>;
4003
- declare class ParticleMeshStandardMaterial extends StandardMaterial {
4004
- readonly isParticleMeshStandardMaterial = true;
4005
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
4006
- }
4007
- declare class ParticleMeshPhysicsMaterial extends PBRMaterial {
4008
- readonly isParticleMeshPhysicsMaterial = true;
4009
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
4010
- }
4011
-
4779
+ /**
4780
+ * Emits from the surface of a Babylon mesh (Unity's Shape: Mesh, Unreal's Skeletal/Static Mesh
4781
+ * Location): a point picked at random over the triangles, weighted by their area, moving along the
4782
+ * triangle's normal at the particle's start speed. The mesh's vertices are read once, when it is
4783
+ * set, in the mesh's own space, and laid in the emitter's space as they are, moved by
4784
+ * {@link transform}; moving the mesh node afterwards does not move the shape. A shape without a
4785
+ * mesh emits from the origin along +Z.
4786
+ */
4012
4787
  declare class MeshSurfaceEmitter implements EmitterShape {
4788
+ /** The shape's type in effect files. */
4013
4789
  type: string;
4014
4790
  private _triangleIndexToArea;
4015
4791
  private _mesh?;
@@ -4018,18 +4794,45 @@ declare class MeshSurfaceEmitter implements EmitterShape {
4018
4794
  private _meshReferenceId?;
4019
4795
  /** Offset, rotation and scale of the mesh within the particle system. */
4020
4796
  transform?: ShapeTransform;
4797
+ /** The mesh emitted from. Setting it reads its positions and indices; a mesh without both emits from the origin. */
4021
4798
  get mesh(): Mesh | undefined;
4022
4799
  set mesh(mesh: Mesh | undefined);
4800
+ /**
4801
+ * @param mesh The mesh to emit from.
4802
+ * @param meshReferenceId The id of a mesh node in the effect file, kept until the loader links it.
4803
+ * @param transform Offset, rotation and scale of the mesh within the system.
4804
+ */
4023
4805
  constructor(mesh?: Mesh, meshReferenceId?: string, transform?: ShapeTransform);
4806
+ /** Places a new particle on the surface and sets its velocity along the triangle's normal. */
4024
4807
  initialize(p: Particle): void;
4808
+ /** The shape in effect-file form; the mesh is written as its node id. */
4025
4809
  toJSON(): ShapeJSON;
4810
+ /** Reads {@link toJSON} output; the mesh stays an id until `QuarksLoader` links it. */
4026
4811
  static fromJSON(json: any): MeshSurfaceEmitter;
4812
+ /** A copy emitting from the same mesh. */
4027
4813
  clone(): EmitterShape;
4814
+ /** Does nothing: the shape keeps no state between steps. */
4028
4815
  update(_system: IParticleSystem, _delta: number): void;
4029
4816
  }
4817
+ /** Registers {@link MeshSurfaceEmitter} with quarks.core's shape table; loaded when the package is imported. */
4030
4818
  declare const MeshSurfaceEmitterPlugin: Plugin;
4031
4819
 
4820
+ /**
4821
+ * The id an effect file knows a node by: the uuid it was loaded under, or, for a node made in code,
4822
+ * a GUID given to it the first time it is asked for and kept from then on. Every link written into
4823
+ * a file (a sub emitter's target, a mesh surface shape's mesh, a prefab animation's target) and
4824
+ * every node's own `uuid` use this, so an effect loaded, saved and loaded again keeps its links,
4825
+ * and a node made in code never takes the id of one loaded from a file.
4826
+ */
4827
+ declare function quarksNodeId(node: object): string;
4828
+
4829
+ /**
4830
+ * The Babylon node a particle system lives at: its position, rotation and scale place the system,
4831
+ * parenting it moves the effect with another node, and disabling it freezes and hides the system.
4832
+ * Every {@link ParticleSystem} makes its own, as `system.emitter`.
4833
+ */
4032
4834
  declare class ParticleEmitter extends TransformNode {
4835
+ /** The particle system this node carries. */
4033
4836
  system: IParticleSystem;
4034
4837
  private _matrixWorld;
4035
4838
  private _matrixWorldFlag;
@@ -4039,21 +4842,45 @@ declare class ParticleEmitter extends TransformNode {
4039
4842
  * `updateFlag`), so repeated reads inside a frame are free.
4040
4843
  */
4041
4844
  get matrixWorld(): Matrix4;
4845
+ /** Whether the node and its parents are enabled; setting it is `setEnabled`. */
4042
4846
  get visible(): boolean;
4043
4847
  set visible(value: boolean);
4848
+ /** The id effect files know this emitter by; see {@link quarksNodeId}. */
4044
4849
  get uuid(): string;
4045
4850
  constructor(system: IParticleSystem, scene?: Scene);
4046
- dispose(): void;
4047
- extractFromCache(cache: any): any[];
4851
+ /**
4852
+ * Disposes the node and the particle system it carries, so `root.dispose()` on an effect tree
4853
+ * also removes its systems from their renderer. Safe to call more than once. When a system
4854
+ * disposes its own emitter (`ParticleSystem.dispose()`, `autoDestroy`), the systems of child
4855
+ * emitters keep playing until they finish or are disposed themselves.
4856
+ */
4857
+ dispose(doNotRecurse?: boolean, disposeMaterialAndTextures?: boolean): void;
4048
4858
  clone(name?: string): ParticleEmitter;
4859
+ /** The node and its system in effect-file form; `serializeEffect` writes whole effects. @internal */
4049
4860
  toJSON(meta?: any, options?: SerializationOptions): any;
4050
4861
  }
4051
4862
 
4863
+ /**
4864
+ * One burst of a system's emission (Unity's Emission Bursts): `count` particles at `time` seconds
4865
+ * into each loop, repeated `cycle` times `interval` seconds apart, each wave with the chance
4866
+ * `probability`. A burst given to the constructor or read from a file is normalised (a missing
4867
+ * `interval` is 0.1 s, `probability` is kept to 0..1, `cycle` to at least 1) and the bursts are
4868
+ * kept in time order.
4869
+ */
4052
4870
  interface BurstParameters {
4871
+ /** Seconds into the system's duration the first wave fires at. */
4053
4872
  time: number;
4873
+ /**
4874
+ * Particles each wave spawns. The generator is rolled when the system plays or restarts, so
4875
+ * a random count is the same for every loop of one play; a curve is read at the wave's time
4876
+ * as a fraction of the duration, 0 to 1, like the start curves.
4877
+ */
4054
4878
  count: ValueGenerator | FunctionValueGenerator;
4879
+ /** How many waves the burst fires, at least 1. */
4055
4880
  cycle: number;
4881
+ /** Seconds between waves; 0 fires them all at once. 0.1 when left out. */
4056
4882
  interval: number;
4883
+ /** Chance from 0 to 1 that a wave spawns at all, rolled per wave. */
4057
4884
  probability: number;
4058
4885
  }
4059
4886
  /**
@@ -4092,38 +4919,69 @@ type ScalingMode = 'shape' | 'hierarchy';
4092
4919
  * every frame.
4093
4920
  */
4094
4921
  type BeamEnd = {
4922
+ /** World x. */
4095
4923
  x: number;
4924
+ /** World y. */
4096
4925
  y: number;
4926
+ /** World z. */
4097
4927
  z: number;
4098
4928
  } | {
4929
+ /** The world position, read every frame. */
4099
4930
  getAbsolutePosition(): {
4931
+ /** World x. */
4100
4932
  x: number;
4933
+ /** World y. */
4101
4934
  y: number;
4935
+ /** World z. */
4102
4936
  z: number;
4103
4937
  };
4104
4938
  };
4939
+ /**
4940
+ * Settings for a new {@link ParticleSystem}. Every one is optional: a setting left out takes the
4941
+ * default named on it, the same default `fromJSON` gives a file that leaves it out.
4942
+ */
4105
4943
  interface ParticleSystemParameters {
4944
+ /** See {@link ParticleSystem.autoDestroy}. Default false. */
4106
4945
  autoDestroy?: boolean;
4946
+ /** See {@link ParticleSystem.looping}. Default true. */
4107
4947
  looping?: boolean;
4948
+ /** See {@link ParticleSystem.prewarm}. Default false. */
4108
4949
  prewarm?: boolean;
4950
+ /** See {@link ParticleSystem.prewarmTime}. Default 0: a whole cycle; only with `prewarm` on a looping system. */
4951
+ prewarmTime?: number;
4952
+ /** See {@link ParticleSystem.duration}. Default 1 second. */
4109
4953
  duration?: number;
4954
+ /** See {@link ParticleSystem.startDelay}. Default 0. */
4110
4955
  startDelay?: ValueGenerator | FunctionValueGenerator;
4956
+ /** Where particles are born and which way they start, see {@link ParticleSystem.emitterShape}. Default a `SphereEmitter`. */
4111
4957
  shape?: EmitterShape;
4958
+ /** See {@link ParticleSystem.startLife}. Default 5 seconds. */
4112
4959
  startLife?: ValueGenerator | FunctionValueGenerator;
4960
+ /** See {@link ParticleSystem.startSpeed}. Default 0. */
4113
4961
  startSpeed?: ValueGenerator | FunctionValueGenerator;
4962
+ /** See {@link ParticleSystem.startRotation}. Default 0. */
4114
4963
  startRotation?: ValueGenerator | FunctionValueGenerator | RotationGenerator;
4964
+ /** See {@link ParticleSystem.startSize}. Default 1. */
4115
4965
  startSize?: ValueGenerator | FunctionValueGenerator | Vector3Generator;
4116
- startLength?: ValueGenerator | FunctionValueGenerator;
4966
+ /** See {@link ParticleSystem.startColor}. Default opaque white. */
4117
4967
  startColor?: ColorGenerator | FunctionColorGenerator;
4968
+ /** See {@link ParticleSystem.emissionOverTime}. Default 10 per second. */
4118
4969
  emissionOverTime?: ValueGenerator | FunctionValueGenerator;
4970
+ /** See {@link ParticleSystem.emissionOverDistance}. Default 0. */
4119
4971
  emissionOverDistance?: ValueGenerator | FunctionValueGenerator;
4972
+ /** See {@link ParticleSystem.emissionBursts}. Default none. */
4120
4973
  emissionBursts?: Array<BurstParameters>;
4121
4974
  /** Most particles alive at once; emission past it is dropped. Leave unset for no limit. */
4122
4975
  maxParticles?: number;
4976
+ /** See {@link ParticleSystem.onlyUsedByOther}. Default false. */
4123
4977
  onlyUsedByOther?: boolean;
4978
+ /** See {@link ParticleSystem.behaviors}. Default none. */
4124
4979
  behaviors?: Array<Behavior>;
4980
+ /** Mesh particles' vertex positions, three values per vertex. Default a unit quad in XY. */
4125
4981
  instancingGeometry?: Float32Array;
4982
+ /** Triangle indices into {@link instancingGeometry}. Default the unit quad's two triangles. */
4126
4983
  instancingIndices?: Uint32Array | Uint16Array;
4984
+ /** Mesh particles' first UV set, two values per vertex. Default the quad's UVs, or zeros for another geometry. */
4127
4985
  instancingUVs?: Float32Array;
4128
4986
  /**
4129
4987
  * A second UV set for the mesh (glTF `TEXCOORD_1`, Unity's `uv2`), what
@@ -4131,26 +4989,55 @@ interface ParticleSystemParameters {
4131
4989
  * Default none: channel 1 reads the first set.
4132
4990
  */
4133
4991
  instancingUVs2?: Float32Array;
4992
+ /** Mesh particles' vertex normals, three values per vertex. Default +Z for every vertex. */
4134
4993
  instancingNormals?: Float32Array;
4994
+ /** See {@link ParticleSystem.renderMode}. Default `RenderMode.BillBoard`. */
4135
4995
  renderMode?: RenderMode;
4996
+ /** See {@link ParticleSystem.rendererEmitterSettings}. Default the render mode's own. */
4136
4997
  rendererEmitterSettings?: RendererEmitterSettings;
4998
+ /** @deprecated Set `speedFactor` in {@link rendererEmitterSettings} instead; this one wins when both are set. */
4137
4999
  speedFactor?: number;
4138
- material?: any;
5000
+ /** See {@link ParticleSystem.material}. Default none. */
5001
+ material?: unknown;
5002
+ /** See {@link ParticleSystem.texture}. Unset takes the material's texture; null draws without one. */
4139
5003
  texture?: Texture | null;
5004
+ /** See {@link ParticleSystem.startTileIndex}. Default 0. */
4140
5005
  startTileIndex?: ValueGenerator;
5006
+ /** See {@link ParticleSystem.uTileCount}. Default 1. */
4141
5007
  uTileCount?: number;
5008
+ /** See {@link ParticleSystem.vTileCount}. Default 1. */
4142
5009
  vTileCount?: number;
5010
+ /** See {@link ParticleSystem.blendTiles}. Default false. */
4143
5011
  blendTiles?: boolean;
5012
+ /**
5013
+ * Fade particles out as they near the scene behind them, like Unity's Soft Particles and
5014
+ * Unreal's Depth Fade, between `softNearFade` and `softFarFade` world units. Needs a depth
5015
+ * texture, see `BatchedRenderer.setDepthTexture`; without one particles draw hard. Applies to
5016
+ * every render mode: billboard, stretched, mesh, beam and trail.
5017
+ */
4144
5018
  softParticles?: boolean;
5019
+ /** See {@link ParticleSystem.softFarFade}. Default 1. */
4145
5020
  softFarFade?: number;
5021
+ /** See {@link ParticleSystem.softNearFade}. Default 0. */
4146
5022
  softNearFade?: number;
5023
+ /** See {@link ParticleSystem.renderOrder}. Default 0. */
4147
5024
  renderOrder?: number;
5025
+ /** See {@link ParticleSystem.worldSpace}. Default false. */
4148
5026
  worldSpace?: boolean;
5027
+ /** Babylon alpha mode the batch blends with, see {@link ParticleSystem.blending}. Default `Constants.ALPHA_ADD`. */
4149
5028
  blendMode?: number;
5029
+ /** Whether the batch draws in the transparent pass. Default true. */
4150
5030
  transparent?: boolean;
5031
+ /**
5032
+ * Whether particles are hidden behind nearer geometry. `false` draws them over everything
5033
+ * (Unity's `ZTest Always`), in every render mode. Default `true`.
5034
+ */
4151
5035
  depthTest?: boolean;
5036
+ /** Whether the particles write depth. Default false. */
4152
5037
  depthWrite?: boolean;
5038
+ /** Alpha below which a fragment is discarded, 0 to 1. Default 0: nothing is. */
4153
5039
  alphaTest?: number;
5040
+ /** Camera layer mask the batch draws for, see {@link ParticleSystem.layers}. Default `0x0fffffff`. */
4154
5041
  layerMask?: number;
4155
5042
  /** Billboard pivot in particle-size units, see {@link VFXBatchSettings.pivot}. */
4156
5043
  pivot?: Vector3;
@@ -4188,36 +5075,79 @@ interface ParticleSystemParameters {
4188
5075
  renderingGroupId?: number;
4189
5076
  /** Whether the scene's fog applies, see {@link ParticleSystem.applyFog}. Default true. */
4190
5077
  applyFog?: boolean;
5078
+ /** Scene the emitter node is created in. Default Babylon's last created scene. */
4191
5079
  scene?: Scene;
4192
5080
  }
5081
+ /** A {@link BurstParameters} in an effect file. A plain number `count` is read as a constant. */
4193
5082
  interface BurstParametersJSON {
5083
+ /** See {@link BurstParameters.time}. */
4194
5084
  time: number;
5085
+ /** See {@link BurstParameters.count}. */
4195
5086
  count: FunctionJSON | number;
5087
+ /** See {@link BurstParameters.cycle}. */
4196
5088
  cycle: number;
5089
+ /** See {@link BurstParameters.interval}. */
4197
5090
  interval: number;
5091
+ /** See {@link BurstParameters.probability}. */
4198
5092
  probability: number;
4199
5093
  }
5094
+ /**
5095
+ * A particle system in an effect file, as {@link ParticleSystem.toJSON} writes it and
5096
+ * {@link ParticleSystem.fromJSON} reads it; `docs/FORMAT.md` describes the document around it.
5097
+ * Each field mirrors the {@link ParticleSystem} member of the same name. Curves and generators
5098
+ * are written as quarks.core's `FunctionJSON`; textures, materials and geometries as uuids into
5099
+ * the document. Most settings are written only when they differ from their default, and a field
5100
+ * that is missing reads as the default, so every field but `version` is optional. The shape, the
5101
+ * start and emission curves except `startDelay`, `startTileIndex`, `instancingGeometry`, `material`
5102
+ * and `behaviors` are always written, because older loaders and three.quarks need them.
5103
+ */
4200
5104
  interface ParticleSystemJSONParameters {
5105
+ /** The quarks.core version line the system was written with. */
4201
5106
  version: string;
4202
- autoDestroy: boolean;
4203
- looping: boolean;
4204
- prewarm: boolean;
4205
- duration: number;
5107
+ /** See {@link ParticleSystem.autoDestroy}. */
5108
+ autoDestroy?: boolean;
5109
+ /** See {@link ParticleSystem.looping}. */
5110
+ looping?: boolean;
5111
+ /** See {@link ParticleSystem.prewarm}. */
5112
+ prewarm?: boolean;
5113
+ /** See {@link ParticleSystem.prewarmTime}. */
5114
+ prewarmTime?: number;
5115
+ /** See {@link ParticleSystem.duration}. */
5116
+ duration?: number;
5117
+ /** See {@link ParticleSystem.startDelay}. */
4206
5118
  startDelay?: FunctionJSON;
4207
- shape: any;
4208
- startLife: FunctionJSON;
4209
- startSpeed: FunctionJSON;
4210
- startRotation: FunctionJSON;
4211
- startSize: FunctionJSON;
4212
- startColor: FunctionJSON;
4213
- emissionOverTime: FunctionJSON;
4214
- emissionOverDistance: FunctionJSON;
5119
+ /** The emitter shape, as its `toJSON` writes it. */
5120
+ shape?: any;
5121
+ /** See {@link ParticleSystem.startLife}. */
5122
+ startLife?: FunctionJSON;
5123
+ /** See {@link ParticleSystem.startSpeed}. */
5124
+ startSpeed?: FunctionJSON;
5125
+ /** See {@link ParticleSystem.startRotation}. */
5126
+ startRotation?: FunctionJSON;
5127
+ /** See {@link ParticleSystem.startSize}. */
5128
+ startSize?: FunctionJSON;
5129
+ /** See {@link ParticleSystem.startColor}. */
5130
+ startColor?: FunctionJSON;
5131
+ /** See {@link ParticleSystem.emissionOverTime}. */
5132
+ emissionOverTime?: FunctionJSON;
5133
+ /** See {@link ParticleSystem.emissionOverDistance}. */
5134
+ emissionOverDistance?: FunctionJSON;
5135
+ /** See {@link ParticleSystem.emissionBursts}. */
4215
5136
  emissionBursts?: Array<BurstParametersJSON>;
5137
+ /** See {@link ParticleSystem.maxParticles}. */
4216
5138
  maxParticles?: number;
4217
- onlyUsedByOther: boolean;
4218
- rendererEmitterSettings: RendererEmitterSettings;
5139
+ /** See {@link ParticleSystem.onlyUsedByOther}. */
5140
+ onlyUsedByOther?: boolean;
5141
+ /**
5142
+ * Trail, stretched or mesh settings; a trail's `startLength` as `FunctionJSON`. Left out when
5143
+ * the render mode has none.
5144
+ */
5145
+ rendererEmitterSettings?: RendererEmitterSettings;
5146
+ /** Uuid of the mesh particles' geometry entry. */
4219
5147
  instancingGeometry?: any;
4220
- renderMode: number;
5148
+ /** A {@link RenderMode} value. */
5149
+ renderMode?: number;
5150
+ /** See {@link ParticleSystem.renderOrder}. */
4221
5151
  renderOrder?: number;
4222
5152
  /** Written only when not 0. */
4223
5153
  renderingGroupId?: number;
@@ -4239,68 +5169,154 @@ interface ParticleSystemJSONParameters {
4239
5169
  minParticleSize?: number;
4240
5170
  /** Written only when limited. */
4241
5171
  maxParticleSize?: number;
5172
+ /** A stretched billboard's speed factor, as older files wrote it outside `rendererEmitterSettings`. */
4242
5173
  speedFactor?: number;
5174
+ /** Uuid of the texture entry. */
4243
5175
  texture?: string;
5176
+ /** Uuid of the material entry. */
4244
5177
  material?: string;
5178
+ /** The camera layer mask. */
4245
5179
  layers?: number;
4246
- startTileIndex: FunctionJSON | number;
4247
- uTileCount: number;
4248
- vTileCount: number;
5180
+ /** See {@link ParticleSystem.startTileIndex}. */
5181
+ startTileIndex?: FunctionJSON | number;
5182
+ /** See {@link ParticleSystem.uTileCount}. */
5183
+ uTileCount?: number;
5184
+ /** See {@link ParticleSystem.vTileCount}. */
5185
+ vTileCount?: number;
5186
+ /** See {@link ParticleSystem.blendTiles}. */
4249
5187
  blendTiles?: boolean;
5188
+ /** See {@link ParticleSystem.softParticles}. */
4250
5189
  softParticles?: boolean;
5190
+ /** See {@link ParticleSystem.softFarFade}. */
4251
5191
  softFarFade?: number;
5192
+ /** See {@link ParticleSystem.softNearFade}. */
4252
5193
  softNearFade?: number;
5194
+ /** See {@link ParticleSystem.blending}. */
4253
5195
  blending?: number;
5196
+ /** See {@link ParticleSystemParameters.transparent}. */
4254
5197
  transparent?: boolean;
5198
+ /** See {@link ParticleSystemParameters.depthTest}. */
4255
5199
  depthTest?: boolean;
5200
+ /** See {@link ParticleSystemParameters.depthWrite}. */
4256
5201
  depthWrite?: boolean;
5202
+ /** See {@link ParticleSystemParameters.alphaTest}. */
4257
5203
  alphaTest?: number;
4258
- behaviors: Array<any>;
4259
- worldSpace: boolean;
5204
+ /** Each behavior as its `toJSON` writes it. */
5205
+ behaviors?: Array<any>;
5206
+ /** See {@link ParticleSystem.worldSpace}. */
5207
+ worldSpace?: boolean;
4260
5208
  /** `[x, y, z]`; written only when non-zero. */
4261
5209
  pivot?: number[];
4262
5210
  /** `[u, v]`; written only when non-zero. */
4263
5211
  flip?: number[];
4264
5212
  }
5213
+ /**
5214
+ * The resources of one effect document, by uuid: what {@link ParticleSystem.toJSON} writes a
5215
+ * system's geometry, material and texture into, and what {@link ParticleSystem.fromJSON} resolves
5216
+ * them from. While writing, entries hold live Babylon objects; `serializeEffect` turns them into
5217
+ * plain data.
5218
+ */
4265
5219
  interface BabylonMetaData {
5220
+ /** Textures by uuid; null for one that could not be made. */
4266
5221
  textures: {
4267
5222
  [uuid: string]: Texture | null;
4268
5223
  };
5224
+ /** Material entries by uuid. */
4269
5225
  materials: {
4270
5226
  [uuid: string]: any;
4271
5227
  };
5228
+ /** Geometry entries by uuid. */
4272
5229
  geometries: {
4273
5230
  [uuid: string]: any;
4274
5231
  };
5232
+ /** Image entries by uuid. */
4275
5233
  images?: {
4276
5234
  [uuid: string]: any;
4277
5235
  };
5236
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4278
5237
  shapes?: {
4279
5238
  [uuid: string]: any;
4280
5239
  };
5240
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4281
5241
  skeletons?: {
4282
5242
  [uuid: string]: any;
4283
5243
  };
5244
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4284
5245
  animations?: {
4285
5246
  [uuid: string]: any;
4286
5247
  };
5248
+ /** Nodes by uuid, which a mesh surface shape links to. */
4287
5249
  nodes?: {
4288
5250
  [uuid: string]: any;
4289
5251
  };
4290
5252
  }
5253
+
5254
+ /**
5255
+ * A particle system, the counterpart of a Unity Shuriken system or a Niagara emitter: it spawns
5256
+ * particles from an {@link emitterShape}, gives them start values, runs its {@link behaviors} on
5257
+ * them every step and hands them to a {@link BatchedRenderer} to draw.
5258
+ *
5259
+ * The system lives at its {@link emitter}, a Babylon node: move, parent or disable that to place
5260
+ * the effect. Add the system to a renderer with `renderer.addSystem(system)`; the renderer
5261
+ * advances it every frame on a fixed 60 Hz step and batches it with systems that draw alike.
5262
+ *
5263
+ * Curves and random values are quarks.core generators (`ConstantValue`, `IntervalValue`,
5264
+ * `PiecewiseBezier`, `Gradient`, ...); a curve's x is the system's time over its duration for
5265
+ * start values and emission, and the particle's age over its life inside behaviors.
5266
+ */
4291
5267
  declare class ParticleSystem implements IParticleSystem {
4292
- private static serializationCounter;
5268
+ /** Dispose the system, its emitter and its batch slot when it finishes. Default false. */
4293
5269
  autoDestroy: boolean;
5270
+ /**
5271
+ * Start a looping system as if it had already run one full cycle (Unity's Prewarm), so a fire
5272
+ * or a mist is full from its first frame. Default false.
5273
+ */
4294
5274
  prewarm: boolean;
5275
+ /**
5276
+ * How much of the cycle {@link prewarm} simulates before the first frame, in seconds
5277
+ * (Niagara's Warmup Time), on a looping system like `prewarm` itself. 0, the default, warms up a whole cycle, as Unity's Prewarm does; a
5278
+ * shorter time warms up the cycle's last part only, with the bursts before it counted as
5279
+ * fired, which is enough for an effect whose particles live shorter than its cycle and keeps
5280
+ * a long cycle's first frame cheap. Longer than the cycle or than
5281
+ * {@link maxPrewarmSeconds}, it is cut to them. Kept at 0 or above.
5282
+ */
5283
+ get prewarmTime(): number;
5284
+ set prewarmTime(seconds: number);
5285
+ private prewarmTimeValue;
5286
+ /** Start the cycle again when {@link duration} ends instead of stopping emission. Default true. */
4295
5287
  looping: boolean;
4296
- duration: number;
5288
+ /**
5289
+ * Length of one emission cycle in seconds; curves over the system's time run over it. Default
5290
+ * 1, and never shorter than one simulation step: a zero, negative or NaN duration is read as
5291
+ * one step, so bursts at time 0 fire and the cycle ends.
5292
+ */
5293
+ get duration(): number;
5294
+ set duration(seconds: number);
5295
+ private durationValue;
5296
+ /** Seconds before the system first emits, rolled on each restart. Default 0. */
4297
5297
  startDelay: ValueGenerator | FunctionValueGenerator;
5298
+ /** Seconds each particle lives, rolled at birth. Default 5. */
4298
5299
  startLife: ValueGenerator | FunctionValueGenerator;
5300
+ /** Speed each particle starts with along the direction its shape gives it, in units per second. Default 0. */
4299
5301
  startSpeed: ValueGenerator | FunctionValueGenerator;
5302
+ /**
5303
+ * Rotation each particle starts with: an angle in radians around the view axis for billboards,
5304
+ * or a rotation generator (`AxisAngleGenerator`, `EulerGenerator`, `RandomQuatGenerator`) for
5305
+ * mesh particles. Default 0.
5306
+ */
4300
5307
  startRotation: ValueGenerator | FunctionValueGenerator | RotationGenerator;
5308
+ /** Size each particle starts with in world units; a `Vector3Generator` sizes each axis (Unity's 3D Start Size). Default 1. */
4301
5309
  startSize: ValueGenerator | FunctionValueGenerator | Vector3Generator;
5310
+ /** Colour and alpha each particle starts with, multiplied with the texture. Default opaque white. */
4302
5311
  startColor: ColorGenerator | FunctionColorGenerator;
5312
+ /** Flipbook cell each particle starts on, counted across rows, see {@link uTileCount}. Default 0. */
4303
5313
  startTileIndex: ValueGenerator;
5314
+ /**
5315
+ * The render mode's own settings: `TrailSettings` for a trail (`startLength` and the trail
5316
+ * flags), `StretchedBillBoardSettings` for a stretched billboard (`speedFactor`,
5317
+ * `lengthFactor`), `MeshSettings` or nothing otherwise. Setting {@link renderMode} replaces it
5318
+ * with that mode's defaults.
5319
+ */
4304
5320
  rendererEmitterSettings: RendererEmitterSettings;
4305
5321
  /**
4306
5322
  * Fraction of billboard particles mirrored along U (x) and V (y), each
@@ -4308,57 +5324,95 @@ declare class ParticleSystem implements IParticleSystem {
4308
5324
  * Undefined: nothing is mirrored. Meshes ignore it.
4309
5325
  */
4310
5326
  flip?: Vector2;
5327
+ /** Particles emitted per second, read over the system's time. Default 10. */
4311
5328
  emissionOverTime: ValueGenerator | FunctionValueGenerator;
5329
+ /** Particles emitted per world unit the emitter moves (Unity's Rate over Distance). Default 0. */
4312
5330
  emissionOverDistance: ValueGenerator | FunctionValueGenerator;
5331
+ /** Bursts of particles at set times in each cycle. Default none. */
4313
5332
  emissionBursts: Array<BurstParameters>;
4314
- /** Most particles alive at once (Unity's Max Particles); emission past it is dropped. Undefined means no limit. */
5333
+ /**
5334
+ * Most particles alive at once (Unity's Max Particles); emission past it is dropped. Undefined
5335
+ * means no limit, as does a negative or NaN count given to the constructor; a fraction is
5336
+ * rounded down.
5337
+ */
4315
5338
  maxParticles?: number;
5339
+ /**
5340
+ * The system emits nothing of its own and only spawns what an `EmitSubParticleSystem` on
5341
+ * another system sends it (a Unity sub emitter). Default false.
5342
+ */
4316
5343
  onlyUsedByOther: boolean;
5344
+ /**
5345
+ * Simulate in world space (Unity's Simulation Space: World): particles stay where they were
5346
+ * born when the emitter moves. False keeps them in the emitter's space, so they move with it.
5347
+ * Default false.
5348
+ */
4317
5349
  worldSpace: boolean;
5350
+ /** How many of {@link particles} are alive. Read only. */
4318
5351
  particleNum: number;
5352
+ /** Set by {@link pause}: the renderer skips the system's simulation while true. */
4319
5353
  paused: boolean;
5354
+ /** The particle pool; the first {@link particleNum} are alive. Read only. */
4320
5355
  particles: Array<Particle>;
4321
- /** Column storage shared by this system's particles. */
5356
+ /** Column storage shared by this system's particles; behaviors read and write it. */
4322
5357
  readonly store: ParticleStore;
5358
+ /** Where particles are born and which way they start (Unity's Shape module). Default a `SphereEmitter`. */
4323
5359
  emitterShape: EmitterShape;
5360
+ /** The node the system lives at; move, parent or disable it to place or hide the effect. */
4324
5361
  emitter: ParticleEmitter;
5362
+ /** What the renderer batches on; read it with {@link getRendererSettings}. @internal */
4325
5363
  rendererSettings: VFXBatchSettings;
5364
+ /**
5365
+ * Set when a render setting changed, so the renderer moves the system to a matching batch.
5366
+ * The system's setters set it; set it yourself after changing {@link getRendererSettings} directly.
5367
+ */
4326
5368
  neededToUpdateRender: boolean;
5369
+ /** Modules run on every particle each step, in order (`ColorOverLife`, `SizeOverLife`, forces, ...). */
4327
5370
  behaviors: Array<Behavior>;
5371
+ /** Emission progress: time in the cycle, burst and distance counters. */
4328
5372
  emissionState: EmissionState;
5373
+ /** The emitter's velocity over the last step, which `InheritVelocity` reads. */
4329
5374
  emitterVelocity: Vector3;
4330
5375
  private prewarmed;
4331
5376
  private emitEnded;
4332
- private markForDestroy;
4333
- private finishedEventFired;
4334
- private startDelayTimeLeft;
5377
+ /**
5378
+ * Whether `finished` fired for this play; the spawner clears it when a sub emission refills an
5379
+ * empty target.
5380
+ * @internal
5381
+ */
5382
+ finishedEventFired: boolean;
5383
+ /** The fixed-step clock: whole steps per frame, start delay and catch-up time. */
5384
+ private readonly clock;
4335
5385
  private previousEmitterPos?;
4336
5386
  private tempEmitterPos;
4337
- private temp;
4338
- /** Emitter matrix moved along the step's path, see spawnAlongPath. */
4339
- private pathMatrix;
4340
- private normalMatrix;
4341
- private memory;
4342
- private listeners;
5387
+ /** The emitter matrix the last simulated step used, to interpolate from; see {@link update}. */
5388
+ private previousEmitterMatrix?;
5389
+ /** The emitter matrix handed to each step of a frame, moved along the emitter's path. */
5390
+ private readonly stepMatrix;
5391
+ /** Makes the newborn particles, see {@link ParticleSpawner}. */
5392
+ private readonly spawner;
5393
+ /** Decides how many particles each step owes, see {@link EmissionController}. */
5394
+ private readonly emission;
5395
+ private readonly events;
4343
5396
  private readonly layerMaskProxy;
4344
5397
  private materialRef;
4345
5398
  private sceneRef;
4346
5399
  private qualityFactor;
4347
- private simulationAccumulator;
4348
5400
  private destroyed;
4349
- /** Behaviors the cached plan was built from, compared by identity. */
4350
- private fusionPlan?;
4351
- private fusionSteps;
4352
- /**
4353
- * Whether any behavior in the plan can change a particle's size or colour
4354
- * after birth. Only then does a step have to snapshot them for the renderer.
4355
- */
4356
- private planChangesSize;
4357
- private planChangesColor;
5401
+ /** How the behaviors run each step, rebuilt when the list changes. */
5402
+ private readonly behaviorPlan;
4358
5403
  /** @internal **/
4359
5404
  _renderer?: BatchedRenderer;
5405
+ /**
5406
+ * Seconds into the current emission cycle. Setting it jumps emission to that point, as Unity's
5407
+ * `Simulate(t)` does for the emission clock: the bursts before it count as fired, the ones
5408
+ * after are due again; particles alive stay, and behaviors are not reset. A value that is not
5409
+ * a finite, non-negative number is 0; one past the duration wraps on a looping system and is
5410
+ * the duration otherwise. A system whose emission has ended stays ended: {@link restart} plays
5411
+ * it again.
5412
+ */
4360
5413
  set time(time: number);
4361
5414
  get time(): number;
5415
+ /** Whether {@link endEmit} ran, or a non-looping system reached the end of its duration. */
4362
5416
  get isEmitEnded(): boolean;
4363
5417
  /** Whether continuous or queued emission can still spawn particles before the system is done. */
4364
5418
  hasPendingEmission(): boolean;
@@ -4368,26 +5422,58 @@ declare class ParticleSystem implements IParticleSystem {
4368
5422
  * {@link endEmit} and whose last particle has died.
4369
5423
  */
4370
5424
  isFinished(): boolean;
5425
+ /**
5426
+ * The camera layer mask the particles draw for (Babylon's `mesh.layerMask`), as
5427
+ * `system.layers.mask`. Default `0x0fffffff`, every camera's default mask. Systems that differ
5428
+ * are batched apart.
5429
+ */
4371
5430
  get layers(): {
5431
+ /** The mask; setting it moves the system to a matching batch. */
4372
5432
  mask: number;
4373
5433
  };
5434
+ /**
5435
+ * The particles' main texture, multiplied with their colour; a flipbook when
5436
+ * {@link uTileCount} or {@link vTileCount} is above 1. Null draws the colour alone. Systems
5437
+ * with different textures are batched apart.
5438
+ */
4374
5439
  get texture(): Texture | null;
4375
5440
  set texture(texture: Texture | null);
5441
+ /**
5442
+ * A Babylon material the system takes its draw settings from (on a loaded system, the material
5443
+ * record of its file): its texture (`albedoTexture`,
5444
+ * `diffuseTexture`, `emissiveTexture` or `opacityTexture`), alpha mode, depth flags, alpha test
5445
+ * and reflection texture. The material itself
5446
+ * is not drawn with; particles always use quarks' own shaders. Null leaves the settings as they
5447
+ * are.
5448
+ */
4376
5449
  get material(): any;
4377
5450
  set material(material: any);
5451
+ /**
5452
+ * Columns of the flipbook in {@link texture} (Unity's Texture Sheet Animation tiles). With
5453
+ * {@link vTileCount}, a particle draws one cell, picked by {@link startTileIndex} and
5454
+ * `FrameOverLife`. A whole number of at least 1; anything else is 1. Default 1. Trails take
5455
+ * their cell on the CPU, so a trail's texture is cut the same way.
5456
+ */
4378
5457
  get uTileCount(): number;
4379
5458
  set uTileCount(u: number);
5459
+ /** Rows of the flipbook in {@link texture}, see {@link uTileCount}. Default 1. */
4380
5460
  get vTileCount(): number;
4381
5461
  set vTileCount(v: number);
5462
+ /**
5463
+ * Cross-fade between a flipbook's cells instead of cutting from one to the next (Unity's
5464
+ * Flip-Book Blending); the last cell fades into the first. Default false. Needs a sheet
5465
+ * (`uTileCount` or `vTileCount` above 1); trails cut their cell on the CPU and do not blend.
5466
+ */
4382
5467
  get blendTiles(): boolean;
4383
5468
  set blendTiles(v: boolean);
4384
- get softParticles(): boolean;
4385
- set softParticles(v: boolean);
4386
5469
  /**
4387
- * Billboard pivot in particle-size units (Unity's renderer Pivot), see
4388
- * {@link VFXBatchSettings.pivot}. Assign a new vector to change it: editing
4389
- * the returned one in place does not reach the renderer.
5470
+ * Fade particles out as they near the scene behind them (Unity's Soft Particles, Unreal's
5471
+ * Depth Fade), between {@link softNearFade} and {@link softFarFade}. Needs a depth texture on
5472
+ * the renderer, see `BatchedRenderer.setDepthTexture`; without one particles draw hard.
5473
+ * Default false.
4390
5474
  */
5475
+ get softParticles(): boolean;
5476
+ set softParticles(v: boolean);
4391
5477
  /**
4392
5478
  * The order this system's batch draws its particles in (Unity's Sort
4393
5479
  * Mode), `'none'` by default. Alpha blended smoke wants `'distance'`;
@@ -4411,6 +5497,11 @@ declare class ParticleSystem implements IParticleSystem {
4411
5497
  */
4412
5498
  get maxParticleSize(): number;
4413
5499
  set maxParticleSize(size: number);
5500
+ /**
5501
+ * Billboard pivot in particle-size units (Unity's renderer Pivot), see
5502
+ * {@link VFXBatchSettings.pivot}. Assign a new vector to change it: editing
5503
+ * the returned one in place does not reach the renderer.
5504
+ */
4414
5505
  get pivot(): Vector3 | undefined;
4415
5506
  set pivot(v: Vector3 | undefined);
4416
5507
  /**
@@ -4480,38 +5571,108 @@ declare class ParticleSystem implements IParticleSystem {
4480
5571
  * before every step; what `'hierarchy'` multiplies start speeds by. Taken
4481
5572
  * from the system's own emitter rather than the emission matrix, whose
4482
5573
  * columns carry a parent particle's velocity for a sub emitter.
5574
+ * @internal
4483
5575
  */
4484
- private readonly hierarchyScale;
5576
+ readonly hierarchyScale: Vector3;
4485
5577
  /** The mean world scale of the emitter for a world-space `'hierarchy'` system, else 1. */
4486
5578
  private measureMotionScale;
4487
- /** `lighting` if it is one of the modes, else the default. */
4488
- private static validLighting;
4489
- private static validSortMode;
4490
- private static validCullingMode;
4491
- private static nonZeroPivot;
4492
- private static nonZeroFlip;
5579
+ /**
5580
+ * Distance in world units in front of the scene at which a soft particle is fully faded out,
5581
+ * at least 0. Default 0. A live parameter: changing it on a system alone in its batch keeps
5582
+ * the batch and its material (see {@link VFXBatchSettings}).
5583
+ */
4493
5584
  get softNearFade(): number;
4494
5585
  set softNearFade(v: number);
5586
+ /**
5587
+ * Distance in world units in front of the scene at which a soft particle is fully opaque, at
5588
+ * least 0. Default 1 (Unreal's Depth Fade distance): the particle fades over the last unit
5589
+ * before the scene. A value at or below {@link softNearFade} cuts the particle off at that
5590
+ * distance instead of fading it. A live parameter, like `softNearFade`.
5591
+ */
4495
5592
  get softFarFade(): number;
4496
5593
  set softFarFade(v: number);
4497
- get instancingGeometry(): Float32Array;
4498
5594
  /**
4499
- * The mesh particles' positions. A new geometry with a different vertex
4500
- * count drops UV sets and normals that no longer fit it: the first UV set
4501
- * falls back to zeros, the second to none, the normals to +Z. Assign {@link instancingUVs} and
4502
- * {@link instancingUVs2} after it.
5595
+ * The mesh particles' positions, three values per vertex.
5596
+ * Setting it restarts the system. A new geometry with a different vertex
5597
+ * count drops UV sets, normals and indices that no longer fit it: the first UV set
5598
+ * falls back to zeros, the second to none, the normals to +Z, the indices to the vertex
5599
+ * sequence. Assign {@link instancingUVs}, {@link instancingUVs2} and {@link instancingIndices}
5600
+ * after it.
4503
5601
  */
5602
+ get instancingGeometry(): Float32Array;
4504
5603
  set instancingGeometry(geometry: Float32Array);
5604
+ /**
5605
+ * Gives a mesh system normals when it has none, +Z per vertex, so the mesh shader always has
5606
+ * the attribute it reads. Called on construction and when the render mode or geometry changes.
5607
+ */
5608
+ private ensureMeshNormals;
5609
+ /**
5610
+ * {@link restart} for a setting that rebuilds the particles: the system is cleared and rewound,
5611
+ * but a paused system stays paused, and a stopped one stays stopped.
5612
+ */
5613
+ private restartKeepingPause;
5614
+ /**
5615
+ * The mesh particles' triangle indices into {@link instancingGeometry}. Mesh systems that share
5616
+ * positions but not indices (sub-meshes of one vertex buffer) are batched apart.
5617
+ */
5618
+ get instancingIndices(): Uint32Array | Uint16Array;
5619
+ set instancingIndices(indices: Uint32Array | Uint16Array);
4505
5620
  /** The mesh particles' first UV set, two values per vertex. */
4506
5621
  get instancingUVs(): Float32Array;
4507
5622
  set instancingUVs(uvs: Float32Array);
4508
5623
  /** The mesh particles' second UV set, read by textures on UV channel 1; see `UVChannel`. */
4509
5624
  get instancingUVs2(): Float32Array | undefined;
4510
5625
  set instancingUVs2(uvs: Float32Array | undefined);
5626
+ /**
5627
+ * Babylon alpha mode the particles blend with: `Constants.ALPHA_ADD` (the default) for glows,
5628
+ * `Constants.ALPHA_COMBINE` for smoke and anything alpha blended. Systems that differ are
5629
+ * batched apart.
5630
+ */
4511
5631
  get blending(): number;
4512
5632
  set blending(blending: number);
5633
+ /**
5634
+ * Whether the particles draw in the transparent pass, blended by {@link blending}; false
5635
+ * draws them opaque, with blending off. Default true, or the material's `needAlphaBlending`.
5636
+ * Systems that differ are batched apart.
5637
+ */
5638
+ get transparent(): boolean;
5639
+ set transparent(transparent: boolean);
5640
+ /**
5641
+ * Whether particles are hidden behind nearer geometry; false draws them over everything
5642
+ * (Unity's `ZTest Always`), for overlays and effects seen through walls. Default true, or the
5643
+ * material's `disableDepthTest` inverted. Systems that differ are batched apart.
5644
+ */
5645
+ get depthTest(): boolean;
5646
+ set depthTest(depthTest: boolean);
5647
+ /**
5648
+ * Whether particles write depth, so later draws are hidden behind them. Default false, or the
5649
+ * material's `disableDepthWrite` inverted. Systems that differ are batched apart.
5650
+ */
5651
+ get depthWrite(): boolean;
5652
+ set depthWrite(depthWrite: boolean);
5653
+ /**
5654
+ * Alpha below which a fragment is discarded (Unity's Alpha Clip Threshold), 0…1; 0 (the
5655
+ * default, or the material's `alphaCutOff`) discards nothing but fragments under 0.01, which no
5656
+ * blend mode can show except additive ones with a bright colour. Switching it on or off
5657
+ * rebuilds the batch's material; a change between non-zero cutoffs on a system alone in its
5658
+ * batch is written to the material in place.
5659
+ */
5660
+ get alphaTest(): number;
5661
+ set alphaTest(cutoff: number);
5662
+ /**
5663
+ * How each particle is drawn (Unity's Render Mode): a camera-facing billboard, a stretched
5664
+ * billboard, a horizontal or vertical billboard, a mesh, a trail or a beam, see
5665
+ * {@link RenderMode}. Changing it gives {@link rendererEmitterSettings} the new mode's
5666
+ * defaults, and switching to or from a trail restarts the system. Switching to a mesh makes
5667
+ * {@link startRotation} an `AxisAngleGenerator` about Y, and switching away from one sets it to 0.
5668
+ */
4513
5669
  get renderMode(): RenderMode;
4514
5670
  set renderMode(renderMode: RenderMode);
5671
+ /**
5672
+ * The batch mesh's `alphaIndex`: among the transparent meshes of one rendering group, lower
5673
+ * draws first, whatever the distance (Unity's Order in Layer). Default 0. Systems that differ
5674
+ * are batched apart.
5675
+ */
4515
5676
  get renderOrder(): number;
4516
5677
  set renderOrder(renderOrder: number);
4517
5678
  /**
@@ -4531,17 +5692,23 @@ declare class ParticleSystem implements IParticleSystem {
4531
5692
  /**
4532
5693
  * Multiplier on the time this system is advanced by (Unity's Simulation
4533
5694
  * Speed): 2 runs the effect twice as fast, 0 freezes it without pausing the
4534
- * renderer. 1 by default; saved in the effect JSON only when it differs.
5695
+ * renderer. 1 by default; saved in the effect JSON only when it differs. A
5696
+ * negative or NaN speed is read as 0, and the clock does not run backwards.
4535
5697
  */
4536
- playbackSpeed: number;
5698
+ get playbackSpeed(): number;
5699
+ set playbackSpeed(speed: number);
5700
+ private playbackSpeedValue;
4537
5701
  /**
4538
5702
  * Runtime multiplier on how many particles the system emits: bursts,
4539
5703
  * emission over time and over distance alike. Unlike
4540
5704
  * {@link setQualityFactor}, which only ever thins an effect, it may go
4541
5705
  * above 1 to make a stronger version of the same effect. The two multiply.
4542
- * 1 by default; not saved in the effect JSON.
5706
+ * 1 by default; a negative or NaN value counts as 0. Not saved in the effect JSON; copied by
5707
+ * {@link clone}.
4543
5708
  */
4544
- emissionMultiplier: number;
5709
+ get emissionMultiplier(): number;
5710
+ set emissionMultiplier(multiplier: number);
5711
+ private emissionMultiplierValue;
4545
5712
  /** What this system does while off screen, see {@link CullingMode}. `'always'` by default. */
4546
5713
  cullingMode: CullingMode;
4547
5714
  /** What the emitter's world scale does to a world-space system, see {@link ScalingMode}. `'shape'` by default. */
@@ -4572,9 +5739,9 @@ declare class ParticleSystem implements IParticleSystem {
4572
5739
  * multiplayer and reproducible tests. Systems this one emits into roll on
4573
5740
  * its generator too. Unset (the default), rolls come from the global source
4574
5741
  * (`setRandomSource` in quarks.core). Saved in the effect JSON when set.
4575
- *
4576
- * Not covered: randomness outside the step, such as a `TurbulenceField`'s
4577
- * offsets, which are rolled when the behavior is created.
5742
+ * The behaviors roll on the same generator, and the ones with their own
5743
+ * randomness (a `TurbulenceField`'s noise) are built from their own seed,
5744
+ * so the whole effect is covered.
4578
5745
  */
4579
5746
  get seed(): number | undefined;
4580
5747
  set seed(seed: number | undefined);
@@ -4584,12 +5751,6 @@ declare class ParticleSystem implements IParticleSystem {
4584
5751
  * @internal
4585
5752
  */
4586
5753
  culled: boolean;
4587
- /**
4588
- * Time a `'pauseAndCatchUp'` system has spent off screen and not yet
4589
- * simulated, in seconds. Capped, so an effect hidden for a minute does not
4590
- * replay the minute.
4591
- */
4592
- private pendingCatchUp;
4593
5754
  /**
4594
5755
  * Time per frame a system coming back into view may spend on the steps it
4595
5756
  * missed, in milliseconds, when it is advanced without a renderer. The
@@ -4597,44 +5758,84 @@ declare class ParticleSystem implements IParticleSystem {
4597
5758
  * instead. Steps that do not fit are dropped, not deferred.
4598
5759
  */
4599
5760
  static catchUpBudgetMs: number;
4600
- /** Axis-aligned bounds of the live particles, in simulation space. See {@link getWorldBounds}. */
4601
- private readonly boundsMin;
4602
- private readonly boundsMax;
4603
- /** How far a particle's quad, mesh or stretch can reach past its position, in simulation units. */
4604
- private boundsPadding;
4605
- private boundsValid;
4606
- /** Steps since the last full measurement; between them the bounds are carried and padded. */
4607
- private stepsSinceBounds;
4608
- private boundsMaxSize;
4609
- private boundsMaxSpeedSq;
4610
- /** True when the bounds are already in world space (a world-space system, or bounds the renderer measured). */
4611
- private boundsInWorld;
4612
- private geometryRadiusFor?;
4613
- private geometryRadius;
5761
+ /**
5762
+ * A performance guard on {@link prewarm}, for every system: the most of a cycle it simulates
5763
+ * before the first frame, in seconds. A longer cycle is warmed up over its last
5764
+ * `maxPrewarmSeconds` only, with the burst waves before that counted as fired, so a long
5765
+ * looping effect does not stall its first frame. 10 by default; raise it in an app whose
5766
+ * effects have longer cycles and particles that live longer than that. It is not an effect's
5767
+ * own warm-up time, which is {@link prewarmTime}, and is not saved with one.
5768
+ */
5769
+ static maxPrewarmSeconds: number;
5770
+ /** What the system draws covers, for culling. See {@link getWorldBounds}. */
5771
+ private readonly bounds;
4614
5772
  constructor(parameters: ParticleSystemParameters);
5773
+ /**
5774
+ * When the env atlas this system draws with is disposed (its cube was, or `disposeEnvAtlas`
5775
+ * ran) while the system still uses it, drops it and builds a new one if the cube is still alive,
5776
+ * so the batch never samples a disposed texture.
5777
+ */
5778
+ private watchEnvAtlas;
4615
5779
  private applyMaterialSettings;
5780
+ /** Freezes the system where it is: particles stay and nothing is simulated until {@link play}. */
4616
5781
  pause(): void;
5782
+ /**
5783
+ * Resumes a paused system. It only resumes: a system that has finished ({@link isFinished})
5784
+ * stays finished, since nothing is left to emit; {@link restart} plays it again from the start.
5785
+ */
4617
5786
  play(): void;
5787
+ /** Clears every particle, rewinds to the start ({@link restart}) and pauses until {@link play}. */
4618
5788
  stop(): void;
5789
+ /**
5790
+ * Removes every particle alive and nothing else (Unity's `Clear`): emission goes on from where
5791
+ * it is, paused stays paused, and the bursts and the random generator are not rewound. The
5792
+ * sub emissions the removed particles were driving end with them; the child systems' own
5793
+ * particles stay, and `particleDied` is not fired.
5794
+ */
5795
+ clear(): void;
5796
+ /**
5797
+ * Drops every trail's recorded samples and keeps the particles (Unity's `TrailRenderer.Clear`):
5798
+ * each ribbon starts over from where its particle is now. For a teleport: {@link pause}, move
5799
+ * the emitter, {@link play} (so the move is not spread over the next frame's steps as motion)
5800
+ * and call this, and no ribbon is drawn across the jump. Does nothing on the other render modes.
5801
+ */
5802
+ clearTrails(): void;
5803
+ /**
5804
+ * Scales how many particles the system emits, from 0.1 to 1 (values outside are clamped), for
5805
+ * lower quality settings or a crowded frame; the renderer's adaptive performance sets it. It
5806
+ * multiplies with {@link emissionMultiplier}. Default 1.
5807
+ */
4619
5808
  setQualityFactor(qualityFactor: number): void;
4620
- /** Quality factor times {@link emissionMultiplier}: what emission counts are scaled by. */
4621
- private emissionFactor;
4622
5809
  /**
4623
- * Appends one particle to the pool, giving it the next row of the store.
4624
- *
4625
- * Growing the store replaces its arrays, so every particle already bound to
4626
- * it has to be re-pointed at the new ones.
4627
- */
4628
- /** Points every particle at the store's columns again, after any were replaced. */
4629
- private rebindParticles;
4630
- private growParticlePool;
4631
- private spawn;
4632
- /** Turns a newborn so that it faces the way its shape sent it; see {@link alignToDirection}. */
4633
- private alignParticleToDirection;
4634
- /** Applies the parent particle's inherited properties to a sub emitted newborn; see `EmitSubParticleSystem.inherit`. */
4635
- private inheritFromParent;
5810
+ * Quality factor times {@link emissionMultiplier}: what emission counts are scaled by.
5811
+ * @internal
5812
+ */
5813
+ emissionFactor(): number;
5814
+ /**
5815
+ * Stops emission and lets the particles alive die out (Unity's `Stop` with
5816
+ * `StopEmitting`). The system fires `emitEnd`, then `finished` when the last particle has
5817
+ * died, and is disposed then if {@link autoDestroy} is set. {@link restart} starts it again.
5818
+ */
4636
5819
  endEmit(): void;
5820
+ /** Whether {@link dispose} has run. A disposed system emits nothing and cannot be restarted. */
5821
+ get isDisposed(): boolean;
5822
+ /**
5823
+ * Removes the system from its renderer, disposes its emitter node (and the nodes under it) and
5824
+ * fires `destroy`. A disposed system cannot be played again. Calling it twice is harmless.
5825
+ */
4637
5826
  dispose(): void;
5827
+ /**
5828
+ * Rolls the system-level generators into the system's memory. Called on construction and on
5829
+ * every restart, which empties the memory: a generator that keeps a slot index into it, such
5830
+ * as `IntervalValue`, would otherwise read past the end and return NaN. A seeded system rolls
5831
+ * them on its own generator, so a restart replays the same rates, counts and delay.
5832
+ */
5833
+ private initSystemGenerators;
5834
+ /**
5835
+ * Clears every particle and starts the system from the beginning: emission time 0, bursts and
5836
+ * the start delay rolled again, behaviors reset, and a seeded system's generator restarted, so
5837
+ * it replays the same effect. Also unpauses it.
5838
+ */
4638
5839
  restart(): void;
4639
5840
  private firstTimeUpdate;
4640
5841
  /**
@@ -4653,13 +5854,18 @@ declare class ParticleSystem implements IParticleSystem {
4653
5854
  /** Runs the steps a system missed while culled, as many as fit before `deadline`. */
4654
5855
  private catchUp;
4655
5856
  /**
4656
- * Records the bounds the sprite step measured over the live particles.
4657
- * Trails are measured by their renderer instead, since their ribbons live
4658
- * outside the store.
5857
+ * Counts the bursts, and the waves of the one in progress, due before `time` seconds into the
5858
+ * cycle as fired, so a jump of the emission clock does not fire them late. The waves are
5859
+ * counted with the arithmetic the emission uses, so none is lost to rounding.
4659
5860
  */
4660
- private storeBounds;
4661
- /** Distance of the farthest vertex of the mesh particles' geometry from its origin. */
4662
- private meshGeometryRadius;
5861
+ private markBurstsBefore;
5862
+ /**
5863
+ * Simulates the end of a cycle before the first frame, on the fixed step directly: no frame
5864
+ * clamp, culling or emitter velocity in the way. The cycle's last {@link prewarmTime} seconds
5865
+ * (the whole cycle when that is 0), and at most {@link maxPrewarmSeconds}, with the bursts
5866
+ * before that counted as fired.
5867
+ */
5868
+ private runPrewarm;
4663
5869
  /**
4664
5870
  * World-space axis-aligned bounds of everything this system draws, padded
4665
5871
  * for particle size, into `min` and `max`. False when the system has no
@@ -4672,7 +5878,8 @@ declare class ParticleSystem implements IParticleSystem {
4672
5878
  /**
4673
5879
  * Where a {@link RenderMode.Beam} system's quads end, see {@link BeamEnd}.
4674
5880
  * Unset (the default), a beam has no length and draws nothing. Not saved
4675
- * in the effect JSON: it is where this instance is aimed at runtime.
5881
+ * in the effect JSON: it is where this instance is aimed at runtime. Copied by
5882
+ * {@link clone}: a point as a copy, a node as the same node.
4676
5883
  */
4677
5884
  beamEnd?: BeamEnd;
4678
5885
  /**
@@ -4690,115 +5897,88 @@ declare class ParticleSystem implements IParticleSystem {
4690
5897
  private readonly beamEndScratch;
4691
5898
  /** The world position of {@link beamEnd} into `out`; false when it is unset. */
4692
5899
  getBeamEnd(out: Vector3): boolean;
4693
- /** The largest axis of the emitter's world scale. */
4694
- private emitterMaxScale;
4695
- private measureWorldBounds;
4696
5900
  /**
4697
5901
  * Records bounds a renderer measured in world space, for systems whose
4698
5902
  * drawn extent the store does not hold (trail ribbons).
4699
5903
  * @internal
4700
5904
  */
4701
5905
  setWorldBounds(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, padding: number): void;
5906
+ /** Length of one simulation step, in seconds. See {@link simulationResidual}. */
5907
+ get simulationStep(): number;
4702
5908
  /**
4703
5909
  * Time the display is ahead of (positive) or still ahead of the simulation
4704
- * (negative — the simulation ran a hair early), in seconds. Magnitude never
4705
- * exceeds one step.
5910
+ * (negative: the simulation ran a hair early), in seconds; 0 while paused.
5911
+ * Its magnitude never exceeds one step.
4706
5912
  *
4707
5913
  * The simulation runs on a fixed 1/60 step so that emission and lifetimes
4708
- * stay in phase — without it a slow emitter flickers when the frame rate
5914
+ * stay in phase; without it a slow emitter flickers when the frame rate
4709
5915
  * wobbles. But frames do not arrive on that grid: a display running at
4710
- * anything other than exactly 60Hz leaves some frames with no step at all
4711
- * (half of them at 120Hz, three in five at 144Hz) and others with two, so
4712
- * the particles are drawn stuttering even while the frame rate is perfect.
4713
- *
4714
- * The steps-per-frame count below is chosen by *rounding* the accumulated
4715
- * time to the nearest step, not flooring it. Flooring always leaves the
4716
- * accumulator positive, and when the real frame rate sits very close to
4717
- * 60Hz (as most displays do) that leftover creeps toward a full step for
4718
- * many consecutive frames before tipping over into a frame that runs two
4719
- * steps at once and resets it to near zero — a visible lurch, every particle
4720
- * in the system at once, with a perfectly steady frame rate the whole time.
4721
- * Rounding lets the leftover go negative instead, which keeps it centered
4722
- * near zero and stops it from ever building up toward that reset.
4723
- *
4724
- * Renderers close the gap by advancing what they draw along each particle's
4725
- * velocity by this much. That reproduces the straight-line part of the
4726
- * motion exactly — it is the same term the next step would integrate — so
5916
+ * anything other than exactly 60 Hz leaves some frames with no step at all
5917
+ * (half of them at 120 Hz, three in five at 144 Hz) and others with two, so
5918
+ * the particles would be drawn stuttering even while the frame rate is
5919
+ * perfect. Renderers close the gap by advancing what they draw along each
5920
+ * particle's velocity by this much. That reproduces the straight-line part
5921
+ * of the motion exactly, the same term the next step would integrate, so
4727
5922
  * the simulation stays fixed-step while the picture moves continuously.
4728
5923
  */
4729
- /** Length of one simulation step, in seconds. See {@link simulationResidual}. */
4730
- get simulationStep(): number;
4731
5924
  get simulationResidual(): number;
4732
5925
  /**
4733
- * Execution plan for this system's behaviors, rebuilt when the list changes.
4734
- *
4735
- * Consecutive behaviors that can be compiled into one loop are merged, so
4736
- * the particles are walked once instead of once per behavior. The plan is
4737
- * keyed on the behavior instances, not their types: swapping one out has to
4738
- * change the generated code's indices.
4739
- */
4740
- private behaviorSteps;
4741
- /**
4742
- * Advances emission, behaviors, motion and culling by one fixed timestep,
4743
- * on the system's own random generator when it has a {@link seed}.
5926
+ * Advances emission, behaviors, motion and culling by one fixed timestep, on the system's own
5927
+ * random generator when it has a {@link seed}, with the emitter at `emitterMatrix`: the
5928
+ * current one, unless a frame interpolates (see {@link update}).
4744
5929
  */
4745
5930
  private simulateStep;
4746
5931
  private stepOnce;
5932
+ /** Re-points every particle at the store, for {@link snapshotPreviousState}. */
5933
+ private readonly rebindParticles;
5934
+ /** Fires `particleDied` for a particle the step retired. */
5935
+ private readonly fireParticleDied;
4747
5936
  private notifyFinished;
4748
- /** Waves a burst fires per loop: its `cycle`, and never fewer than one. */
4749
- private static burstWaveCount;
4750
- /** Seconds between a burst's waves; a missing or negative interval fires them all at once. */
4751
- private static burstInterval;
4752
5937
  /**
4753
- * Fires the burst waves that are due by `emissionState.time`.
4754
- *
4755
- * Wave `w` of a burst is due at `burst.time + w * burst.interval`, and the
4756
- * burst fires `cycle` of them, each rolling `probability` on its own — the
4757
- * way Unity repeats a burst. Bursts start in time order, as they always
4758
- * have; their repeats are tracked per burst so a burst that is still
4759
- * repeating never holds back a later one. Repeats falling past the
4760
- * system's duration are dropped (a looping system starts them over on its
4761
- * next loop), matching Unity, which never emits a burst cycle beyond the
4762
- * end of the duration.
4763
- */
4764
- private emitBursts;
4765
- /** Spawns one wave of `burst`, if its probability roll passes. */
4766
- private fireBurstWave;
4767
- /** True while a burst that has started still has a wave due within the duration. */
4768
- private hasPendingBurstWaves;
4769
- /**
4770
- * Spawns `count` particles owed to emission over distance, each where the
4771
- * emitter crossed its metre mark on the way from `from` to where
4772
- * `emitterMatrix` has it now, rather than all of them at the end of the
4773
- * path: a fast emitter then leaves a continuous trail instead of one clump
4774
- * per step.
4775
- *
4776
- * `carried` is how far the emitter had already gone past its last mark
4777
- * before this step, so the marks keep their spacing across steps. Only the
4778
- * position is interpolated; the emitter's current rotation and scale are
4779
- * used for every particle.
5938
+ * Spawns what this step's emission calls for. Called by the simulation step, and by
5939
+ * `EmitSubParticleSystem` on a sub emitter target with the parent particle's state and matrix.
4780
5940
  */
4781
- private spawnAlongPath;
4782
5941
  emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4): void;
5942
+ /**
5943
+ * Writes this system's settings. Its geometry, material and textures go into `metaData` as
5944
+ * entries the result names by uuid; give the same `metaData` to every system of a document so
5945
+ * shared ones are written once. The material entry holds live Babylon objects, so to write a
5946
+ * file use `serializeEffect`, which turns them into plain data. Runtime-only state
5947
+ * (`tint`, `beamEnd`, the playing time) is not written.
5948
+ */
4783
5949
  toJSON(metaData?: BabylonMetaData | string, _options?: SerializationOptions): ParticleSystemJSONParameters;
5950
+ /**
5951
+ * Builds a system from {@link toJSON} output, resolving its geometry, material and texture
5952
+ * uuids through `meta`. A setting the file leaves out takes the constructor's default; an
5953
+ * unknown shape, behavior or curve type warns and takes its default. Sub emitter targets stay
5954
+ * uuids until `QuarksLoader` links them.
5955
+ */
4784
5956
  static fromJSON(json: ParticleSystemJSONParameters, meta: BabylonMetaData, dependencies?: {
4785
5957
  [uuid: string]: Behavior;
4786
5958
  }, scene?: Scene): ParticleSystem;
4787
- private static nextSerializationId;
4788
- /** Normals facing +Z, one array per geometry so systems sharing it still batch together. */
4789
- private static createFallbackNormals;
4790
- private toRendererSettingsJSON;
4791
- private ensureGeometryMeta;
4792
- private ensureMaterialMeta;
4793
- private static resolveGeometryData;
5959
+ /** Appends a behavior to {@link behaviors}; it runs on existing particles from the next step. */
4794
5960
  addBehavior(behavior: Behavior): void;
5961
+ /**
5962
+ * The settings the renderer batches this system on. Prefer the system's setters, which move it
5963
+ * to a matching batch; after changing a field here directly, set {@link neededToUpdateRender}.
5964
+ */
4795
5965
  getRendererSettings(): VFXBatchSettings;
5966
+ /**
5967
+ * Calls `callback` on each `event`: `'emitEnd'` when emission ends, `'finished'` when the last
5968
+ * particle of an ended system dies, `'particleDied'` per particle (with `event.particle`), and
5969
+ * `'destroy'` on dispose.
5970
+ */
4796
5971
  addEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
5972
+ /** Removes every callback registered for `event`. */
4797
5973
  removeAllEventListeners(event: ParticleSystemEventType): void;
5974
+ /** Removes one callback added with {@link addEventListener}. */
4798
5975
  removeEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
4799
- /** True when at least one callback is registered for the event type. */
4800
- private hasListeners;
4801
- private fire;
5976
+ /**
5977
+ * A new system with the same settings, behaviors and generators (copied, so the two roll
5978
+ * independently), on a new emitter node with no parent. It shares the texture, material and
5979
+ * geometry. It is not added to a renderer: call `renderer.addSystem` on it, or use
5980
+ * `QuarksUtil.instantiate` to copy a whole effect tree.
5981
+ */
4802
5982
  clone(): ParticleSystem;
4803
5983
  }
4804
5984
 
@@ -4811,10 +5991,21 @@ type QuarksResourceKind = 'effect' | 'geometry' | 'image';
4811
5991
  interface QuarksResourceResolver {
4812
5992
  /** Resolve a relative url to an absolute / blob / data url. Default: {@link QuarksLoader.joinUrl}. */
4813
5993
  resolve?(url: string, kind: QuarksResourceKind, baseUrl: string): string | Promise<string>;
4814
- /** Load a JSON asset (geometry files). Default: `fetch(resolvedUrl).json()`. */
4815
- fetchJson?(resolvedUrl: string): Promise<unknown>;
5994
+ /**
5995
+ * Load a JSON asset (effect and geometry files). Default: `fetch(resolvedUrl).json()`.
5996
+ * `options.signal` is passed for an effect document, whose fetch belongs to one load; geometry
5997
+ * fetches are shared between loads and get none.
5998
+ */
5999
+ fetchJson?(resolvedUrl: string, options?: {
6000
+ signal?: AbortSignal;
6001
+ }): Promise<unknown>;
4816
6002
  }
6003
+ /** Options for a {@link QuarksLoader}, shared by every load it does. */
4817
6004
  interface QuarksLoaderOptions {
6005
+ /**
6006
+ * Prefix joined to relative geometry and image urls (see {@link QuarksLoader.joinUrl}).
6007
+ * Unset, {@link QuarksLoader.load} uses the effect file's own folder and the other loads `''`.
6008
+ */
4818
6009
  baseUrl?: string;
4819
6010
  /**
4820
6011
  * Reuse one Texture per scene for every effect that references the same image with the same
@@ -4827,9 +6018,32 @@ interface QuarksLoaderOptions {
4827
6018
  shareResources?: boolean;
4828
6019
  /** Custom url / fetch backend (File picker, CDN, IndexedDB). */
4829
6020
  resolver?: QuarksResourceResolver;
6021
+ /**
6022
+ * Makes `load`, `loadFromJSON`, `loadAll` and `loadFromJSONAll` resolve only once every texture
6023
+ * the effect uses has loaded or failed, so it does not draw its first frames without them.
6024
+ * A texture a scene with `useDelayedTextureLoading` would load only once drawn is loaded at
6025
+ * once. `parse` never waits. Default false: they resolve when the nodes are built.
6026
+ */
6027
+ waitForTextures?: boolean;
6028
+ /**
6029
+ * Called for a geometry file or image that fails to load. The effect still loads: a geometry
6030
+ * keeps its link unresolved, and a texture draws nothing. Default: a console warning.
6031
+ */
6032
+ onResourceError?: (kind: QuarksResourceKind, url: string, error: unknown) => void;
6033
+ }
6034
+ /** Options for one {@link QuarksLoader.load} or {@link QuarksLoader.loadFromJSON}. */
6035
+ interface QuarksLoadOptions {
6036
+ /**
6037
+ * Cancels the load, e.g. on a level change. The promise rejects with the signal's reason as
6038
+ * soon as it is aborted, and no node of the effect is left in the scene. The effect document's
6039
+ * own fetch is cancelled; a geometry fetch shared with other loads runs on, and its result is
6040
+ * dropped. A scene disposed during the load rejects it the same way.
6041
+ */
6042
+ signal?: AbortSignal;
4830
6043
  }
4831
6044
  /** One in-memory effect for {@link QuarksLoader.loadFromJSONAll}. */
4832
6045
  interface QuarksJSONLoadEntry {
6046
+ /** The effect document, as {@link serializeEffect} or the editor writes it. Left unchanged. */
4833
6047
  json: unknown;
4834
6048
  /** Overrides loader `baseUrl` for relative texture / geometry links in this effect. */
4835
6049
  baseUrl?: string;
@@ -4839,7 +6053,7 @@ interface QuarksJSONLoadEntry {
4839
6053
  * Batch loads share the per-scene fetch cache and `shareResources`, so N effects that point at
4840
6054
  * the same `assets/geometries/*.json` or texture only pay for that asset once.
4841
6055
  */
4842
- interface QuarksBatchLoadOptions {
6056
+ interface QuarksBatchLoadOptions extends QuarksLoadOptions {
4843
6057
  /**
4844
6058
  * Max concurrent effect-document fetches (phase 1). Linked geometry/image resolve still runs
4845
6059
  * across the whole pack in parallel so shared urls coalesce. Default: all at once.
@@ -4856,17 +6070,60 @@ interface QuarksBatchLoadOptions {
4856
6070
  */
4857
6071
  continueOnError?: boolean;
4858
6072
  }
6073
+ /**
6074
+ * Thrown for a document the loader cannot read at all, such as one with no `object`. A part it
6075
+ * cannot read (an unknown behavior, shape or curve type, a missing setting) only warns, and that
6076
+ * part takes its default.
6077
+ */
6078
+ declare class QuarksFormatError extends Error {
6079
+ constructor(message: string);
6080
+ }
6081
+ /**
6082
+ * Loads effects saved as JSON into a scene: fetches the document and the geometry and image files
6083
+ * it links, builds the nodes, particle systems, textures and materials, and returns the root.
6084
+ * Add the systems to a {@link BatchedRenderer} with {@link QuarksUtil.addToBatchRenderer} to draw
6085
+ * them, and free the effect with {@link QuarksLoader.disposeEffect}.
6086
+ *
6087
+ * @example
6088
+ * ```ts
6089
+ * const loader = new QuarksLoader(scene, {waitForTextures: true});
6090
+ * const effect = await loader.load('effects/fireball.json');
6091
+ * QuarksUtil.addToBatchRenderer(effect, renderer);
6092
+ * QuarksUtil.play(effect);
6093
+ * ```
6094
+ */
4859
6095
  declare class QuarksLoader {
4860
6096
  private scene;
4861
6097
  private options;
4862
6098
  constructor(scene: Scene, options?: QuarksLoaderOptions);
4863
- /** Fetches an effect JSON from `url`, resolves linked sources, and parses it. */
4864
- load(url: string): Promise<TransformNode>;
4865
6099
  /**
4866
- * Resolves linked geometry / image urls on `json` (via {@link resolveResources}) then parses.
4867
- * Use when the effect JSON is already in hand (File, CDN payload, editor import).
6100
+ * Fetches an effect JSON from `url`, resolves linked sources, and parses it. Free the effect
6101
+ * with {@link disposeEffect}.
6102
+ */
6103
+ load(url: string, options?: QuarksLoadOptions): Promise<TransformNode>;
6104
+ /**
6105
+ * Resolves linked geometry / image urls (via {@link resolveResources}) then parses. Use when
6106
+ * the effect JSON is already in hand (File, CDN payload, editor import). `json` itself is
6107
+ * left as it was, so the same document can be loaded again, into another scene or with
6108
+ * another base url.
6109
+ */
6110
+ loadFromJSON(json: any, baseUrl?: string, options?: QuarksLoadOptions): Promise<TransformNode>;
6111
+ /**
6112
+ * Disposes an effect a loader built: its nodes and systems, the materials made for it, and
6113
+ * each texture it uses once no other loaded effect uses it (textures are shared per scene,
6114
+ * see {@link QuarksLoaderOptions.shareResources}). Copies made with
6115
+ * `QuarksUtil.instantiate` hold the textures too, so disposing the source effect leaves them
6116
+ * drawing. The same happens when the root is disposed any other way (`root.dispose()`, its
6117
+ * parent's dispose, the scene's). The materials and textures are freed even when other code
6118
+ * was handed them; give that code its own. For a root the loader did not build, this is
6119
+ * `root.dispose()`.
6120
+ */
6121
+ static disposeEffect(root: TransformNode): void;
6122
+ /**
6123
+ * Waits for the effect's textures when the loader is asked to, and frees the effect when the
6124
+ * load is stopped meanwhile.
4868
6125
  */
4869
- loadFromJSON(json: any, baseUrl?: string): Promise<TransformNode>;
6126
+ private finishLoad;
4870
6127
  /**
4871
6128
  * Loads many effects in parallel for battle / level preload. Phase 1 fetches every effect
4872
6129
  * JSON (optionally concurrency-limited); phase 2 resolves all linked geometries/images across
@@ -4897,18 +6154,23 @@ declare class QuarksLoader {
4897
6154
  }): Promise<(TransformNode | null)[]>;
4898
6155
  /**
4899
6156
  * Inlines external geometry files and rewrites relative image urls through the loader's
4900
- * {@link QuarksResourceResolver}. Idempotent for already-inlined geometries. Failures warn
4901
- * and leave the entry as is.
6157
+ * {@link QuarksResourceResolver}, in place on `json`. Each document is resolved once:
6158
+ * geometries already inlined and image urls this method already rewrote are left alone, so
6159
+ * loading the same document again does not join its base url twice. Failures warn and leave
6160
+ * the entry as is.
4902
6161
  */
4903
6162
  resolveResources(json: any, baseUrl?: string): Promise<void>;
4904
6163
  /**
4905
6164
  * Same as instance {@link resolveResources}, but usable without constructing a loader (e.g.
4906
6165
  * editor import that only prepares JSON). Pass `scene` to share the per-scene fetch cache.
6166
+ * Like it, resolves each document once. A geometry file that fails to load goes to
6167
+ * `onResourceError` (default: a console warning) and keeps its link.
4907
6168
  */
4908
6169
  static resolveLinkedResources(json: any, options?: {
4909
6170
  baseUrl?: string;
4910
6171
  resolver?: QuarksResourceResolver;
4911
6172
  scene?: Scene;
6173
+ onResourceError?: QuarksLoaderOptions['onResourceError'];
4912
6174
  }): Promise<void>;
4913
6175
  /**
4914
6176
  * Inlines geometries that an export wrote to their own file (`{uuid, type: 'QuarksGeometry',
@@ -4917,7 +6179,15 @@ declare class QuarksLoader {
4917
6179
  * `loadGeometry` and no `QuarksLoader` instance.
4918
6180
  */
4919
6181
  static resolveExternalGeometries(json: any, loadGeometry: (url: string) => Promise<any>): Promise<void>;
6182
+ /**
6183
+ * Builds the node tree of an effect document whose linked files are already inline (see
6184
+ * {@link loadFromJSON}). `baseUrl` is joined to relative image urls. Parts the loader cannot
6185
+ * read warn and take their defaults; a document with no `object` throws
6186
+ * {@link QuarksFormatError}. Free the effect with {@link disposeEffect}.
6187
+ */
4920
6188
  parse(json: any, baseUrl?: string): TransformNode;
6189
+ /** {@link parse}, and the textures the effect uses. */
6190
+ private parseDocument;
4921
6191
  private parseGeometries;
4922
6192
  /** The scene's copy of an identical geometry when resources are shared, else `geometry` itself. */
4923
6193
  private share;
@@ -4941,12 +6211,15 @@ declare class QuarksLoader {
4941
6211
  * scene fetch cache), then parse. Each index settles exactly once for `onProgress`.
4942
6212
  */
4943
6213
  private loadDocuments;
6214
+ private loadResolvedDocuments;
4944
6215
  /** Runs `fn` over `items` with at most `concurrency` in flight (or all if unset/≤0). */
4945
6216
  private static mapPool;
4946
6217
  private static resolveWith;
4947
6218
  /** One in-flight fetch per scene + resolved url when `scene` is set; otherwise uncached. */
4948
6219
  private static fetchJsonWith;
4949
6220
  private static inlineGeometryEntries;
6221
+ private static warnResourceError;
6222
+ private reportResourceError;
4950
6223
  private parseImages;
4951
6224
  /**
4952
6225
  * Flags an image entry that is plainly not an image, which otherwise only
@@ -4970,57 +6243,278 @@ declare class QuarksLoader {
4970
6243
  private linkReferences;
4971
6244
  }
4972
6245
 
6246
+ /**
6247
+ * A clip a {@link QuarksPrefab} timeline can drive, such as a Babylon `AnimationGroup`. Every
6248
+ * member is optional; the prefab calls only what is there.
6249
+ */
4973
6250
  interface QuarksTimelineClip {
6251
+ /** Names the clip in a saved prefab, so it can be found again on load. */
4974
6252
  uuid?: string;
6253
+ /** Length in seconds, used when the track gives none. */
4975
6254
  duration?: number;
6255
+ /** Called when the timeline enters the track. */
4976
6256
  play?: () => void;
6257
+ /** Called when the prefab pauses. */
4977
6258
  pause?: () => void;
6259
+ /** Called when the timeline leaves the track or the prefab stops. */
4978
6260
  stop?: () => void;
6261
+ /** Called while scrubbing with {@link QuarksPrefab.setTime}, with the time into the track in seconds. */
4979
6262
  setTime?: (time: number) => void;
4980
6263
  }
6264
+ /** One track on a {@link QuarksPrefab} timeline. */
4981
6265
  interface AnimationData extends IAnimationData {
6266
+ /**
6267
+ * `'ps'` plays a particle system, `'three'` plays a {@link QuarksTimelineClip}. The names are
6268
+ * the effect format's, shared with three.quarks, where a `'three'` track plays a three.js
6269
+ * `AnimationClip`; here the clip is whatever the host registered on the target node.
6270
+ */
4982
6271
  type: 'three' | 'ps';
6272
+ /** The node the track drives: a {@link ParticleEmitter} for `'ps'`, any node for `'three'`. */
4983
6273
  target: TransformNode;
6274
+ /** Restart when the track ends instead of letting it finish. */
4984
6275
  loop: boolean;
6276
+ /** The clip a `'three'` track plays. */
4985
6277
  clip?: QuarksTimelineClip;
6278
+ /** The id of the clip on `target`, written to and read from JSON. */
4986
6279
  clipUUID?: string;
4987
6280
  }
6281
+ /**
6282
+ * A node with a timeline that starts and stops the particle systems and clips under it, like a
6283
+ * Unity Timeline or a Niagara System's emitter spawn schedule. Each track starts at `startTime`
6284
+ * and lasts `duration` seconds: a particle system restarts when its track begins and stops
6285
+ * emitting when it ends, a clip plays and stops.
6286
+ *
6287
+ * Call {@link QuarksPrefab.update} every frame (or {@link QuarksPrefab.setTime} to scrub).
6288
+ */
4988
6289
  declare class QuarksPrefab extends TransformNode implements IPrefab {
6290
+ /** Always `'QuarksPrefab'`; written to JSON. */
4989
6291
  type: string;
6292
+ /** The tracks, in the order they were added. */
4990
6293
  animationData: Array<AnimationData>;
6294
+ /** Whether {@link QuarksPrefab.update} advances the timeline. */
4991
6295
  isPlaying: boolean;
6296
+ /** Time on the timeline in seconds; just below 0 before the first update, so a track at 0 starts. */
4992
6297
  currentTime: number;
6298
+ /** Playback speed; 1 is real time. */
4993
6299
  timeScale: number;
6300
+ /** End of the last track in seconds; the prefab stops when it passes it. */
4994
6301
  duration: number;
4995
6302
  private _lastUpdateTimeMs;
4996
6303
  private _batchedRenderer?;
4997
6304
  private _tempAnimationJSON;
4998
6305
  constructor(name?: string, scene?: Scene);
6306
+ /** The renderer that a particle system is added to again when its track starts. */
4999
6307
  registerBatchedRenderer(renderer: BatchedRenderer): void;
6308
+ /**
6309
+ * Adds a track that plays `emitter`'s system, and pauses the prefab.
6310
+ * @param startTime - Seconds into the timeline.
6311
+ * @param duration - Seconds; 0 or less uses the system's own duration.
6312
+ * @param loop - Restart the system when the track ends.
6313
+ */
5000
6314
  addParticleSystemAnimation(emitter: ParticleEmitter, startTime?: number, duration?: number, loop?: boolean): AnimationData;
6315
+ /**
6316
+ * Adds a track that plays `clip` on `target`.
6317
+ * @param startTime - Seconds into the timeline.
6318
+ * @param duration - Seconds; 0 or less uses the clip's duration.
6319
+ * @param loop - Play the clip again when the track ends.
6320
+ * @param clipUUID - Saved in JSON to find the clip on load; defaults to `clip.uuid`.
6321
+ */
5001
6322
  addThreeAnimation(target: TransformNode, clip?: QuarksTimelineClip, startTime?: number, duration?: number, loop?: boolean, clipUUID?: string): AnimationData;
6323
+ /** Removes the track at `index` in {@link QuarksPrefab.animationData}. */
5002
6324
  removeAnimation(index: number): void;
6325
+ /**
6326
+ * Starts or resumes the timeline from {@link QuarksPrefab.currentTime}, resuming the systems and
6327
+ * clips of the tracks it is inside, which {@link QuarksPrefab.pause} paused.
6328
+ */
5003
6329
  play(): void;
6330
+ /** Pauses the timeline and every system and clip on it. */
5004
6331
  pause(): void;
6332
+ /** Pauses, rewinds to the start, and stops every system and clip on it. */
5005
6333
  stop(): void;
6334
+ /**
6335
+ * Advances the timeline, starting and ending tracks it crosses. Stops past {@link QuarksPrefab.duration}.
6336
+ * @param forceDelta - Seconds to advance; by default the wall-clock time since the last update.
6337
+ */
5006
6338
  update(forceDelta?: number): void;
6339
+ /** Jumps to `time` seconds, starting and ending tracks it crosses and scrubbing clips to it. */
5007
6340
  setTime(time: number): void;
6341
+ /** Same as {@link QuarksPrefab.duration}. */
5008
6342
  getDuration(): number;
6343
+ /**
6344
+ * Links the tracks read by {@link QuarksPrefab.fromJSON} to the nodes under `root` they name.
6345
+ * {@link QuarksLoader} calls it once the whole effect is built; tracks whose node is missing are dropped.
6346
+ */
5009
6347
  resolveReferences(root: TransformNode): void;
6348
+ /** Writes the prefab's name, time scale (when not 1) and tracks. */
5010
6349
  toJSON(): any;
6350
+ /** Reads a prefab written by {@link QuarksPrefab.toJSON}; call {@link QuarksPrefab.resolveReferences} afterwards. */
5011
6351
  static fromJSON(json: any, scene?: Scene): QuarksPrefab;
5012
6352
  private resolveTimelineClip;
5013
6353
  private updateDuration;
5014
6354
  }
5015
6355
 
6356
+ /**
6357
+ * The version of the effect file format this library writes, in `metadata.quarksFormat`. It goes
6358
+ * up when a release writes something an older loader would read wrongly. `QuarksLoader`
6359
+ * reads every earlier version, and files written before the field existed, and warns about a
6360
+ * file from a newer version.
6361
+ */
6362
+ declare const QUARKS_FORMAT_VERSION = 1;
6363
+ /** An image a texture reads: a url, a root-relative path, or a `data:` URI. */
6364
+ interface QuarksImageJSON {
6365
+ /** Unique within the file; other entries refer to it by this. */
6366
+ uuid: string;
6367
+ /** Relative to the file's base url, absolute, or a `data:` url. */
6368
+ url: string;
6369
+ }
6370
+ /**
6371
+ * A texture and its sampler state. Every field after `image` is written only when it differs from
6372
+ * Babylon's default for a `Texture`. `wrap` uses the three.js codes the format inherited: 1000
6373
+ * repeat, 1001 clamp, 1002 mirror.
6374
+ */
6375
+ interface QuarksTextureJSON {
6376
+ /** Unique within the file; other entries refer to it by this. */
6377
+ uuid: string;
6378
+ /** The {@link QuarksImageJSON} uuid; absent when the texture had no url a file can point at. */
6379
+ image?: string;
6380
+ /** Default true. */
6381
+ invertY?: boolean;
6382
+ /** Default false. */
6383
+ noMipmap?: boolean;
6384
+ /** A Babylon sampling mode constant. Default trilinear. */
6385
+ samplingMode?: number;
6386
+ /** `[u, v]`. Default repeat on both. */
6387
+ wrap?: [number, number];
6388
+ /** `[uScale, vScale]`. Default `[1, 1]`. */
6389
+ repeat?: [number, number];
6390
+ /** `[uOffset, vOffset]`. Default `[0, 0]`. */
6391
+ offset?: [number, number];
6392
+ /** `wAng`, in radians. Default 0. */
6393
+ rotation?: number;
6394
+ }
6395
+ /** Mesh data, inline. */
6396
+ interface QuarksGeometryJSON {
6397
+ /** Unique within the file; other entries refer to it by this. */
6398
+ uuid: string;
6399
+ /** Always `'QuarksGeometry'`. */
6400
+ type: 'QuarksGeometry';
6401
+ /** `x, y, z` per vertex. */
6402
+ positions: number[];
6403
+ /** Three per triangle. */
6404
+ indices: number[];
6405
+ /** First UV set, `u, v` per vertex. */
6406
+ uvs?: number[];
6407
+ /** Second UV set, `u, v` per vertex. */
6408
+ uvs2?: number[];
6409
+ /** `x, y, z` per vertex. */
6410
+ normals?: number[];
6411
+ }
6412
+ /** A node of an effect: a group, an emitter, a mesh or a prefab, with its children. */
6413
+ interface QuarksNodeJSON {
6414
+ /** Unique within the file; other entries refer to it by this. */
6415
+ uuid: string;
6416
+ /** What the node is; a type the loader does not know loads as an empty node. */
6417
+ type: 'Group' | 'ParticleEmitter' | 'Mesh' | 'QuarksPrefab' | string;
6418
+ /** The node's name. */
6419
+ name?: string;
6420
+ /** Local transform, column-major, as Babylon's `Matrix.asArray()`. */
6421
+ matrix: number[];
6422
+ /** Written only when the node is disabled; loads it disabled, with everything under it. */
6423
+ visible?: false;
6424
+ /** `Mesh`: written only when the mesh is not drawn (`isVisible`), which leaves its children drawn. */
6425
+ isVisible?: false;
6426
+ /** Child nodes, in order. */
6427
+ children?: QuarksNodeJSON[];
6428
+ /** `ParticleEmitter`: the system. */
6429
+ ps?: ParticleSystemJSONParameters;
6430
+ /** `Mesh`: the {@link QuarksGeometryJSON} uuid. */
6431
+ geometry?: string;
6432
+ /** `Mesh`: the material uuid. */
6433
+ material?: string;
6434
+ [key: string]: unknown;
6435
+ }
6436
+ /** A whole effect, as {@link serializeEffect} writes it and `QuarksLoader` reads it. */
6437
+ interface QuarksEffectJSON {
6438
+ /** What wrote the file, and which format version it follows. */
6439
+ metadata: {
6440
+ /** The three.js object format version the envelope follows. */
6441
+ version: number;
6442
+ /** Always `'Object3D'`. */
6443
+ type: 'Object3D';
6444
+ /** The tool that wrote the file, from {@link SerializeEffectOptions.generator}. */
6445
+ generator: string;
6446
+ /** See {@link QUARKS_FORMAT_VERSION}. */
6447
+ quarksFormat: number;
6448
+ };
6449
+ /** Meshes the nodes and particle systems use. */
6450
+ geometries: QuarksGeometryJSON[];
6451
+ /** Materials the particle systems and `Mesh` nodes use, referred to by uuid. */
6452
+ materials: Array<Record<string, unknown>>;
6453
+ /** Textures the particle systems use. */
6454
+ textures: QuarksTextureJSON[];
6455
+ /** Image files the textures load. */
6456
+ images: QuarksImageJSON[];
6457
+ /** The effect's root node. */
6458
+ object: QuarksNodeJSON;
6459
+ }
6460
+ /** Options for {@link serializeEffect}. */
6461
+ interface SerializeEffectOptions {
6462
+ /** Written to `metadata.generator`. Default `'babylon.quarks'`. */
6463
+ generator?: string;
6464
+ /**
6465
+ * Leaves a node and everything under it out of the file when it returns false, e.g. helpers an
6466
+ * editor parents under an effect.
6467
+ */
6468
+ filter?: (node: TransformNode) => boolean;
6469
+ /**
6470
+ * Called for each part of the effect the file cannot hold as it is, such as a texture with no
6471
+ * url a file can point at. Default: `console.warn`.
6472
+ */
6473
+ onWarning?: (message: string) => void;
6474
+ /** Several roots are written as children of one group; its name. Default `'effect'`. */
6475
+ name?: string;
6476
+ /**
6477
+ * The url written for a texture's image. Default: the url the texture's image had in the file
6478
+ * it was loaded from (see {@link textureSourceUrl}), so a file saved next to its source loads
6479
+ * the same images; for a texture made in code, its `url`. Return a path relative to where the
6480
+ * file will be saved when that differs from the source, or give a texture made in code a url or
6481
+ * a `data:` URI. Return `null` to write the texture without an image.
6482
+ */
6483
+ imageUrl?: (texture: Texture) => string | null | undefined;
6484
+ }
6485
+ /**
6486
+ * Writes an effect, the node tree under `root` with its emitters, meshes and prefabs, as one JSON
6487
+ * document `QuarksLoader` loads back: the counterpart of `loader.load()`. The result holds
6488
+ * only plain data, so `JSON.stringify` takes it as is. Nodes keep their ids
6489
+ * ({@link quarksNodeId}), so sub emitters, mesh surface shapes and prefab animations still find
6490
+ * their targets, and a loaded effect saved again writes the same file.
6491
+ *
6492
+ * Textures are written by url, with their sampler state. One with no url a file can point at is
6493
+ * written without its image and reported through `onWarning`. Several roots are written as
6494
+ * children of one group.
6495
+ */
6496
+ declare function serializeEffect(root: TransformNode | TransformNode[], options?: SerializeEffectOptions): QuarksEffectJSON;
6497
+
6498
+ /**
6499
+ * Helpers that act on a whole effect: every particle system under a root node, as a loaded effect
6500
+ * or a hand-built tree has them.
6501
+ */
5016
6502
  declare class QuarksUtil {
6503
+ /** Calls `callback` on `root` and every node under it that is a {@link ParticleEmitter}. */
5017
6504
  static runOnAllParticleEmitters(root: Node, callback: (emitter: ParticleEmitter) => void): void;
6505
+ /** Adds every system under `root` to `batchRenderer`. */
5018
6506
  static addToBatchRenderer(root: Node, batchRenderer: BatchedRenderer): void;
6507
+ /** Resumes every system under `root`, see {@link ParticleSystem.play}. */
5019
6508
  static play(root: Node): void;
6509
+ /** Clears, rewinds and pauses every system under `root`, see {@link ParticleSystem.stop}. */
5020
6510
  static stop(root: Node): void;
6511
+ /** Pauses every system under `root`, see {@link ParticleSystem.pause}. */
5021
6512
  static pause(root: Node): void;
6513
+ /** Restarts every system under `root` from the beginning, see {@link ParticleSystem.restart}. */
5022
6514
  static restart(root: Node): void;
6515
+ /** Sets {@link ParticleSystem.autoDestroy} on every system under `root`. */
5023
6516
  static setAutoDestroy(root: Node, autoDestroy: boolean): void;
6517
+ /** Ends emission on every system under `root` and lets the particles die out, see {@link ParticleSystem.endEmit}. */
5024
6518
  static endEmit(root: Node): void;
5025
6519
  /**
5026
6520
  * True when every system under `root` is finished: non-looping ones that
@@ -5055,258 +6549,135 @@ declare class QuarksUtil {
5055
6549
  private static traverseNode;
5056
6550
  }
5057
6551
 
5058
- declare function registerShaderChunks(): void;
5059
- declare function getShaderChunk(chunkName: string): string | undefined;
5060
- declare function getRegisteredShaderChunks(): Readonly<Record<string, string>>;
5061
-
5062
- declare const _default$7: string;
5063
-
5064
- 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";
5065
-
5066
- declare const _default$5: string;
5067
-
5068
- declare const _default$4: string;
5069
-
5070
- declare const _default$3: string;
5071
-
5072
- declare const _default$2: string;
5073
-
5074
- declare const _default$1: string;
5075
-
5076
- declare const _default: string;
6552
+ /**
6553
+ * Picking the shader language a batch compiles in, and putting the source where
6554
+ * the engine will look for it.
6555
+ *
6556
+ * WebGPU speaks WGSL. Handing it GLSL is not an error — Babylon transpiles —
6557
+ * but the transpilers are two WASM modules it downloads from cdn.babylonjs.com
6558
+ * the first time a GLSL shader is compiled. That is a third-party request on
6559
+ * first draw, a hard failure under a Content-Security-Policy that does not list
6560
+ * the CDN or with no network at all, and a GLSL to SPIR-V to WGSL round trip
6561
+ * before the first particle appears. Shipping the WGSL means none of that
6562
+ * happens.
6563
+ *
6564
+ * The two languages live in separate stores keyed by the same name, so a scene
6565
+ * that somehow ran both would not collide.
6566
+ */
6567
+ interface ShaderSources {
6568
+ /** GLSL source, used on every WebGL engine. */
6569
+ glsl: string;
6570
+ /** WGSL source, used on WebGPU. */
6571
+ wgsl: string;
6572
+ }
5077
6573
 
5078
- declare class SpriteBatch extends VFXBatch {
5079
- private static whiteTextureByScene;
5080
- /** 1×1 white map so mesh batches always have a sampler2D (iOS WebKit). */
5081
- private static whiteTexture;
5082
- private offsetBuffer;
5083
- private rotationBuffer;
5084
- private sizeBuffer;
5085
- private colorBuffer;
5086
- private uvTileBuffer;
5087
- private velocityBuffer?;
5088
- /** Concretely typed handle on the batch material, see syncStretchedSpeedFactor. */
5089
- private shaderMaterial;
5090
- /** The `'fixed'` mesh light, as shader uniforms; see applyMeshLighting. */
5091
- private readonly fixedLightDirection;
5092
- private readonly fixedLightColor;
5093
- private readonly fixedAmbientColor;
5094
- private offsetVB;
5095
- private rotationVB;
5096
- private sizeVB;
5097
- private colorVB;
5098
- private uvTileVB;
5099
- private velocityVB?;
5100
- constructor(settings: VFXBatchSettings, scene: Scene);
5101
- setupBuffers(): void;
5102
- /**
5103
- * True when a mesh batch reads UV channel 1 and has a second UV set to
5104
- * read it from, two values per vertex. A set of any other length is left
5105
- * out with a warning, and channel 1 then reads the first set.
5106
- */
5107
- private warnedUV2;
5108
- private meshUV2;
5109
- /** Releases the instance vertex buffers so a resize does not leak GPU memory. */
5110
- private disposeExpandableBuffers;
5111
- private buildExpandableBuffers;
5112
- expandBuffers(target: number): void;
5113
- /** The screen-size limits as a uniform value, or null when the batch has none that apply. */
5114
- private sizeLimits;
5115
- private sortScratch?;
5116
- /** One spare array per attribute buffer, gathered into and swapped in; indexed by buffer slot. */
5117
- private readonly gatherScratch;
5118
- /**
5119
- * Reorders the `count` filled instances by the batch's sort mode, so that
5120
- * the later (covering) draws are the nearer or the chosen-age particles.
5121
- * The order is computed once as a permutation and every attribute buffer
5122
- * is gathered through it into a spare array that then takes its place.
5123
- */
5124
- private sortInstances;
5125
- /** Gathers `source` in `order` into the spare array of `slot` and returns it; the source becomes the spare. */
5126
- private gatherInto;
5127
- rebuildMaterial(): void;
5128
- applyMeshLighting(lighting: MeshLightingSettings): void;
5129
- private storeFixedLighting;
5130
- private writeFixedLighting;
5131
- /**
5132
- * Reads the scene's key light for `'scene'` mesh lighting: the first
5133
- * enabled directional or hemispheric light, its diffuse colour times its
5134
- * intensity, plus the scene's ambient colour. A hemispheric light lights
5135
- * from its `direction` (which points at the sky) and adds its ground colour
5136
- * to the ambient, which approximates its sky-to-ground blend with the one
5137
- * directional term the shader has. False when there is no such light.
5138
- */
5139
- static readSceneLight(scene: Scene, direction: Vector3$1, color: Vector3$1, ambient: Vector3$1): boolean;
5140
- private vector_;
5141
- private vector2_;
5142
- private vector3_;
5143
- private quaternion_;
5144
- private quaternion2_;
5145
- private quaternion3_;
5146
- private quaternion4_;
5147
- private quaternion5_;
5148
- private rotationMat_;
5149
- private rotationMat2_;
5150
- private lastStretchedSpeedFactor;
5151
- /** Slot 0 holds the zero-alpha instance since the batch last went empty. */
5152
- private clearedInstanceUploaded;
5153
- update(): void;
5154
- /**
5155
- * Pushes the stretched-billboard speed factor to the shader when it changed.
5156
- *
5157
- * Deliberately kept out of `update`: touching the loosely typed
5158
- * `mesh.material` from inside that function gives V8 a generic property
5159
- * access it has no feedback for, which knocks the whole particle loop out of
5160
- * optimised code on every frame.
5161
- */
5162
- private syncStretchedSpeedFactor;
5163
- /** Stretched billboards and beams: drawn along a per-instance vector, by the stretched shader. */
5164
- private static drawsAlongVelocity;
5165
- private readonly beamEnd_;
5166
- /**
5167
- * Writes, for the `count` instances from `first`, the world vector from
5168
- * each one's drawn position to the system's beam end into the velocity
5169
- * buffer, which the stretched shader under `BEAM` lays the quad along. A
5170
- * beam without an end gets no length.
5171
- */
5172
- private writeBeams;
5173
- /** The quads that take a pivot and flip: every billboard kind, stretched included, but not meshes or beams. */
5174
- private static takesPivotAndFlip;
5175
- /** Multiplies `count` RGBA colours starting at `base` by a system's {@link ParticleSystem.tint}. */
5176
- private static applyTint;
5177
- /**
5178
- * Negates the size of each flipped particle along the axes it flips on,
5179
- * starting at `base` in `sizes`. The billboard shader scales the quad by
5180
- * the size, so a negative one mirrors it — and with it the texture, the
5181
- * quad being centred — the way Unity's renderer Flip mirrors U and V. The
5182
- * stretched shader reads the sign and mirrors the texture coordinates.
5183
- */
5184
- private static applyFlip;
5185
- /** The same for a system without a store, read off the particles. */
5186
- private static applyFlipFromParticles;
5187
- /**
5188
- * Writes the mesh rotations for rows `[0, count)` of a store: each
5189
- * particle's quaternion, carried on by `fraction` of its last turn (see
5190
- * {@link partialTurn}) and, for a local-space system, turned by the
5191
- * emitter's rotation `parent`.
5192
- */
5193
- private static writeQuaternions;
5194
- /**
5195
- * Writes the stretched billboards' velocity attribute for rows `[0, count)`
5196
- * of a store: the velocity carried on by `fraction` of the last step (see
5197
- * {@link extrapolate}), turned into world space by `rotation` when the
5198
- * system simulates locally, scaled by the speed factor, with the length
5199
- * factor in `w`.
5200
- */
5201
- private static writeVelocities;
5202
- /**
5203
- * The fraction `f` of a turn, as a normalised lerp from no rotation toward
5204
- * `step`, written into `out`.
5205
- *
5206
- * A true slerp would be exact, but `step` is one simulation step of turning
5207
- * and `f` is below 1, so the arc being split is small enough that the lerp
5208
- * is within a rounding error of it and costs a fraction as much.
5209
- */
5210
- private static partialTurn;
5211
- /**
5212
- * Continues a three-component column by `fraction` of the step it just took,
5213
- * never below zero.
5214
- *
5215
- * Size fades to nothing at the end of a life, so the last step before death
5216
- * can point past zero; a negative size turns a sprite inside out.
5217
- */
5218
- private static continueVector3;
5219
- /** The same for colour, whose alpha runs out at the end of a life too. */
5220
- private static continueColor;
6574
+ /**
6575
+ * The part of a batch's settings that decides its shader: the render mode, which textures and
6576
+ * effects are compiled in, and the blend state the fog and the fade read. Everything else a
6577
+ * batch holds (geometry, draw order, the effects' parameters) is a buffer or a uniform value.
6578
+ */
6579
+ type ShaderSettings = Pick<StoredBatchSettings, 'renderMode' | 'texture' | 'reflectionAtlas' | 'uTileCount' | 'vTileCount' | 'blendTiles' | 'softParticles' | 'materialAlphaTest' | 'materialTransparent' | 'materialBlendMode' | 'applyFog' | 'pivot' | 'minParticleSize' | 'maxParticleSize' | 'lighting' | 'rim' | 'mapUV' | 'uvDistortion' | 'gradientMap' | 'erosion'>;
6580
+ /** What the material needs to know about the depth texture soft particles read. */
6581
+ interface ShaderDepth {
6582
+ /** Whether the depth is packed into four 8-bit channels, as a `DepthRenderer` of type `UNSIGNED_BYTE` writes it. */
6583
+ packed: boolean;
6584
+ }
6585
+ /**
6586
+ * What a batch knows at compile time that its settings do not say: whether the textures it
6587
+ * depends on are there to be sampled.
6588
+ */
6589
+ interface ShaderContext {
5221
6590
  /**
5222
- * Writes rows `[0, count)` of the store's positions into `target` at `base`,
5223
- * each carried on by `fraction` of the step it just took.
5224
- *
5225
- * Continuing the measured last step covers every way a particle can move —
5226
- * velocity integration, an orbit, noise, a plugin's own behavior — because
5227
- * it reads what happened rather than predicting from one term of it. Over
5228
- * less than a step it is a straight line through a path that may curve,
5229
- * which for a sixtieth of a second is well under a pixel.
5230
- *
5231
- * A particle born during the step has the same position on both sides and
5232
- * so does not move at all, which is what puts it at the emitter rather than
5233
- * a step's travel away from it.
6591
+ * The depth texture soft particles read, when one is attached to the renderer. Soft particles
6592
+ * compile only with a depth texture.
5234
6593
  */
5235
- private static extrapolate;
5236
- /** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
5237
- private uploadClearedInstance;
5238
- dispose(): void;
6594
+ depth: ShaderDepth | null;
6595
+ /** Whether the mesh batch's reflection atlas has finished loading; it is sampled only then. */
6596
+ envAtlasReady: boolean;
6597
+ /** Whether the mesh batch has a second UV set to read for {@link UVChannel} 1. */
6598
+ meshUV2: boolean;
5239
6599
  }
6600
+ /**
6601
+ * One compiled shader of the library: the sources in both languages and the defines, attributes,
6602
+ * uniforms and samplers the material is built with. Built by {@link shaderProgram} from a
6603
+ * batch's settings, so a batch and a shader validator describe the same material.
6604
+ */
6605
+ interface ShaderProgram {
6606
+ /** The name the sources are registered under in Babylon's shader store, one per render mode. */
6607
+ name: string;
6608
+ /** The vertex shader in both languages. */
6609
+ vertex: ShaderSources;
6610
+ /** The fragment shader in both languages. */
6611
+ fragment: ShaderSources;
6612
+ /** The preprocessor defines, without the `#define`. */
6613
+ defines: string[];
6614
+ /** The vertex attributes the material binds. */
6615
+ attributes: string[];
6616
+ /** The uniforms the material declares. */
6617
+ uniforms: string[];
6618
+ /** The texture samplers the material declares. */
6619
+ samplers: string[];
6620
+ }
6621
+ /** The shader program a batch with `settings` compiles, given what it knows about its textures. */
6622
+ declare function shaderProgram(settings: ShaderSettings, context: ShaderContext): ShaderProgram;
5240
6623
 
5241
- declare class TrailBatch extends VFXBatch {
5242
- private positionBuffer;
5243
- private previousBuffer;
5244
- private nextBuffer;
5245
- private uvBuffer;
5246
- /** UV channel 1: along the trail and across it, without the sheet's cell; only when a texture reads it. */
5247
- private uv1Buffer;
5248
- private sideBuffer;
5249
- private widthBuffer;
5250
- private colorBuffer;
5251
- private indexBuffer;
5252
- /** True while the batch is parked on the degenerate draw, see uploadGeometry. */
5253
- private drawsNothing;
5254
- private previousVB;
5255
- private nextVB;
5256
- private sideVB;
5257
- private widthVB;
5258
- constructor(settings: VFXBatchSettings, scene: Scene);
5259
- setupBuffers(): void;
5260
- private buildGeometryBuffers;
5261
- expandBuffers(target: number): void;
5262
- rebuildMaterial(): void;
5263
- private vector_;
5264
- private vector2_;
5265
- private vector3_;
5266
- private quaternion_;
5267
- /**
5268
- * Brings the emitter's world matrix up to date when its transform changed.
5269
- *
5270
- * Babylon only recomputes a world matrix once per render id, so a frame that
5271
- * moves the emitter after that (or a step driven without rendering) would
5272
- * draw the ribbon against the old one. Recomputing unconditionally every
5273
- * frame costs a matrix compose per system; checking the transform cache
5274
- * first makes a still emitter free.
5275
- */
5276
- /**
5277
- * Writes a swept ribbon's vertex pair at `pi`: the sample at (x, y, z)
5278
- * pushed `half` widths along its side (sx, sy, sz) one way for the first
5279
- * vertex and the other way for the second.
5280
- */
5281
- private writeSweptPair;
5282
- private static ensureWorldMatrix;
5283
- update(): void;
5284
- /**
5285
- * Records a system's world bounds from the ribbon vertices just written for
5286
- * it, padded by the widest ribbon. The store only holds each trail's head,
5287
- * so this is where a trail's extent is known.
5288
- */
5289
- private measureSystemBounds;
5290
- /**
5291
- * Uploads the vertex data written by `update` and resizes the sub mesh.
5292
- *
5293
- * Split out of `update` on purpose: the Babylon mesh/sub-mesh plumbing here
5294
- * runs a handful of times per frame, and folding it into the per-vertex loop
5295
- * costs that loop its optimised code.
5296
- */
5297
- private uploadGeometry;
5298
- /**
5299
- * Points every sub mesh at the mesh's own bounds.
5300
- *
5301
- * Updating indices rebuilds the sub meshes, and a fresh one computes its
5302
- * bounds from the vertex data — which this batch keeps deliberately stale
5303
- * beyond the range it draws. Transparent sorting reads those bounds every
5304
- * frame, so they have to be replaced again after every index update, not
5305
- * only when the geometry is built.
5306
- */
5307
- private adoptMeshBounds;
5308
- dispose(): void;
6624
+ /**
6625
+ * One shader the library can compile: a {@link ShaderProgram} with the settings that produce it,
6626
+ * named for the renderer's benefit. See {@link shaderVariants}.
6627
+ */
6628
+ interface ShaderVariant {
6629
+ /** The render mode and the features compiled in, for a report. */
6630
+ name: string;
6631
+ /** The program a batch with these settings builds. */
6632
+ program: ShaderProgram;
5309
6633
  }
6634
+ /**
6635
+ * Every shader program the library can compile, one per distinct set of defines: every render
6636
+ * mode with every combination of sheet, map, soft particles, alpha test and fog, and the texture
6637
+ * effects alone and together on each shader family. What a shader validator compiles, and what
6638
+ * an application can warm the shader cache with before its first frame (Unity's
6639
+ * ShaderVariantCollection). Built by {@link shaderProgram}, so a variant here is a material a
6640
+ * batch would build.
6641
+ */
6642
+ declare function shaderVariants(): ShaderVariant[];
6643
+
6644
+ /**
6645
+ * The url a texture's image had in the effect file it was loaded from, relative to that file.
6646
+ * `serializeEffect` writes it by default, so a file saved next to the one it was loaded from loads
6647
+ * the same images.
6648
+ *
6649
+ * `undefined` when there is no such url: a texture made in code or loaded another way; a texture
6650
+ * whose image the loader's resolver inlined (`data:` or `blob:`), which holds the image itself; and
6651
+ * a texture whose `url` was changed since it was loaded (`updateURL`, or a `data:` URI assigned
6652
+ * before saving), since the file's path no longer names what it shows.
6653
+ *
6654
+ * A texture shared between effects (see `QuarksLoaderOptions.shareResources`) keeps the url of the
6655
+ * first effect that loaded it; effects in different folders that join to the same image share it.
6656
+ */
6657
+ declare function textureSourceUrl(texture: Texture): string | undefined;
6658
+
6659
+ /**
6660
+ * The normalised values of a trail's optional settings (`TrailSettings`), each read with its
6661
+ * default for a value that is unset or out of range, so the batch, the simulation, JSON and
6662
+ * clones agree on what a setting means.
6663
+ */
6664
+ /** Most segments one recorded segment of a trail is drawn as, see `TrailSettings.tessellation`. */
6665
+ declare const MAX_TRAIL_TESSELLATION = 16;
6666
+ /** A trail's tessellation, a whole number from 0 (the default: none) to {@link MAX_TRAIL_TESSELLATION}. */
6667
+ declare function trailTessellation(settings: TrailSettings | undefined): number;
6668
+ /** A trail's curve tension, from 0 (the default: Catmull-Rom) to 1 (straight segments). */
6669
+ declare function trailCurveTension(settings: TrailSettings | undefined): number;
6670
+ /** A trail's texture mode, `'stretch'` (the default) unless set to one of the others. */
6671
+ declare function trailTextureMode(settings: TrailSettings | undefined): TrailTextureMode;
6672
+ /** A trail's texture scale: a finite number above 0, else the default 1. */
6673
+ declare function trailTextureScale(settings: TrailSettings | undefined): number;
6674
+ /** A trail's minimum distance between samples: a finite number of at least 0, else the default 0. */
6675
+ declare function trailMinVertexDistance(settings: TrailSettings | undefined): number;
6676
+ /**
6677
+ * How long a trail keeps a sample, in seconds: a finite number above 0, else `Infinity` (the
6678
+ * default, as 0 is: until the history is full).
6679
+ */
6680
+ declare function trailLifetime(settings: TrailSettings | undefined): number;
5310
6681
 
5311
- export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, BoxEmitFrom, BoxEmitter, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EdgeEmitter, EffectPool, EmitSubParticleSystem, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GRADIENT_MAP_WEIGHTS, 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, QuaternionView, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, ShapeTransform, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteBatch, SpriteParticle, SubEmitterInheritMask, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, UV_DISTORTION_DEFAULT_UV, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, createSeededRandom, cubeFaceUrls, damp, defaultMeshLighting, degToRad, denormalize, ensureEnvAtlasFromCube, erosionEqual, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRandomSource, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, gradientMapEqual, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, mapUVEqual, meshRimEqual, normalize, normalizeErosion, normalizeGradientMap, normalizeMapUV, normalizeMeshRim, normalizeTextureUV, normalizeUVDistortion, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, random, readsUV1, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, setRandomSource, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, subEmitterInheritMask, textureUVEqual, textureUVToJSON, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin, uvDistortionEqual, withRandomSource };
5312
- export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, BeamEnd, Behavior, BehaviorPlugin, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, CullingMode, DonutEmitterParameters, EdgeEmitterParameters, EffectPoolOptions, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FrameOverLifeOptions, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GradientMapChannel, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleErosion, ParticleErosionOptions, ParticleGradientMap, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, ParticleUVDistortion, ParticleUVDistortionOptions, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RandomSource, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, ScalingMode, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SortMode, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, SubEmitterInheritance, TextureUV, TrailSettings, UVChannel, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };
6682
+ export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, BoxEmitFrom, BoxEmitter, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EROSION_DEFAULT_SOFTNESS, EdgeEmitter, EffectPool, EmitSubParticleSystem, EmitterFrame, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GRADIENT_MAP_WEIGHTS, GeneratorFromJSON, Gradient, GravityForce, GridEmitter, HemisphereEmitter, InheritVelocity, IntervalValue, LimitSpeedOverLife, MAX_TRAIL_TESSELLATION, MathUtils, Matrix3, Matrix4, MeshSurfaceEmitter, MeshSurfaceEmitterPlugin, NodeParticle, Noise, OrbitOverLife, ParticleEmitter, ParticleStore, ParticleSystem, PiecewiseBezier, PiecewiseFunction, Plugins, PointEmitter, QUARKS_FORMAT_VERSION, QuarksFormatError, QuarksLoader, QuarksPrefab, QuarksUtil, Quaternion, QuaternionView, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, ShapeTransform, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteParticle, SubEmitterInheritMask, SubParticleEmitMode, TextureSequencer, TrailParticle, TurbulenceField, UV_DISTORTION_DEFAULT_STRENGTH, UV_DISTORTION_DEFAULT_UV, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, createSeededRandom, cubeFaceUrls, damp, decodeSoftDepth, defaultMeshLighting, degToRad, denormalize, disposeEnvAtlas, ensureEnvAtlasFromCube, erosionEqual, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRandomSource, getValueFromEmitterMode, gradientMapEqual, inverseLerp, isPowerOfTwo, lerp, loadPlugin, mapLinear, mapUVEqual, meshRimEqual, normalize, normalizeErosion, normalizeGradientMap, normalizeMapUV, normalizeMeshRim, normalizeTextureUV, normalizeUVDistortion, pingpong, planBehaviorFusion, quarksNodeId, radToDeg, randFloat, randFloatSpread, randInt, random, readBehaviorSpace, readsUV1, seededRandom, serializeEffect, setPhysicsResolver, setQuaternionFromProperEuler, setRandomSource, shaderProgram, shaderVariants, smootherstep, smoothstep, softDepthParams, speedFraction, subEmitterInheritMask, textureSourceUrl, textureUVEqual, textureUVToJSON, trailCurveTension, trailLifetime, trailMinVertexDistance, trailTessellation, trailTextureMode, trailTextureScale, unloadPlugin, uvDistortionEqual, withRandomSource };
6683
+ export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BeamEnd, Behavior, BehaviorPlugin, BehaviorSpace, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, CullingMode, DepthTextureOptions, DonutEmitterParameters, EdgeEmitterParameters, EffectPoolOptions, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FrameOverLifeOptions, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GradientMapChannel, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleErosion, ParticleErosionOptions, ParticleGradientMap, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, ParticleUVDistortion, ParticleUVDistortionOptions, PhysicsResolver, Plugin, QuarksBatchLoadOptions, QuarksEffectJSON, QuarksGeometryJSON, QuarksImageJSON, QuarksJSONLoadEntry, QuarksLoadOptions, QuarksLoaderOptions, QuarksNodeJSON, QuarksResourceKind, QuarksResourceResolver, QuarksTextureJSON, QuarksTimelineClip, RandomSource, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, ScalingMode, Sequencer, SerializationOptions, SerializeEffectOptions, ShaderContext, ShaderDepth, ShaderProgram, ShaderSettings, ShaderSources, ShaderVariant, ShapeJSON, ShapeTransformJSON, SoftDepthEncoding, SortMode, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, SubEmitterInheritance, TextureUV, TrailSettings, TrailTextureMode, UVChannel, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };