babylon.quarks 0.23.0 → 0.24.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 (35) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/dist/babylon.quarks.cjs +1 -1
  3. package/dist/babylon.quarks.cjs.map +1 -1
  4. package/dist/babylon.quarks.esm.js +1 -1
  5. package/dist/babylon.quarks.esm.js.map +1 -1
  6. package/dist/babylon.quarks.umd.min.js +1 -1
  7. package/dist/babylon.quarks.umd.min.js.map +1 -1
  8. package/dist/types/index.d.ts +529 -20
  9. package/package.json +2 -2
  10. package/src/BatchedRenderer.ts +146 -2
  11. package/src/EffectPool.ts +165 -0
  12. package/src/MeshSurfaceEmitter.ts +4 -4
  13. package/src/ParticleEmitter.ts +2 -1
  14. package/src/ParticleSystem.ts +592 -15
  15. package/src/QuarksUtil.ts +55 -7
  16. package/src/SpriteBatch.ts +127 -3
  17. package/src/TrailBatch.ts +49 -12
  18. package/src/VFXBatch.ts +154 -3
  19. package/src/index.ts +4 -1
  20. package/src/instanceSort.ts +121 -0
  21. package/src/shaders/chunks/fog.ts +127 -0
  22. package/src/shaders/local_particle_physics_vert.glsl.ts +4 -0
  23. package/src/shaders/local_particle_physics_vert.wgsl.ts +4 -0
  24. package/src/shaders/particle_frag.glsl.ts +4 -0
  25. package/src/shaders/particle_frag.wgsl.ts +4 -0
  26. package/src/shaders/particle_physics_frag.glsl.ts +4 -0
  27. package/src/shaders/particle_physics_frag.wgsl.ts +4 -0
  28. package/src/shaders/particle_vert.glsl.ts +23 -4
  29. package/src/shaders/particle_vert.wgsl.ts +23 -4
  30. package/src/shaders/stretched_bb_particle_vert.glsl.ts +17 -0
  31. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +18 -1
  32. package/src/shaders/trail_frag.glsl.ts +4 -0
  33. package/src/shaders/trail_frag.wgsl.ts +4 -0
  34. package/src/shaders/trail_vert.glsl.ts +4 -0
  35. package/src/shaders/trail_vert.wgsl.ts +4 -0
@@ -2,12 +2,13 @@ import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture';
2
2
  import { Texture } from '@babylonjs/core/Materials/Textures/texture';
3
3
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
4
4
  import { Scene } from '@babylonjs/core/scene';
5
+ import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial';
5
6
  import { Color3 } from '@babylonjs/core/Maths/math.color';
6
7
  import { Vector3 as Vector3$1 } from '@babylonjs/core/Maths/math.vector';
7
8
  import { Mesh } from '@babylonjs/core/Meshes/mesh';
9
+ import { Node } from '@babylonjs/core/node';
8
10
  import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
9
11
  import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
10
- import { Node } from '@babylonjs/core/node';
11
12
 
12
13
  declare class Vector2 {
13
14
  x: number;
@@ -1047,6 +1048,10 @@ interface EmissionState {
1047
1048
  waitEmiting: number;
1048
1049
  travelDistance: number;
1049
1050
  previousWorldPos?: Vector3;
1051
+ /** The particle a sub emission comes from, when it does; see `EmitSubParticleSystem.inherit`. */
1052
+ particle?: Particle;
1053
+ /** Bit mask of the parent's properties the spawned particles take, see `SubEmitterInheritMask`. */
1054
+ inherit?: number;
1050
1055
  }
1051
1056
  interface Resource {
1052
1057
  }
@@ -2023,15 +2028,33 @@ declare enum SubParticleEmitMode {
2023
2028
  Birth = 1,
2024
2029
  Frame = 2
2025
2030
  }
2031
+ /** A parent particle property sub emitted particles can take over (Unity's sub emitter Inherit). */
2032
+ type SubEmitterInheritance = 'color' | 'size' | 'rotation' | 'lifetime';
2033
+ /** Bits of `EmissionState.inherit`, one per {@link SubEmitterInheritance}. */
2034
+ declare const SubEmitterInheritMask: {
2035
+ readonly color: 1;
2036
+ readonly size: 2;
2037
+ readonly rotation: 4;
2038
+ readonly lifetime: 8;
2039
+ };
2040
+ /** The mask for a list of inherited properties. */
2041
+ declare function subEmitterInheritMask(inherit: ReadonlyArray<SubEmitterInheritance>): number;
2026
2042
  /**
2027
2043
  * Emit a sub particle system from particles.
2028
2044
  */
2029
2045
  declare class EmitSubParticleSystem implements Behavior {
2030
- private particleSystem;
2046
+ particleSystem: IParticleSystem;
2031
2047
  useVelocityAsBasis: boolean;
2032
2048
  subParticleSystem: IEmitter | undefined;
2033
2049
  mode: SubParticleEmitMode;
2034
2050
  emitProbability: number;
2051
+ /**
2052
+ * Which of the parent particle's properties the sub particles start
2053
+ * from: its current colour and size multiply theirs, its rotation adds
2054
+ * to theirs, and its remaining lifetime fraction scales theirs (so
2055
+ * lifetime suits birth sub emitters, not death ones).
2056
+ */
2057
+ inherit: SubEmitterInheritance[];
2035
2058
  type: string;
2036
2059
  private q_;
2037
2060
  private v_;
@@ -2039,7 +2062,14 @@ declare class EmitSubParticleSystem implements Behavior {
2039
2062
  private subEmissions;
2040
2063
  /** Finished emission states, kept for reuse: a burst of deaths would otherwise allocate one plus a matrix each. */
2041
2064
  private spareEmissions;
2042
- constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number);
2065
+ constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number,
2066
+ /**
2067
+ * Which of the parent particle's properties the sub particles start
2068
+ * from: its current colour and size multiply theirs, its rotation adds
2069
+ * to theirs, and its remaining lifetime fraction scales theirs (so
2070
+ * lifetime suits birth sub emitters, not death ones).
2071
+ */
2072
+ inherit?: SubEmitterInheritance[]);
2043
2073
  initialize(particle: Particle): void;
2044
2074
  update(particle: Particle, delta: number): void;
2045
2075
  /**
@@ -2055,6 +2085,7 @@ declare class EmitSubParticleSystem implements Behavior {
2055
2085
  static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
2056
2086
  clone(): Behavior;
2057
2087
  reset(): void;
2088
+ private static validInherit;
2058
2089
  private setMatrixFromParticle;
2059
2090
  }
2060
2091
 
@@ -2176,9 +2207,38 @@ declare class Noise implements Behavior {
2176
2207
  power: FunctionValueGenerator | ValueGenerator;
2177
2208
  positionAmount: FunctionValueGenerator | ValueGenerator;
2178
2209
  rotationAmount: FunctionValueGenerator | ValueGenerator;
2210
+ /**
2211
+ * How fast the noise field moves past the particles (Unity's Scroll
2212
+ * Speed), in noise time per second; 0 leaves it still. Sampled once per
2213
+ * frame, so a curve is read at t = 0.
2214
+ */
2215
+ scrollSpeed: FunctionValueGenerator | ValueGenerator;
2216
+ /**
2217
+ * Reshapes the raw noise (Unity's Remap): the curve is read at the
2218
+ * noise value mapped from [-1, 1] to [0, 1], and what it returns is
2219
+ * used in its place. Unset, the noise is used as is.
2220
+ */
2221
+ remap?: FunctionValueGenerator | undefined;
2179
2222
  type: string;
2180
2223
  duration: number;
2181
- constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator);
2224
+ constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator,
2225
+ /**
2226
+ * How fast the noise field moves past the particles (Unity's Scroll
2227
+ * Speed), in noise time per second; 0 leaves it still. Sampled once per
2228
+ * frame, so a curve is read at t = 0.
2229
+ */
2230
+ scrollSpeed?: FunctionValueGenerator | ValueGenerator,
2231
+ /**
2232
+ * Reshapes the raw noise (Unity's Remap): the curve is read at the
2233
+ * noise value mapped from [-1, 1] to [0, 1], and what it returns is
2234
+ * used in its place. Unset, the noise is used as is.
2235
+ */
2236
+ remap?: FunctionValueGenerator | undefined);
2237
+ /** Noise time the field has scrolled by so far. */
2238
+ private scrollOffset;
2239
+ private readonly scrollMemory;
2240
+ /** The noise value a generator gives at `time`, through the remap when there is one. */
2241
+ private sample;
2182
2242
  initialize(particle: Particle): void;
