@triforge/particle-core 0.1.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 (153) hide show
  1. package/dist/core/BaseEmitter.d.ts +50 -0
  2. package/dist/core/BaseEmitter.d.ts.map +1 -0
  3. package/dist/core/BaseEmitter.js +53 -0
  4. package/dist/core/BaseEmitter.js.map +1 -0
  5. package/dist/core/BaseForce.d.ts +21 -0
  6. package/dist/core/BaseForce.d.ts.map +1 -0
  7. package/dist/core/BaseForce.js +15 -0
  8. package/dist/core/BaseForce.js.map +1 -0
  9. package/dist/core/BaseRenderer.d.ts +96 -0
  10. package/dist/core/BaseRenderer.d.ts.map +1 -0
  11. package/dist/core/BaseRenderer.js +190 -0
  12. package/dist/core/BaseRenderer.js.map +1 -0
  13. package/dist/core/DeflectorCollider.d.ts +46 -0
  14. package/dist/core/DeflectorCollider.d.ts.map +1 -0
  15. package/dist/core/DeflectorCollider.js +113 -0
  16. package/dist/core/DeflectorCollider.js.map +1 -0
  17. package/dist/core/Particle.d.ts +29 -0
  18. package/dist/core/Particle.d.ts.map +1 -0
  19. package/dist/core/Particle.js +41 -0
  20. package/dist/core/Particle.js.map +1 -0
  21. package/dist/core/ParticleCache.d.ts +73 -0
  22. package/dist/core/ParticleCache.d.ts.map +1 -0
  23. package/dist/core/ParticleCache.js +206 -0
  24. package/dist/core/ParticleCache.js.map +1 -0
  25. package/dist/core/ParticleSystem.d.ts +192 -0
  26. package/dist/core/ParticleSystem.d.ts.map +1 -0
  27. package/dist/core/ParticleSystem.js +484 -0
  28. package/dist/core/ParticleSystem.js.map +1 -0
  29. package/dist/core/SeededRandom.d.ts +17 -0
  30. package/dist/core/SeededRandom.d.ts.map +1 -0
  31. package/dist/core/SeededRandom.js +27 -0
  32. package/dist/core/SeededRandom.js.map +1 -0
  33. package/dist/emitters/EdgeEmitter.d.ts +43 -0
  34. package/dist/emitters/EdgeEmitter.d.ts.map +1 -0
  35. package/dist/emitters/EdgeEmitter.js +78 -0
  36. package/dist/emitters/EdgeEmitter.js.map +1 -0
  37. package/dist/emitters/MeshEmitter.d.ts +83 -0
  38. package/dist/emitters/MeshEmitter.d.ts.map +1 -0
  39. package/dist/emitters/MeshEmitter.js +240 -0
  40. package/dist/emitters/MeshEmitter.js.map +1 -0
  41. package/dist/emitters/PointEmitter.d.ts +22 -0
  42. package/dist/emitters/PointEmitter.d.ts.map +1 -0
  43. package/dist/emitters/PointEmitter.js +26 -0
  44. package/dist/emitters/PointEmitter.js.map +1 -0
  45. package/dist/forces/BoidField.d.ts +58 -0
  46. package/dist/forces/BoidField.d.ts.map +1 -0
  47. package/dist/forces/BoidField.js +82 -0
  48. package/dist/forces/BoidField.js.map +1 -0
  49. package/dist/forces/BoidForce.d.ts +54 -0
  50. package/dist/forces/BoidForce.d.ts.map +1 -0
  51. package/dist/forces/BoidForce.js +233 -0
  52. package/dist/forces/BoidForce.js.map +1 -0
  53. package/dist/forces/ChargeForce.d.ts +22 -0
  54. package/dist/forces/ChargeForce.d.ts.map +1 -0
  55. package/dist/forces/ChargeForce.js +35 -0
  56. package/dist/forces/ChargeForce.js.map +1 -0
  57. package/dist/forces/CurveGuideForce.d.ts +43 -0
  58. package/dist/forces/CurveGuideForce.d.ts.map +1 -0
  59. package/dist/forces/CurveGuideForce.js +118 -0
  60. package/dist/forces/CurveGuideForce.js.map +1 -0
  61. package/dist/forces/DragForce.d.ts +19 -0
  62. package/dist/forces/DragForce.d.ts.map +1 -0
  63. package/dist/forces/DragForce.js +31 -0
  64. package/dist/forces/DragForce.js.map +1 -0
  65. package/dist/forces/FlowFieldForce.d.ts +72 -0
  66. package/dist/forces/FlowFieldForce.d.ts.map +1 -0
  67. package/dist/forces/FlowFieldForce.js +68 -0
  68. package/dist/forces/FlowFieldForce.js.map +1 -0
  69. package/dist/forces/ForceField.d.ts +26 -0
  70. package/dist/forces/ForceField.d.ts.map +1 -0
  71. package/dist/forces/ForceField.js +41 -0
  72. package/dist/forces/ForceField.js.map +1 -0
  73. package/dist/forces/GravityForce.d.ts +9 -0
  74. package/dist/forces/GravityForce.d.ts.map +1 -0
  75. package/dist/forces/GravityForce.js +12 -0
  76. package/dist/forces/GravityForce.js.map +1 -0
  77. package/dist/forces/HarmonicForce.d.ts +22 -0
  78. package/dist/forces/HarmonicForce.d.ts.map +1 -0
  79. package/dist/forces/HarmonicForce.js +31 -0
  80. package/dist/forces/HarmonicForce.js.map +1 -0
  81. package/dist/forces/LennardJonesForce.d.ts +23 -0
  82. package/dist/forces/LennardJonesForce.d.ts.map +1 -0
  83. package/dist/forces/LennardJonesForce.js +38 -0
  84. package/dist/forces/LennardJonesForce.js.map +1 -0
  85. package/dist/forces/MagneticForce.d.ts +21 -0
  86. package/dist/forces/MagneticForce.d.ts.map +1 -0
  87. package/dist/forces/MagneticForce.js +30 -0
  88. package/dist/forces/MagneticForce.js.map +1 -0
  89. package/dist/forces/TextureForce.d.ts +37 -0
  90. package/dist/forces/TextureForce.d.ts.map +1 -0
  91. package/dist/forces/TextureForce.js +56 -0
  92. package/dist/forces/TextureForce.js.map +1 -0
  93. package/dist/forces/TurbulenceForce.d.ts +21 -0
  94. package/dist/forces/TurbulenceForce.d.ts.map +1 -0
  95. package/dist/forces/TurbulenceForce.js +39 -0
  96. package/dist/forces/TurbulenceForce.js.map +1 -0
  97. package/dist/forces/VortexForce.d.ts +21 -0
  98. package/dist/forces/VortexForce.d.ts.map +1 -0
  99. package/dist/forces/VortexForce.js +29 -0
  100. package/dist/forces/VortexForce.js.map +1 -0
  101. package/dist/forces/WindForce.d.ts +21 -0
  102. package/dist/forces/WindForce.d.ts.map +1 -0
  103. package/dist/forces/WindForce.js +29 -0
  104. package/dist/forces/WindForce.js.map +1 -0
  105. package/dist/index.d.ts +56 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +44 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/physics/KeyedPhysics.d.ts +43 -0
  110. package/dist/physics/KeyedPhysics.d.ts.map +1 -0
  111. package/dist/physics/KeyedPhysics.js +73 -0
  112. package/dist/physics/KeyedPhysics.js.map +1 -0
  113. package/dist/physics/SPHPhysics.d.ts +27 -0
  114. package/dist/physics/SPHPhysics.d.ts.map +1 -0
  115. package/dist/physics/SPHPhysics.js +119 -0
  116. package/dist/physics/SPHPhysics.js.map +1 -0
  117. package/dist/renderers/BillboardRenderer.d.ts +75 -0
  118. package/dist/renderers/BillboardRenderer.d.ts.map +1 -0
  119. package/dist/renderers/BillboardRenderer.js +106 -0
  120. package/dist/renderers/BillboardRenderer.js.map +1 -0
  121. package/dist/renderers/CollectionRenderer.d.ts +83 -0
  122. package/dist/renderers/CollectionRenderer.d.ts.map +1 -0
  123. package/dist/renderers/CollectionRenderer.js +161 -0
  124. package/dist/renderers/CollectionRenderer.js.map +1 -0
  125. package/dist/renderers/HaloRenderer.d.ts +3 -0
  126. package/dist/renderers/HaloRenderer.d.ts.map +1 -0
  127. package/dist/renderers/HaloRenderer.js +4 -0
  128. package/dist/renderers/HaloRenderer.js.map +1 -0
  129. package/dist/renderers/InstanceRenderer.d.ts +70 -0
  130. package/dist/renderers/InstanceRenderer.d.ts.map +1 -0
  131. package/dist/renderers/InstanceRenderer.js +86 -0
  132. package/dist/renderers/InstanceRenderer.js.map +1 -0
  133. package/dist/renderers/LineRenderer.d.ts +52 -0
  134. package/dist/renderers/LineRenderer.d.ts.map +1 -0
  135. package/dist/renderers/LineRenderer.js +96 -0
  136. package/dist/renderers/LineRenderer.js.map +1 -0
  137. package/dist/renderers/NoneRenderer.d.ts +19 -0
  138. package/dist/renderers/NoneRenderer.d.ts.map +1 -0
  139. package/dist/renderers/NoneRenderer.js +24 -0
  140. package/dist/renderers/NoneRenderer.js.map +1 -0
  141. package/dist/renderers/ObjectRenderer.d.ts +3 -0
  142. package/dist/renderers/ObjectRenderer.d.ts.map +1 -0
  143. package/dist/renderers/ObjectRenderer.js +4 -0
  144. package/dist/renderers/ObjectRenderer.js.map +1 -0
  145. package/dist/renderers/StrandRenderer.d.ts +169 -0
  146. package/dist/renderers/StrandRenderer.d.ts.map +1 -0
  147. package/dist/renderers/StrandRenderer.js +235 -0
  148. package/dist/renderers/StrandRenderer.js.map +1 -0
  149. package/dist/renderers/TrailRenderer.d.ts +54 -0
  150. package/dist/renderers/TrailRenderer.d.ts.map +1 -0
  151. package/dist/renderers/TrailRenderer.js +114 -0
  152. package/dist/renderers/TrailRenderer.js.map +1 -0
  153. package/package.json +45 -0
