babylon.quarks 0.25.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 +854 -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 +2210 -613
  11. package/package.json +12 -6
  12. package/src/BatchedRenderer.ts +215 -106
  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 +1012 -1962
  17. package/src/QuarksLoader.ts +463 -75
  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 +149 -238
  22. package/src/TrailBatch.ts +586 -286
  23. package/src/VFXBatch.ts +517 -153
  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 +51 -35
  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 +132 -42
  35. package/src/shaders/local_particle_physics_vert.glsl.ts +28 -27
  36. package/src/shaders/local_particle_physics_vert.wgsl.ts +30 -28
  37. package/src/shaders/particle_frag.glsl.ts +6 -22
  38. package/src/shaders/particle_frag.wgsl.ts +6 -23
  39. package/src/shaders/particle_physics_frag.glsl.ts +22 -29
  40. package/src/shaders/particle_physics_frag.wgsl.ts +22 -30
  41. package/src/shaders/particle_vert.glsl.ts +11 -26
  42. package/src/shaders/particle_vert.wgsl.ts +11 -25
  43. package/src/shaders/stretched_bb_particle_vert.glsl.ts +21 -39
  44. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +22 -40
  45. package/src/shaders/trail_frag.glsl.ts +14 -1
  46. package/src/shaders/trail_frag.wgsl.ts +14 -0
  47. package/src/shaders/trail_vert.glsl.ts +53 -36
  48. package/src/shaders/trail_vert.wgsl.ts +54 -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;