2183
2243
  /**
2184
2244
  * Values of the generators that are constants, cached by {@link frameUpdate};
@@ -2417,10 +2477,18 @@ declare class VelocityOverLife implements Behavior {
2417
2477
  orbitalY: FunctionValueGenerator | ValueGenerator;
2418
2478
  orbitalZ: FunctionValueGenerator | ValueGenerator;
2419
2479
  space: VelocityOverLifeSpace;
2480
+ /** Speed away from the orbit centre (Unity's Radial), in the authored space's units. */
2481
+ radial: FunctionValueGenerator | ValueGenerator;
2482
+ /** Where the orbital speeds turn around, relative to the emitter (Unity's Orbital Offset). */
2483
+ orbitalOffset: Vector3;
2420
2484
  type: string;
2421
2485
  /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2422
2486
  ps?: IParticleSystem;
2423
- constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace);
2487
+ constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace,
2488
+ /** Speed away from the orbit centre (Unity's Radial), in the authored space's units. */
2489
+ radial?: FunctionValueGenerator | ValueGenerator,
2490
+ /** Where the orbital speeds turn around, relative to the emitter (Unity's Orbital Offset). */
2491
+ orbitalOffset?: Vector3);
2424
2492
  _temp: Vector3;
2425
2493
  _tempEmitterPos: Vector3;
2426
2494
  _tempQ: Quaternion;