@@ -0,0 +1,106 @@
1
+ import { Points, BufferGeometry, BufferAttribute, PointsMaterial, AdditiveBlending, NormalBlending, Color, } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * BillboardRenderer — renders particles as camera-facing point sprites.
5
+ * Uses THREE.Points for GPU-efficient batched rendering.
6
+ * (Blender: Render → Halo / Billboard)
7
+ *
8
+ * No allocations inside update() — all buffers are pre-allocated.
9
+ */
10
+ export class BillboardRenderer extends BaseRenderer {
11
+ constructor(opts = {}) {
12
+ super();
13
+ const max = opts.maxCount ?? 10000;
14
+ this._maxCount = max;
15
+ const low = opts.colourLow ?? [1, 0, 0];
16
+ const high = opts.colourHigh ?? [0, 0, 1];
17
+ this.parameters = {
18
+ fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
19
+ opacity: opts.opacity ?? 1,
20
+ size: 0.5,
21
+ colourMode: opts.colourMode ?? 0,
22
+ colourLowR: low[0], colourLowG: low[1], colourLowB: low[2],
23
+ colourHighR: high[0], colourHighG: high[1], colourHighB: high[2],
24
+ velocityMax: opts.velocityMax ?? 10,
25
+ };
26
+ this._positions = new Float32Array(max * 3);
27
+ this._sizes = new Float32Array(max);
28
+ this._colors = new Float32Array(max * 3);
29
+ const geo = new BufferGeometry();
30
+ this._posAttr = new BufferAttribute(this._positions, 3).setUsage(35048); // DYNAMIC_DRAW
31
+ this._sizeAttr = new BufferAttribute(this._sizes, 1).setUsage(35048);
32
+ this._colorAttr = new BufferAttribute(this._colors, 3).setUsage(35048);
33
+ geo.setAttribute('position', this._posAttr);
34
+ geo.setAttribute('size', this._sizeAttr);
35
+ geo.setAttribute('color', this._colorAttr);
36
+ geo.setDrawRange(0, 0);
37
+ const mat = new PointsMaterial({
38
+ color: new Color(opts.color ?? 0xffffff),
39
+ map: opts.map ?? null,
40
+ opacity: this.parameters.opacity,
41
+ transparent: true,
42
+ depthWrite: false,
43
+ blending: opts.additive ? AdditiveBlending : NormalBlending,
44
+ sizeAttenuation: opts.sizeAttenuation ?? true,
45
+ size: 0.5, // world-space size — updated each frame from particle pool
46
+ alphaTest: 0.01,
47
+ });
48
+ this.object3D = new Points(geo, mat);
49
+ this.object3D.frustumCulled = false;
50
+ this.object3D.visible = opts.showHelpers ?? true;
51
+ // Pre-allocate draw buffer for child expansion
52
+ this._allocDrawBuf(max);
53
+ }
54
+ update(particles, aliveCount, params, childRng) {
55
+ const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
56
+ const childType = params ? Math.round(params.childType ?? 0) : 0;
57
+ const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
58
+ const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
59
+ const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
60
+ const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
61
+ const pr = this.parameters;
62
+ const fadeOut = pr.fadeOut >= 0.5;
63
+ const mode = Math.round(pr.colourMode);
64
+ let avgSize = 0;
65
+ for (let i = 0; i < drawCount; i++) {
66
+ const p = this._drawBuf[i];
67
+ const i3 = i * 3;
68
+ this._positions[i3] = p.position.x;
69
+ this._positions[i3 + 1] = p.position.y;
70
+ this._positions[i3 + 2] = p.position.z;
71
+ const s = p.size * (fadeOut ? 1 - p.normalised : 1);
72
+ this._sizes[i] = s;
73
+ avgSize += s;
74
+ if (mode > 0) {
75
+ let t;
76
+ if (mode === 1) {
77
+ const spd = Math.sqrt(p.velocity.x * p.velocity.x +
78
+ p.velocity.y * p.velocity.y +
79
+ p.velocity.z * p.velocity.z);
80
+ t = Math.min(1, spd / Math.max(pr.velocityMax, 0.0001));
81
+ }
82
+ else {
83
+ t = p.normalised;
84
+ }
85
+ this._colors[i3] = pr.colourLowR + (pr.colourHighR - pr.colourLowR) * t;
86
+ this._colors[i3 + 1] = pr.colourLowG + (pr.colourHighG - pr.colourLowG) * t;
87
+ this._colors[i3 + 2] = pr.colourLowB + (pr.colourHighB - pr.colourLowB) * t;
88
+ }
89
+ }
90
+ const mat = this.object3D.material;
91
+ mat.opacity = pr.opacity;
92
+ mat.vertexColors = mode > 0;
93
+ if (drawCount > 0)
94
+ mat.size = avgSize / drawCount;
95
+ this._posAttr.needsUpdate = true;
96
+ this._sizeAttr.needsUpdate = true;
97
+ if (mode > 0)
98
+ this._colorAttr.needsUpdate = true;
99
+ this.object3D.geometry.setDrawRange(0, drawCount);
100
+ }
101
+ dispose() {
102
+ this.object3D.geometry.dispose();
103
+ this.object3D.material.dispose();
104
+ }
105
+ }
106
+ //# sourceMappingURL=BillboardRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BillboardRenderer.js","sourceRoot":"","sources":["../../src/renderers/BillboardRenderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { Group, BufferGeometry, Material, Camera } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ import type { ParticleLike } from '../core/BaseRenderer.js';
4
+ import type { SeededRandom } from '../core/SeededRandom.js';
5
+ export interface CollectionMesh {
6
+ geometry: BufferGeometry;
7
+ material: Material;
8
+ }
9
+ export interface CollectionRendererOptions {
10
+ /** Array of mesh configs — each particle is randomly assigned to one. */
11
+ meshes: CollectionMesh[];
12
+ /** Pool size — must match or exceed ParticleSystem.count. Default 1000. */
13
+ maxCount?: number;
14
+ /**
15
+ * Rotate each instance to face the camera.
16
+ * Blender: Render → Collection with "Face Camera" orientation. Default: true.
17
+ */
18
+ billboard?: boolean;
19
+ /**
20
+ * Shrink each instance to scale 0 over its lifetime. Default: true.
21
+ */
22
+ fadeOut?: boolean;
23
+ /**
24
+ * Shifts random mesh assignment — different seeds give different distributions.
25
+ * Default: 0.
26
+ */
27
+ seed?: number;
28
+ /**
29
+ * Relative spawn probability for each mesh (Blender: Render → Collection → Dupliweights).
30
+ * Length must match meshes.length. Values are normalised internally — [1,1,2] means
31
+ * mesh 0 and 1 each get 25%, mesh 2 gets 50%. Omit for uniform distribution.
32
+ */
33
+ weights?: number[];
34
+ }
35
+ /**
36
+ * CollectionRenderer — picks randomly from a list of meshes and instances each group.
37
+ * (Blender: Render → Collection)
38
+ *
39
+ * Creates one THREE.InstancedMesh per collection entry, bundled in a THREE.Group.
40
+ * Assignment uses poolIdx so children of a parent always get the same mesh variant
41
+ * as their parent — stable across frames.
42
+ *
43
+ * No allocations inside update() — all temporaries are pre-allocated.
44
+ */
45
+ export declare class CollectionRenderer extends BaseRenderer {
46
+ readonly object3D: Group;
47
+ /**
48
+ * Scalar inputs — safe to animate with GSAP or the keyframe system.
49
+ * fadeOut: 1 = shrink to 0 over lifetime, 0 = constant size.
50
+ * billboard: 1 = face camera, 0 = use particle rotation.
51
+ * seed: integer offset for mesh assignment.
52
+ * weight0…N: per-mesh relative weights (Blender: Dupliweights).
53
+ * Changing these at runtime calls _rebuildCDF() on the next update().
54
+ */
55
+ parameters: Record<string, number>;
56
+ /** Set this to your active camera when billboard is 1 (the default). */
57
+ camera: Camera | null;
58
+ private readonly _instances;
59
+ private readonly _counts;
60
+ private readonly _prevCounts;
61
+ private readonly _matrix;
62
+ private readonly _pos;
63
+ private readonly _quat;
64
+ private readonly _camQuat;
65
+ private readonly _euler;
66
+ private readonly _scale;
67
+ private readonly _zeroMat;
68
+ private _maxCount;
69
+ /** Cumulative distribution function for weighted mesh selection. */
70
+ private _cdf;
71
+ /** Snapshot of weight keys at last CDF build — used to detect runtime changes. */
72
+ private _weightDigest;
73
+ constructor(opts: CollectionRendererOptions);
74
+ update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
75
+ /** Rebuild the CDF from current weight0…weightN parameters. */
76
+ private _rebuildCDF;
77
+ /** Sample the CDF with r ∈ [0,1) → mesh index. */
78
+ private _cdfSample;
79
+ /** Fast digest of current weight values — used to detect runtime changes. */
80
+ private _weightDigest_;
81
+ dispose(): void;
82
+ }
83
+ //# sourceMappingURL=CollectionRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/CollectionRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAAiB,cAAc,EAAE,QAAQ,EACT,MAAM,EAC5C,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAG,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,yEAAyE;IACzE,MAAM,EAAM,cAAc,EAAE,CAAA;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAG,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,OAAO,CAAC,EAAI,OAAO,CAAA;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAO,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAI,MAAM,EAAE,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAA;IAExB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAElC,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAO;IAE5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkD;IAC3E,OAAO,CAAC,SAAS,CAAQ;IACzB,oEAAoE;IACpE,OAAO,CAAC,IAAI,CAAuB;IACnC,kFAAkF;IAClF,OAAO,CAAC,aAAa,CAAQ;gBAEjB,IAAI,EAAE,yBAAyB;IAyC3C,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IAwEP,+DAA+D;IAC/D,OAAO,CAAC,WAAW;IAgBnB,kDAAkD;IAClD,OAAO,CAAC,UAAU;IAQlB,6EAA6E;IAC7E,OAAO,CAAC,cAAc;IAUtB,OAAO,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,161 @@
1
+ import { Group, InstancedMesh, Matrix4, Quaternion, Vector3, Euler, } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * CollectionRenderer — picks randomly from a list of meshes and instances each group.
5
+ * (Blender: Render → Collection)
6
+ *
7
+ * Creates one THREE.InstancedMesh per collection entry, bundled in a THREE.Group.
8
+ * Assignment uses poolIdx so children of a parent always get the same mesh variant
9
+ * as their parent — stable across frames.
10
+ *
11
+ * No allocations inside update() — all temporaries are pre-allocated.
12
+ */
13
+ export class CollectionRenderer extends BaseRenderer {
14
+ constructor(opts) {
15
+ super();
16
+ /** Set this to your active camera when billboard is 1 (the default). */
17
+ this.camera = null;
18
+ this._matrix = new Matrix4();
19
+ this._pos = new Vector3();
20
+ this._quat = new Quaternion();
21
+ this._camQuat = new Quaternion();
22
+ this._euler = new Euler();
23
+ this._scale = new Vector3();
24
+ this._zeroMat = new Matrix4().makeScale(0, 0, 0);
25
+ const max = opts.maxCount ?? 1000;
26
+ this._maxCount = max;
27
+ const weightParams = {};
28
+ const n = opts.meshes.length;
29
+ for (let i = 0; i < n; i++) {
30
+ weightParams[`weight${i}`] = opts.weights?.[i] ?? 1;
31
+ }
32
+ this.parameters = {
33
+ billboard: (opts.billboard ?? true) ? 1 : 0,
34
+ fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
35
+ seed: opts.seed ?? 0,
36
+ ...weightParams,
37
+ };
38
+ this._cdf = new Float64Array(n);
39
+ this._weightDigest = -1; // force CDF build on first update
40
+ this._rebuildCDF();
41
+ this.object3D = new Group();
42
+ this.object3D.frustumCulled = false;
43
+ this._instances = opts.meshes.map(m => {
44
+ const mesh = new InstancedMesh(m.geometry, m.material, max);
45
+ mesh.frustumCulled = false;
46
+ mesh.count = 0;
47
+ for (let i = 0; i < max; i++)
48
+ mesh.setMatrixAt(i, this._zeroMat);
49
+ mesh.instanceMatrix.needsUpdate = true;
50
+ this.object3D.add(mesh);
51
+ return mesh;
52
+ });
53
+ this._counts = new Int32Array(n);
54
+ this._prevCounts = new Int32Array(n);
55
+ this._allocDrawBuf(max);
56
+ }
57
+ update(particles, aliveCount, params, childRng) {
58
+ const n = this._instances.length;
59
+ if (n === 0)
60
+ return;
61
+ const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
62
+ const childType = params ? Math.round(params.childType ?? 0) : 0;
63
+ const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
64
+ const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
65
+ const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
66
+ const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
67
+ const billboard = this.parameters.billboard >= 0.5;
68
+ const fadeOut = this.parameters.fadeOut >= 0.5;
69
+ const seed = Math.floor(Math.abs(this.parameters.seed));
70
+ if (billboard && this.camera) {
71
+ this.camera.getWorldQuaternion(this._camQuat);
72
+ }
73
+ // Rebuild CDF if any weight parameter changed since last frame
74
+ const digest = this._weightDigest_(n);
75
+ if (digest !== this._weightDigest) {
76
+ this._rebuildCDF();
77
+ this._weightDigest = digest;
78
+ }
79
+ // Reset per-mesh write cursors
80
+ for (let i = 0; i < n; i++)
81
+ this._counts[i] = 0;
82
+ for (let di = 0; di < drawCount; di++) {
83
+ const d = this._drawBuf[di];
84
+ // Use parent's pool index for stable, deterministic mesh assignment.
85
+ // Mix seed into a cheap hash so seed shifts the distribution without
86
+ // breaking the per-particle stability guarantee.
87
+ const hash = (d.poolIdx * 2654435761 + seed * 40503) >>> 0;
88
+ const r = (hash & 0xFFFF) / 65536; // [0,1)
89
+ const mi = this._cdfSample(r);
90
+ const slot = this._counts[mi];
91
+ const s = d.size * (fadeOut ? 1 - d.normalised : 1);
92
+ this._pos.set(d.position.x, d.position.y, d.position.z);
93
+ this._scale.setScalar(Math.max(s, 0));
94
+ if (billboard && this.camera) {
95
+ this._matrix.compose(this._pos, this._camQuat, this._scale);
96
+ }
97
+ else {
98
+ this._euler.set(d.rotation.x, d.rotation.y, d.rotation.z);
99
+ this._quat.setFromEuler(this._euler);
100
+ this._matrix.compose(this._pos, this._quat, this._scale);
101
+ }
102
+ this._instances[mi].setMatrixAt(slot, this._matrix);
103
+ this._counts[mi]++;
104
+ }
105
+ for (let i = 0; i < n; i++) {
106
+ const mesh = this._instances[i];
107
+ // Zero slots that were alive last frame but aren't now
108
+ for (let j = this._counts[i]; j < this._prevCounts[i]; j++) {
109
+ mesh.setMatrixAt(j, this._zeroMat);
110
+ }
111
+ this._prevCounts[i] = this._counts[i];
112
+ mesh.count = this._counts[i];
113
+ mesh.instanceMatrix.needsUpdate = true;
114
+ }
115
+ }
116
+ /** Rebuild the CDF from current weight0…weightN parameters. */
117
+ _rebuildCDF() {
118
+ const n = this._cdf.length;
119
+ let sum = 0;
120
+ for (let i = 0; i < n; i++) {
121
+ const w = Math.max(0, this.parameters[`weight${i}`] ?? 1);
122
+ sum += w;
123
+ this._cdf[i] = sum;
124
+ }
125
+ if (sum > 0) {
126
+ for (let i = 0; i < n; i++)
127
+ this._cdf[i] /= sum;
128
+ }
129
+ else {
130
+ // All zero weights → uniform fallback
131
+ for (let i = 0; i < n; i++)
132
+ this._cdf[i] = (i + 1) / n;
133
+ }
134
+ }
135
+ /** Sample the CDF with r ∈ [0,1) → mesh index. */
136
+ _cdfSample(r) {
137
+ const n = this._cdf.length;
138
+ for (let i = 0; i < n; i++) {
139
+ if (r < this._cdf[i])
140
+ return i;
141
+ }
142
+ return n - 1;
143
+ }
144
+ /** Fast digest of current weight values — used to detect runtime changes. */
145
+ _weightDigest_(n) {
146
+ let h = 0;
147
+ for (let i = 0; i < n; i++) {
148
+ const w = this.parameters[`weight${i}`] ?? 1;
149
+ // FNV-1a inspired mix
150
+ h = ((h ^ Math.round(w * 1000)) * 16777619) >>> 0;
151
+ }
152
+ return h;
153
+ }
154
+ dispose() {
155
+ for (const mesh of this._instances) {
156
+ mesh.geometry.dispose();
157
+ mesh.material.dispose();
158
+ }
159
+ }
160
+ }
161
+ //# sourceMappingURL=CollectionRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CollectionRenderer.js","sourceRoot":"","sources":["../../src/renderers/CollectionRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,GACpC,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAoC5D;;;;;;;;;GASG;AACH,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAgClD,YAAY,IAA+B;QACzC,KAAK,EAAE,CAAA;QApBT,wEAAwE;QACxE,WAAM,GAAkB,IAAI,CAAA;QAKX,YAAO,GAAmB,IAAI,OAAO,EAAE,CAAA;QACvC,SAAI,GAAsB,IAAI,OAAO,EAAE,CAAA;QACvC,UAAK,GAAqB,IAAI,UAAU,EAAE,CAAA;QAC1C,aAAQ,GAAkB,IAAI,UAAU,EAAE,CAAA;QAC1C,WAAM,GAAoB,IAAI,KAAK,EAAE,CAAA;QACrC,WAAM,GAAoB,IAAI,OAAO,EAAE,CAAA;QACvC,aAAQ,GAAkB,IAAI,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QASzE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAA;QACjC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAA;QAEpB,MAAM,YAAY,GAA2B,EAAE,CAAA;QAC/C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAA;QAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACrD,CAAC;QAED,IAAI,CAAC,UAAU,GAAG;YAChB,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO,EAAI,CAAC,IAAI,CAAC,OAAO,IAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,EAAO,IAAI,CAAC,IAAI,IAAI,CAAC;YACzB,GAAG,YAAY;SAChB,CAAA;QAED,IAAI,CAAC,IAAI,GAAY,IAAI,YAAY,CAAC,CAAC,CAAC,CAAA;QACxC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC,CAAA,CAAE,kCAAkC;QAC3D,IAAI,CAAC,WAAW,EAAE,CAAA;QAElB,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,EAAE,CAAA;QAC3B,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,KAAK,CAAA;QAEnC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;YACpC,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;YAC3D,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;YAC1B,IAAI,CAAC,KAAK,GAAG,CAAC,CAAA;YACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE;gBAAE,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;YAChE,IAAI,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAA;YACtC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACvB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,OAAO,GAAO,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;QACpC,IAAI,CAAC,WAAW,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;QAEpC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAED,MAAM,CACJ,SAAyB,EACzB,UAAkB,EAClB,MAAkC,EAClC,QAAwB;QAExB,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAA;QAChC,IAAI,CAAC,KAAK,CAAC;YAAE,OAAM;QAEnB,MAAM,UAAU,GAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,IAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACjF,MAAM,SAAS,GAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,IAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EACzD,QAAQ,IAAI,IAAI,EAAE,IAAI,CAAC,SAAS,CACjC,CAAA;QAED,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACtF,MAAM,SAAS,GAAG,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAA;QAEtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,GAAG,CAAA;QAClD,MAAM,OAAO,GAAK,IAAI,CAAC,UAAU,CAAC,OAAO,IAAM,GAAG,CAAA;QAClD,MAAM,IAAI,GAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QAE5D,IAAI,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC/C,CAAC;QAED,+DAA+D;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAA;QACrC,IAAI,MAAM,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;YAClC,IAAI,CAAC,WAAW,EAAE,CAAA;YAClB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAA;QAC7B,CAAC;QAED,+BAA+B;QAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAE/C,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC;YACtC,MAAM,CAAC,GAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;YAC5B,qEAAqE;YACrE,qEAAqE;YACrE,iDAAiD;YACjD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,UAAU,GAAG,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;YAC1D,MAAM,CAAC,GAAM,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,KAAK,CAAA,CAAQ,QAAQ;YACpD,MAAM,EAAE,GAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;YAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAE7B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;YAErC,IAAI,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;gBACzD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACpC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC1D,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;YACnD,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAA;QACpB,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;YAC/B,uDAAuD;YACvD,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3D,IAAI,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;YACpC,CAAC;YACD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;YACrC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;YAC5B,IAAI,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAA;QACxC,CAAC;IACH,CAAC;IAED,+DAA+D;IACvD,WAAW;QACjB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;QAC1B,IAAI,GAAG,GAAG,CAAC,CAAA;QACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;YACzD,GAAG,IAAI,CAAC,CAAA;YACR,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAA;QACpB,CAAC;QACD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAA;QACjD,CAAC;aAAM,CAAC;YACN,sCAAsC;YACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;IAED,kDAAkD;IAC1C,UAAU,CAAC,CAAS;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAA;QAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,CAAA;QAChC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,CAAA;IACd,CAAC;IAED,6EAA6E;IACrE,cAAc,CAAC,CAAS;QAC9B,IAAI,CAAC,GAAG,CAAC,CAAA;QACT,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;YAC5C,sBAAsB;YACtB,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;QACnD,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC;IAED,OAAO;QACL,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACnC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CACtB;YAAC,IAAI,CAAC,QAAqB,CAAC,OAAO,EAAE,CAAA;QACxC,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { BillboardRenderer as HaloRenderer } from './BillboardRenderer.js';
2
+ export type { BillboardRendererOptions as HaloRendererOptions } from './BillboardRenderer.js';
3
+ //# sourceMappingURL=HaloRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HaloRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/HaloRenderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC1E,YAAY,EAAE,wBAAwB,IAAI,mBAAmB,EAAE,MAAM,wBAAwB,CAAA"}
@@ -0,0 +1,4 @@
1
+ // Blender "Halo" render mode alias → BillboardRenderer.
2
+ // Both names are exported so code may use either; they are the same class.
3
+ export { BillboardRenderer as HaloRenderer } from './BillboardRenderer.js';
4
+ //# sourceMappingURL=HaloRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HaloRenderer.js","sourceRoot":"","sources":["../../src/renderers/HaloRenderer.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,2EAA2E;AAC3E,OAAO,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
@@ -0,0 +1,70 @@
1
+ import { InstancedMesh, BufferGeometry, Material, Camera } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ import type { ParticleLike } from '../core/BaseRenderer.js';
4
+ import type { SeededRandom } from '../core/SeededRandom.js';
5
+ export interface InstanceRendererOptions {
6
+ /** Geometry stamped at every particle position */
7
+ geometry: BufferGeometry;
8
+ /** Any Three.js material — including compiled shader node graphs */
9
+ material: Material;
10
+ /** Pool size — must match or exceed ParticleSystem.count */
11
+ maxCount?: number;
12
+ /**
13
+ * Rotate each instance to face the camera.
14
+ * Essential for flat foam/splash meshes — without this they render edge-on.
15
+ * Blender: Render → Object with "Face Camera" orientation.
16
+ * Default: true.
17
+ */
18
+ billboard?: boolean;
19
+ /**
20
+ * Shrink the instance scale to 0 over its lifetime.
21
+ * Simulates a fade when the material has no transparency.
22
+ * Default: true.
23
+ */
24
+ fadeOut?: boolean;
25
+ /**
26
+ * Show instances on startup.
27
+ * Mirrors Blender's viewport display toggle. Default: true.
28
+ */
29
+ showHelpers?: boolean;
30
+ }
31
+ /**
32
+ * InstanceRenderer — renders each particle as a full mesh instance.
33
+ * Uses THREE.InstancedMesh — one draw call regardless of particle count.
34
+ * Blender parallel: Particle System → Render → Object / Collection.
35
+ *
36
+ * Assign any material here, including a compiled @st-shader-core node graph,
37
+ * to get full PBR shading on every particle.
38
+ *
39
+ * No allocations inside update() — all temporaries are pre-allocated.
40
+ */
41
+ export declare class InstanceRenderer extends BaseRenderer {
42
+ readonly object3D: InstancedMesh;
43
+ /**
44
+ * Scalar inputs — safe to animate with GSAP or the keyframe system.
45
+ * fadeOut: 1 = shrink to 0 over lifetime, 0 = constant size.
46
+ * billboard: 1 = face camera, 0 = use particle rotation.
47
+ */
48
+ parameters: {
49
+ fadeOut: number;
50
+ billboard: number;
51
+ };
52
+ /**
53
+ * Set this to your active camera to enable billboard alignment.
54
+ * Required when billboard: 1 (the default).
55
+ */
56
+ camera: Camera | null;
57
+ private readonly _matrix;
58
+ private readonly _pos;
59
+ private readonly _quat;
60
+ private readonly _camQuat;
61
+ private readonly _euler;
62
+ private readonly _scale;
63
+ private readonly _zeroMatrix;
64
+ private _prevCount;
65
+ private _maxCount;
66
+ constructor(opts: InstanceRendererOptions);
67
+ update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
68
+ dispose(): void;
69
+ }
70
+ //# sourceMappingURL=InstanceRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstanceRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/InstanceRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAAE,cAAc,EAAE,QAAQ,EACF,MAAM,EAC5C,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,QAAQ,EAAI,cAAc,CAAA;IAC1B,oEAAoE;IACpE,QAAQ,EAAI,QAAQ,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAG,MAAM,CAAA;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAI,OAAO,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAEhC;;;;OAIG;IACH,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAElD;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+C;IAC3E,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE,uBAAuB;IAuBzC,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IA8CP,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,86 @@
1
+ import { InstancedMesh, Matrix4, Quaternion, Vector3, Euler, } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * InstanceRenderer — renders each particle as a full mesh instance.
5
+ * Uses THREE.InstancedMesh — one draw call regardless of particle count.
6
+ * Blender parallel: Particle System → Render → Object / Collection.
7
+ *
8
+ * Assign any material here, including a compiled @st-shader-core node graph,
9
+ * to get full PBR shading on every particle.
10
+ *
11
+ * No allocations inside update() — all temporaries are pre-allocated.
12
+ */
13
+ export class InstanceRenderer extends BaseRenderer {
14
+ constructor(opts) {
15
+ super();
16
+ /**
17
+ * Set this to your active camera to enable billboard alignment.
18
+ * Required when billboard: 1 (the default).
19
+ */
20
+ this.camera = null;
21
+ this._matrix = new Matrix4();
22
+ this._pos = new Vector3();
23
+ this._quat = new Quaternion();
24
+ this._camQuat = new Quaternion();
25
+ this._euler = new Euler();
26
+ this._scale = new Vector3();
27
+ this._zeroMatrix = new Matrix4().makeScale(0, 0, 0);
28
+ this._prevCount = 0;
29
+ const max = opts.maxCount ?? 1000;
30
+ this._maxCount = max;
31
+ this.parameters = {
32
+ billboard: (opts.billboard ?? true) ? 1 : 0,
33
+ fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
34
+ };
35
+ this.object3D = new InstancedMesh(opts.geometry, opts.material, max);
36
+ this.object3D.frustumCulled = false;
37
+ this.object3D.count = 0;
38
+ this.object3D.visible = opts.showHelpers ?? true;
39
+ // Pre-zero all slots so no stale instances flash on first frame
40
+ for (let i = 0; i < max; i++) {
41
+ this.object3D.setMatrixAt(i, this._zeroMatrix);
42
+ }
43
+ this.object3D.instanceMatrix.needsUpdate = true;
44
+ this._allocDrawBuf(max);
45
+ }
46
+ update(particles, aliveCount, params, childRng) {
47
+ const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
48
+ const childType = params ? Math.round(params.childType ?? 0) : 0;
49
+ const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
50
+ const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
51
+ const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
52
+ const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
53
+ const billboard = this.parameters.billboard >= 0.5;
54
+ const fadeOut = this.parameters.fadeOut >= 0.5;
55
+ if (billboard && this.camera) {
56
+ this.camera.getWorldQuaternion(this._camQuat);
57
+ }
58
+ for (let i = 0; i < drawCount; i++) {
59
+ const p = this._drawBuf[i];
60
+ const s = p.size * (fadeOut ? 1 - p.normalised : 1);
61
+ this._pos.set(p.position.x, p.position.y, p.position.z);
62
+ this._scale.setScalar(Math.max(s, 0));
63
+ if (billboard && this.camera) {
64
+ this._matrix.compose(this._pos, this._camQuat, this._scale);
65
+ }
66
+ else {
67
+ this._euler.set(p.rotation.x, p.rotation.y, p.rotation.z);
68
+ this._quat.setFromEuler(this._euler);
69
+ this._matrix.compose(this._pos, this._quat, this._scale);
70
+ }
71
+ this.object3D.setMatrixAt(i, this._matrix);
72
+ }
73
+ // Zero out slots that were alive last frame but aren't now
74
+ for (let i = drawCount; i < this._prevCount; i++) {
75
+ this.object3D.setMatrixAt(i, this._zeroMatrix);
76
+ }
77
+ this._prevCount = drawCount;
78
+ this.object3D.count = drawCount;
79
+ this.object3D.instanceMatrix.needsUpdate = true;
80
+ }
81
+ dispose() {
82
+ this.object3D.geometry.dispose();
83
+ this.object3D.material.dispose();
84
+ }
85
+ }
86
+ //# sourceMappingURL=InstanceRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InstanceRenderer.js","sourceRoot":"","sources":["../../src/renderers/InstanceRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,GACpC,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AA+B5D;;;;;;;;;GASG;AACH,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAyBhD,YAAY,IAA6B;QACvC,KAAK,EAAE,CAAA;QAhBT;;;WAGG;QACH,WAAM,GAAkB,IAAI,CAAA;QACX,YAAO,GAAmB,IAAI,OAAO,EAAE,CAAA;QACvC,SAAI,GAAsB,IAAI,OAAO,EAAE,CAAA;QACvC,UAAK,GAAqB,IAAI,UAAU,EAAE,CAAA;QAC1C,aAAQ,GAAkB,IAAI,UAAU,EAAE,CAAA;QAC1C,WAAM,GAAoB,IAAI,KAAK,EAAE,CAAA;QACrC,WAAM,GAAoB,IAAI,OAAO,EAAE,CAAA;QACvC,gBAAW,GAAe,IAAI,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACnE,eAAU,GAAW,CAAC,CAAA;QAK5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAA;QACjC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAA;QACpB,IAAI,CAAC,UAAU,GAAG;YAChB,SAAS,EAAE,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,OAAO,EAAI,CAAC,IAAI,CAAC,OAAO,IAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAC5C,CAAA;QAED,IAAI,CAAC,QAAQ,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QACpE,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,KAAK,CAAA;QACnC,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAW,CAAC,CAAA;QAC/B,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAS,IAAI,CAAC,WAAW,IAAI,IAAI,CAAA;QAEtD,gEAAgE;QAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAA;QAE/C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAA;IACzB,CAAC;IAED,MAAM,CACJ,SAAyB,EACzB,UAAkB,EAClB,MAAkC,EAClC,QAAwB;QAExB,MAAM,UAAU,GAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,IAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACjF,MAAM,SAAS,GAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,IAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EACzD,QAAQ,IAAI,IAAI,EAAE,IAAI,CAAC,SAAS,CACjC,CAAA;QAED,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACtF,MAAM,SAAS,GAAG,aAAa,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,aAAa,CAAC,CAAA;QAEtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,IAAI,GAAG,CAAA;QAClD,MAAM,OAAO,GAAK,IAAI,CAAC,UAAU,CAAC,OAAO,IAAM,GAAG,CAAA;QAClD,IAAI,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QAC/C,CAAC;QAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;YACvD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;YAErC,IAAI,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC7D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;gBACzD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACpC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YAC1D,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAC5C,CAAC;QAED,2DAA2D;QAC3D,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAChD,CAAC;QAED,IAAI,CAAC,UAAU,GAAG,SAAS,CAAA;QAC3B,IAAI,CAAC,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAA;QAC/B,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,WAAW,GAAG,IAAI,CAAA;IACjD,CAAC;IAED,OAAO;QACL,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,CAC/B;QAAC,IAAI,CAAC,QAAQ,CAAC,QAAqB,CAAC,OAAO,EAAE,CAAA;IACjD,CAAC;CACF"}
@@ -0,0 +1,52 @@
1
+ import { LineSegments } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ import type { ParticleLike } from '../core/BaseRenderer.js';
4
+ import type { SeededRandom } from '../core/SeededRandom.js';
5
+ export interface LineRendererOptions {
6
+ maxCount?: number;
7
+ color?: string | number;
8
+ /** Length multiplier — line extends velocity.length × scale behind particle */
9
+ lengthScale?: number;
10
+ /** Colour mode: 0=flat, 1=by velocity, 2=by age (Blender: Display Colour) */
11
+ colourMode?: number;
12
+ /** Low-speed / young colour RGB components [0–1] */
13
+ colourLow?: [number, number, number];
14
+ /** High-speed / old colour RGB components [0–1] */
15
+ colourHigh?: [number, number, number];
16
+ /** Velocity magnitude that maps to colourHigh in mode 1 */
17
+ velocityMax?: number;
18
+ }
19
+ /**
20
+ * LineRenderer — renders each particle as a velocity-aligned line segment.
21
+ * (Blender: Render → Line)
22
+ */
23
+ export declare class LineRenderer extends BaseRenderer {
24
+ readonly object3D: LineSegments;
25
+ /**
26
+ * Scalar inputs — safe to animate with GSAP or the keyframe system.
27
+ * lengthScale: line extends velocity × lengthScale behind the particle.
28
+ * opacity: overall alpha [0–1].
29
+ * colourMode: 0=flat, 1=by velocity, 2=by age.
30
+ */
31
+ parameters: {
32
+ lengthScale: number;
33
+ opacity: number;
34
+ colourMode: number;
35
+ colourLowR: number;
36
+ colourLowG: number;
37
+ colourLowB: number;
38
+ colourHighR: number;
39
+ colourHighG: number;
40
+ colourHighB: number;
41
+ velocityMax: number;
42
+ };
43
+ private _positions;
44
+ private _colors;
45
+ private _posAttr;
46
+ private _colorAttr;
47
+ private _maxCount;
48
+ constructor(opts?: LineRendererOptions);
49
+ update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
50
+ dispose(): void;
51
+ }
52
+ //# sourceMappingURL=LineRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LineRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/LineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAEb,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAK,MAAM,CAAA;IACpB,KAAK,CAAC,EAAQ,MAAM,GAAG,MAAM,CAAA;IAC7B,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6EAA6E;IAC7E,UAAU,CAAC,EAAG,MAAM,CAAA;IACpB,oDAAoD;IACpD,SAAS,CAAC,EAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,mDAAmD;IACnD,UAAU,CAAC,EAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAE/B;;;;;OAKG;IACH,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;QACpC,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;QAC1D,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;QAC7D,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,GAAE,mBAAwB;IAuC1C,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IA0DP,OAAO,IAAI,IAAI;CAIhB"}