@@ -1121,13 +1135,82 @@ interface TrailSettings {
1121
1135
  * @type {boolean}
1122
1136
  */
1123
1137
  recordWorldSpace?: boolean;
1124
- }
1125
- interface MeshSettings {
1126
1138
  /**
1127
- * Rotation axis.
1139
+ * Sweep the ribbon along this axis of the emitter instead of turning it to
1140
+ * face the camera: every sample records the axis as the emitter held it,
1141
+ * and the ribbon spans the particle's width along it, centred on the
1142
+ * particle. With the emitter on a blade, the axis along the blade and the
1143
+ * width the blade's length, the trail is the surface the blade swept, as a
1144
+ * weapon trail (Unreal's AnimTrail) is. The emitter's scale applies to the
1145
+ * width, and so does the axis's length: give a unit vector for the width
1146
+ * as set. Unset (the default): a camera-facing ribbon.
1128
1147
  * @type {Vector3}
1129
1148
  */
1130
- rotationAxis?: Vector3;
1149
+ sideAxis?: Vector3;
1150
+ /**
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}
1208
+ */
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 {
1131
1214
  /**
1132
1215
  * Initial rotation around the X-axis.
1133
1216
  * @type {ValueGenerator | FunctionValueGenerator}
@@ -1196,6 +1279,12 @@ interface IParticleSystem {
1196
1279
  * @type {boolean}
1197
1280
  */
1198
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;
1199
1288
  /**
1200
1289
  * Whether the ParticleSystem should be automatically disposed when it finishes emitting particles.
1201
1290
  * @type {string}
@@ -1415,6 +1504,14 @@ interface Particle extends IParticle {
1415
1504
  * @type {Vector3}
1416
1505
  */
1417
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;
1418
1515
  reset(): void;
1419
1516
  }
1420
1517
  /**
@@ -1490,6 +1587,8 @@ declare class SpriteParticle implements Particle {
1490
1587
  * @type {Matrix4}
1491
1588
  */
1492
1589
  parentMatrix?: Matrix4;
1590
+ /** See {@link Particle.serial}. */
1591
+ serial?: number;
1493
1592
  /**
1494
1593
  * Initial speed of the particle, kept in the store's `startSpeed` column.
1495
1594
  * @type {number}
@@ -1646,6 +1745,8 @@ declare class TrailParticle implements Particle {
1646
1745
  * @type {Matrix4}
1647
1746
  */
1648
1747
  parentMatrix?: Matrix4;
1748
+ /** See {@link Particle.serial}. */
1749
+ serial?: number;
1649
1750
  /**
1650
1751
  * Initial speed of the particle, kept in the store's `startSpeed` column.
1651
1752
  * @type {number}
@@ -1716,7 +1817,8 @@ declare class TrailParticle implements Particle {
1716
1817
  get speedModifier(): number;
1717
1818
  set speedModifier(value: number);
1718
1819
  /**
1719
- * 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.
1720
1822
  * @type {number}
1721
1823
  */
1722
1824
  length: number;
@@ -1760,7 +1862,21 @@ declare class TrailParticle implements Particle {
1760
1862
  headWidthScale: number;
1761
1863
  /** Ring buffer of recorded colors, 4 floats per sample. */
1762
1864
  historyColors: Float32Array;
1763
- /** Number of samples the ring buffers can hold. */
1865
+ /**
1866
+ * Ring buffer of recorded side vectors, 3 floats per sample, in the space
1867
+ * the positions are recorded in. Empty unless the trail is swept along an
1868
+ * axis (`TrailSettings.sideAxis`); see {@link ensureSideHistory}.
1869
+ */
1870
+ historySides: Float32Array;
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. */
1764
1880
  historyCapacity: number;
1765
1881
  /** Slot the next sample is written to. */
1766
1882
  historyHead: number;
@@ -1780,10 +1896,14 @@ declare class TrailParticle implements Particle {
1780
1896
  /** Re-points the vector views after the store grew its arrays. */
1781
1897
  rebind(): void;
1782
1898
  /**
1783
- * 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.
1784
1902
  * @param {number} capacity - Number of samples to hold.
1785
1903
  */
1786
1904
  ensureHistoryCapacity(capacity: number): void;
1905
+ /** Allocates {@link historySides} for the current capacity, once a trail is swept. */
1906
+ ensureSideHistory(): void;
1787
1907
  /** Drops every recorded sample without releasing the buffers. */
1788
1908
  resetHistory(): void;
1789
1909
  /**
@@ -1792,10 +1912,25 @@ declare class TrailParticle implements Particle {
1792
1912
  */
1793
1913
  getHistoryIndex(i: number): number;
1794
1914
  /**
1795
- * Records the current state into the trail ring buffer, or retires the
1796
- * 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.
1797
1930
  */
1798
- update(): void;
1931
+ measureHeadDistance(): void;
1932
+ /** Drops the oldest sample, the one the tail is drawn from, keeping the rest. */
1933
+ dropOldest(): void;
1799
1934
  /**
1800
1935
  * Indicates if the particle has died.
1801
1936
  * @type {boolean}
@@ -1816,12 +1951,42 @@ type ParameterType = FieldType | 'self';
1816
1951
  type ParameterPair = [string, Array<ParameterType>];
1817
1952
 
1818
1953
  /**
1819
- * Interface for particle behaviors.
1820
- * 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.
1821
1983
  */
1822
1984
  interface Behavior {
1985
+ /** The name the behavior is registered under in {@link BehaviorTypes}. */
1823
1986
  type: string;
1987
+ /** Called once per particle when it is emitted; see the interface's description for when. */
1824
1988
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
1989
+ /** Called once per live particle per step, with the step's length in seconds. */
1825
1990
  update(particle: Particle, delta: number): void;
1826
1991
  /**
1827
1992
  * Optional bulk form of {@link update}, applied to `particles[0..count)`.
@@ -1830,15 +1995,19 @@ interface Behavior {
1830
1995
  * behavior type, which leaves it megamorphic: V8 can neither inline it nor
1831
1996
  * specialise the generator calls inside. A behavior that implements this
1832
1997
  * instead gets one call per frame and a loop it owns, where those calls are
1833
- * monomorphic. Implementations must skip dead particles exactly as the
1834
- * 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.
1835
2000
  *
1836
2001
  * Behaviors that do not implement it keep working unchanged.
1837
2002
  */
1838
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. */
1839
2005
  frameUpdate(delta: number): void;
2006
+ /** The behavior's settings as plain data, with its `type`; see the interface's description. */
1840
2007
  toJSON(): any;
2008
+ /** A copy with the same settings that shares nothing mutable with this one. */
1841
2009
  clone(): Behavior;
2010
+ /** Called when the system restarts: forget state accumulated across steps. */
1842
2011
  reset(): void;
1843
2012
  }
1844
2013
  interface BehaviorPlugin {
@@ -1850,22 +2019,63 @@ interface BehaviorPlugin {
1850
2019
  declare const BehaviorTypes: {
1851
2020
  [key: string]: BehaviorPlugin;
1852
2021
  };
2022
+ /**
2023
+ * Reads a behavior. A type no plugin registered warns and gives `null`; the system loads without
2024
+ * that behavior.
2025
+ */
1853
2026
  declare function BehaviorFromJSON(json: any, particleSystem: IParticleSystem): Behavior | null;
1854
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
+ */
1855
2032
  interface PhysicsResolver {
1856
- 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;
1857
2039
  }
1858
- declare function setPhysicsResolver(resolver: PhysicsResolver): void;
1859
- declare function getPhysicsResolver(): PhysicsResolver;
1860
2040
  /**
1861
- * 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.
1862
2060
  */
1863
2061
  declare class ApplyCollision implements Behavior {
1864
- 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. */
1865
2068
  bounce: number;
1866
2069
  type: string;
1867
2070
  tempV: Vector3;
1868
- 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);
1869
2079
  initialize(particle: Particle): void;
1870
2080
  update(particle: Particle, delta: number): void;
1871
2081
  frameUpdate(delta: number): void;
@@ -1876,19 +2086,98 @@ declare class ApplyCollision implements Behavior {
1876
2086
  }
1877
2087
 
1878
2088
  /**
1879
- * 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.
1880
2152
  */
1881
2153
  declare class ApplyForce implements Behavior {
2154
+ /** The direction of the force; its length scales it. */
1882
2155
  direction: Vector3;
2156
+ /** The force's strength, in units per second squared, rolled per particle. */
1883
2157
  magnitude: ValueGenerator;
2158
+ /** The space the direction is authored in; `'world'` by default. */
2159
+ space: BehaviorSpace;
1884
2160
  type: string;
1885
- magnitudeValue: number;
1886
- memory: {
1887
- data: never[];
1888
- dataCount: number;
1889
- };
1890
- constructor(direction: Vector3, magnitude: ValueGenerator);
1891
- 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;
1892
2181
  update(particle: Particle, delta: number): void;
1893
2182
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
1894
2183
  frameUpdate(delta: number): void;
@@ -1903,7 +2192,11 @@ interface Sequencer {
1903
2192
  toJSON(): any;
1904
2193
  clone(): Sequencer;
1905
2194
  }
1906
- 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;
1907
2200
 
1908
2201
  /**
1909
2202
  * Apply sequences to particles.
@@ -1976,17 +2269,17 @@ interface FusionStep {
1976
2269
  declare function planBehaviorFusion(behaviors: Array<Behavior>): Array<FusionStep>;
1977
2270
 
1978
2271
  /**
1979
- * 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.
1980
2275
  */
1981
2276
  declare class ChangeEmitDirection implements Behavior {
1982
2277
  angle: ValueGenerator;
1983
2278
  type: string;
1984
2279
  _temp: Vector3;
1985
2280
  _q: Quaternion;
1986
- memory: {
1987
- data: never[];
1988
- dataCount: number;
1989
- };
2281
+ /** Scratch for the angle generator's per-spawn sample; cleared before every spawn. */
2282
+ memory: GeneratorMemory;
1990
2283
  constructor(angle: ValueGenerator);
1991
2284
  initialize(particle: Particle): void;
1992
2285
  update(particle: Particle, delta: number): void;
@@ -1998,7 +2291,9 @@ declare class ChangeEmitDirection implements Behavior {
1998
2291
  }
1999
2292
 
2000
2293
  /**
2001
- * 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.
2002
2297
  */
2003
2298
  declare class ColorBySpeed implements Behavior {
2004
2299
  color: FunctionColorGenerator;
@@ -2059,14 +2354,16 @@ declare class EmitSubParticleSystem implements Behavior {
2059
2354
  /**
2060
2355
  * Which of the parent particle's properties the sub particles start
2061
2356
  * from: its current colour and size multiply theirs, its rotation adds
2062
- * to theirs, and its remaining lifetime fraction scales theirs (so
2063
- * 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.
2064
2360
  */
2065
2361
  inherit: SubEmitterInheritance[];
2066
2362
  type: string;
2067
2363
  private q_;
2068
2364
  private v_;
2069
2365
  private v2_;
2366
+ private v3_;
2070
2367
  private subEmissions;
2071
2368
  /** Finished emission states, kept for reuse: a burst of deaths would otherwise allocate one plus a matrix each. */
2072
2369
  private spareEmissions;
@@ -2074,8 +2371,9 @@ declare class EmitSubParticleSystem implements Behavior {
2074
2371
  /**
2075
2372
  * Which of the parent particle's properties the sub particles start
2076
2373
  * from: its current colour and size multiply theirs, its rotation adds
2077
- * to theirs, and its remaining lifetime fraction scales theirs (so
2078
- * 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.
2079
2377
  */
2080
2378
  inherit?: SubEmitterInheritance[]);
2081
2379
  initialize(particle: Particle): void;
@@ -2083,8 +2381,8 @@ declare class EmitSubParticleSystem implements Behavior {
2083
2381
  /**
2084
2382
  * The system to emit into, or undefined when `subParticleSystem` does not
2085
2383
  * hold a resolved emitter — unset, or a uuid string a loader could not
2086
- * link. Every use goes through here, so a bad value is skipped rather
2087
- * 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.
2088
2386
  */
2089
2387
  private get target();
2090
2388
  private emit;
@@ -2093,29 +2391,62 @@ declare class EmitSubParticleSystem implements Behavior {
2093
2391
  static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
2094
2392
  clone(): Behavior;
2095
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;
2096
2401
  private static validInherit;
2097
2402
  private setMatrixFromParticle;
2098
2403
  }
2099
2404
 
2100
2405
  /**
2101
- * 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.
2102
2414
  */
2103
2415
  declare class ForceOverLife implements Behavior {
2416
+ /** Force along X over the particle's life, in units per second squared. */
2104
2417
  x: FunctionValueGenerator | ValueGenerator;
2418
+ /** Force along Y over the particle's life, in units per second squared. */
2105
2419
  y: FunctionValueGenerator | ValueGenerator;
2420
+ /** Force along Z over the particle's life, in units per second squared. */
2106
2421
  z: FunctionValueGenerator | ValueGenerator;
2422
+ /** The space the force is authored in; `'world'` by default. */
2423
+ space: BehaviorSpace;
2107
2424
  type: string;
2108
2425
  _temp: Vector3;
2109
2426
  /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2110
2427
  ps?: IParticleSystem;
2428
+ /** The emitter's transform this frame, refreshed by {@link frameUpdate}. */
2429
+ readonly _frame: EmitterFrame;
2111
2430
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
2112
- 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;
2113
2446
  update(particle: Particle, delta: number): void;
2114
2447
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2115
2448
  toJSON(): any;
2116
2449
  static fromJSON(json: any): Behavior;
2117
- _tempScale: Vector3;
2118
- _tempQ: Quaternion;
2119
2450
  frameUpdate(delta: number): void;
2120
2451
  clone(): Behavior;
2121
2452
  reset(): void;
@@ -2149,6 +2480,13 @@ interface FrameOverLifeOptions {
2149
2480
  frameCount?: number;
2150
2481
  /** FPS mode: wrap back to the first frame of the segment (default) or hold its last. */
2151
2482
  loop?: boolean;
2483
+ /**
2484
+ * FPS mode: every `1 / fps` seconds show a random frame of the segment
2485
+ * instead of the next one, each particle its own sequence: the flicker of
2486
+ * lightning, sparks or a neon sign. Needs {@link frameCount}; `loop` does
2487
+ * not apply. Default false.
2488
+ */
2489
+ random?: boolean;
2152
2490
  /**
2153
2491
  * Per-particle frame offset, sampled once at birth: an `IntervalValue(0, n)`
2154
2492
  * starts each particle on a random frame (Unity's "Start Frame"). Default none.
@@ -2161,7 +2499,8 @@ interface FrameOverLifeOptions {
2161
2499
  * By default `frame` is sampled at the particle's life fraction. The
2162
2500
  * {@link FrameOverLifeOptions} add the rest of Unity's texture sheet
2163
2501
  * animation: playing at a fixed frame rate, several cycles per life, a frame
2164
- * segment that loops or holds, and a random start frame.
2502
+ * segment that loops or holds, a random start frame, and a random frame on
2503
+ * every tick.
2165
2504
  */
2166
2505
  declare class FrameOverLife implements Behavior {
2167
2506
  type: string;
@@ -2170,7 +2509,10 @@ declare class FrameOverLife implements Behavior {
2170
2509
  cycles: number;
2171
2510
  frameCount: number;
2172
2511
  loop: boolean;
2512
+ random: boolean;
2173
2513
  startFrame?: ValueGenerator;
2514
+ /** A per-particle sample that sets each particle's random sequence apart. */
2515
+ private readonly salt;
2174
2516
  constructor(frame: FunctionValueGenerator | ValueGenerator, options?: FrameOverLifeOptions);
2175
2517
  get frame(): FunctionValueGenerator | ValueGenerator;
2176
2518
  set frame(frame: FunctionValueGenerator | ValueGenerator);
@@ -2182,6 +2524,10 @@ declare class FrameOverLife implements Behavior {
2182
2524
  /** The tile for `particle` at `age` seconds, `t` being that age over its life. */
2183
2525
  frameAt(particle: Particle, age: number, t: number): number;
2184
2526
  private offset;
2527
+ /** The particle's salt; 0 for a particle born before this behaviour was added. */
2528
+ private saltOf;
2529
+ /** A stable pseudo-random number in [0, 1) for a tick of a particle's sequence. */
2530
+ private static hash;
2185
2531
  private static wrap;
2186
2532
  private sampleFrame;
2187
2533
  frameUpdate(delta: number): void;
@@ -2192,16 +2538,26 @@ declare class FrameOverLife implements Behavior {
2192
2538
  }
2193
2539
 
2194
2540
  /**
2195
- * Apply a gravity force to particles.
2196
- * the gravity force is calculated as:
2197
- * 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.
2198
2548
  */
2199
2549
  declare class GravityForce implements Behavior {
2550
+ /** The point pulled toward, in the simulation space. */
2200
2551
  center: Vector3;
2552
+ /** Strength of the pull at distance 1, in units per second squared. */
2201
2553
  magnitude: number;
2202
2554
  type: string;
2203
2555
  temp: Vector3;
2204
- 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);
2205
2561
  initialize(particle: Particle): void;
2206
2562
  update(particle: Particle, delta: number): void;
2207
2563
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
@@ -2240,10 +2596,18 @@ declare class InheritVelocity implements Behavior {
2240
2596
  }
2241
2597
 
2242
2598
  /**
2243
- * 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.
2244
2601
  */
2245
2602
  declare class LimitSpeedOverLife implements Behavior {
2603
+ /** The speed limit over the particle's life. */
2246
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
+ */
2247
2611
  dampen: number;
2248
2612
  type: string;
2249
2613
  /** Learned in {@link initialize}; its motion scale multiplies the limit of a world-space system. */
@@ -2251,7 +2615,18 @@ declare class LimitSpeedOverLife implements Behavior {
2251
2615
  initialize(particle: Particle, particleSystem?: IParticleSystem): void;
2252
2616
  /** What the limit is multiplied by: the system's motion scale in world space, else 1. */
2253
2617
  motionScale(): number;
2254
- 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;
2255
2630
  update(particle: Particle, delta: number): void;
2256
2631
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2257
2632
  toJSON(): any;
@@ -2262,7 +2637,18 @@ declare class LimitSpeedOverLife implements Behavior {
2262
2637
  }
2263
2638
 
2264
2639
  /**
2265
- * 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.
2266
2652
  */
2267
2653
  declare class Noise implements Behavior {
2268
2654
  frequency: FunctionValueGenerator | ValueGenerator;
@@ -2311,6 +2697,13 @@ declare class Noise implements Behavior {
2311
2697
  private _positionAmount;
2312
2698
  private _rotationAmount;
2313
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;
2314
2707
  update(particle: Particle, _: number): void;
2315
2708
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2316
2709
  toJSON(): any;
@@ -2321,16 +2714,52 @@ declare class Noise implements Behavior {
2321
2714
  }
2322
2715
 
2323
2716
  /**
2324
- * 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`.
2325
2732
  */
2326
2733
  declare class OrbitOverLife implements Behavior {
2734
+ /** Angular speed around the axis over the particle's life, in radians per second. */
2327
2735
  orbitSpeed: FunctionValueGenerator | ValueGenerator;
2736
+ /** The axis orbited, in {@link OrbitOverLife.space | space}; its length is ignored. */
2328
2737
  axis: Vector3;
2738
+ /** The space the axis and the pivot are authored in; `'local'` (the emitter's) by default. */
2739
+ space: BehaviorSpace;
2329
2740
  type: string;
2330
2741
  rotation: Quaternion;
2331
2742
  temp: Vector3;
2332
- constructor(orbitSpeed: FunctionValueGenerator | ValueGenerator, axis?: Vector3);
2333
- 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;
2334
2763
  update(particle: Particle, delta: number): void;
2335
2764
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2336
2765
  frameUpdate(delta: number): void;
@@ -2359,7 +2788,9 @@ declare class Rotation3DOverLife implements Behavior {
2359
2788
  }
2360
2789
 
2361
2790
  /**
2362
- * 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.
2363
2794
  */
2364
2795
  declare class RotationBySpeed implements Behavior {
2365
2796
  angularVelocity: ValueGenerator | FunctionValueGenerator;
@@ -2407,7 +2838,9 @@ declare class RotationOverLife implements Behavior {
2407
2838
  }
2408
2839
 
2409
2840
  /**
2410
- * 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.
2411
2844
  */
2412
2845
  declare class SizeBySpeed implements Behavior {
2413
2846
  size: FunctionValueGenerator | Vector3Generator;
@@ -2443,6 +2876,13 @@ declare class SizeOverLife implements Behavior {
2443
2876
  reset(): void;
2444
2877
  }
2445
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
+
2446
2886
  /**
2447
2887
  * Apply speed to particles based on their life.
2448
2888
  */
@@ -2502,19 +2942,51 @@ declare class SimplexNoise {
2502
2942
  }
2503
2943
 
2504
2944
  /**
2505
- * 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.
2506
2959
  */
2507
2960
  declare class TurbulenceField implements Behavior {
2961
+ /** Size of one noise cell per axis, in the simulation space. */
2508
2962
  scale: Vector3;
2963
+ /** How many layers of noise are summed; more is finer and dearer. */
2509
2964
  octaves: number;
2965
+ /** Push per axis, in units per second squared. */
2510
2966
  velocityMultiplier: Vector3;
2967
+ /** How fast the field drifts per axis, in noise time per second. */
2511
2968
  timeScale: Vector3;
2969
+ /** The seed the field is built from; 0 by default. */
2970
+ seed: number;
2512
2971
  type: string;
2513
2972
  generator: SimplexNoise;
2973
+ /** Where in time the field is sampled now; starts at {@link initialOffset} and drifts by `timeScale`. */
2514
2974
  timeOffset: Vector3;
2975
+ /** The time offset the field starts from, derived from {@link seed}; restored by {@link reset}. */
2976
+ readonly initialOffset: Vector3;
2515
2977
  temp: Vector3;
2516
2978
  temp2: Vector3;
2517
- 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);
2518
2990
  initialize(particle: Particle): void;
2519
2991
  update(particle: Particle, delta: number): void;
2520
2992
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
@@ -2522,10 +2994,12 @@ declare class TurbulenceField implements Behavior {
2522
2994
  frameUpdate(delta: number): void;
2523
2995
  static fromJSON(json: any): Behavior;
2524
2996
  clone(): Behavior;
2997
+ /** Rewinds the field's drift to where it started, so a restarted system swirls the same way. */
2525
2998
  reset(): void;
2526
2999
  }
2527
3000
 
2528
- type VelocityOverLifeSpace = 'local' | 'world';
3001
+ /** The space a `VelocityOverLife` is authored in; the same choice as {@link BehaviorSpace}. */
3002
+ type VelocityOverLifeSpace = BehaviorSpace;
2529
3003
  /**
2530
3004
  * Move particles with a direct velocity over their life (Unity's "Velocity over Lifetime").
2531
3005
  * Applied as a positional displacement, so it is not affected by speed modifiers,
@@ -2582,7 +3056,7 @@ declare class VelocityOverLife implements Behavior {
2582
3056
  /**
2583
3057
  * Shapes a trail's width along its length — Unity's Width over Trail.
2584
3058
  *
2585
- * 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
2586
3060
  * multiplier on the width each sample was recorded with (the particle's
2587
3061
  * `size.x` at that moment): a curve from 1 to 0 tapers the trail from the
2588
3062
  * particle's size at the head down to nothing at the tail, whatever that size
@@ -2694,23 +3168,24 @@ interface ShapeJSON {
2694
3168
  * Enum representing the emitter modes for particles.
2695
3169
  */
2696
3170
  declare enum EmitterMode {
2697
- /**
2698
- * Emit particles randomly over the specified duration.
2699
- */
3171
+ /** Each particle starts at a random point of the arc. */
2700
3172
  Random = 0,
2701
- /**
2702
- * Emit particles in a continuous loop.
2703
- */
3173
+ /** The start point sweeps the arc at the shape's `speed` (arcs per second) and wraps around. */
2704
3174
  Loop = 1,
2705
- /**
2706
- * Emit particles back and forth in a ping-pong manner.
2707
- */
3175
+ /** The start point sweeps the arc back and forth, starting at the arc's start. */
2708
3176
  PingPong = 2,
2709
- /**
2710
- * Emit particles in bursts.
2711
- */
3177
+ /** A burst's particles are spread evenly over the arc; particles emitted by rate start at random. */
2712
3178
  Burst = 3
2713
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
+ */
2714
3189
  declare function getValueFromEmitterMode(mode: EmitterMode, currentValue: number, spread: number, emissionState: EmissionState): number;
2715
3190
  interface EmitterShape {
2716
3191
  type: string;
@@ -2723,6 +3198,12 @@ interface EmitterShape {
2723
3198
  * by the shape itself at the end of {@link initialize}.
2724
3199
  */
2725
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;
2726
3207
  }
2727
3208
 
2728
3209
  /**
@@ -2753,6 +3234,11 @@ interface BoxEmitterParameters {
2753
3234
  * box size: 0 keeps them on the surface, 0.5 reaches the center.
2754
3235
  */
2755
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;
2756
3242
  }
2757
3243
  /**
2758
3244
  * A particle emitter that emits particles from a box centered on the emitter, all moving along +Z
@@ -2765,6 +3251,7 @@ declare class BoxEmitter implements EmitterShape {
2765
3251
  depth: number;
2766
3252
  emitFrom: BoxEmitFrom;
2767
3253
  boxThickness: [number, number, number];
3254
+ transform?: ShapeTransform;
2768
3255
  private readonly _point;
2769
3256
  constructor(parameters?: BoxEmitterParameters);
2770
3257
  update(_system: IParticleSystem, _delta: number): void;
@@ -2832,6 +3319,7 @@ declare class CircleEmitter implements EmitterShape {
2832
3319
  memory: GeneratorMemory;
2833
3320
  transform?: ShapeTransform;
2834
3321
  private currentValue;
3322
+ reset(): void;
2835
3323
  constructor(parameters?: CircleEmitterParameters);
2836
3324
  update(system: IParticleSystem, delta: number): void;
2837
3325
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -2893,6 +3381,7 @@ declare class ConeEmitter implements EmitterShape {
2893
3381
  memory: GeneratorMemory;
2894
3382
  transform?: ShapeTransform;
2895
3383
  private currentValue;
3384
+ reset(): void;
2896
3385
  constructor(parameters?: ConeEmitterParameters);
2897
3386
  update(system: IParticleSystem, delta: number): void;
2898
3387
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -2956,6 +3445,7 @@ declare class DonutEmitter implements EmitterShape {
2956
3445
  _m1: Matrix4;
2957
3446
  constructor(parameters?: DonutEmitterParameters);
2958
3447
  private currentValue;
3448
+ reset(): void;
2959
3449
  update(system: IParticleSystem, delta: number): void;
2960
3450
  initialize(p: Particle, emissionState: EmissionState): void;
2961
3451
  toJSON(): ShapeJSON;
@@ -2984,6 +3474,11 @@ interface EdgeEmitterParameters {
2984
3474
  * {@link EmitterMode}
2985
3475
  */
2986
3476
  speed?: ValueGenerator | FunctionValueGenerator;
3477
+ /**
3478
+ * Offset, rotation and scale of the shape within the particle system.
3479
+ * {@link ShapeTransform}
3480
+ */
3481
+ transform?: ShapeTransform;
2987
3482
  }
2988
3483
  /**
2989
3484
  * A particle emitter that emits particles from a line along X, all moving along +Y like Unity's
@@ -2996,7 +3491,9 @@ declare class EdgeEmitter implements EmitterShape {
2996
3491
  spread: number;
2997
3492
  speed: ValueGenerator | FunctionValueGenerator;
2998
3493
  memory: GeneratorMemory;
3494
+ transform?: ShapeTransform;
2999
3495
  private currentValue;
3496
+ reset(): void;
3000
3497
  constructor(parameters?: EdgeEmitterParameters);
3001
3498
  update(system: IParticleSystem, delta: number): void;
3002
3499
  initialize(p: Particle, emissionState: EmissionState): void;
@@ -3014,6 +3511,10 @@ interface EmitterShapePlugin {
3014
3511
  declare const EmitterShapes: {
3015
3512
  [key: string]: EmitterShapePlugin;
3016
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
+ */
3017
3518
  declare function EmitterFromJSON(json: ShapeJSON, meta: JsonMetaData): EmitterShape;
3018
3519
 
3019
3520
  /**
@@ -3107,6 +3608,7 @@ declare class HemisphereEmitter implements EmitterShape {
3107
3608
  _m1: Matrix4;
3108
3609
  constructor(parameters?: HemisphereEmitterParameters);
3109
3610
  private currentValue;
3611
+ reset(): void;
3110
3612
  update(system: IParticleSystem, delta: number): void;
3111
3613
  initialize(p: Particle, emissionState: EmissionState): void;
3112
3614
  toJSON(): ShapeJSON;
@@ -3185,6 +3687,7 @@ declare class RectangleEmitter implements EmitterShape {
3185
3687
  memory: GeneratorMemory;
3186
3688
  transform?: ShapeTransform;
3187
3689
  private currentValue;
3690
+ reset(): void;
3188
3691
  private _m1;
3189
3692
  constructor(parameters?: RectangleEmitterParameters);
3190
3693
  update(system: IParticleSystem, delta: number): void;
@@ -3244,6 +3747,7 @@ declare class SphereEmitter implements EmitterShape {
3244
3747
  _m1: Matrix4;
3245
3748
  constructor(parameters?: SphereEmitterParameters);
3246
3749
  private currentValue;
3750
+ reset(): void;
3247
3751
  update(system: IParticleSystem, delta: number): void;
3248
3752
  initialize(p: Particle, emissionState: EmissionState): void;
3249
3753
  toJSON(): ShapeJSON;
@@ -3258,7 +3762,12 @@ interface Plugin {
3258
3762
  behaviors: Array<BehaviorPlugin>;
3259
3763
  }
3260
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
+ */
3261
3769
  declare function loadPlugin(plugin: Plugin): void;
3770
+ /** Removes a plugin and the types it registered; types another plugin registered stay. */
3262
3771
  declare function unloadPlugin(pluginId: string): void;
3263
3772
 
3264
3773
  declare class TextureSequencer implements Sequencer {
@@ -3306,6 +3815,58 @@ declare function createSeededRandom(seed: number): RandomSource;
3306
3815
  /** Runs `fn` with `generator` as the random source, restoring the previous one after. */
3307
3816
  declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3308
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
+
3309
3870
  /**
3310
3871
  * The order the particles of a batch are drawn in (Unity's Sort Mode). Alpha
3311
3872
  * blended particles cover what was drawn before them, so the order shows.
@@ -3318,12 +3879,25 @@ declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3318
3879
  * Sorting runs over the whole batch after each fill. Trails are not sorted.
3319
3880
  */
3320
3881
  type SortMode = 'none' | 'distance' | 'oldestInFront' | 'youngestInFront';
3882
+ /** How a system draws its particles (Unity's Render Mode), see {@link ParticleSystem.renderMode}. */
3321
3883
  declare enum RenderMode {
3884
+ /** A quad facing the camera (Unity's Billboard). The default. */
3322
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
+ */
3323
3890
  StretchedBillBoard = 1,
3891
+ /** The system's mesh, one instance per particle (Unity's Mesh), see {@link ParticleSystem.instancingGeometry}. */
3324
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
+ */
3325
3897
  Trail = 3,
3898
+ /** A quad lying flat in the world's XZ plane, facing up (Unity's Horizontal Billboard). */
3326
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). */
3327
3901
  VerticalBillBoard = 5,
3328
3902
  /**
3329
3903
  * A quad laid from each particle to the system's {@link ParticleSystem.beamEnd}
@@ -3372,9 +3946,12 @@ interface MeshRim {
3372
3946
  strength: number;
3373
3947
  /**
3374
3948
  * `'add'` (default) adds the colour, for a glowing edge; `'mix'` blends the
3375
- * surface toward it, for an outline (a dark ink line with a dark colour).
3949
+ * surface toward it, for an outline (a dark ink line with a dark colour);
3950
+ * `'fade'` leaves the colour and fades the faces turned to the camera by
3951
+ * `strength` instead, alpha times `1 - strength * (1 - edge)`: a wall of
3952
+ * light that reads thick along its silhouette and thin across its face.
3376
3953
  */
3377
- mode: 'add' | 'mix';
3954
+ mode: 'add' | 'mix' | 'fade';
3378
3955
  }
3379
3956
  /**
3380
3957
  * A complete rim from a partial one, every field defaulted and kept in range,
@@ -3383,6 +3960,81 @@ interface MeshRim {
3383
3960
  declare function normalizeMeshRim(rim: Partial<MeshRim> | null | undefined): MeshRim | undefined;
3384
3961
  /** True when both describe the same rim (or both none). */
3385
3962
  declare function meshRimEqual(a: MeshRim | undefined, b: MeshRim | undefined): boolean;
3963
+ /**
3964
+ * Which texture coordinates a texture is sampled with, as Unity's UV channels
3965
+ * and Niagara's ribbon UV0 / UV1:
3966
+ *
3967
+ * - `0`: the particle's first UV, with the sprite sheet's cell applied: on a
3968
+ * sheet the current frame's cell, on a trail the cell's stretch along it, on
3969
+ * a mesh its first UV set. Read before the map's own layout and distortion,
3970
+ * so a texture on it does not move with them.
3971
+ * - `1`: the particle's own UV, never moved by the sheet. The whole quad on a
3972
+ * billboard, a stretched billboard or a beam (mirrored with the quad when it
3973
+ * flips); on a trail U along it the way the map's runs (from the tail, or
3974
+ * from the head with `uvFromHead`) and V across it; on a mesh its second UV
3975
+ * set (`instancingUVs2`), or its first when it has none.
3976
+ *
3977
+ * A mesh can then repeat its picture along UV0 while a mask on UV1 runs once
3978
+ * across its whole length, as a lightmap UV does in a game engine.
3979
+ */
3980
+ type UVChannel = 0 | 1;
3981
+ /**
3982
+ * How a texture is laid over the particle: its UV channel, then tiling and
3983
+ * offset as in Unity's material Tiling / Offset, then a scroll on the
3984
+ * renderer's clock as Unreal's Panner. Sampled at
3985
+ * `uv(channel) * tiling + offset + scroll * time`; the offset is used as
3986
+ * given, so a clamped texture can be moved off its edge, and only the
3987
+ * scroll's share is wrapped (over two repeats, so a mirrored texture stays
3988
+ * seamless). A texture that scrolls or tiles should repeat.
3989
+ */
3990
+ interface TextureUV {
3991
+ /** See {@link UVChannel}. Default 0. */
3992
+ channel: UVChannel;
3993
+ /** Repeats across the channel's 0…1, `[u, v]`. Default `[1, 1]`. */
3994
+ tiling: [number, number];
3995
+ /** Added after tiling, in texture UV units. Default `[0, 0]`. */
3996
+ offset: [number, number];
3997
+ /** UV units per second on the renderer's clock. Default `[0, 0]`. */
3998
+ scroll: [number, number];
3999
+ }
4000
+ /** A complete {@link TextureUV} from a partial one, with `defaults` under the fields left out. */
4001
+ declare function normalizeTextureUV(uv: Partial<TextureUV> | null | undefined, defaults?: Partial<TextureUV>): TextureUV;
4002
+ /** True when both lay a texture the same way. */
4003
+ declare function textureUVEqual(a: TextureUV, b: TextureUV): boolean;
4004
+ /** The fields of `uv` that differ from `defaults`, for JSON written only when set. */
4005
+ declare function textureUVToJSON(uv: TextureUV, defaults?: Partial<TextureUV>): Partial<TextureUV> | undefined;
4006
+ /**
4007
+ * Which value of the map's texel picks the colour along a gradient map's
4008
+ * ramp: one channel, so a texture can pack several masks (Unreal's and
4009
+ * Unity's channel-packed textures), or the Rec. 709 luminance of its colour.
4010
+ */
4011
+ type GradientMapChannel = 'r' | 'g' | 'b' | 'a' | 'luminance';
4012
+ /**
4013
+ * A gradient map (colour ramp): the map is recoloured by looking its
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}.
4017
+ */
4018
+ interface ParticleGradientMap {
4019
+ /**
4020
+ * The ramp, read along U at mid V: low values on the left. Make it without
4021
+ * mipmaps and clamped. Required: without one there is no gradient map.
4022
+ */
4023
+ ramp: BaseTexture | null;
4024
+ /**
4025
+ * The texel value the ramp is looked up by. Default `'r'`. With `'a'` the
4026
+ * ramp's alpha becomes the texel's alpha, so a soft shape can glow at its
4027
+ * fringe and stay solid at its heart; with any other channel the ramp's
4028
+ * alpha multiplies the map's.
4029
+ */
4030
+ channel: GradientMapChannel;
4031
+ }
4032
+ /** The weights a texel is dotted with to look up the ramp, per {@link GradientMapChannel}. */
4033
+ declare const GRADIENT_MAP_WEIGHTS: Readonly<Record<GradientMapChannel, readonly [number, number, number, number]>>;
4034
+ /** A complete gradient map, or undefined when unset or without a ramp. */
4035
+ declare function normalizeGradientMap(gradientMap: Partial<ParticleGradientMap> | null | undefined): ParticleGradientMap | undefined;
4036
+ /** True when both recolour the same way (or both not at all). */
4037
+ declare function gradientMapEqual(a: ParticleGradientMap | undefined, b: ParticleGradientMap | undefined): boolean;
3386
4038
  /**
3387
4039
  * Alpha erosion: the particle's alpha decides how much of its shape is left
3388
4040
  * instead of how transparent it is, so `ColorOverLife` fading alpha out
@@ -3391,51 +4043,135 @@ declare function meshRimEqual(a: MeshRim | undefined, b: MeshRim | undefined): b
3391
4043
  */
3392
4044
  interface ParticleErosion {
3393
4045
  /**
3394
- * Mask whose red channel orders what goes first, sampled with the
3395
- * particle's UV (the quad, mesh or trail UV, unscrolled). Null: the map's
3396
- * own alpha, so a soft shape shrinks from its edges.
4046
+ * Mask whose red channel orders what goes first, laid by {@link maskUV}.
4047
+ * Null: the map's own alpha, so a soft shape shrinks from its edges.
3397
4048
  */
3398
4049
  mask: BaseTexture | null;
4050
+ /**
4051
+ * How the mask is laid over the particle, see {@link TextureUV}. On UV
4052
+ * channel 1 a gradient mask wipes a whole trail or mesh however its map
4053
+ * repeats. Default channel 0, untiled, still.
4054
+ */
4055
+ maskUV: TextureUV;
3399
4056
  /** Width of the soft transition at the cut, in mask units. Default 0.05. */
3400
4057
  softness: number;
3401
4058
  /** Width of the glowing band above the cut, in mask units; 0 (default) draws none. */
3402
4059
  edgeWidth: number;
3403
4060
  /** Colour added in the edge band, linear RGB, may exceed 1. Default `[1, 1, 1]`. */
3404
4061
  edgeColor: [number, number, number];
3405
- /** Mask UV scroll, UV units per second. Default `[0, 0]`. */
3406
- maskScroll: [number, number];
3407
4062
  }
4063
+ /** {@link ParticleErosion} as given: any field may be left out, the mask's layout too. */
4064
+ type ParticleErosionOptions = Partial<Omit<ParticleErosion, 'maskUV'>> & {
4065
+ /** See {@link ParticleErosion.maskUV}; fields left out take their defaults. */
4066
+ maskUV?: Partial<TextureUV>;
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;
3408
4070
  /** A complete erosion from a partial one, every field defaulted, or undefined when `erosion` is unset. */
3409
- declare function normalizeErosion(erosion: Partial<ParticleErosion> | null | undefined): ParticleErosion | undefined;
4071
+ declare function normalizeErosion(erosion: ParticleErosionOptions | null | undefined): ParticleErosion | undefined;
3410
4072
  /** True when both describe the same erosion (or both none). */
3411
4073
  declare function erosionEqual(a: ParticleErosion | undefined, b: ParticleErosion | undefined): boolean;
3412
- /** A UV scroll speed, or undefined when unset or zero. */
3413
- declare function normalizeUVScroll(scroll: ArrayLike<number> | null | undefined): [number, number] | undefined;
3414
- /** True when both scroll the same way (or both not at all). */
3415
- declare function uvScrollEqual(a: [number, number] | undefined, b: [number, number] | undefined): boolean;
4074
+ /** The distortion noise's default layout: drifting up half a repeat a second. */
4075
+ declare const UV_DISTORTION_DEFAULT_UV: Partial<TextureUV>;
4076
+ /**
4077
+ * UV distortion: the map's UV pushed about by a noise texture, for heat
4078
+ * shimmer, licking flames and breathing auras. See
4079
+ * {@link VFXBatchSettings.uvDistortion}.
4080
+ */
4081
+ interface ParticleUVDistortion {
4082
+ /**
4083
+ * Noise whose red and green channels, around 0.5, push U and V. It should
4084
+ * wrap (repeat). Required: without one there is no distortion.
4085
+ */
4086
+ map: BaseTexture | null;
4087
+ /**
4088
+ * How the noise is laid over the particle, see {@link TextureUV}. Default
4089
+ * channel 0, untiled, scrolling `[0, 0.5]`.
4090
+ */
4091
+ mapUV: TextureUV;
4092
+ /** How far the map's UV is pushed at most, in UV units. Default 0.05. */
4093
+ strength: number;
4094
+ }
4095
+ /** {@link ParticleUVDistortion} as given: any field may be left out, the noise's layout too. */
4096
+ type ParticleUVDistortionOptions = Partial<Omit<ParticleUVDistortion, 'mapUV'>> & {
4097
+ /** See {@link ParticleUVDistortion.mapUV}; fields left out take their defaults. */
4098
+ mapUV?: Partial<TextureUV>;
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;
4102
+ /** A complete distortion from a partial one, or undefined when unset or without a map. */
4103
+ declare function normalizeUVDistortion(distortion: ParticleUVDistortionOptions | null | undefined): ParticleUVDistortion | undefined;
4104
+ /** True when both describe the same distortion (or both none). */
4105
+ declare function uvDistortionEqual(a: ParticleUVDistortion | undefined, b: ParticleUVDistortion | undefined): boolean;
4106
+ /**
4107
+ * The main map's layout, or undefined when it is the identity (channel 0,
4108
+ * untiled, unmoved, still), which costs nothing in the shader.
4109
+ */
4110
+ declare function normalizeMapUV(uv: Partial<TextureUV> | null | undefined): TextureUV | undefined;
4111
+ /** True when both lay the map the same way (or both as drawn). */
4112
+ declare function mapUVEqual(a: TextureUV | undefined, b: TextureUV | undefined): boolean;
4113
+ /**
4114
+ * True when a texture effect of `settings` samples UV channel 1, see
4115
+ * {@link UVChannel}: the map, the distortion noise or an erosion mask laid
4116
+ * on it.
4117
+ */
4118
+ declare function readsUV1(settings: {
4119
+ mapUV?: TextureUV;
4120
+ uvDistortion?: ParticleUVDistortion;
4121
+ erosion?: ParticleErosion;
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
+ */
3416
4129
  interface StoredBatchSettings {
4130
+ /** See {@link VFXBatchSettings.instancingGeometry}. */
3417
4131
  instancingGeometry: Float32Array;
4132
+ /** See {@link VFXBatchSettings.instancingIndices}. */
3418
4133
  instancingIndices: Uint32Array | Uint16Array;
4134
+ /** See {@link VFXBatchSettings.instancingUVs}. */
3419
4135
  instancingUVs?: Float32Array;
4136
+ /** The mesh's second UV set, see {@link UVChannel}. */
4137
+ instancingUVs2?: Float32Array;
4138
+ /** See {@link VFXBatchSettings.instancingNormals}. */
3420
4139
  instancingNormals?: Float32Array;
4140
+ /** See {@link VFXBatchSettings.renderMode}. */
3421
4141
  renderMode: RenderMode;
4142
+ /** See {@link VFXBatchSettings.renderOrder}. */
3422
4143
  renderOrder: number;
4144
+ /** See {@link VFXBatchSettings.uTileCount}. */
3423
4145
  uTileCount: number;
4146
+ /** See {@link VFXBatchSettings.vTileCount}. */
3424
4147
  vTileCount: number;
4148
+ /** See {@link VFXBatchSettings.blendTiles}. */
3425
4149
  blendTiles: boolean;
4150
+ /** See {@link VFXBatchSettings.softParticles}. */
3426
4151
  softParticles: boolean;
4152
+ /** See {@link VFXBatchSettings.softNearFade}. */
3427
4153
  softNearFade: number;
4154
+ /** See {@link VFXBatchSettings.softFarFade}. */
3428
4155
  softFarFade: number;
4156
+ /** See {@link VFXBatchSettings.materialBlendMode}. */
3429
4157
  materialBlendMode: number;
4158
+ /** See {@link VFXBatchSettings.materialTransparent}. */
3430
4159
  materialTransparent: boolean;
4160
+ /** See {@link VFXBatchSettings.materialDepthTest}. */
3431
4161
  materialDepthTest: boolean;
4162
+ /** See {@link VFXBatchSettings.materialDepthWrite}. */
3432
4163
  materialDepthWrite: boolean;
4164
+ /** See {@link VFXBatchSettings.materialAlphaTest}. */
3433
4165
  materialAlphaTest: number;
3434
- texture: any;
4166
+ /** See {@link VFXBatchSettings.texture}. */
4167
+ texture: BaseTexture | null;
4168
+ /** See {@link VFXBatchSettings.reflectionTexture}. */
3435
4169
  reflectionTexture: BaseTexture | null;
4170
+ /** See {@link VFXBatchSettings.reflectionLevel}. */
3436
4171
  reflectionLevel: number;
3437
- reflectionFaces: BaseTexture[] | null;
4172
+ /** See {@link VFXBatchSettings.reflectionAtlas}. */
3438
4173
  reflectionAtlas: BaseTexture | null;
4174
+ /** See {@link VFXBatchSettings.layerMask}. */
3439
4175
  layerMask: number;
3440
4176
  /** Babylon rendering group the batch mesh draws in, see {@link VFXBatchSettings.renderingGroupId}. */
3441
4177
  renderingGroupId: number;
@@ -3453,21 +4189,41 @@ interface StoredBatchSettings {
3453
4189
  lighting?: MeshLighting;
3454
4190
  /** Mesh particle rim, see {@link VFXBatchSettings.rim}. */
3455
4191
  rim?: MeshRim;
3456
- /** Map UV scroll, see {@link VFXBatchSettings.uvScroll}. */
3457
- uvScroll?: [number, number];
4192
+ /** The main map's layout, see {@link VFXBatchSettings.mapUV}. */
4193
+ mapUV?: TextureUV;
4194
+ /** Map UV distortion, see {@link VFXBatchSettings.uvDistortion}. */
4195
+ uvDistortion?: ParticleUVDistortion;
3458
4196
  /** Colour ramp for the map, see {@link VFXBatchSettings.gradientMap}. */
3459
- gradientMap: BaseTexture | null;
4197
+ gradientMap?: ParticleGradientMap;
3460
4198
  /** Alpha erosion, see {@link VFXBatchSettings.erosion}. */
3461
4199
  erosion?: ParticleErosion;
3462
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
+ */
3463
4207
  declare abstract class VFXBatch {
4208
+ /** The Babylon mesh the batch draws with. */
3464
4209
  mesh: Mesh;
4210
+ /** The systems drawn by this batch. */
3465
4211
  systems: Set<IParticleSystem>;
4212
+ /** The settings every system in the batch shares, with what the render mode ignores at its default. */
3466
4213
  settings: StoredBatchSettings;
4214
+ /** @internal */
3467
4215
  protected maxParticles: number;
4216
+ /** @internal */
3468
4217
  protected scene: Scene;
4218
+ /** @internal */
3469
4219
  protected readonly visibleSystems: IParticleSystem[];
3470
- 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);
3471
4227
  /**
3472
4228
  * Applies the batch-level scene settings to {@link mesh}. Called on every
3473
4229
  * mesh the batch creates, since the buffers rebuild it.
@@ -3489,25 +4245,45 @@ declare abstract class VFXBatch {
3489
4245
  */
3490
4246
  protected refreshBoundingInfo(): void;
3491
4247
  /**
3492
- * Fog defines and uniforms for a material of this batch, and the per-bind
3493
- * 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
3494
4256
  * disabled, so toggling fog at runtime needs no recompile.
4257
+ * @internal
3495
4258
  */
3496
- protected static readonly FOG_UNIFORMS: string[];
3497
- protected fogDefines(): string[];
3498
4259
  protected bindFog(material: ShaderMaterial): void;
3499
4260
  /**
3500
4261
  * Seconds of renderer time, set by the renderer before each fill; what UV
3501
4262
  * and erosion mask scrolling advance by.
3502
4263
  */
3503
4264
  time: number;
3504
- /** Defines of the texture effects (see `shaders/chunks/surface.ts`) this batch uses. */
3505
- protected surfaceDefines(): string[];
3506
- /** Adds the uniforms and samplers of the texture effects this batch uses. */
3507
- protected surfaceUniforms(uniforms: string[], samplers: string[]): void;
4265
+ /** True when a texture effect of this batch samples UV channel 1, see {@link UVChannel}. */
4266
+ protected usesUV1(): boolean;
3508
4267
  /** Sets the texture effects' textures and constants, and advances their scrolling on every bind. */
3509
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 */
3510
4285
  addSystem(system: IParticleSystem): void;
4286
+ /** @internal */
3511
4287
  removeSystem(system: IParticleSystem): void;
3512
4288
  /**
3513
4289
  * Visible systems of this batch, written into a buffer owned by the batch.
@@ -3515,54 +4291,115 @@ declare abstract class VFXBatch {
3515
4291
  * reallocated; treat it as valid only until the next call.
3516
4292
  */
3517
4293
  getVisibleSystems(): IParticleSystem[];
3518
- applyDepthTexture(depthTexture: BaseTexture | null): void;
3519
- /** 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
+ */
3520
4316
  applyMeshLighting(_lighting: MeshLightingSettings): void;
4317
+ /** @internal */
3521
4318
  abstract setupBuffers(): void;
4319
+ /** @internal */
3522
4320
  abstract expandBuffers(target: number): void;
4321
+ /** @internal */
3523
4322
  abstract rebuildMaterial(): void;
4323
+ /** @internal */
3524
4324
  abstract update(): void;
4325
+ /** @internal */
3525
4326
  dispose(): void;
3526
4327
  }
3527
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
+ */
3528
4347
  interface VFXBatchSettings {
4348
+ /** Mesh particles' vertex positions, see {@link ParticleSystem.instancingGeometry}. A quad for other modes. */
3529
4349
  instancingGeometry: Float32Array;
4350
+ /** Triangle indices into {@link instancingGeometry}. */
3530
4351
  instancingIndices: Uint32Array | Uint16Array;
4352
+ /** The mesh's first UV set, two values per vertex. */
3531
4353
  instancingUVs?: Float32Array;
4354
+ /** The mesh's second UV set, see {@link UVChannel}. */
4355
+ instancingUVs2?: Float32Array;
4356
+ /** The mesh's vertex normals; mesh particles fall back to +Z. */
3532
4357
  instancingNormals?: Float32Array;
4358
+ /** See {@link ParticleSystem.renderMode}. */
3533
4359
  renderMode: RenderMode;
4360
+ /** See {@link ParticleSystem.renderOrder}. */
3534
4361
  renderOrder: number;
4362
+ /** See {@link ParticleSystem.uTileCount}. */
3535
4363
  uTileCount: number;
4364
+ /** See {@link ParticleSystem.vTileCount}. */
3536
4365
  vTileCount: number;
4366
+ /** See {@link ParticleSystem.blendTiles}; read with a sheet, and not by trails. */
3537
4367
  blendTiles: boolean;
4368
+ /** See {@link ParticleSystem.softParticles}. */
3538
4369
  softParticles: boolean;
4370
+ /** See {@link ParticleSystem.softNearFade}. */
3539
4371
  softNearFade: number;
4372
+ /** See {@link ParticleSystem.softFarFade}. */
3540
4373
  softFarFade: number;
4374
+ /** Babylon alpha mode, see {@link ParticleSystem.blending}. */
3541
4375
  materialBlendMode: number;
4376
+ /** Whether the batch draws in the transparent pass. */
3542
4377
  materialTransparent: boolean;
4378
+ /** Whether particles are hidden behind nearer geometry. */
3543
4379
  materialDepthTest: boolean;
4380
+ /** Whether particles write depth. */
3544
4381
  materialDepthWrite: boolean;
4382
+ /** Alpha below which a fragment is discarded; 0 discards nothing. */
3545
4383
  materialAlphaTest: number;
4384
+ /** See {@link ParticleSystem.texture}. */
3546
4385
  texture: Texture | null;
3547
4386
  /**
3548
- * Cubemap (or other reflection texture) harvested from a Babylon material's
3549
- * `reflectionTexture`. Mesh batches sample it like StandardMaterial cubic
3550
- * 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.
3551
4391
  */
3552
4392
  reflectionTexture: BaseTexture | null;
3553
4393
  /** Multiplier for the reflection sample — mirrors `texture.level`. */
3554
4394
  reflectionLevel: number;
3555
4395
  /**
3556
- * Optional six cube-face 2D textures (px,py,pz,nx,ny,nz). Prefer
3557
- * `reflectionAtlas` on iOS — many simultaneous face samplers still trip
3558
- * GL_INVALID_OPERATION on WebKit.
3559
- */
3560
- reflectionFaces: BaseTexture[] | null;
3561
- /**
3562
- * Single 3×2 atlas of cube faces (px py pz / nx ny nz). One sampler2D —
3563
- * 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.
3564
4400
  */
3565
4401
  reflectionAtlas: BaseTexture | null;
4402
+ /** Camera layer mask of the batch mesh, see {@link ParticleSystem.layers}. */
3566
4403
  layerMask: number;
3567
4404
  /**
3568
4405
  * Babylon rendering group (`mesh.renderingGroupId`) the batch draws in,
@@ -3571,8 +4408,11 @@ interface VFXBatchSettings {
3571
4408
  renderingGroupId: number;
3572
4409
  /**
3573
4410
  * Whether the scene's fog applies to the particles, as it does to any other
3574
- * mesh; true by default. Additive particles fade toward black rather than
3575
- * 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.
3576
4416
  */
3577
4417
  applyFog: boolean;
3578
4418
  /**
@@ -3604,41 +4444,70 @@ interface VFXBatchSettings {
3604
4444
  lighting?: MeshLighting;
3605
4445
  /** Rim (Fresnel) term on mesh particles; unset draws none. See {@link MeshRim}. */
3606
4446
  rim?: MeshRim;
3607
- /**
3608
- * Scrolls the map's UV by this many UV units per second, `[u, v]`, on the
3609
- * renderer's clock. The texture should wrap; scrolling one tile of a sheet
3610
- * runs into its neighbours. Unset or zero: no scroll. Systems that differ
3611
- * are batched apart.
3612
- */
3613
- uvScroll?: [number, number];
3614
- /**
3615
- * Colour ramp the map is recoloured through: the map's red channel picks
3616
- * a colour along U of this texture, and its alpha multiplies the map's. The
3617
- * particle colour still tints the result. Unset: none. Systems that differ
3618
- * are batched apart.
3619
- */
3620
- gradientMap?: BaseTexture | null;
4447
+ /** How the main map is laid over the particle, see {@link TextureUV}. Unset: as drawn. Systems that differ are batched apart. */
4448
+ mapUV?: TextureUV;
4449
+ /** Colour ramp the map is recoloured through, see {@link ParticleGradientMap}. Unset: none. Systems that differ are batched apart. */
4450
+ gradientMap?: ParticleGradientMap;
4451
+ /** Map UV distortion by a noise texture, see {@link ParticleUVDistortion}. Unset: none. Systems that differ are batched apart. */
4452
+ uvDistortion?: ParticleUVDistortion;
3621
4453
  /** Alpha erosion (dissolve / wipe), see {@link ParticleErosion}. Unset: none. Systems that differ are batched apart. */
3622
4454
  erosion?: ParticleErosion;
3623
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
+ */
3624
4462
  interface AdaptivePerformanceOptions {
4463
+ /** CPU time in milliseconds the renderer's update may take before quality drops. Default 16.7. */
3625
4464
  targetFrameMs: number;
4465
+ /** Lowest quality factor, 0.1 to 1 ({@link ParticleSystem.setQualityFactor} clamps lower values). Default 0.35. */
3626
4466
  minQuality: number;
4467
+ /** Highest quality factor, `minQuality` to 1. Default 1. */
3627
4468
  maxQuality: number;
4469
+ /** Quality lost per update over budget. Default 0.08. */
3628
4470
  decreaseStep: number;
4471
+ /** Quality regained per update within budget. Default 0.02. */
3629
4472
  increaseStep: number;
3630
4473
  }
4474
+ /** A snapshot of the renderer's adaptive performance, from {@link BatchedRenderer.getAdaptivePerformanceState}. */
3631
4475
  interface AdaptivePerformanceState extends AdaptivePerformanceOptions {
4476
+ /** Whether adaptive performance is on. */
3632
4477
  enabled: boolean;
4478
+ /** The quality factor the systems run at now. */
3633
4479
  currentQuality: number;
4480
+ /** CPU time the last measured update took, in milliseconds; kept from the last update while off. */
3634
4481
  lastFrameCpuMs: number;
3635
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
+ */
3636
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. */
3637
4505
  batches: Array<VFXBatch>;
3638
4506
  /** Seconds this renderer has been updated for; the clock UV and erosion scrolling run on. */
3639
4507
  private elapsed;
4508
+ /** Index into {@link batches} of each system's batch. The renderer owns it. */
3640
4509
  systemToBatchIndex: Map<IParticleSystem, number>;
3641
- depthTexture: BaseTexture | null;
4510
+ private depth;
3642
4511
  /** Systems in insertion order — iterated every frame, unlike the map. */
3643
4512
  private systems;
3644
4513
  /**
@@ -3703,19 +4572,47 @@ declare class BatchedRenderer extends TransformNode {
3703
4572
  */
3704
4573
  private isSystemInView;
3705
4574
  private static clamp;
3706
- 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
+ */
3707
4579
  addSystem(system: IParticleSystem): void;
3708
4580
  /** Places a system into a compatible batch, creating one when none matches. */
3709
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
+ */
3710
4586
  deleteSystem(system: IParticleSystem): boolean;
3711
4587
  /** Detaches a system from its batch, leaving the renderer's system list alone. */
3712
4588
  private removeFromBatch;
3713
4589
  /**
3714
- * Re-buckets a system whose render settings changed. The system keeps its
3715
- * 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.
3716
4594
  */
3717
4595
  updateSystem(system: IParticleSystem): void;
3718
- 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;
3719
4616
  /**
3720
4617
  * Sets the light mesh particles with `lighting: 'fixed'` (the default) are
3721
4618
  * lit by, for every mesh batch of this renderer, including ones created
@@ -3730,8 +4627,15 @@ declare class BatchedRenderer extends TransformNode {
3730
4627
  setMeshLighting(lighting: Partial<MeshLightingSettings>): void;
3731
4628
  /** A copy of the light set with {@link setMeshLighting}. */
3732
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
+ */
3733
4635
  configureAdaptivePerformance(options?: Partial<AdaptivePerformanceOptions>): void;
4636
+ /** Turns adaptive performance off, and by default puts every system back at `maxQuality`. */
3734
4637
  disableAdaptivePerformance(resetQuality?: boolean): void;
4638
+ /** A copy of the adaptive performance settings and the current quality. */
3735
4639
  getAdaptivePerformanceState(): AdaptivePerformanceState;
3736
4640
  private applyAdaptiveQuality;
3737
4641
  /** @internal Called when a system's behaviors change, which can add a sub emitter. */
@@ -3745,6 +4649,11 @@ declare class BatchedRenderer extends TransformNode {
3745
4649
  * cannot be satisfied by any order; it is left as found rather than dropped.
3746
4650
  */
3747
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
+ */
3748
4657
  update(delta: number): void;
3749
4658
  /** Rebuild instance buffers from current particle state without advancing simulation. */
3750
4659
  refreshBatches(): void;
@@ -3752,17 +4661,25 @@ declare class BatchedRenderer extends TransformNode {
3752
4661
  private removeBatch;
3753
4662
  /** Per-batch particle vs GPU instance counts — for diagnosing stale render state. */
3754
4663
  getBatchRenderStats(): Array<{
4664
+ /** Index into {@link batches}. */
3755
4665
  batchIndex: number;
4666
+ /** The batch's render mode. */
3756
4667
  renderMode: RenderMode;
4668
+ /** Instances the batch mesh draws. */
3757
4669
  instanceCount: number;
4670
+ /** Live particles of the batch's systems. */
3758
4671
  particleCount: number;
4672
+ /** The emitter names of the batch's systems. */
3759
4673
  systemNames: string[];
3760
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
+ */
3761
4679
  dispose(): void;
3762
4680
  }
3763
4681
 
3764
- declare const BatchedParticleRenderer: typeof BatchedRenderer;
3765
-
4682
+ /** Options for a new {@link EffectPool}. */
3766
4683
  interface EffectPoolOptions {
3767
4684
  /** The renderer every copy the pool makes is added to. */
3768
4685
  renderer: BatchedRenderer;
@@ -3822,33 +4739,53 @@ declare class EffectPool {
3822
4739
 
3823
4740
  /** Reads the six face URLs from a Babylon CubeTexture (px py pz nx ny nz). */
3824
4741
  declare function cubeFaceUrls(reflection: BaseTexture | null | undefined): string[] | null;
3825
- /** Returns a previously built atlas for this cube, if any. */
3826
- declare function getCachedEnvAtlas(cube: BaseTexture): Texture | null;
3827
- /** 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
+ */
3828
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;
3829
4767
  /**
3830
4768
  * Packs six cube-face images into one 3×2 atlas Texture (px py pz / nx ny nz).
3831
4769
  * Uses invertY:false so UV cellY=0 maps to the +faces row matching the shader.
3832
4770
  */
3833
4771
  declare function createEnvAtlasFromFaceUrls(urls: string[], scene: Scene): Promise<Texture>;
3834
4772
  /**
3835
- * Ensures a 3×2 env atlas exists for a CubeTexture. Returns a cached atlas
3836
- * synchronously when available; otherwise starts (or joins) an async build and
3837
- * 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.
3838
4776
  */
3839
4777
  declare function ensureEnvAtlasFromCube(cube: BaseTexture, scene: Scene, onReady: (atlas: Texture) => void): Texture | null;
3840
4778
 
3841
- type BabylonParticleMaterialParameters = Record<string, any>;
3842
- declare class ParticleMeshStandardMaterial extends StandardMaterial {
3843
- readonly isParticleMeshStandardMaterial = true;
3844
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
3845
- }
3846
- declare class ParticleMeshPhysicsMaterial extends PBRMaterial {
3847
- readonly isParticleMeshPhysicsMaterial = true;
3848
- constructor(name: string, scene?: Scene, parameters?: BabylonParticleMaterialParameters);
3849
- }
3850
-
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
+ */
3851
4787
  declare class MeshSurfaceEmitter implements EmitterShape {
4788
+ /** The shape's type in effect files. */
3852
4789
  type: string;
3853
4790
  private _triangleIndexToArea;
3854
4791
  private _mesh?;
@@ -3857,18 +4794,45 @@ declare class MeshSurfaceEmitter implements EmitterShape {
3857
4794
  private _meshReferenceId?;
3858
4795
  /** Offset, rotation and scale of the mesh within the particle system. */
3859
4796
  transform?: ShapeTransform;
4797
+ /** The mesh emitted from. Setting it reads its positions and indices; a mesh without both emits from the origin. */
3860
4798
  get mesh(): Mesh | undefined;
3861
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
+ */
3862
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. */
3863
4807
  initialize(p: Particle): void;
4808
+ /** The shape in effect-file form; the mesh is written as its node id. */
3864
4809
  toJSON(): ShapeJSON;
4810
+ /** Reads {@link toJSON} output; the mesh stays an id until `QuarksLoader` links it. */
3865
4811
  static fromJSON(json: any): MeshSurfaceEmitter;
4812
+ /** A copy emitting from the same mesh. */
3866
4813
  clone(): EmitterShape;
4814
+ /** Does nothing: the shape keeps no state between steps. */
3867
4815
  update(_system: IParticleSystem, _delta: number): void;
3868
4816
  }
4817
+ /** Registers {@link MeshSurfaceEmitter} with quarks.core's shape table; loaded when the package is imported. */
3869
4818
  declare const MeshSurfaceEmitterPlugin: Plugin;
3870
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
+ */
3871
4834
  declare class ParticleEmitter extends TransformNode {
4835
+ /** The particle system this node carries. */
3872
4836
  system: IParticleSystem;
3873
4837
  private _matrixWorld;
3874
4838
  private _matrixWorldFlag;
@@ -3878,21 +4842,45 @@ declare class ParticleEmitter extends TransformNode {
3878
4842
  * `updateFlag`), so repeated reads inside a frame are free.
3879
4843
  */
3880
4844
  get matrixWorld(): Matrix4;
4845
+ /** Whether the node and its parents are enabled; setting it is `setEnabled`. */
3881
4846
  get visible(): boolean;
3882
4847
  set visible(value: boolean);
4848
+ /** The id effect files know this emitter by; see {@link quarksNodeId}. */
3883
4849
  get uuid(): string;
3884
4850
  constructor(system: IParticleSystem, scene?: Scene);
3885
- dispose(): void;
3886
- 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;
3887
4858
  clone(name?: string): ParticleEmitter;
4859
+ /** The node and its system in effect-file form; `serializeEffect` writes whole effects. @internal */
3888
4860
  toJSON(meta?: any, options?: SerializationOptions): any;
3889
4861
  }
3890
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
+ */
3891
4870
  interface BurstParameters {
4871
+ /** Seconds into the system's duration the first wave fires at. */
3892
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
+ */
3893
4878
  count: ValueGenerator | FunctionValueGenerator;
4879
+ /** How many waves the burst fires, at least 1. */
3894
4880
  cycle: number;
4881
+ /** Seconds between waves; 0 fires them all at once. 0.1 when left out. */
3895
4882
  interval: number;
4883
+ /** Chance from 0 to 1 that a wave spawns at all, rolled per wave. */
3896
4884
  probability: number;
3897
4885
  }
3898
4886
  /**
@@ -3931,59 +4919,125 @@ type ScalingMode = 'shape' | 'hierarchy';
3931
4919
  * every frame.
3932
4920
  */
3933
4921
  type BeamEnd = {
4922
+ /** World x. */
3934
4923
  x: number;
4924
+ /** World y. */
3935
4925
  y: number;
4926
+ /** World z. */
3936
4927
  z: number;
3937
4928
  } | {
4929
+ /** The world position, read every frame. */
3938
4930
  getAbsolutePosition(): {
4931
+ /** World x. */
3939
4932
  x: number;
4933
+ /** World y. */
3940
4934
  y: number;
4935
+ /** World z. */
3941
4936
  z: number;
3942
4937
  };
3943
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
+ */
3944
4943
  interface ParticleSystemParameters {
4944
+ /** See {@link ParticleSystem.autoDestroy}. Default false. */
3945
4945
  autoDestroy?: boolean;
4946
+ /** See {@link ParticleSystem.looping}. Default true. */
3946
4947
  looping?: boolean;
4948
+ /** See {@link ParticleSystem.prewarm}. Default false. */
3947
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. */
3948
4953
  duration?: number;
4954
+ /** See {@link ParticleSystem.startDelay}. Default 0. */
3949
4955
  startDelay?: ValueGenerator | FunctionValueGenerator;
4956
+ /** Where particles are born and which way they start, see {@link ParticleSystem.emitterShape}. Default a `SphereEmitter`. */
3950
4957
  shape?: EmitterShape;
4958
+ /** See {@link ParticleSystem.startLife}. Default 5 seconds. */
3951
4959
  startLife?: ValueGenerator | FunctionValueGenerator;
4960
+ /** See {@link ParticleSystem.startSpeed}. Default 0. */
3952
4961
  startSpeed?: ValueGenerator | FunctionValueGenerator;
4962
+ /** See {@link ParticleSystem.startRotation}. Default 0. */
3953
4963
  startRotation?: ValueGenerator | FunctionValueGenerator | RotationGenerator;
4964
+ /** See {@link ParticleSystem.startSize}. Default 1. */
3954
4965
  startSize?: ValueGenerator | FunctionValueGenerator | Vector3Generator;
3955
- startLength?: ValueGenerator | FunctionValueGenerator;
4966
+ /** See {@link ParticleSystem.startColor}. Default opaque white. */
3956
4967
  startColor?: ColorGenerator | FunctionColorGenerator;
4968
+ /** See {@link ParticleSystem.emissionOverTime}. Default 10 per second. */
3957
4969
  emissionOverTime?: ValueGenerator | FunctionValueGenerator;
4970
+ /** See {@link ParticleSystem.emissionOverDistance}. Default 0. */
3958
4971
  emissionOverDistance?: ValueGenerator | FunctionValueGenerator;
4972
+ /** See {@link ParticleSystem.emissionBursts}. Default none. */
3959
4973
  emissionBursts?: Array<BurstParameters>;
3960
4974
  /** Most particles alive at once; emission past it is dropped. Leave unset for no limit. */
3961
4975
  maxParticles?: number;
4976
+ /** See {@link ParticleSystem.onlyUsedByOther}. Default false. */
3962
4977
  onlyUsedByOther?: boolean;
4978
+ /** See {@link ParticleSystem.behaviors}. Default none. */
3963
4979
  behaviors?: Array<Behavior>;
4980
+ /** Mesh particles' vertex positions, three values per vertex. Default a unit quad in XY. */
3964
4981
  instancingGeometry?: Float32Array;
4982
+ /** Triangle indices into {@link instancingGeometry}. Default the unit quad's two triangles. */
3965
4983
  instancingIndices?: Uint32Array | Uint16Array;
4984
+ /** Mesh particles' first UV set, two values per vertex. Default the quad's UVs, or zeros for another geometry. */
3966
4985
  instancingUVs?: Float32Array;
4986
+ /**
4987
+ * A second UV set for the mesh (glTF `TEXCOORD_1`, Unity's `uv2`), what
4988
+ * textures on UV channel 1 read on a mesh particle; see `UVChannel`.
4989
+ * Default none: channel 1 reads the first set.
4990
+ */
4991
+ instancingUVs2?: Float32Array;
4992
+ /** Mesh particles' vertex normals, three values per vertex. Default +Z for every vertex. */
3967
4993
  instancingNormals?: Float32Array;
4994
+ /** See {@link ParticleSystem.renderMode}. Default `RenderMode.BillBoard`. */
3968
4995
  renderMode?: RenderMode;
4996
+ /** See {@link ParticleSystem.rendererEmitterSettings}. Default the render mode's own. */
3969
4997
  rendererEmitterSettings?: RendererEmitterSettings;
4998
+ /** @deprecated Set `speedFactor` in {@link rendererEmitterSettings} instead; this one wins when both are set. */
3970
4999
  speedFactor?: number;
3971
- 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. */
3972
5003
  texture?: Texture | null;
5004
+ /** See {@link ParticleSystem.startTileIndex}. Default 0. */
3973
5005
  startTileIndex?: ValueGenerator;
5006
+ /** See {@link ParticleSystem.uTileCount}. Default 1. */
3974
5007
  uTileCount?: number;
5008
+ /** See {@link ParticleSystem.vTileCount}. Default 1. */
3975
5009
  vTileCount?: number;
5010
+ /** See {@link ParticleSystem.blendTiles}. Default false. */
3976
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
+ */
3977
5018
  softParticles?: boolean;
5019
+ /** See {@link ParticleSystem.softFarFade}. Default 1. */
3978
5020
  softFarFade?: number;
5021
+ /** See {@link ParticleSystem.softNearFade}. Default 0. */
3979
5022
  softNearFade?: number;
5023
+ /** See {@link ParticleSystem.renderOrder}. Default 0. */
3980
5024
  renderOrder?: number;
5025
+ /** See {@link ParticleSystem.worldSpace}. Default false. */
3981
5026
  worldSpace?: boolean;
5027
+ /** Babylon alpha mode the batch blends with, see {@link ParticleSystem.blending}. Default `Constants.ALPHA_ADD`. */
3982
5028
  blendMode?: number;
5029
+ /** Whether the batch draws in the transparent pass. Default true. */
3983
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
+ */
3984
5035
  depthTest?: boolean;
5036
+ /** Whether the particles write depth. Default false. */
3985
5037
  depthWrite?: boolean;
5038
+ /** Alpha below which a fragment is discarded, 0 to 1. Default 0: nothing is. */
3986
5039
  alphaTest?: number;
5040
+ /** Camera layer mask the batch draws for, see {@link ParticleSystem.layers}. Default `0x0fffffff`. */
3987
5041
  layerMask?: number;
3988
5042
  /** Billboard pivot in particle-size units, see {@link VFXBatchSettings.pivot}. */
3989
5043
  pivot?: Vector3;
@@ -3993,12 +5047,14 @@ interface ParticleSystemParameters {
3993
5047
  lighting?: MeshLighting;
3994
5048
  /** Rim (Fresnel) term on mesh particles, see {@link ParticleSystem.rim}. Default none. */
3995
5049
  rim?: Partial<MeshRim>;
3996
- /** Map UV scroll in UV units per second, see {@link ParticleSystem.uvScroll}. Default none. */
3997
- uvScroll?: [number, number];
5050
+ /** The main map's layout, see {@link ParticleSystem.mapUV}. Default as drawn. */
5051
+ mapUV?: Partial<TextureUV>;
3998
5052
  /** Colour ramp for the map, see {@link ParticleSystem.gradientMap}. Default none. */
3999
- gradientMap?: BaseTexture | null;
5053
+ gradientMap?: Partial<ParticleGradientMap>;
4000
5054
  /** Alpha erosion, see {@link ParticleSystem.erosion}. Default none. */
4001
- erosion?: Partial<ParticleErosion>;
5055
+ erosion?: ParticleErosionOptions;
5056
+ /** Map UV distortion, see {@link ParticleSystem.uvDistortion}. Default none. */
5057
+ uvDistortion?: ParticleUVDistortionOptions;
4002
5058
  /** Multiplier on the time the system is advanced by, see {@link ParticleSystem.playbackSpeed}. Default 1. */
4003
5059
  playbackSpeed?: number;
4004
5060
  /** What the system does while off screen, see {@link CullingMode}. Default `'always'`. */
@@ -4019,36 +5075,79 @@ interface ParticleSystemParameters {
4019
5075
  renderingGroupId?: number;
4020
5076
  /** Whether the scene's fog applies, see {@link ParticleSystem.applyFog}. Default true. */
4021
5077
  applyFog?: boolean;
5078
+ /** Scene the emitter node is created in. Default Babylon's last created scene. */
4022
5079
  scene?: Scene;
4023
5080
  }
5081
+ /** A {@link BurstParameters} in an effect file. A plain number `count` is read as a constant. */
4024
5082
  interface BurstParametersJSON {
5083
+ /** See {@link BurstParameters.time}. */
4025
5084
  time: number;
5085
+ /** See {@link BurstParameters.count}. */
4026
5086
  count: FunctionJSON | number;
5087
+ /** See {@link BurstParameters.cycle}. */
4027
5088
  cycle: number;
5089
+ /** See {@link BurstParameters.interval}. */
4028
5090
  interval: number;
5091
+ /** See {@link BurstParameters.probability}. */
4029
5092
  probability: number;
4030
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
+ */
4031
5104
  interface ParticleSystemJSONParameters {
5105
+ /** The quarks.core version line the system was written with. */
4032
5106
  version: string;
4033
- autoDestroy: boolean;
4034
- looping: boolean;
4035
- prewarm: boolean;
4036
- 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}. */
4037
5118
  startDelay?: FunctionJSON;
4038
- shape: any;
4039
- startLife: FunctionJSON;
4040
- startSpeed: FunctionJSON;
4041
- startRotation: FunctionJSON;
4042
- startSize: FunctionJSON;
4043
- startColor: FunctionJSON;
4044
- emissionOverTime: FunctionJSON;
4045
- 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}. */
4046
5136
  emissionBursts?: Array<BurstParametersJSON>;
5137
+ /** See {@link ParticleSystem.maxParticles}. */
4047
5138
  maxParticles?: number;
4048
- onlyUsedByOther: boolean;
4049
- 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. */
4050
5147
  instancingGeometry?: any;
4051
- renderMode: number;
5148
+ /** A {@link RenderMode} value. */
5149
+ renderMode?: number;
5150
+ /** See {@link ParticleSystem.renderOrder}. */
4052
5151
  renderOrder?: number;
4053
5152
  /** Written only when not 0. */
4054
5153
  renderingGroupId?: number;
@@ -4070,68 +5169,154 @@ interface ParticleSystemJSONParameters {
4070
5169
  minParticleSize?: number;
4071
5170
  /** Written only when limited. */
4072
5171
  maxParticleSize?: number;
5172
+ /** A stretched billboard's speed factor, as older files wrote it outside `rendererEmitterSettings`. */
4073
5173
  speedFactor?: number;
5174
+ /** Uuid of the texture entry. */
4074
5175
  texture?: string;
5176
+ /** Uuid of the material entry. */
4075
5177
  material?: string;
5178
+ /** The camera layer mask. */
4076
5179
  layers?: number;
4077
- startTileIndex: FunctionJSON | number;
4078
- uTileCount: number;
4079
- 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}. */
4080
5187
  blendTiles?: boolean;
5188
+ /** See {@link ParticleSystem.softParticles}. */
4081
5189
  softParticles?: boolean;
5190
+ /** See {@link ParticleSystem.softFarFade}. */
4082
5191
  softFarFade?: number;
5192
+ /** See {@link ParticleSystem.softNearFade}. */
4083
5193
  softNearFade?: number;
5194
+ /** See {@link ParticleSystem.blending}. */
4084
5195
  blending?: number;
5196
+ /** See {@link ParticleSystemParameters.transparent}. */
4085
5197
  transparent?: boolean;
5198
+ /** See {@link ParticleSystemParameters.depthTest}. */
4086
5199
  depthTest?: boolean;
5200
+ /** See {@link ParticleSystemParameters.depthWrite}. */
4087
5201
  depthWrite?: boolean;
5202
+ /** See {@link ParticleSystemParameters.alphaTest}. */
4088
5203
  alphaTest?: number;
4089
- behaviors: Array<any>;
4090
- worldSpace: boolean;
5204
+ /** Each behavior as its `toJSON` writes it. */
5205
+ behaviors?: Array<any>;
5206
+ /** See {@link ParticleSystem.worldSpace}. */
5207
+ worldSpace?: boolean;
4091
5208
  /** `[x, y, z]`; written only when non-zero. */
4092
5209
  pivot?: number[];
4093
5210
  /** `[u, v]`; written only when non-zero. */
4094
5211
  flip?: number[];
4095
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
+ */
4096
5219
  interface BabylonMetaData {
5220
+ /** Textures by uuid; null for one that could not be made. */
4097
5221
  textures: {
4098
5222
  [uuid: string]: Texture | null;
4099
5223
  };
5224
+ /** Material entries by uuid. */
4100
5225
  materials: {
4101
5226
  [uuid: string]: any;
4102
5227
  };
5228
+ /** Geometry entries by uuid. */
4103
5229
  geometries: {
4104
5230
  [uuid: string]: any;
4105
5231
  };
5232
+ /** Image entries by uuid. */
4106
5233
  images?: {
4107
5234
  [uuid: string]: any;
4108
5235
  };
5236
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4109
5237
  shapes?: {
4110
5238
  [uuid: string]: any;
4111
5239
  };
5240
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4112
5241
  skeletons?: {
4113
5242
  [uuid: string]: any;
4114
5243
  };
5244
+ /** Not used by babylon.quarks; kept for three.js-shaped documents. */
4115
5245
  animations?: {
4116
5246
  [uuid: string]: any;
4117
5247
  };
5248
+ /** Nodes by uuid, which a mesh surface shape links to. */
4118
5249
  nodes?: {
4119
5250
  [uuid: string]: any;
4120
5251
  };
4121
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
+ */
4122
5267
  declare class ParticleSystem implements IParticleSystem {
4123
- private static serializationCounter;
5268
+ /** Dispose the system, its emitter and its batch slot when it finishes. Default false. */
4124
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
+ */
4125
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. */
4126
5287
  looping: boolean;
4127
- 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. */
4128
5297
  startDelay: ValueGenerator | FunctionValueGenerator;
5298
+ /** Seconds each particle lives, rolled at birth. Default 5. */
4129
5299
  startLife: ValueGenerator | FunctionValueGenerator;
5300
+ /** Speed each particle starts with along the direction its shape gives it, in units per second. Default 0. */
4130
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
+ */
4131
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. */
4132
5309
  startSize: ValueGenerator | FunctionValueGenerator | Vector3Generator;
5310
+ /** Colour and alpha each particle starts with, multiplied with the texture. Default opaque white. */
4133
5311
  startColor: ColorGenerator | FunctionColorGenerator;
5312
+ /** Flipbook cell each particle starts on, counted across rows, see {@link uTileCount}. Default 0. */
4134
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
+ */
4135
5320
  rendererEmitterSettings: RendererEmitterSettings;
4136
5321
  /**
4137
5322
  * Fraction of billboard particles mirrored along U (x) and V (y), each
@@ -4139,57 +5324,95 @@ declare class ParticleSystem implements IParticleSystem {
4139
5324
  * Undefined: nothing is mirrored. Meshes ignore it.
4140
5325
  */
4141
5326
  flip?: Vector2;
5327
+ /** Particles emitted per second, read over the system's time. Default 10. */
4142
5328
  emissionOverTime: ValueGenerator | FunctionValueGenerator;
5329
+ /** Particles emitted per world unit the emitter moves (Unity's Rate over Distance). Default 0. */
4143
5330
  emissionOverDistance: ValueGenerator | FunctionValueGenerator;
5331
+ /** Bursts of particles at set times in each cycle. Default none. */
4144
5332
  emissionBursts: Array<BurstParameters>;
4145
- /** 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
+ */
4146
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
+ */
4147
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
+ */
4148
5349
  worldSpace: boolean;
5350
+ /** How many of {@link particles} are alive. Read only. */
4149
5351
  particleNum: number;
5352
+ /** Set by {@link pause}: the renderer skips the system's simulation while true. */
4150
5353
  paused: boolean;
5354
+ /** The particle pool; the first {@link particleNum} are alive. Read only. */
4151
5355
  particles: Array<Particle>;
4152
- /** Column storage shared by this system's particles. */
5356
+ /** Column storage shared by this system's particles; behaviors read and write it. */
4153
5357
  readonly store: ParticleStore;
5358
+ /** Where particles are born and which way they start (Unity's Shape module). Default a `SphereEmitter`. */
4154
5359
  emitterShape: EmitterShape;
5360
+ /** The node the system lives at; move, parent or disable it to place or hide the effect. */
4155
5361
  emitter: ParticleEmitter;
5362
+ /** What the renderer batches on; read it with {@link getRendererSettings}. @internal */
4156
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
+ */
4157
5368
  neededToUpdateRender: boolean;
5369
+ /** Modules run on every particle each step, in order (`ColorOverLife`, `SizeOverLife`, forces, ...). */
4158
5370
  behaviors: Array<Behavior>;
5371
+ /** Emission progress: time in the cycle, burst and distance counters. */
4159
5372
  emissionState: EmissionState;
5373
+ /** The emitter's velocity over the last step, which `InheritVelocity` reads. */
4160
5374
  emitterVelocity: Vector3;
4161
5375
  private prewarmed;
4162
5376
  private emitEnded;
4163
- private markForDestroy;
4164
- private finishedEventFired;
4165
- 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;
4166
5385
  private previousEmitterPos?;
4167
5386
  private tempEmitterPos;
4168
- private temp;
4169
- /** Emitter matrix moved along the step's path, see spawnAlongPath. */
4170
- private pathMatrix;
4171
- private normalMatrix;
4172
- private memory;
4173
- 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;
4174
5396
  private readonly layerMaskProxy;
4175
5397
  private materialRef;
4176
5398
  private sceneRef;
4177
5399
  private qualityFactor;
4178
- private simulationAccumulator;
4179
5400
  private destroyed;
4180
- /** Behaviors the cached plan was built from, compared by identity. */
4181
- private fusionPlan?;
4182
- private fusionSteps;
4183
- /**
4184
- * Whether any behavior in the plan can change a particle's size or colour
4185
- * after birth. Only then does a step have to snapshot them for the renderer.
4186
- */
4187
- private planChangesSize;
4188
- private planChangesColor;
5401
+ /** How the behaviors run each step, rebuilt when the list changes. */
5402
+ private readonly behaviorPlan;
4189
5403
  /** @internal **/
4190
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
+ */
4191
5413
  set time(time: number);
4192
5414
  get time(): number;
5415
+ /** Whether {@link endEmit} ran, or a non-looping system reached the end of its duration. */
4193
5416
  get isEmitEnded(): boolean;
4194
5417
  /** Whether continuous or queued emission can still spawn particles before the system is done. */
4195
5418
  hasPendingEmission(): boolean;
@@ -4199,26 +5422,58 @@ declare class ParticleSystem implements IParticleSystem {
4199
5422
  * {@link endEmit} and whose last particle has died.
4200
5423
  */
4201
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
+ */
4202
5430
  get layers(): {
5431
+ /** The mask; setting it moves the system to a matching batch. */
4203
5432
  mask: number;
4204
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
+ */
4205
5439
  get texture(): Texture | null;
4206
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
+ */
4207
5449
  get material(): any;
4208
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
+ */
4209
5457
  get uTileCount(): number;
4210
5458
  set uTileCount(u: number);
5459
+ /** Rows of the flipbook in {@link texture}, see {@link uTileCount}. Default 1. */
4211
5460
  get vTileCount(): number;
4212
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
+ */
4213
5467
  get blendTiles(): boolean;
4214
5468
  set blendTiles(v: boolean);
4215
- get softParticles(): boolean;
4216
- set softParticles(v: boolean);
4217
5469
  /**
4218
- * Billboard pivot in particle-size units (Unity's renderer Pivot), see
4219
- * {@link VFXBatchSettings.pivot}. Assign a new vector to change it: editing
4220
- * 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.
4221
5474
  */
5475
+ get softParticles(): boolean;
5476
+ set softParticles(v: boolean);
4222
5477
  /**
4223
5478
  * The order this system's batch draws its particles in (Unity's Sort
4224
5479
  * Mode), `'none'` by default. Alpha blended smoke wants `'distance'`;
@@ -4242,6 +5497,11 @@ declare class ParticleSystem implements IParticleSystem {
4242
5497
  */
4243
5498
  get maxParticleSize(): number;
4244
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
+ */
4245
5505
  get pivot(): Vector3 | undefined;
4246
5506
  set pivot(v: Vector3 | undefined);
4247
5507
  /**
@@ -4264,22 +5524,28 @@ declare class ParticleSystem implements IParticleSystem {
4264
5524
  get rim(): MeshRim | undefined;
4265
5525
  set rim(rim: Partial<MeshRim> | undefined);
4266
5526
  /**
4267
- * Scrolls the map's UV by `[u, v]` UV units per second on the renderer's
4268
- * clock: flowing energy, lava, a smear running along a mesh. The texture
4269
- * should wrap. Undefined (the default) or zero does not scroll. Assign a
4270
- * new array to change it. Saved with the material in the effect JSON.
4271
- */
4272
- get uvScroll(): [number, number] | undefined;
4273
- set uvScroll(scroll: [number, number] | undefined);
4274
- /**
4275
- * Colour ramp the map is recoloured through (a gradient map): the map's
4276
- * red channel picks a colour along U of this texture, whose alpha
4277
- * multiplies the map's; the particle colour still tints the result. One
4278
- * greyscale texture then serves every palette. Null (the default): none.
4279
- * Saved with the material in the effect JSON.
4280
- */
4281
- get gradientMap(): BaseTexture | null;
4282
- set gradientMap(texture: BaseTexture | null);
5527
+ * How the main map is laid over the particle, see {@link TextureUV}: its
5528
+ * UV channel, tiling and offset (Unity's Tiling / Offset) and a scroll on
5529
+ * the renderer's clock (Unreal's Panner), for flowing energy, lava or a
5530
+ * smear running along a mesh. A scrolled or tiled map should repeat. On a
5531
+ * sprite sheet (UV channel 0) the layout applies to the sheet's UV, so a
5532
+ * scroll or tiling there runs into the neighbouring cells. Undefined (the
5533
+ * default), or the identity: the map as drawn. Fields left out take their
5534
+ * defaults; assign a new object to change it. Saved with the material in
5535
+ * the effect JSON.
5536
+ */
5537
+ get mapUV(): TextureUV | undefined;
5538
+ set mapUV(uv: Partial<TextureUV> | undefined);
5539
+ /**
5540
+ * Colour ramp the map is recoloured through (a gradient map), see
5541
+ * {@link ParticleGradientMap}: a channel of the map, or its luminance,
5542
+ * picks a colour along U of the ramp; the particle colour still tints the
5543
+ * result. One greyscale or channel-packed texture then serves every
5544
+ * palette. Undefined (the default), or without a ramp: none. Assign a new
5545
+ * object to change it. Saved with the material in the effect JSON.
5546
+ */
5547
+ get gradientMap(): ParticleGradientMap | undefined;
5548
+ set gradientMap(gradientMap: Partial<ParticleGradientMap> | undefined);
4283
5549
  /**
4284
5550
  * Alpha erosion, see {@link ParticleErosion}: the particle's alpha decides
4285
5551
  * how much of the shape is left rather than how transparent it is, so a
@@ -4290,32 +5556,123 @@ declare class ParticleSystem implements IParticleSystem {
4290
5556
  * Saved with the material in the effect JSON.
4291
5557
  */
4292
5558
  get erosion(): ParticleErosion | undefined;
4293
- set erosion(erosion: Partial<ParticleErosion> | undefined);
5559
+ set erosion(erosion: ParticleErosionOptions | undefined);
5560
+ /**
5561
+ * Map UV distortion, see {@link ParticleUVDistortion}: a scrolling noise
5562
+ * texture pushes the map's UV about, for heat shimmer and licking,
5563
+ * breathing shapes. Undefined (the default), or without a map: none.
5564
+ * Fields left out take their defaults; assign a new object to change it.
5565
+ * Saved with the material in the effect JSON.
5566
+ */
5567
+ get uvDistortion(): ParticleUVDistortion | undefined;
5568
+ set uvDistortion(distortion: ParticleUVDistortionOptions | undefined);
4294
5569
  /**
4295
5570
  * The emitter's world scale per axis, measured with {@link motionScale}
4296
5571
  * before every step; what `'hierarchy'` multiplies start speeds by. Taken
4297
5572
  * from the system's own emitter rather than the emission matrix, whose
4298
5573
  * columns carry a parent particle's velocity for a sub emitter.
5574
+ * @internal
4299
5575
  */
4300
- private readonly hierarchyScale;
5576
+ readonly hierarchyScale: Vector3;
4301
5577
  /** The mean world scale of the emitter for a world-space `'hierarchy'` system, else 1. */
4302
5578
  private measureMotionScale;
4303
- /** `lighting` if it is one of the modes, else the default. */
4304
- private static validLighting;
4305
- private static validSortMode;
4306
- private static validCullingMode;
4307
- private static nonZeroPivot;
4308
- 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
+ */
4309
5584
  get softNearFade(): number;
4310
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
+ */
4311
5592
  get softFarFade(): number;
4312
5593
  set softFarFade(v: number);
5594
+ /**
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.
5601
+ */
4313
5602
  get instancingGeometry(): Float32Array;
4314
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);
5620
+ /** The mesh particles' first UV set, two values per vertex. */
5621
+ get instancingUVs(): Float32Array;
5622
+ set instancingUVs(uvs: Float32Array);
5623
+ /** The mesh particles' second UV set, read by textures on UV channel 1; see `UVChannel`. */
5624
+ get instancingUVs2(): Float32Array | undefined;
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
+ */
4315
5631
  get blending(): number;
4316
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
+ */
4317
5669
  get renderMode(): RenderMode;
4318
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
+ */
4319
5676
  get renderOrder(): number;
4320
5677
  set renderOrder(renderOrder: number);
4321
5678
  /**
@@ -4335,17 +5692,23 @@ declare class ParticleSystem implements IParticleSystem {
4335
5692
  /**
4336
5693
  * Multiplier on the time this system is advanced by (Unity's Simulation
4337
5694
  * Speed): 2 runs the effect twice as fast, 0 freezes it without pausing the
4338
- * 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.
4339
5697
  */
4340
- playbackSpeed: number;
5698
+ get playbackSpeed(): number;
5699
+ set playbackSpeed(speed: number);
5700
+ private playbackSpeedValue;
4341
5701
  /**
4342
5702
  * Runtime multiplier on how many particles the system emits: bursts,
4343
5703
  * emission over time and over distance alike. Unlike
4344
5704
  * {@link setQualityFactor}, which only ever thins an effect, it may go
4345
5705
  * above 1 to make a stronger version of the same effect. The two multiply.
4346
- * 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}.
4347
5708
  */
4348
- emissionMultiplier: number;
5709
+ get emissionMultiplier(): number;
5710
+ set emissionMultiplier(multiplier: number);
5711
+ private emissionMultiplierValue;
4349
5712
  /** What this system does while off screen, see {@link CullingMode}. `'always'` by default. */
4350
5713
  cullingMode: CullingMode;
4351
5714
  /** What the emitter's world scale does to a world-space system, see {@link ScalingMode}. `'shape'` by default. */
@@ -4376,9 +5739,9 @@ declare class ParticleSystem implements IParticleSystem {
4376
5739
  * multiplayer and reproducible tests. Systems this one emits into roll on
4377
5740
  * its generator too. Unset (the default), rolls come from the global source
4378
5741
  * (`setRandomSource` in quarks.core). Saved in the effect JSON when set.
4379
- *
4380
- * Not covered: randomness outside the step, such as a `TurbulenceField`'s
4381
- * 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.
4382
5745
  */
4383
5746
  get seed(): number | undefined;
4384
5747
  set seed(seed: number | undefined);
@@ -4388,12 +5751,6 @@ declare class ParticleSystem implements IParticleSystem {
4388
5751
  * @internal
4389
5752
  */
4390
5753
  culled: boolean;
4391
- /**
4392
- * Time a `'pauseAndCatchUp'` system has spent off screen and not yet
4393
- * simulated, in seconds. Capped, so an effect hidden for a minute does not
4394
- * replay the minute.
4395
- */
4396
- private pendingCatchUp;
4397
5754
  /**
4398
5755
  * Time per frame a system coming back into view may spend on the steps it
4399
5756
  * missed, in milliseconds, when it is advanced without a renderer. The
@@ -4401,44 +5758,84 @@ declare class ParticleSystem implements IParticleSystem {
4401
5758
  * instead. Steps that do not fit are dropped, not deferred.
4402
5759
  */
4403
5760
  static catchUpBudgetMs: number;
4404
- /** Axis-aligned bounds of the live particles, in simulation space. See {@link getWorldBounds}. */
4405
- private readonly boundsMin;
4406
- private readonly boundsMax;
4407
- /** How far a particle's quad, mesh or stretch can reach past its position, in simulation units. */
4408
- private boundsPadding;
4409
- private boundsValid;
4410
- /** Steps since the last full measurement; between them the bounds are carried and padded. */
4411
- private stepsSinceBounds;
4412
- private boundsMaxSize;
4413
- private boundsMaxSpeedSq;
4414
- /** True when the bounds are already in world space (a world-space system, or bounds the renderer measured). */
4415
- private boundsInWorld;
4416
- private geometryRadiusFor?;
4417
- 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;
4418
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;
4419
5779
  private applyMaterialSettings;
5780
+ /** Freezes the system where it is: particles stay and nothing is simulated until {@link play}. */
4420
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
+ */
4421
5786
  play(): void;
5787
+ /** Clears every particle, rewinds to the start ({@link restart}) and pauses until {@link play}. */
4422
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
+ */
4423
5808
  setQualityFactor(qualityFactor: number): void;
4424
- /** Quality factor times {@link emissionMultiplier}: what emission counts are scaled by. */
4425
- private emissionFactor;
4426
5809
  /**
4427
- * Appends one particle to the pool, giving it the next row of the store.
4428
- *
4429
- * Growing the store replaces its arrays, so every particle already bound to
4430
- * it has to be re-pointed at the new ones.
4431
- */
4432
- /** Points every particle at the store's columns again, after any were replaced. */
4433
- private rebindParticles;
4434
- private growParticlePool;
4435
- private spawn;
4436
- /** Turns a newborn so that it faces the way its shape sent it; see {@link alignToDirection}. */
4437
- private alignParticleToDirection;
4438
- /** Applies the parent particle's inherited properties to a sub emitted newborn; see `EmitSubParticleSystem.inherit`. */
4439
- 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
+ */
4440
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
+ */
4441
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
+ */
4442
5839
  restart(): void;
4443
5840
  private firstTimeUpdate;
4444
5841
  /**
@@ -4457,13 +5854,18 @@ declare class ParticleSystem implements IParticleSystem {
4457
5854
  /** Runs the steps a system missed while culled, as many as fit before `deadline`. */
4458
5855
  private catchUp;
4459
5856
  /**
4460
- * Records the bounds the sprite step measured over the live particles.
4461
- * Trails are measured by their renderer instead, since their ribbons live
4462
- * 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.
5860
+ */
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.
4463
5867
  */
4464
- private storeBounds;
4465
- /** Distance of the farthest vertex of the mesh particles' geometry from its origin. */
4466
- private meshGeometryRadius;
5868
+ private runPrewarm;
4467
5869
  /**
4468
5870
  * World-space axis-aligned bounds of everything this system draws, padded
4469
5871
  * for particle size, into `min` and `max`. False when the system has no
@@ -4476,120 +5878,107 @@ declare class ParticleSystem implements IParticleSystem {
4476
5878
  /**
4477
5879
  * Where a {@link RenderMode.Beam} system's quads end, see {@link BeamEnd}.
4478
5880
  * Unset (the default), a beam has no length and draws nothing. Not saved
4479
- * 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.
4480
5883
  */
4481
5884
  beamEnd?: BeamEnd;
5885
+ /**
5886
+ * Multiplies every particle's colour, alpha included, as it is drawn:
5887
+ * a colour or a fade driven from code for this instance (Unity's custom
5888
+ * per-instance data, Unreal's user parameters). With {@link erosion},
5889
+ * alpha is the erosion level, so this wipes the shape in and out. The
5890
+ * particles' own colours are untouched, so clearing it restores them, and
5891
+ * systems with different tints still batch together. Under additive
5892
+ * (`ALPHA_ONEONE`) or premultiplied blending, which ignore alpha, fade
5893
+ * with the colour instead, or with erosion on. Unset (the default): none.
5894
+ * Not saved in the effect JSON; copied by {@link clone}.
5895
+ */
5896
+ tint?: Vector4;
4482
5897
  private readonly beamEndScratch;
4483
5898
  /** The world position of {@link beamEnd} into `out`; false when it is unset. */
4484
5899
  getBeamEnd(out: Vector3): boolean;
4485
- /** The largest axis of the emitter's world scale. */
4486
- private emitterMaxScale;
4487
- private measureWorldBounds;
4488
5900
  /**
4489
5901
  * Records bounds a renderer measured in world space, for systems whose
4490
5902
  * drawn extent the store does not hold (trail ribbons).
4491
5903
  * @internal
4492
5904
  */
4493
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;
4494
5908
  /**
4495
5909
  * Time the display is ahead of (positive) or still ahead of the simulation
4496
- * (negative — the simulation ran a hair early), in seconds. Magnitude never
4497
- * exceeds one step.
5910
+ * (negative: the simulation ran a hair early), in seconds; 0 while paused.
5911
+ * Its magnitude never exceeds one step.
4498
5912
  *
4499
5913
  * The simulation runs on a fixed 1/60 step so that emission and lifetimes
4500
- * 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
4501
5915
  * wobbles. But frames do not arrive on that grid: a display running at
4502
- * anything other than exactly 60Hz leaves some frames with no step at all
4503
- * (half of them at 120Hz, three in five at 144Hz) and others with two, so
4504
- * the particles are drawn stuttering even while the frame rate is perfect.
4505
- *
4506
- * The steps-per-frame count below is chosen by *rounding* the accumulated
4507
- * time to the nearest step, not flooring it. Flooring always leaves the
4508
- * accumulator positive, and when the real frame rate sits very close to
4509
- * 60Hz (as most displays do) that leftover creeps toward a full step for
4510
- * many consecutive frames before tipping over into a frame that runs two
4511
- * steps at once and resets it to near zero — a visible lurch, every particle
4512
- * in the system at once, with a perfectly steady frame rate the whole time.
4513
- * Rounding lets the leftover go negative instead, which keeps it centered
4514
- * near zero and stops it from ever building up toward that reset.
4515
- *
4516
- * Renderers close the gap by advancing what they draw along each particle's
4517
- * velocity by this much. That reproduces the straight-line part of the
4518
- * 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
4519
5922
  * the simulation stays fixed-step while the picture moves continuously.
4520
5923
  */
4521
- /** Length of one simulation step, in seconds. See {@link simulationResidual}. */
4522
- get simulationStep(): number;
4523
5924
  get simulationResidual(): number;
4524
5925
  /**
4525
- * Execution plan for this system's behaviors, rebuilt when the list changes.
4526
- *
4527
- * Consecutive behaviors that can be compiled into one loop are merged, so
4528
- * the particles are walked once instead of once per behavior. The plan is
4529
- * keyed on the behavior instances, not their types: swapping one out has to
4530
- * change the generated code's indices.
4531
- */
4532
- private behaviorSteps;
4533
- /**
4534
- * Advances emission, behaviors, motion and culling by one fixed timestep,
4535
- * 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}).
4536
5929
  */
4537
5930
  private simulateStep;
4538
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;
4539
5936
  private notifyFinished;
4540
- /** Waves a burst fires per loop: its `cycle`, and never fewer than one. */
4541
- private static burstWaveCount;
4542
- /** Seconds between a burst's waves; a missing or negative interval fires them all at once. */
4543
- private static burstInterval;
4544
5937
  /**
4545
- * Fires the burst waves that are due by `emissionState.time`.
4546
- *
4547
- * Wave `w` of a burst is due at `burst.time + w * burst.interval`, and the
4548
- * burst fires `cycle` of them, each rolling `probability` on its own — the
4549
- * way Unity repeats a burst. Bursts start in time order, as they always
4550
- * have; their repeats are tracked per burst so a burst that is still
4551
- * repeating never holds back a later one. Repeats falling past the
4552
- * system's duration are dropped (a looping system starts them over on its
4553
- * next loop), matching Unity, which never emits a burst cycle beyond the
4554
- * end of the duration.
4555
- */
4556
- private emitBursts;
4557
- /** Spawns one wave of `burst`, if its probability roll passes. */
4558
- private fireBurstWave;
4559
- /** True while a burst that has started still has a wave due within the duration. */
4560
- private hasPendingBurstWaves;
4561
- /**
4562
- * Spawns `count` particles owed to emission over distance, each where the
4563
- * emitter crossed its metre mark on the way from `from` to where
4564
- * `emitterMatrix` has it now, rather than all of them at the end of the
4565
- * path: a fast emitter then leaves a continuous trail instead of one clump
4566
- * per step.
4567
- *
4568
- * `carried` is how far the emitter had already gone past its last mark
4569
- * before this step, so the marks keep their spacing across steps. Only the
4570
- * position is interpolated; the emitter's current rotation and scale are
4571
- * 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.
4572
5940
  */
4573
- private spawnAlongPath;
4574
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
+ */
4575
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
+ */
4576
5956
  static fromJSON(json: ParticleSystemJSONParameters, meta: BabylonMetaData, dependencies?: {
4577
5957
  [uuid: string]: Behavior;
4578
5958
  }, scene?: Scene): ParticleSystem;
4579
- private static nextSerializationId;
4580
- private static createFallbackNormals;
4581
- private toRendererSettingsJSON;
4582
- private ensureGeometryMeta;
4583
- private ensureMaterialMeta;
4584
- private static resolveGeometryData;
5959
+ /** Appends a behavior to {@link behaviors}; it runs on existing particles from the next step. */
4585
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
+ */
4586
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
+ */
4587
5971
  addEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
5972
+ /** Removes every callback registered for `event`. */
4588
5973
  removeAllEventListeners(event: ParticleSystemEventType): void;
5974
+ /** Removes one callback added with {@link addEventListener}. */
4589
5975
  removeEventListener(event: ParticleSystemEventType, callback: (event: ParticleSystemEvent) => void): void;
4590
- /** True when at least one callback is registered for the event type. */
4591
- private hasListeners;
4592
- 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
+ */
4593
5982
  clone(): ParticleSystem;
4594
5983
  }
4595
5984
 
@@ -4602,10 +5991,21 @@ type QuarksResourceKind = 'effect' | 'geometry' | 'image';
4602
5991
  interface QuarksResourceResolver {
4603
5992
  /** Resolve a relative url to an absolute / blob / data url. Default: {@link QuarksLoader.joinUrl}. */
4604
5993
  resolve?(url: string, kind: QuarksResourceKind, baseUrl: string): string | Promise<string>;
4605
- /** Load a JSON asset (geometry files). Default: `fetch(resolvedUrl).json()`. */
4606
- 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>;
4607
6002
  }
6003
+ /** Options for a {@link QuarksLoader}, shared by every load it does. */
4608
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
+ */
4609
6009
  baseUrl?: string;
4610
6010
  /**
4611
6011
  * Reuse one Texture per scene for every effect that references the same image with the same
@@ -4618,9 +6018,32 @@ interface QuarksLoaderOptions {
4618
6018
  shareResources?: boolean;
4619
6019
  /** Custom url / fetch backend (File picker, CDN, IndexedDB). */
4620
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;
4621
6043
  }
4622
6044
  /** One in-memory effect for {@link QuarksLoader.loadFromJSONAll}. */
4623
6045
  interface QuarksJSONLoadEntry {
6046
+ /** The effect document, as {@link serializeEffect} or the editor writes it. Left unchanged. */
4624
6047
  json: unknown;
4625
6048
  /** Overrides loader `baseUrl` for relative texture / geometry links in this effect. */
4626
6049
  baseUrl?: string;
@@ -4630,7 +6053,7 @@ interface QuarksJSONLoadEntry {
4630
6053
  * Batch loads share the per-scene fetch cache and `shareResources`, so N effects that point at
4631
6054
  * the same `assets/geometries/*.json` or texture only pay for that asset once.
4632
6055
  */
4633
- interface QuarksBatchLoadOptions {
6056
+ interface QuarksBatchLoadOptions extends QuarksLoadOptions {
4634
6057
  /**
4635
6058
  * Max concurrent effect-document fetches (phase 1). Linked geometry/image resolve still runs
4636
6059
  * across the whole pack in parallel so shared urls coalesce. Default: all at once.
@@ -4647,17 +6070,60 @@ interface QuarksBatchLoadOptions {
4647
6070
  */
4648
6071
  continueOnError?: boolean;
4649
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
+ */
4650
6095
  declare class QuarksLoader {
4651
6096
  private scene;
4652
6097
  private options;
4653
6098
  constructor(scene: Scene, options?: QuarksLoaderOptions);
4654
- /** Fetches an effect JSON from `url`, resolves linked sources, and parses it. */
4655
- load(url: string): Promise<TransformNode>;
4656
6099
  /**
4657
- * Resolves linked geometry / image urls on `json` (via {@link resolveResources}) then parses.
4658
- * 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.
4659
6125
  */
4660
- loadFromJSON(json: any, baseUrl?: string): Promise<TransformNode>;
6126
+ private finishLoad;
4661
6127
  /**
4662
6128
  * Loads many effects in parallel for battle / level preload. Phase 1 fetches every effect
4663
6129
  * JSON (optionally concurrency-limited); phase 2 resolves all linked geometries/images across
@@ -4688,18 +6154,23 @@ declare class QuarksLoader {
4688
6154
  }): Promise<(TransformNode | null)[]>;
4689
6155
  /**
4690
6156
  * Inlines external geometry files and rewrites relative image urls through the loader's
4691
- * {@link QuarksResourceResolver}. Idempotent for already-inlined geometries. Failures warn
4692
- * 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.
4693
6161
  */
4694
6162
  resolveResources(json: any, baseUrl?: string): Promise<void>;
4695
6163
  /**
4696
6164
  * Same as instance {@link resolveResources}, but usable without constructing a loader (e.g.
4697
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.
4698
6168
  */
4699
6169
  static resolveLinkedResources(json: any, options?: {
4700
6170
  baseUrl?: string;
4701
6171
  resolver?: QuarksResourceResolver;
4702
6172
  scene?: Scene;
6173
+ onResourceError?: QuarksLoaderOptions['onResourceError'];
4703
6174
  }): Promise<void>;
4704
6175
  /**
4705
6176
  * Inlines geometries that an export wrote to their own file (`{uuid, type: 'QuarksGeometry',
@@ -4708,7 +6179,15 @@ declare class QuarksLoader {
4708
6179
  * `loadGeometry` and no `QuarksLoader` instance.
4709
6180
  */
4710
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
+ */
4711
6188
  parse(json: any, baseUrl?: string): TransformNode;
6189
+ /** {@link parse}, and the textures the effect uses. */
6190
+ private parseDocument;
4712
6191
  private parseGeometries;
4713
6192
  /** The scene's copy of an identical geometry when resources are shared, else `geometry` itself. */
4714
6193
  private share;
@@ -4732,12 +6211,15 @@ declare class QuarksLoader {
4732
6211
  * scene fetch cache), then parse. Each index settles exactly once for `onProgress`.
4733
6212
  */
4734
6213
  private loadDocuments;
6214
+ private loadResolvedDocuments;
4735
6215
  /** Runs `fn` over `items` with at most `concurrency` in flight (or all if unset/≤0). */
4736
6216
  private static mapPool;
4737
6217
  private static resolveWith;
4738
6218
  /** One in-flight fetch per scene + resolved url when `scene` is set; otherwise uncached. */
4739
6219
  private static fetchJsonWith;
4740
6220
  private static inlineGeometryEntries;
6221
+ private static warnResourceError;
6222
+ private reportResourceError;
4741
6223
  private parseImages;
4742
6224
  /**
4743
6225
  * Flags an image entry that is plainly not an image, which otherwise only
@@ -4761,57 +6243,278 @@ declare class QuarksLoader {
4761
6243
  private linkReferences;
4762
6244
  }
4763
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
+ */
4764
6250
  interface QuarksTimelineClip {
6251
+ /** Names the clip in a saved prefab, so it can be found again on load. */
4765
6252
  uuid?: string;
6253
+ /** Length in seconds, used when the track gives none. */
4766
6254
  duration?: number;
6255
+ /** Called when the timeline enters the track. */
4767
6256
  play?: () => void;
6257
+ /** Called when the prefab pauses. */
4768
6258
  pause?: () => void;
6259
+ /** Called when the timeline leaves the track or the prefab stops. */
4769
6260
  stop?: () => void;
6261
+ /** Called while scrubbing with {@link QuarksPrefab.setTime}, with the time into the track in seconds. */
4770
6262
  setTime?: (time: number) => void;
4771
6263
  }
6264
+ /** One track on a {@link QuarksPrefab} timeline. */
4772
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
+ */
4773
6271
  type: 'three' | 'ps';
6272
+ /** The node the track drives: a {@link ParticleEmitter} for `'ps'`, any node for `'three'`. */
4774
6273
  target: TransformNode;
6274
+ /** Restart when the track ends instead of letting it finish. */
4775
6275
  loop: boolean;
6276
+ /** The clip a `'three'` track plays. */
4776
6277
  clip?: QuarksTimelineClip;
6278
+ /** The id of the clip on `target`, written to and read from JSON. */
4777
6279
  clipUUID?: string;
4778
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
+ */
4779
6289
  declare class QuarksPrefab extends TransformNode implements IPrefab {
6290
+ /** Always `'QuarksPrefab'`; written to JSON. */
4780
6291
  type: string;
6292
+ /** The tracks, in the order they were added. */
4781
6293
  animationData: Array<AnimationData>;
6294
+ /** Whether {@link QuarksPrefab.update} advances the timeline. */
4782
6295
  isPlaying: boolean;
6296
+ /** Time on the timeline in seconds; just below 0 before the first update, so a track at 0 starts. */
4783
6297
  currentTime: number;
6298
+ /** Playback speed; 1 is real time. */
4784
6299
  timeScale: number;
6300
+ /** End of the last track in seconds; the prefab stops when it passes it. */
4785
6301
  duration: number;
4786
6302
  private _lastUpdateTimeMs;
4787
6303
  private _batchedRenderer?;
4788
6304
  private _tempAnimationJSON;
4789
6305
  constructor(name?: string, scene?: Scene);
6306
+ /** The renderer that a particle system is added to again when its track starts. */
4790
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
+ */
4791
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
+ */
4792
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}. */
4793
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
+ */
4794
6329
  play(): void;
6330
+ /** Pauses the timeline and every system and clip on it. */
4795
6331
  pause(): void;
6332
+ /** Pauses, rewinds to the start, and stops every system and clip on it. */
4796
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
+ */
4797
6338
  update(forceDelta?: number): void;
6339
+ /** Jumps to `time` seconds, starting and ending tracks it crosses and scrubbing clips to it. */
4798
6340
  setTime(time: number): void;
6341
+ /** Same as {@link QuarksPrefab.duration}. */
4799
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
+ */
4800
6347
  resolveReferences(root: TransformNode): void;
6348
+ /** Writes the prefab's name, time scale (when not 1) and tracks. */
4801
6349
  toJSON(): any;
6350
+ /** Reads a prefab written by {@link QuarksPrefab.toJSON}; call {@link QuarksPrefab.resolveReferences} afterwards. */
4802
6351
  static fromJSON(json: any, scene?: Scene): QuarksPrefab;
4803
6352
  private resolveTimelineClip;
4804
6353
  private updateDuration;
4805
6354
  }
4806
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
+ */
4807
6502
  declare class QuarksUtil {
6503
+ /** Calls `callback` on `root` and every node under it that is a {@link ParticleEmitter}. */
4808
6504
  static runOnAllParticleEmitters(root: Node, callback: (emitter: ParticleEmitter) => void): void;
6505
+ /** Adds every system under `root` to `batchRenderer`. */
4809
6506
  static addToBatchRenderer(root: Node, batchRenderer: BatchedRenderer): void;
6507
+ /** Resumes every system under `root`, see {@link ParticleSystem.play}. */
4810
6508
  static play(root: Node): void;
6509
+ /** Clears, rewinds and pauses every system under `root`, see {@link ParticleSystem.stop}. */
4811
6510
  static stop(root: Node): void;
6511
+ /** Pauses every system under `root`, see {@link ParticleSystem.pause}. */
4812
6512
  static pause(root: Node): void;
6513
+ /** Restarts every system under `root` from the beginning, see {@link ParticleSystem.restart}. */
4813
6514
  static restart(root: Node): void;
6515
+ /** Sets {@link ParticleSystem.autoDestroy} on every system under `root`. */
4814
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}. */
4815
6518
  static endEmit(root: Node): void;
4816
6519
  /**
4817
6520
  * True when every system under `root` is finished: non-looping ones that
@@ -4846,241 +6549,135 @@ declare class QuarksUtil {
4846
6549
  private static traverseNode;
4847
6550
  }
4848
6551
 
4849
- declare function registerShaderChunks(): void;
4850
- declare function getShaderChunk(chunkName: string): string | undefined;
4851
- declare function getRegisteredShaderChunks(): Readonly<Record<string, string>>;
4852
-
4853
- declare const _default$7: string;
4854
-
4855
- 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";
4856
-
4857
- declare const _default$5: string;
4858
-
4859
- declare const _default$4: string;
4860
-
4861
- declare const _default$3: string;
4862
-
4863
- declare const _default$2: string;
4864
-
4865
- declare const _default$1: string;
4866
-
4867
- 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
+ }
4868
6573
 
4869
- declare class SpriteBatch extends VFXBatch {
4870
- private static whiteTextureByScene;
4871
- /** 1×1 white map so mesh batches always have a sampler2D (iOS WebKit). */
4872
- private static whiteTexture;
4873
- private offsetBuffer;
4874
- private rotationBuffer;
4875
- private sizeBuffer;
4876
- private colorBuffer;
4877
- private uvTileBuffer;
4878
- private velocityBuffer?;
4879
- /** Concretely typed handle on the batch material, see syncStretchedSpeedFactor. */
4880
- private shaderMaterial;
4881
- /** The `'fixed'` mesh light, as shader uniforms; see applyMeshLighting. */
4882
- private readonly fixedLightDirection;
4883
- private readonly fixedLightColor;
4884
- private readonly fixedAmbientColor;
4885
- private offsetVB;
4886
- private rotationVB;
4887
- private sizeVB;
4888
- private colorVB;
4889
- private uvTileVB;
4890
- private velocityVB?;
4891
- constructor(settings: VFXBatchSettings, scene: Scene);
4892
- setupBuffers(): void;
4893
- /** Releases the instance vertex buffers so a resize does not leak GPU memory. */
4894
- private disposeExpandableBuffers;
4895
- private buildExpandableBuffers;
4896
- expandBuffers(target: number): void;
4897
- /** The screen-size limits as a uniform value, or null when the batch has none that apply. */
4898
- private sizeLimits;
4899
- private sortScratch?;
4900
- /** One spare array per attribute buffer, gathered into and swapped in; indexed by buffer slot. */
4901
- private readonly gatherScratch;
4902
- /**
4903
- * Reorders the `count` filled instances by the batch's sort mode, so that
4904
- * the later (covering) draws are the nearer or the chosen-age particles.
4905
- * The order is computed once as a permutation and every attribute buffer
4906
- * is gathered through it into a spare array that then takes its place.
4907
- */
4908
- private sortInstances;
4909
- /** Gathers `source` in `order` into the spare array of `slot` and returns it; the source becomes the spare. */
4910
- private gatherInto;
4911
- rebuildMaterial(): void;
4912
- applyMeshLighting(lighting: MeshLightingSettings): void;
4913
- private storeFixedLighting;
4914
- private writeFixedLighting;
4915
- /**
4916
- * Reads the scene's key light for `'scene'` mesh lighting: the first
4917
- * enabled directional or hemispheric light, its diffuse colour times its
4918
- * intensity, plus the scene's ambient colour. A hemispheric light lights
4919
- * from its `direction` (which points at the sky) and adds its ground colour
4920
- * to the ambient, which approximates its sky-to-ground blend with the one
4921
- * directional term the shader has. False when there is no such light.
4922
- */
4923
- static readSceneLight(scene: Scene, direction: Vector3$1, color: Vector3$1, ambient: Vector3$1): boolean;
4924
- private vector_;
4925
- private vector2_;
4926
- private vector3_;
4927
- private quaternion_;
4928
- private quaternion2_;
4929
- private quaternion3_;
4930
- private quaternion4_;
4931
- private quaternion5_;
4932
- private rotationMat_;
4933
- private rotationMat2_;
4934
- private lastStretchedSpeedFactor;
4935
- /** Slot 0 holds the zero-alpha instance since the batch last went empty. */
4936
- private clearedInstanceUploaded;
4937
- update(): void;
4938
- /**
4939
- * Pushes the stretched-billboard speed factor to the shader when it changed.
4940
- *
4941
- * Deliberately kept out of `update`: touching the loosely typed
4942
- * `mesh.material` from inside that function gives V8 a generic property
4943
- * access it has no feedback for, which knocks the whole particle loop out of
4944
- * optimised code on every frame.
4945
- */
4946
- private syncStretchedSpeedFactor;
4947
- /** Stretched billboards and beams: drawn along a per-instance vector, by the stretched shader. */
4948
- private static drawsAlongVelocity;
4949
- private readonly beamEnd_;
4950
- /**
4951
- * Writes, for the `count` instances from `first`, the world vector from
4952
- * each one's drawn position to the system's beam end into the velocity
4953
- * buffer, which the stretched shader under `BEAM` lays the quad along. A
4954
- * beam without an end gets no length.
4955
- */
4956
- private writeBeams;
4957
- /** The quads that take a pivot and flip: every billboard kind, stretched included, but not meshes or beams. */
4958
- private static takesPivotAndFlip;
4959
- /**
4960
- * Negates the size of each flipped particle along the axes it flips on,
4961
- * starting at `base` in `sizes`. The billboard shader scales the quad by
4962
- * the size, so a negative one mirrors it — and with it the texture, the
4963
- * quad being centred — the way Unity's renderer Flip mirrors U and V. The
4964
- * stretched shader reads the sign and mirrors the texture coordinates.
4965
- */
4966
- private static applyFlip;
4967
- /** The same for a system without a store, read off the particles. */
4968
- private static applyFlipFromParticles;
4969
- /**
4970
- * Writes the mesh rotations for rows `[0, count)` of a store: each
4971
- * particle's quaternion, carried on by `fraction` of its last turn (see
4972
- * {@link partialTurn}) and, for a local-space system, turned by the
4973
- * emitter's rotation `parent`.
4974
- */
4975
- private static writeQuaternions;
4976
- /**
4977
- * Writes the stretched billboards' velocity attribute for rows `[0, count)`
4978
- * of a store: the velocity carried on by `fraction` of the last step (see
4979
- * {@link extrapolate}), turned into world space by `rotation` when the
4980
- * system simulates locally, scaled by the speed factor, with the length
4981
- * factor in `w`.
4982
- */
4983
- private static writeVelocities;
4984
- /**
4985
- * The fraction `f` of a turn, as a normalised lerp from no rotation toward
4986
- * `step`, written into `out`.
4987
- *
4988
- * A true slerp would be exact, but `step` is one simulation step of turning
4989
- * and `f` is below 1, so the arc being split is small enough that the lerp
4990
- * is within a rounding error of it and costs a fraction as much.
4991
- */
4992
- private static partialTurn;
4993
- /**
4994
- * Continues a three-component column by `fraction` of the step it just took,
4995
- * never below zero.
4996
- *
4997
- * Size fades to nothing at the end of a life, so the last step before death
4998
- * can point past zero; a negative size turns a sprite inside out.
4999
- */
5000
- private static continueVector3;
5001
- /** The same for colour, whose alpha runs out at the end of a life too. */
5002
- 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 {
5003
6590
  /**
5004
- * Writes rows `[0, count)` of the store's positions into `target` at `base`,
5005
- * each carried on by `fraction` of the step it just took.
5006
- *
5007
- * Continuing the measured last step covers every way a particle can move —
5008
- * velocity integration, an orbit, noise, a plugin's own behavior — because
5009
- * it reads what happened rather than predicting from one term of it. Over
5010
- * less than a step it is a straight line through a path that may curve,
5011
- * which for a sixtieth of a second is well under a pixel.
5012
- *
5013
- * A particle born during the step has the same position on both sides and
5014
- * so does not move at all, which is what puts it at the emitter rather than
5015
- * 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.
5016
6593
  */
5017
- private static extrapolate;
5018
- /** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
5019
- private uploadClearedInstance;
5020
- 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;
5021
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;
5022
6623
 
5023
- declare class TrailBatch extends VFXBatch {
5024
- private positionBuffer;
5025
- private previousBuffer;
5026
- private nextBuffer;
5027
- private uvBuffer;
5028
- private sideBuffer;
5029
- private widthBuffer;
5030
- private colorBuffer;
5031
- private indexBuffer;
5032
- /** True while the batch is parked on the degenerate draw, see uploadGeometry. */
5033
- private drawsNothing;
5034
- private previousVB;
5035
- private nextVB;
5036
- private sideVB;
5037
- private widthVB;
5038
- constructor(settings: VFXBatchSettings, scene: Scene);
5039
- setupBuffers(): void;
5040
- private buildGeometryBuffers;
5041
- expandBuffers(target: number): void;
5042
- rebuildMaterial(): void;
5043
- private vector_;
5044
- private vector2_;
5045
- private vector3_;
5046
- private quaternion_;
5047
- /**
5048
- * Brings the emitter's world matrix up to date when its transform changed.
5049
- *
5050
- * Babylon only recomputes a world matrix once per render id, so a frame that
5051
- * moves the emitter after that (or a step driven without rendering) would
5052
- * draw the ribbon against the old one. Recomputing unconditionally every
5053
- * frame costs a matrix compose per system; checking the transform cache
5054
- * first makes a still emitter free.
5055
- */
5056
- private static ensureWorldMatrix;
5057
- update(): void;
5058
- /**
5059
- * Records a system's world bounds from the ribbon vertices just written for
5060
- * it, padded by the widest ribbon. The store only holds each trail's head,
5061
- * so this is where a trail's extent is known.
5062
- */
5063
- private measureSystemBounds;
5064
- /**
5065
- * Uploads the vertex data written by `update` and resizes the sub mesh.
5066
- *
5067
- * Split out of `update` on purpose: the Babylon mesh/sub-mesh plumbing here
5068
- * runs a handful of times per frame, and folding it into the per-vertex loop
5069
- * costs that loop its optimised code.
5070
- */
5071
- private uploadGeometry;
5072
- /**
5073
- * Points every sub mesh at the mesh's own bounds.
5074
- *
5075
- * Updating indices rebuilds the sub meshes, and a fresh one computes its
5076
- * bounds from the vertex data — which this batch keeps deliberately stale
5077
- * beyond the range it draws. Transparent sorting reads those bounds every
5078
- * frame, so they have to be replaced again after every index update, not
5079
- * only when the geometry is built.
5080
- */
5081
- private adoptMeshBounds;
5082
- 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;
5083
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;
5084
6681
 
5085
- 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, 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, 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, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, meshRimEqual, normalize, normalizeErosion, normalizeMeshRim, normalizeUVScroll, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, random, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, setRandomSource, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, subEmitterInheritMask, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin, uvScrollEqual, withRandomSource };
5086
- 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, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleErosion, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RandomSource, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, ScalingMode, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SortMode, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, SubEmitterInheritance, TrailSettings, 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 };