@@ -2437,6 +2505,8 @@ declare class VelocityOverLife implements Behavior {
2437
2505
  _axisX: Vector3;
2438
2506
  _axisY: Vector3;
2439
2507
  _axisZ: Vector3;
2508
+ /** The orbit centre in the simulation space, refreshed with the axes. */
2509
+ _center: Vector3;
2440
2510
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
2441
2511
  frameUpdate(delta: number): void;
2442
2512
  update(particle: Particle, delta: number): void;
@@ -3142,6 +3212,50 @@ declare class TextureSequencer implements Sequencer {
3142
3212
  fromImage(img: CanvasImageSource, threshold: number): void;
3143
3213
  }
3144
3214
 
3215
+ /**
3216
+ * The one source of randomness for particle simulation.
3217
+ *
3218
+ * Every roll a particle system makes — spawn positions, interval values,
3219
+ * random colours and rotations, burst probability, noise offsets — goes
3220
+ * through {@link random}, so it can be replaced: with a seeded generator for
3221
+ * reproducible tests, replays and lock-step multiplayer, or with a system's own
3222
+ * generator while that system steps (see `ParticleSystem.seed`).
3223
+ *
3224
+ * UUIDs are deliberately not drawn from here; two effects loaded under the same
3225
+ * seed must still get distinct ids.
3226
+ */
3227
+ /** A generator in the shape of `Math.random`: uniform in [0, 1). */
3228
+ type RandomSource = () => number;
3229
+ /** Uniform random number in [0, 1) from the current source. */
3230
+ declare function random(): number;
3231
+ /** The generator {@link random} currently draws from. */
3232
+ declare function getRandomSource(): RandomSource;
3233
+ /**
3234
+ * Replaces the generator every roll draws from; `null` restores `Math.random`.
3235
+ * Returns the previous source, so a caller can put it back.
3236
+ */
3237
+ declare function setRandomSource(next: RandomSource | null): RandomSource;
3238
+ /**
3239
+ * A small, fast seeded generator (mulberry32): the same seed always yields
3240
+ * the same sequence, on every platform. Good enough for visual randomness;
3241
+ * not for anything cryptographic.
3242
+ */
3243
+ declare function createSeededRandom(seed: number): RandomSource;
3244
+ /** Runs `fn` with `generator` as the random source, restoring the previous one after. */
3245
+ declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3246
+
3247
+ /**
3248
+ * The order the particles of a batch are drawn in (Unity's Sort Mode). Alpha
3249
+ * blended particles cover what was drawn before them, so the order shows.
3250
+ *
3251
+ * - `'none'`: as they are, system by system. Right for additive blending.
3252
+ * - `'distance'`: farthest from the active camera first, so nearer particles
3253
+ * cover farther ones.
3254
+ * - `'oldestInFront'` / `'youngestInFront'`: by age.
3255
+ *
3256
+ * Sorting runs over the whole batch after each fill. Trails are not sorted.
3257
+ */
3258
+ type SortMode = 'none' | 'distance' | 'oldestInFront' | 'youngestInFront';
3145
3259
  declare enum RenderMode {
3146
3260
  BillBoard = 0,
3147
3261
  StretchedBillBoard = 1,
@@ -3224,8 +3338,18 @@ interface StoredBatchSettings {
3224
3338
  reflectionFaces: BaseTexture[] | null;
3225
3339
  reflectionAtlas: BaseTexture | null;
3226
3340
  layerMask: number;
3341
+ /** Babylon rendering group the batch mesh draws in, see {@link VFXBatchSettings.renderingGroupId}. */
3342
+ renderingGroupId: number;
3343
+ /** Whether the scene's fog is applied, see {@link VFXBatchSettings.applyFog}. */
3344
+ applyFog: boolean;
3227
3345
  /** Billboard pivot in particle-size units, see {@link VFXBatchSettings.pivot}. */
3228
3346
  pivot?: Vector3;
3347
+ /** Draw order within the batch, see {@link SortMode}. */
3348
+ sortMode: SortMode;
3349
+ /** Smallest size a particle may have on screen, see {@link VFXBatchSettings.minParticleSize}. */
3350
+ minParticleSize: number;
3351
+ /** Largest size a particle may have on screen, see {@link VFXBatchSettings.maxParticleSize}. */
3352
+ maxParticleSize: number;
3229
3353
  /** Mesh particle lighting, see {@link VFXBatchSettings.lighting}. */
3230
3354
  lighting?: MeshLighting;
3231
3355
  /** Mesh particle rim, see {@link VFXBatchSettings.rim}. */
@@ -3237,8 +3361,36 @@ declare abstract class VFXBatch {
3237
3361
  settings: StoredBatchSettings;
3238
3362
  protected maxParticles: number;
3239
3363
  protected scene: Scene;
3240
- private readonly visibleSystems;
3364
+ protected readonly visibleSystems: IParticleSystem[];
3241
3365
  protected constructor(settings: VFXBatchSettings, scene: Scene);
3366
+ /**
3367
+ * Applies the batch-level scene settings to {@link mesh}. Called on every
3368
+ * mesh the batch creates, since the buffers rebuild it.
3369
+ *
3370
+ * The bounds of a batch mesh are not kept, so Babylon cannot sort it among
3371
+ * the scene's transparent meshes by distance; `alphaIndex` from the
3372
+ * system's render order puts it where the author said, and the rendering
3373
+ * group and layer mask reach the mesh at all (they used to stop at the
3374
+ * settings).
3375
+ */
3376
+ protected configureMesh(): void;
3377
+ private readonly boundsMin_;
3378
+ private readonly boundsMax_;
3379
+ /**
3380
+ * Sets the batch mesh's bounds to the union of its filled systems' world
3381
+ * bounds, so Babylon skips the draw when none of them is in view. Called
3382
+ * after each fill, over the systems {@link getVisibleSystems} last returned.
3383
+ * A batch whose systems have no measured bounds stays always drawn.
3384
+ */
3385
+ protected refreshBoundingInfo(): void;
3386
+ /**
3387
+ * Fog defines and uniforms for a material of this batch, and the per-bind
3388
+ * upload of the scene's current fog. Mode 0 (none) when the scene has fog
3389
+ * disabled, so toggling fog at runtime needs no recompile.
3390
+ */
3391
+ protected static readonly FOG_UNIFORMS: string[];
3392
+ protected fogDefines(): string[];
3393
+ protected bindFog(material: ShaderMaterial): void;
3242
3394
  addSystem(system: IParticleSystem): void;
3243
3395
  removeSystem(system: IParticleSystem): void;
3244
3396
  /**
@@ -3296,6 +3448,17 @@ interface VFXBatchSettings {
3296
3448
  */
3297
3449
  reflectionAtlas: BaseTexture | null;
3298
3450
  layerMask: number;
3451
+ /**
3452
+ * Babylon rendering group (`mesh.renderingGroupId`) the batch draws in,
3453
+ * 0 by default. Systems with different groups are batched apart.
3454
+ */
3455
+ renderingGroupId: number;
3456
+ /**
3457
+ * Whether the scene's fog applies to the particles, as it does to any other
3458
+ * mesh; true by default. Additive particles fade toward black rather than
3459
+ * the fog colour. Systems that differ are batched apart.
3460
+ */
3461
+ applyFog: boolean;
3299
3462
  /**
3300
3463
  * Offset of billboard quads from their particle, in particle-size units
3301
3464
  * (Unity's renderer Pivot). On billboards x/y move the quad in its own plane
@@ -3304,6 +3467,20 @@ interface VFXBatchSettings {
3304
3467
  * y across, and z is unused. Absent or zero: no offset. Meshes ignore it.
3305
3468
  */
3306
3469
  pivot?: Vector3;
3470
+ /** Draw order within the batch, see {@link SortMode}. Unset is `'none'`. Systems that differ are batched apart. */
3471
+ sortMode?: SortMode;
3472
+ /**
3473
+ * Smallest size a billboard or stretched particle may have on screen, as a
3474
+ * fraction of the viewport height (Unity's Min Particle Size); 0 by default.
3475
+ * Meshes and trails ignore it. Systems that differ are batched apart.
3476
+ */
3477
+ minParticleSize?: number;
3478
+ /**
3479
+ * Largest size a billboard or stretched particle may have on screen, as a
3480
+ * fraction of the viewport height (Unity's Max Particle Size); unlimited by
3481
+ * default. Meshes and trails ignore it. Systems that differ are batched apart.
3482
+ */
3483
+ maxParticleSize?: number;
3307
3484
  /**
3308
3485
  * How mesh particles are lit (`'unlit'`, `'fixed'` or `'scene'`); unset is
3309
3486
  * `'fixed'`. See {@link MeshLighting}. Other render modes ignore it.
@@ -3354,7 +3531,43 @@ declare class BatchedRenderer extends TransformNode {
3354
3531
  private adaptivePerformanceState;
3355
3532
  private lastAppliedQuality;
3356
3533
  private meshLighting;
3534
+ /**
3535
+ * Whether systems whose {@link ParticleSystem.cullingMode} is not
3536
+ * `'always'` are tested against the active cameras each frame and paused
3537
+ * while unseen. Off, every system simulates every frame; the batches' own
3538
+ * frustum culling of the draw stays on either way.
3539
+ */
3540
+ cullingEnabled: boolean;
3541
+ /**
3542
+ * Time per frame, in milliseconds, that systems coming back into view may
3543
+ * spend together on the steps they missed while culled (`'pauseAndCatchUp'`).
3544
+ * Steps that do not fit are dropped, not deferred, so a crowd of effects
3545
+ * reappearing at once costs at most this. 2 by default.
3546
+ */
3547
+ catchUpBudgetMs: number;
3548
+ /**
3549
+ * Time per frame, in milliseconds, after which the systems still to be
3550
+ * advanced run one step instead of catching up on a long frame. The time
3551
+ * the skipped steps would have covered is dropped, so a frame that already
3552
+ * ran long cannot make the next one longer still. Unlimited by default;
3553
+ * {@link configureAdaptivePerformance} does not set it.
3554
+ */
3555
+ simulationBudgetMs: number;
3556
+ /** Frustum planes of the active cameras, six per camera, rebuilt each update. */
3557
+ private frustumPlanes;
3558
+ private readonly boundsMin;
3559
+ private readonly boundsMax;
3357
3560
  constructor(name: string, scene: Scene);
3561
+ /**
3562
+ * Gathers the frustum planes of the cameras the scene renders with, six per
3563
+ * camera. Empty when there is no camera yet; systems are then never culled.
3564
+ */
3565
+ private collectFrustumPlanes;
3566
+ /**
3567
+ * True when `system`'s world bounds reach into at least one camera's
3568
+ * frustum, or when it has no bounds to test (empty, or not yet measured).
3569
+ */
3570
+ private isSystemInView;
3358
3571
  private static clamp;
3359
3572
  private static equals;
3360
3573
  addSystem(system: IParticleSystem): void;
@@ -3416,6 +3629,63 @@ declare class BatchedRenderer extends TransformNode {
3416
3629
 
3417
3630
  declare const BatchedParticleRenderer: typeof BatchedRenderer;
3418
3631
 
3632
+ interface EffectPoolOptions {
3633
+ /** The renderer every copy the pool makes is added to. */
3634
+ renderer: BatchedRenderer;
3635
+ /** Copies made up front, so the first plays do not pay for cloning. Default 0. */
3636
+ prewarm?: number;
3637
+ /** Most copies the pool will ever hold; {@link EffectPool.acquire} returns null past it. Default unlimited. */
3638
+ maxSize?: number;
3639
+ }
3640
+ /**
3641
+ * A pool of copies of one effect, for effects played many times over: hits,
3642
+ * footsteps, muzzle flashes, pickups.
3643
+ *
3644
+ * {@link acquire} hands out an idle copy (or makes one), places it and plays
3645
+ * it; a copy whose every system has finished goes back to the pool by itself,
3646
+ * so a one-shot effect needs nothing more. A looping effect is ended with
3647
+ * {@link stop}, which lets its particles die out before the copy returns, or
3648
+ * dropped at once with {@link release}.
3649
+ *
3650
+ * Idle copies are parked disabled, which costs the renderer nothing, and keep
3651
+ * their place in its batches, so acquiring one allocates nothing.
3652
+ *
3653
+ * The template itself is never played by the pool; it is only cloned. Disable
3654
+ * it, or keep it out of the renderer, if it is not meant to be seen.
3655
+ */
3656
+ declare class EffectPool {
3657
+ private readonly template;
3658
+ private readonly options;
3659
+ private readonly idle;
3660
+ private readonly playing;
3661
+ private readonly systemsOf;
3662
+ private disposed;
3663
+ constructor(template: TransformNode, options: EffectPoolOptions);
3664
+ /** Copies currently playing. */
3665
+ get activeCount(): number;
3666
+ /** Copies parked and ready. */
3667
+ get idleCount(): number;
3668
+ /**
3669
+ * Takes an idle copy (making one when none is idle and the pool is under
3670
+ * its size), parents it, places it and starts it from the beginning.
3671
+ * Null when the pool is full or disposed.
3672
+ */
3673
+ acquire(position?: Vector3$1, parent?: Node | null): TransformNode | null;
3674
+ /**
3675
+ * Ends the emission of a playing copy; it returns to the pool on its own
3676
+ * once its particles have died, looping systems included.
3677
+ */
3678
+ stop(copy: TransformNode): void;
3679
+ /** Puts a copy back at once, particles and all, parked and disabled. */
3680
+ release(copy: TransformNode): void;
3681
+ /** Disposes every copy, playing or idle. The template is left alone. */
3682
+ dispose(): void;
3683
+ private makeCopy;
3684
+ private disposeCopy;
3685
+ /** The copy a system belongs to is done when all of its systems are. */
3686
+ private readonly onSystemFinished;
3687
+ }
3688
+
3419
3689
  /** Reads the six face URLs from a Babylon CubeTexture (px py pz nx ny nz). */
3420
3690
  declare function cubeFaceUrls(reflection: BaseTexture | null | undefined): string[] | null;
3421
3691
  /** Returns a previously built atlas for this cube, if any. */
@@ -3491,6 +3761,23 @@ interface BurstParameters {
3491
3761
  interval: number;
3492
3762
  probability: number;
3493
3763
  }
3764
+ /**
3765
+ * What a system does while no camera can see its particles (Unity's Culling
3766
+ * Mode). The {@link BatchedRenderer} tests each system's bounds against the
3767
+ * active cameras' frusta every frame.
3768
+ *
3769
+ * - `'always'` keeps simulating off screen, so an effect is exactly where it
3770
+ * would have been when it comes back into view. The default, and the only
3771
+ * safe choice for an emitter whose particles reach the screen from off it.
3772
+ * - `'pause'` freezes the system off screen and resumes it where it left off.
3773
+ * - `'pauseAndCatchUp'` freezes it too, then runs the missed time (up to a few
3774
+ * seconds) within the renderer's catch-up budget when it is seen again.
3775
+ *
3776
+ * An empty system is never culled, so it can start emitting and grow the
3777
+ * bounds that decide its visibility. A system another one emits into is never
3778
+ * culled either; its parent decides.
3779
+ */
3780
+ type CullingMode = 'always' | 'pause' | 'pauseAndCatchUp';
3494
3781
  interface ParticleSystemParameters {
3495
3782
  autoDestroy?: boolean;
3496
3783
  looping?: boolean;
@@ -3543,6 +3830,24 @@ interface ParticleSystemParameters {
3543
3830
  lighting?: MeshLighting;
3544
3831
  /** Rim (Fresnel) term on mesh particles, see {@link ParticleSystem.rim}. Default none. */
3545
3832
  rim?: Partial<MeshRim>;
3833
+ /** Multiplier on the time the system is advanced by, see {@link ParticleSystem.playbackSpeed}. Default 1. */
3834
+ playbackSpeed?: number;
3835
+ /** What the system does while off screen, see {@link CullingMode}. Default `'always'`. */
3836
+ cullingMode?: CullingMode;
3837
+ /** Seed for this system's own random generator, see {@link ParticleSystem.seed}. Default none. */
3838
+ seed?: number;
3839
+ /** Draw order within the batch, see {@link ParticleSystem.sortMode}. Default `'none'`. */
3840
+ sortMode?: SortMode;
3841
+ /** Whether particles start turned along their direction of travel, see {@link ParticleSystem.alignToDirection}. Default false. */
3842
+ alignToDirection?: boolean;
3843
+ /** Smallest on-screen size, as a fraction of the viewport height, see {@link ParticleSystem.minParticleSize}. Default 0. */
3844
+ minParticleSize?: number;
3845
+ /** Largest on-screen size, as a fraction of the viewport height, see {@link ParticleSystem.maxParticleSize}. Default unlimited. */
3846
+ maxParticleSize?: number;
3847
+ /** Babylon rendering group of the batch, see {@link ParticleSystem.renderingGroupId}. Default 0. */
3848
+ renderingGroupId?: number;
3849
+ /** Whether the scene's fog applies, see {@link ParticleSystem.applyFog}. Default true. */
3850
+ applyFog?: boolean;
3546
3851
  scene?: Scene;
3547
3852
  }
3548
3853
  interface BurstParametersJSON {
@@ -3574,6 +3879,24 @@ interface ParticleSystemJSONParameters {
3574
3879
  instancingGeometry?: any;
3575
3880
  renderMode: number;
3576
3881
  renderOrder?: number;
3882
+ /** Written only when not 0. */
3883
+ renderingGroupId?: number;
3884
+ /** Written only when false. */
3885
+ applyFog?: boolean;
3886
+ /** Written only when not 1. */
3887
+ playbackSpeed?: number;
3888
+ /** Written only when not `'always'`. */
3889
+ cullingMode?: CullingMode;
3890
+ /** Written only when set. */
3891
+ seed?: number;
3892
+ /** Written only when not `'none'`. */
3893
+ sortMode?: SortMode;
3894
+ /** Written only when true. */
3895
+ alignToDirection?: boolean;
3896
+ /** Written only when not 0. */
3897
+ minParticleSize?: number;
3898
+ /** Written only when limited. */
3899
+ maxParticleSize?: number;
3577
3900
  speedFactor?: number;
3578
3901
  texture?: string;
3579
3902
  material?: string;
@@ -3697,7 +4020,11 @@ declare class ParticleSystem implements IParticleSystem {
3697
4020
  get isEmitEnded(): boolean;
3698
4021
  /** Whether continuous or queued emission can still spawn particles before the system is done. */
3699
4022
  hasPendingEmission(): boolean;
3700
- /** Non-looping system with no particles left and nothing left to emit. */
4023
+ /**
4024
+ * No particles left and nothing left to emit: a non-looping system that
4025
+ * ran its course, or a looping one whose emission was ended with
4026
+ * {@link endEmit} and whose last particle has died.
4027
+ */
3701
4028
  isFinished(): boolean;
3702
4029
  get layers(): {
3703
4030
  mask: number;
@@ -3719,6 +4046,29 @@ declare class ParticleSystem implements IParticleSystem {
3719
4046
  * {@link VFXBatchSettings.pivot}. Assign a new vector to change it: editing
3720
4047
  * the returned one in place does not reach the renderer.
3721
4048
  */
4049
+ /**
4050
+ * The order this system's batch draws its particles in (Unity's Sort
4051
+ * Mode), `'none'` by default. Alpha blended smoke wants `'distance'`;
4052
+ * additive effects need nothing. Sorting covers the whole batch, so systems
4053
+ * with different modes are batched apart. See {@link SortMode}.
4054
+ */
4055
+ get sortMode(): SortMode;
4056
+ set sortMode(mode: SortMode);
4057
+ /**
4058
+ * Smallest size a billboard or stretched particle is drawn at, as a
4059
+ * fraction of the viewport height (Unity's Min Particle Size); 0 by
4060
+ * default. Keeps distant sparks from vanishing. Meshes and trails ignore it.
4061
+ */
4062
+ get minParticleSize(): number;
4063
+ set minParticleSize(size: number);
4064
+ /**
4065
+ * Largest size a billboard or stretched particle is drawn at, as a fraction
4066
+ * of the viewport height (Unity's Max Particle Size, 0.5 there); unlimited
4067
+ * by default. Keeps a close particle from filling the screen. Meshes and
4068
+ * trails ignore it.
4069
+ */
4070
+ get maxParticleSize(): number;
4071
+ set maxParticleSize(size: number);
3722
4072
  get pivot(): Vector3 | undefined;
3723
4073
  set pivot(v: Vector3 | undefined);
3724
4074
  /**
@@ -3742,6 +4092,8 @@ declare class ParticleSystem implements IParticleSystem {
3742
4092
  set rim(rim: Partial<MeshRim> | undefined);
3743
4093
  /** `lighting` if it is one of the modes, else the default. */
3744
4094
  private static validLighting;
4095
+ private static validSortMode;
4096
+ private static validCullingMode;
3745
4097
  private static nonZeroPivot;
3746
4098
  private static nonZeroFlip;
3747
4099
  get softNearFade(): number;
@@ -3756,6 +4108,87 @@ declare class ParticleSystem implements IParticleSystem {
3756
4108
  set renderMode(renderMode: RenderMode);
3757
4109
  get renderOrder(): number;
3758
4110
  set renderOrder(renderOrder: number);
4111
+ /**
4112
+ * Babylon rendering group the particles draw in (`mesh.renderingGroupId`),
4113
+ * 0 by default. Use it to draw an effect after the scene's other transparent
4114
+ * meshes, or before an overlay group.
4115
+ */
4116
+ get renderingGroupId(): number;
4117
+ set renderingGroupId(group: number);
4118
+ /**
4119
+ * Whether the scene's fog applies to the particles, as it does to any other
4120
+ * mesh; true by default. Additive particles fade toward black rather than
4121
+ * the fog colour. Saved in the effect JSON only when switched off.
4122
+ */
4123
+ get applyFog(): boolean;
4124
+ set applyFog(apply: boolean);
4125
+ /**
4126
+ * Multiplier on the time this system is advanced by (Unity's Simulation
4127
+ * Speed): 2 runs the effect twice as fast, 0 freezes it without pausing the
4128
+ * renderer. 1 by default; saved in the effect JSON only when it differs.
4129
+ */
4130
+ playbackSpeed: number;
4131
+ /** What this system does while off screen, see {@link CullingMode}. `'always'` by default. */
4132
+ cullingMode: CullingMode;
4133
+ /**
4134
+ * Whether each particle starts turned along the direction its shape sends
4135
+ * it (Unity's Align To Direction): a mesh particle's +Z is pointed along
4136
+ * the velocity, a billboard's top is turned toward it in the emitter's XY
4137
+ * plane. The start rotation is applied on top. A particle with no speed is
4138
+ * left as it is. False by default.
4139
+ */
4140
+ alignToDirection: boolean;
4141
+ private seedValue?;
4142
+ /** The system's own generator while it steps, when seeded; see {@link seed}. */
4143
+ private rng?;
4144
+ /**
4145
+ * Seed for this system's own random generator. Set, every roll the system
4146
+ * makes while it steps (spawn positions, interval values, random colours
4147
+ * and rotations, burst probability) comes from a generator started from
4148
+ * this seed, and restarted with it on {@link restart}: the effect plays out
4149
+ * identically every time, on every machine — for replays, lock-step
4150
+ * multiplayer and reproducible tests. Systems this one emits into roll on
4151
+ * its generator too. Unset (the default), rolls come from the global source
4152
+ * (`setRandomSource` in quarks.core). Saved in the effect JSON when set.
4153
+ *
4154
+ * Not covered: randomness outside the step, such as a `TurbulenceField`'s
4155
+ * offsets, which are rolled when the behavior is created.
4156
+ */
4157
+ get seed(): number | undefined;
4158
+ set seed(seed: number | undefined);
4159
+ /**
4160
+ * Set by the renderer each frame: true while no active camera sees the
4161
+ * system's bounds and its {@link cullingMode} is not `'always'`.
4162
+ * @internal
4163
+ */
4164
+ culled: boolean;
4165
+ /**
4166
+ * Time a `'pauseAndCatchUp'` system has spent off screen and not yet
4167
+ * simulated, in seconds. Capped, so an effect hidden for a minute does not
4168
+ * replay the minute.
4169
+ */
4170
+ private pendingCatchUp;
4171
+ /**
4172
+ * Time per frame a system coming back into view may spend on the steps it
4173
+ * missed, in milliseconds, when it is advanced without a renderer. The
4174
+ * {@link BatchedRenderer} shares its own budget among all its systems
4175
+ * instead. Steps that do not fit are dropped, not deferred.
4176
+ */
4177
+ static catchUpBudgetMs: number;
4178
+ /** Axis-aligned bounds of the live particles, in simulation space. See {@link getWorldBounds}. */
4179
+ private readonly boundsMin;
4180
+ private readonly boundsMax;
4181
+ /** How far a particle's quad, mesh or stretch can reach past its position, in simulation units. */
4182
+ private boundsPadding;
4183
+ private boundsValid;
4184
+ /** Steps since the last full measurement; between them the bounds are carried and padded. */
4185
+ private stepsSinceBounds;
4186
+ private boundsMaxSize;
4187
+ private boundsMaxSpeedSq;
4188
+ /** True when the bounds are already in world space (a world-space system, or bounds the renderer measured). */
4189
+ private boundsInWorld;
4190
+ private geometryRadiusFor?;
4191
+ private geometryRadius;
3759
4192
  constructor(parameters: ParticleSystemParameters);
3760
4193
  private applyMaterialSettings;
3761
4194
  pause(): void;
@@ -3772,12 +4205,52 @@ declare class ParticleSystem implements IParticleSystem {
3772
4205
  private rebindParticles;
3773
4206
  private growParticlePool;
3774
4207
  private spawn;
4208
+ /** Turns a newborn so that it faces the way its shape sent it; see {@link alignToDirection}. */
4209
+ private alignParticleToDirection;
4210
+ /** Applies the parent particle's inherited properties to a sub emitted newborn; see `EmitSubParticleSystem.inherit`. */
4211
+ private inheritFromParent;
3775
4212
  endEmit(): void;
3776
4213
  dispose(): void;
3777
4214
  restart(): void;
3778
4215
  private firstTimeUpdate;
3779
- /** @internal */
3780
- update(delta: number): void;
4216
+ /**
4217
+ * Advances the system by `delta` seconds of host time.
4218
+ *
4219
+ * `stepDeadline` is a `performance.now()` time after which no further
4220
+ * catch-up step of this frame is run: a frame long enough to need several
4221
+ * steps gets at least one, and the time the rest would have covered is
4222
+ * dropped rather than carried, so one slow frame does not grow the next.
4223
+ * `catchUpDeadline` bounds the steps a `'pauseAndCatchUp'` system runs on
4224
+ * coming back into view; unset, the system allows itself
4225
+ * {@link catchUpBudgetMs}. The renderer supplies both from its budgets.
4226
+ * @internal
4227
+ */
4228
+ update(delta: number, stepDeadline?: number, catchUpDeadline?: number): void;
4229
+ /** Runs the steps a system missed while culled, as many as fit before `deadline`. */
4230
+ private catchUp;
4231
+ /**
4232
+ * Records the bounds the sprite step measured over the live particles.
4233
+ * Trails are measured by their renderer instead, since their ribbons live
4234
+ * outside the store.
4235
+ */
4236
+ private storeBounds;
4237
+ /** Distance of the farthest vertex of the mesh particles' geometry from its origin. */
4238
+ private meshGeometryRadius;
4239
+ /**
4240
+ * World-space axis-aligned bounds of everything this system draws, padded
4241
+ * for particle size, into `min` and `max`. False when the system has no
4242
+ * particles, or none have been measured yet; the caller should then treat
4243
+ * it as visible. Measured in full every few simulated steps and carried,
4244
+ * padded for the motion since, in between: conservative, and at most a
4245
+ * frame behind the display.
4246
+ */
4247
+ getWorldBounds(min: Vector3, max: Vector3): boolean;
4248
+ /**
4249
+ * Records bounds a renderer measured in world space, for systems whose
4250
+ * drawn extent the store does not hold (trail ribbons).
4251
+ * @internal
4252
+ */
4253
+ setWorldBounds(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, padding: number): void;
3781
4254
  /**
3782
4255
  * Time the display is ahead of (positive) or still ahead of the simulation
3783
4256
  * (negative — the simulation ran a hair early), in seconds. Magnitude never
@@ -3817,8 +4290,12 @@ declare class ParticleSystem implements IParticleSystem {
3817
4290
  * change the generated code's indices.
3818
4291
  */
3819
4292
  private behaviorSteps;
3820
- /** Advances emission, behaviors, motion and culling by one fixed timestep. */
4293
+ /**
4294
+ * Advances emission, behaviors, motion and culling by one fixed timestep,
4295
+ * on the system's own random generator when it has a {@link seed}.
4296
+ */
3821
4297
  private simulateStep;
4298
+ private stepOnce;
3822
4299
  private notifyFinished;
3823
4300
  /** Waves a burst fires per loop: its `cycle`, and never fewer than one. */
3824
4301
  private static burstWaveCount;
@@ -4096,8 +4573,20 @@ declare class QuarksUtil {
4096
4573
  static restart(root: Node): void;
4097
4574
  static setAutoDestroy(root: Node, autoDestroy: boolean): void;
4098
4575
  static endEmit(root: Node): void;
4099
- /** True when every emitter under `root` is a finished non-looping system (or looping). */
4576
+ /**
4577
+ * True when every system under `root` is finished: non-looping ones that
4578
+ * ran their course, looping ones whose emission was ended (see
4579
+ * {@link endEmit}) and whose particles are gone. A looping system still
4580
+ * emitting keeps the effect unfinished.
4581
+ */
4100
4582
  static isEffectFinished(root: Node): boolean;
4583
+ /**
4584
+ * A deep copy of an effect: the node tree under `root` with every particle
4585
+ * system cloned, sub emitter links pointing at the copies, and the same
4586
+ * transforms and enabled state. The copy is not added to any renderer.
4587
+ * Nodes that are neither transform nodes nor emitters are skipped.
4588
+ */
4589
+ static instantiate(root: TransformNode, name?: string): TransformNode;
4101
4590
  private static traverseNode;
4102
4591
  }
4103
4592
 
@@ -4105,21 +4594,21 @@ declare function registerShaderChunks(): void;
4105
4594
  declare function getShaderChunk(chunkName: string): string | undefined;
4106
4595
  declare function getRegisteredShaderChunks(): Readonly<Record<string, string>>;
4107
4596
 
4108
- declare const _default$7: "\nattribute vec3 position;\nattribute vec2 uv;\nattribute vec3 normal;\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 scaledPosition = position * size;\n vec3 rotatedPosition = applyQuaternion(scaledPosition, rotation);\n vec3 rotatedNormal = normalize(applyQuaternion(normal, rotation));\n vec3 localPos = rotatedPosition + offset;\n\n vec4 worldPos = world * vec4(localPos, 1.0);\n vec4 viewPos = view * worldPos;\n gl_Position = projection * viewPos;\n\n vWorldPos = worldPos.xyz;\n vNormal = normalize((world * vec4(rotatedNormal, 0.0)).xyz);\n\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -viewPos.z;\n#endif\n\n#ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n#else\n vUV = uv;\n#endif\n\n vColor = color;\n}\n";
4597
+ declare const _default$7: string;
4109
4598
 
4110
4599
  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";
4111
4600
 
4112
- declare const _default$5: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_COLOR_AS_ALPHA\n baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n gl_FragColor = baseColor;\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
4601
+ declare const _default$5: string;
4113
4602
 
4114
- declare const _default$4: "\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\n#ifndef MESH_UNLIT\nuniform vec3 lightDirection;\nuniform vec3 lightColor;\nuniform vec3 ambientColor;\n#endif\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#if defined(USE_ENVMAP_ATLAS) || defined(MESH_RIM)\nuniform vec3 eyePosition;\n#endif\n\n#ifdef MESH_RIM\nuniform vec3 rimColor;\nuniform vec2 rimParams;\n#endif\n\n// One 3\u00D72 atlas (px py pz / nx ny nz). Avoids samplerCube and multi-face\n// sampler bindings that raise GL_INVALID_OPERATION on iOS WebKit.\n#ifdef USE_ENVMAP_ATLAS\nuniform sampler2D envAtlas;\nuniform float reflectionLevel;\n\nvec3 sampleEnvAtlas(vec3 r) {\n vec3 a = abs(r);\n vec2 localUV;\n float cellX;\n float cellY;\n // Atlas layout: +X +Y +Z on row 0, -X -Y -Z on row 1.\n if (a.x >= a.y && a.x >= a.z) {\n cellX = 0.0;\n if (r.x >= 0.0) {\n cellY = 0.0;\n localUV = vec2(-r.z, -r.y) / a.x * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.z, -r.y) / a.x * 0.5 + 0.5;\n }\n } else if (a.y >= a.z) {\n cellX = 1.0;\n if (r.y >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, r.z) / a.y * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.x, -r.z) / a.y * 0.5 + 0.5;\n }\n } else {\n cellX = 2.0;\n if (r.z >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, -r.y) / a.z * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(-r.x, -r.y) / a.z * 0.5 + 0.5;\n }\n }\n vec2 uv = (vec2(cellX, cellY) + clamp(localUV, 0.0, 1.0)) / vec2(3.0, 2.0);\n return texture2D(envAtlas, uv).rgb;\n}\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n vec3 N = normalize(vNormal);\n#ifdef MESH_UNLIT\n vec3 color = baseColor.rgb;\n#else\n vec3 L = normalize(-lightDirection);\n float NdotL = max(dot(N, L), 0.0);\n vec3 litColor = ambientColor + lightColor * NdotL;\n\n vec3 color = baseColor.rgb * litColor;\n#endif\n\n#ifdef USE_ENVMAP_ATLAS\n vec3 viewDir = normalize(vWorldPos - eyePosition);\n vec3 reflectionCoords = reflect(viewDir, N);\n color += sampleEnvAtlas(reflectionCoords) * reflectionLevel;\n#endif\n\n#ifdef MESH_RIM\n // Fresnel: strongest where the surface turns away from the camera.\n vec3 V = normalize(eyePosition - vWorldPos);\n float rim = pow(1.0 - abs(dot(N, V)), rimParams.x) * rimParams.y;\n #ifdef MESH_RIM_MIX\n color = mix(color, rimColor, clamp(rim, 0.0, 1.0));\n #else\n color += rimColor * rim;\n #endif\n#endif\n\n gl_FragColor = vec4(color, baseColor.a);\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
4603
+ declare const _default$4: string;
4115
4604
 
4116
- declare const _default$3: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n#ifdef PIVOT\n// Quad offset in particle-size units: xy in the quad's plane, z toward the camera.\nuniform vec3 pivot;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float c = cos(rotation);\n float s = sin(rotation);\n\n // A negative size mirrors the quad, which is how flipped particles arrive.\n vec2 alignedPosition = position.xy * size.xy;\n#ifdef PIVOT\n // The pivot turns with the particle but is not mirrored with it.\n alignedPosition += pivot.xy * abs(size.xy);\n#endif\n vec2 rotatedPosition;\n rotatedPosition.x = c * alignedPosition.x - s * alignedPosition.y;\n rotatedPosition.y = s * alignedPosition.x + c * alignedPosition.y;\n\n#ifdef HORIZONTAL\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.x += rotatedPosition.x;\n mvPosition.z -= rotatedPosition.y;\n#ifdef PIVOT\n mvPosition.y += pivot.z * abs(size.x);\n#endif\n mvPosition = view * mvPosition;\n#elif defined(VERTICAL)\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.y += rotatedPosition.y;\n mvPosition = view * mvPosition;\n mvPosition.x += rotatedPosition.x;\n#else\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n mvPosition.xy += rotatedPosition;\n#endif\n#ifdef PIVOT\n#ifndef HORIZONTAL\n // Toward the camera along its view axis, whichever way the view space\n // faces: anything in front of the camera has the sign of the far side.\n mvPosition.z -= sign(mvPosition.z) * pivot.z * abs(size.x);\n#endif\n#endif\n\n gl_Position = projection * mvPosition;\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
4605
+ declare const _default$3: string;
4117
4606
 
4118
- declare const _default$2: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\nattribute vec4 velocity;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform float speedFactor;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n#ifdef PIVOT\n// Streak offset in particle-size units: x from head to tail, y across.\nuniform vec3 pivot;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float lengthFactor = velocity.w;\n // A flipped particle arrives with a negative size: the streak keeps its\n // extent and mirrors its texture instead (see quadUV below).\n float avgSize = (abs(size.x) + abs(size.y)) * 0.5;\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n vec3 viewVelocity = mat3(view * world) * velocity.xyz;\n float vlength = length(viewVelocity);\n // Stretch direction is the velocity direction; only a genuinely motionless particle has none.\n // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0\n // (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.\n vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);\n vec3 side = normalize(cross(mvPosition.xyz, vdir));\n mvPosition.xyz += position.y * side * avgSize;\n // Equivalent to viewVelocity * (1.0 + lengthFactor / vlength) for moving particles, but the\n // size-based term (vdir * lengthFactor) survives when the velocity contribution vanishes.\n mvPosition.xyz -= (position.x + 0.5) * (viewVelocity + vdir * lengthFactor) * avgSize;\n#ifdef PIVOT\n // In particle-size units along the quad's own axes: x from head to tail, y across.\n mvPosition.xyz += (pivot.y * side - pivot.x * vdir) * avgSize;\n#endif\n gl_Position = projection * mvPosition;\n vec2 quadUV = vec2(size.x < 0.0 ? 1.0 - uv.x : uv.x, size.y < 0.0 ? 1.0 - uv.y : uv.y);\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = quadUV / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = quadUV / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = quadUV;\n #endif\n\n vColor = color;\n}\n";
4607
+ declare const _default$2: string;
4119
4608
 
4120
- declare const _default$1: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n baseColor *= texColor;\n#endif\n\n if (baseColor.a < 0.01) discard;\n\n gl_FragColor = baseColor;\n}\n";
4609
+ declare const _default$1: string;
4121
4610
 
4122
- declare const _default: "\nattribute vec3 position;\nattribute vec3 previous;\nattribute vec3 next;\nattribute float side;\nattribute float width;\nattribute vec2 uv;\nattribute vec4 color;\n\nuniform mat4 view;\nuniform mat4 projection;\nuniform float lineWidth;\nuniform vec2 resolution;\nuniform float sizeAttenuation;\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec2 fix(vec4 i, float aspect) {\n vec2 res = i.xy / i.w;\n res.x *= aspect;\n return res;\n}\n\nvoid main() {\n float aspect = resolution.x / resolution.y;\n vec4 finalPosition = projection * view * vec4(position, 1.0);\n vec4 prevPos = projection * view * vec4(previous, 1.0);\n vec4 nextPos = projection * view * vec4(next, 1.0);\n\n vec2 currentP = fix(finalPosition, aspect);\n vec2 prevP = fix(prevPos, aspect);\n vec2 nextP = fix(nextPos, aspect);\n\n float w = lineWidth * width;\n vec2 dir;\n if (distance(nextP, currentP) < 0.0001) {\n dir = normalize(currentP - prevP);\n } else if (distance(prevP, currentP) < 0.0001) {\n dir = normalize(nextP - currentP);\n } else {\n vec2 dir1 = normalize(currentP - prevP);\n vec2 dir2 = normalize(nextP - currentP);\n dir = normalize(dir1 + dir2);\n }\n vec4 normal = vec4(-dir.y, dir.x, 0.0, 1.0);\n normal.xy *= 0.5 * w;\n normal *= projection;\n if (sizeAttenuation == 0.0) {\n normal.xy *= finalPosition.w;\n normal.xy /= (vec4(resolution, 0.0, 1.0) * projection).xy;\n }\n finalPosition.xy += normal.xy * side;\n gl_Position = finalPosition;\n vUV = uv;\n vColor = color;\n}\n";
4611
+ declare const _default: string;
4123
4612
 
4124
4613
  declare class SpriteBatch extends VFXBatch {
4125
4614
  private static whiteTextureByScene;
@@ -4149,6 +4638,20 @@ declare class SpriteBatch extends VFXBatch {
4149
4638
  private disposeExpandableBuffers;
4150
4639
  private buildExpandableBuffers;
4151
4640
  expandBuffers(target: number): void;
4641
+ /** The screen-size limits as a uniform value, or null when the batch has none that apply. */
4642
+ private sizeLimits;
4643
+ private sortScratch?;
4644
+ /** One spare array per attribute buffer, gathered into and swapped in; indexed by buffer slot. */
4645
+ private readonly gatherScratch;
4646
+ /**
4647
+ * Reorders the `count` filled instances by the batch's sort mode, so that
4648
+ * the later (covering) draws are the nearer or the chosen-age particles.
4649
+ * The order is computed once as a permutation and every attribute buffer
4650
+ * is gathered through it into a spare array that then takes its place.
4651
+ */
4652
+ private sortInstances;
4653
+ /** Gathers `source` in `order` into the spare array of `slot` and returns it; the source becomes the spare. */
4654
+ private gatherInto;
4152
4655
  rebuildMaterial(): void;
4153
4656
  applyMeshLighting(lighting: MeshLightingSettings): void;
4154
4657
  private storeFixedLighting;
@@ -4286,6 +4789,12 @@ declare class TrailBatch extends VFXBatch {
4286
4789
  */
4287
4790
  private static ensureWorldMatrix;
4288
4791
  update(): void;
4792
+ /**
4793
+ * Records a system's world bounds from the ribbon vertices just written for
4794
+ * it, padded by the widest ribbon. The store only holds each trail's head,
4795
+ * so this is where a trail's extent is known.
4796
+ */
4797
+ private measureSystemBounds;
4289
4798
  /**
4290
4799
  * Uploads the vertex data written by `update` and resizes the sub mesh.
4291
4800
  *
@@ -4307,5 +4816,5 @@ declare class TrailBatch extends VFXBatch {
4307
4816
  dispose(): void;
4308
4817
  }
4309
4818
 
4310
- export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, BoxEmitFrom, BoxEmitter, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EdgeEmitter, 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, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, cubeFaceUrls, damp, defaultMeshLighting, degToRad, denormalize, ensureEnvAtlasFromCube, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, meshRimEqual, normalize, normalizeMeshRim, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin };
4311
- export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, DonutEmitterParameters, EdgeEmitterParameters, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };
4819
+ 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, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRandomSource, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, meshRimEqual, normalize, normalizeMeshRim, _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, withRandomSource };
4820
+ export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, CullingMode, DonutEmitterParameters, EdgeEmitterParameters, EffectPoolOptions, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RandomSource, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SortMode, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, SubEmitterInheritance, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };