@codexo/exojs-particles 0.15.3 → 0.16.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.
- package/README.md +21 -43
- package/dist/esm/ParticleStorage.d.ts +188 -0
- package/dist/esm/ParticleStorage.d.ts.map +1 -0
- package/dist/esm/ParticleStorage.js +208 -0
- package/dist/esm/ParticleStorage.js.map +1 -0
- package/dist/esm/ParticleSystem.d.ts +189 -60
- package/dist/esm/ParticleSystem.d.ts.map +1 -0
- package/dist/esm/ParticleSystem.js +660 -560
- package/dist/esm/ParticleSystem.js.map +1 -1
- package/dist/esm/distributions/BoxArea.d.ts +1 -0
- package/dist/esm/distributions/BoxArea.d.ts.map +1 -0
- package/dist/esm/distributions/BoxArea.js +38 -44
- package/dist/esm/distributions/BoxArea.js.map +1 -1
- package/dist/esm/distributions/CircleArea.d.ts +1 -0
- package/dist/esm/distributions/CircleArea.d.ts.map +1 -0
- package/dist/esm/distributions/CircleArea.js +30 -28
- package/dist/esm/distributions/CircleArea.js.map +1 -1
- package/dist/esm/distributions/ColorGradient.d.ts +3 -2
- package/dist/esm/distributions/ColorGradient.d.ts.map +1 -0
- package/dist/esm/distributions/ColorGradient.js +70 -75
- package/dist/esm/distributions/ColorGradient.js.map +1 -1
- package/dist/esm/distributions/ConeDirection.d.ts +2 -1
- package/dist/esm/distributions/ConeDirection.d.ts.map +1 -0
- package/dist/esm/distributions/ConeDirection.js +41 -39
- package/dist/esm/distributions/ConeDirection.js.map +1 -1
- package/dist/esm/distributions/Constant.d.ts +1 -0
- package/dist/esm/distributions/Constant.d.ts.map +1 -0
- package/dist/esm/distributions/Constant.js +32 -32
- package/dist/esm/distributions/Constant.js.map +1 -1
- package/dist/esm/distributions/Curve.d.ts +2 -1
- package/dist/esm/distributions/Curve.d.ts.map +1 -0
- package/dist/esm/distributions/Curve.js +46 -55
- package/dist/esm/distributions/Curve.js.map +1 -1
- package/dist/esm/distributions/Distribution.d.ts +4 -3
- package/dist/esm/distributions/Distribution.d.ts.map +1 -0
- package/dist/esm/distributions/LineSegment.d.ts +1 -0
- package/dist/esm/distributions/LineSegment.d.ts.map +1 -0
- package/dist/esm/distributions/LineSegment.js +25 -23
- package/dist/esm/distributions/LineSegment.js.map +1 -1
- package/dist/esm/distributions/Range.d.ts +1 -0
- package/dist/esm/distributions/Range.d.ts.map +1 -0
- package/dist/esm/distributions/Range.js +18 -16
- package/dist/esm/distributions/Range.js.map +1 -1
- package/dist/esm/distributions/VectorRange.d.ts +1 -0
- package/dist/esm/distributions/VectorRange.d.ts.map +1 -0
- package/dist/esm/distributions/VectorRange.js +29 -27
- package/dist/esm/distributions/VectorRange.js.map +1 -1
- package/dist/esm/distributions/index.d.ts +1 -0
- package/dist/esm/distributions/index.d.ts.map +1 -0
- package/dist/esm/gpu/ParticleGpuState.d.ts +143 -18
- package/dist/esm/gpu/ParticleGpuState.d.ts.map +1 -0
- package/dist/esm/gpu/ParticleGpuState.js +655 -497
- package/dist/esm/gpu/ParticleGpuState.js.map +1 -1
- package/dist/esm/gpu/shaders/particle-simulate.wgsl.js +6 -0
- package/dist/esm/gpu/shaders/particle-simulate.wgsl.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +39 -32
- package/dist/esm/modules/AlphaFadeOverLifetime.d.ts +4 -3
- package/dist/esm/modules/AlphaFadeOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/AlphaFadeOverLifetime.js +68 -55
- package/dist/esm/modules/AlphaFadeOverLifetime.js.map +1 -1
- package/dist/esm/modules/ApplyForce.d.ts +4 -3
- package/dist/esm/modules/ApplyForce.d.ts.map +1 -0
- package/dist/esm/modules/ApplyForce.js +49 -43
- package/dist/esm/modules/ApplyForce.js.map +1 -1
- package/dist/esm/modules/AttractToPoint.d.ts +4 -3
- package/dist/esm/modules/AttractToPoint.d.ts.map +1 -0
- package/dist/esm/modules/AttractToPoint.js +73 -62
- package/dist/esm/modules/AttractToPoint.js.map +1 -1
- package/dist/esm/modules/BurstSpawn.d.ts +6 -18
- package/dist/esm/modules/BurstSpawn.d.ts.map +1 -0
- package/dist/esm/modules/BurstSpawn.js +56 -91
- package/dist/esm/modules/BurstSpawn.js.map +1 -1
- package/dist/esm/modules/ColorOverLifetime.d.ts +4 -3
- package/dist/esm/modules/ColorOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/ColorOverLifetime.js +65 -53
- package/dist/esm/modules/ColorOverLifetime.js.map +1 -1
- package/dist/esm/modules/ColorOverSpeed.d.ts +5 -4
- package/dist/esm/modules/ColorOverSpeed.d.ts.map +1 -0
- package/dist/esm/modules/ColorOverSpeed.js +90 -75
- package/dist/esm/modules/ColorOverSpeed.js.map +1 -1
- package/dist/esm/modules/DeathModule.d.ts +26 -10
- package/dist/esm/modules/DeathModule.d.ts.map +1 -0
- package/dist/esm/modules/DeathModule.js +38 -22
- package/dist/esm/modules/DeathModule.js.map +1 -1
- package/dist/esm/modules/Drag.d.ts +3 -2
- package/dist/esm/modules/Drag.d.ts.map +1 -0
- package/dist/esm/modules/Drag.js +43 -37
- package/dist/esm/modules/Drag.js.map +1 -1
- package/dist/esm/modules/OrbitalForce.d.ts +4 -3
- package/dist/esm/modules/OrbitalForce.d.ts.map +1 -0
- package/dist/esm/modules/OrbitalForce.js +70 -58
- package/dist/esm/modules/OrbitalForce.js.map +1 -1
- package/dist/esm/modules/RateSpawn.d.ts +7 -22
- package/dist/esm/modules/RateSpawn.d.ts.map +1 -0
- package/dist/esm/modules/RateSpawn.js +39 -71
- package/dist/esm/modules/RateSpawn.js.map +1 -1
- package/dist/esm/modules/RepelFromPoint.d.ts +4 -3
- package/dist/esm/modules/RepelFromPoint.d.ts.map +1 -0
- package/dist/esm/modules/RepelFromPoint.js +72 -62
- package/dist/esm/modules/RepelFromPoint.js.map +1 -1
- package/dist/esm/modules/RotateOverLifetime.d.ts +3 -2
- package/dist/esm/modules/RotateOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/RotateOverLifetime.js +40 -36
- package/dist/esm/modules/RotateOverLifetime.js.map +1 -1
- package/dist/esm/modules/ScaleOverLifetime.d.ts +5 -4
- package/dist/esm/modules/ScaleOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/ScaleOverLifetime.js +60 -50
- package/dist/esm/modules/ScaleOverLifetime.js.map +1 -1
- package/dist/esm/modules/SpawnModule.d.ts +15 -12
- package/dist/esm/modules/SpawnModule.d.ts.map +1 -0
- package/dist/esm/modules/SpawnModule.js +32 -28
- package/dist/esm/modules/SpawnModule.js.map +1 -1
- package/dist/esm/modules/SpawnOnDeath.d.ts +13 -9
- package/dist/esm/modules/SpawnOnDeath.d.ts.map +1 -0
- package/dist/esm/modules/SpawnOnDeath.js +41 -43
- package/dist/esm/modules/SpawnOnDeath.js.map +1 -1
- package/dist/esm/modules/Turbulence.d.ts +4 -3
- package/dist/esm/modules/Turbulence.d.ts.map +1 -0
- package/dist/esm/modules/Turbulence.js +101 -89
- package/dist/esm/modules/Turbulence.js.map +1 -1
- package/dist/esm/modules/UpdateModule.d.ts +21 -13
- package/dist/esm/modules/UpdateModule.d.ts.map +1 -0
- package/dist/esm/modules/UpdateModule.js +65 -63
- package/dist/esm/modules/UpdateModule.js.map +1 -1
- package/dist/esm/modules/VelocityOverLifetime.d.ts +7 -6
- package/dist/esm/modules/VelocityOverLifetime.d.ts.map +1 -0
- package/dist/esm/modules/VelocityOverLifetime.js +75 -73
- package/dist/esm/modules/VelocityOverLifetime.js.map +1 -1
- package/dist/esm/modules/WgslContribution.d.ts +16 -15
- package/dist/esm/modules/WgslContribution.d.ts.map +1 -0
- package/dist/esm/modules/WgslContribution.js +37 -29
- package/dist/esm/modules/WgslContribution.js.map +1 -1
- package/dist/esm/modules/index.d.ts +3 -1
- package/dist/esm/modules/index.d.ts.map +1 -0
- package/dist/esm/modules/spawnFields.d.ts +32 -0
- package/dist/esm/modules/spawnFields.d.ts.map +1 -0
- package/dist/esm/modules/spawnFields.js +31 -0
- package/dist/esm/modules/spawnFields.js.map +1 -0
- package/dist/esm/particlesBuildInfo.d.ts +1 -0
- package/dist/esm/particlesBuildInfo.d.ts.map +1 -0
- package/dist/esm/particlesBuildInfo.js +6 -4
- package/dist/esm/particlesBuildInfo.js.map +1 -1
- package/dist/esm/particlesExtension.d.ts +13 -5
- package/dist/esm/particlesExtension.d.ts.map +1 -0
- package/dist/esm/particlesExtension.js +38 -42
- package/dist/esm/particlesExtension.js.map +1 -1
- package/dist/esm/public.d.ts +11 -0
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/renderModes/MeshParticles.d.ts +128 -0
- package/dist/esm/renderModes/MeshParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/MeshParticles.js +263 -0
- package/dist/esm/renderModes/MeshParticles.js.map +1 -0
- package/dist/esm/renderModes/ParticleBufferLayout.d.ts +59 -0
- package/dist/esm/renderModes/ParticleBufferLayout.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleBufferLayout.js +99 -0
- package/dist/esm/renderModes/ParticleBufferLayout.js.map +1 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.d.ts +58 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.js +173 -0
- package/dist/esm/renderModes/ParticleInstanceWriter.js.map +1 -0
- package/dist/esm/renderModes/ParticleMaterial.d.ts +18 -0
- package/dist/esm/renderModes/ParticleMaterial.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleMaterial.js +24 -0
- package/dist/esm/renderModes/ParticleMaterial.js.map +1 -0
- package/dist/esm/renderModes/ParticleRenderMode.d.ts +114 -0
- package/dist/esm/renderModes/ParticleRenderMode.d.ts.map +1 -0
- package/dist/esm/renderModes/ParticleRenderMode.js +99 -0
- package/dist/esm/renderModes/ParticleRenderMode.js.map +1 -0
- package/dist/esm/renderModes/QuadParticles.d.ts +55 -0
- package/dist/esm/renderModes/QuadParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/QuadParticles.js +95 -0
- package/dist/esm/renderModes/QuadParticles.js.map +1 -0
- package/dist/esm/renderModes/RibbonParticles.d.ts +96 -0
- package/dist/esm/renderModes/RibbonParticles.d.ts.map +1 -0
- package/dist/esm/renderModes/RibbonParticles.js +202 -0
- package/dist/esm/renderModes/RibbonParticles.js.map +1 -0
- package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/mesh-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/mesh.vert.js +6 -0
- package/dist/esm/renderModes/shaders/mesh.vert.js.map +1 -0
- package/dist/esm/renderModes/shaders/quad-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/quad-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon-particles.wgsl.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon.frag.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon.frag.js.map +1 -0
- package/dist/esm/renderModes/shaders/ribbon.vert.js +6 -0
- package/dist/esm/renderModes/shaders/ribbon.vert.js.map +1 -0
- package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts +48 -20
- package/dist/esm/renderers/WebGl2ParticleRenderer.d.ts.map +1 -0
- package/dist/esm/renderers/WebGl2ParticleRenderer.js +317 -321
- package/dist/esm/renderers/WebGl2ParticleRenderer.js.map +1 -1
- package/dist/esm/renderers/WebGpuParticleRenderer.d.ts +99 -18
- package/dist/esm/renderers/WebGpuParticleRenderer.d.ts.map +1 -0
- package/dist/esm/renderers/WebGpuParticleRenderer.js +542 -551
- package/dist/esm/renderers/WebGpuParticleRenderer.js.map +1 -1
- package/dist/esm/renderers/shaders/particle.frag.js +6 -0
- package/dist/esm/renderers/shaders/particle.frag.js.map +1 -0
- package/dist/esm/renderers/shaders/particle.vert.js +6 -0
- package/dist/esm/renderers/shaders/particle.vert.js.map +1 -0
- package/package.json +8 -15
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/register.d.ts +0 -1
- package/dist/esm/register.js +0 -43
- package/dist/esm/register.js.map +0 -1
- package/dist/esm/renderers/glsl/particle.frag.js +0 -4
- package/dist/esm/renderers/glsl/particle.frag.js.map +0 -1
- package/dist/esm/renderers/glsl/particle.vert.js +0 -4
- package/dist/esm/renderers/glsl/particle.vert.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticleSystem.js","sources":["../../../src/ParticleSystem.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ParticleSystem.js","names":[],"sources":["../../src/ParticleSystem.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n\nimport type { Seconds } from '@codexo/exojs';\nimport { Rectangle } from '@codexo/exojs';\nimport { Drawable } from '@codexo/exojs';\nimport { logger } from '@codexo/exojs';\nimport { Spritesheet } from '@codexo/exojs';\nimport { Texture } from '@codexo/exojs';\nimport type { RenderPlanBuilder } from '@codexo/exojs/renderer-sdk';\nimport type { RenderBackend } from '@codexo/exojs/renderer-sdk';\n\nimport { ParticleGpuState } from '#gpu/ParticleGpuState';\nimport type { DeathModule } from '#modules/DeathModule';\nimport type { SpawnModule } from '#modules/SpawnModule';\nimport type { UpdateModule } from '#modules/UpdateModule';\nimport type { ParticleBatch, ParticleDeathContext, ParticleEmitter, ParticleWriter } from '#ParticleStorage';\nimport { ParticleSlotWriter, ParticleStorage } from '#ParticleStorage';\nimport type { ParticleRenderMode } from '#renderModes/ParticleRenderMode';\nimport { QuadParticles } from '#renderModes/QuadParticles';\n\nconst defaultCapacity = 4096;\n\n/**\n * Lazily-initialised 1×1 opaque-white texture used as the default sprite\n * when a {@link ParticleSystem} is constructed without one. Particles\n * render as solid color quads (the per-particle `color` channel times\n * white-with-alpha-1). Shared across systems to avoid wasted texture\n * allocations.\n */\nlet defaultWhiteTexture: Texture | null = null;\nconst getDefaultWhiteTexture = (): Texture => {\n if (defaultWhiteTexture === null) {\n const canvas = document.createElement('canvas');\n\n canvas.width = 1;\n canvas.height = 1;\n\n const ctx = canvas.getContext('2d');\n\n if (ctx !== null) {\n ctx.fillStyle = '#ffffff';\n ctx.fillRect(0, 0, 1, 1);\n }\n\n defaultWhiteTexture = new Texture(canvas);\n }\n\n return defaultWhiteTexture;\n};\n\n/**\n * The process-wide default render mode, created on first use.\n *\n * Every system constructed without `ParticleSystemOptions.render` draws with\n * this one instance. The backends key their GPU resources on the mode's\n * material, so sharing it means N systems cost one compiled program / pipeline\n * set, one vertex array object and one vertex buffer between them - what a\n * single system costs.\n *\n * Sharing the mode also shares its scratch buffer, which is safe because that\n * buffer is only live between a `build()` and the upload that immediately\n * follows it: the WebGL2 renderer flushes the pending system at the top of\n * every `render()` before building the next one, and the WebGPU renderer\n * copies the built bytes out through `queue.writeBuffer` before it moves on to\n * the next drawcall. That is exactly how the renderers behaved when each of\n * them owned one shared pack buffer for all systems.\n *\n * Never destroyed. It outlives every individual system (see\n * {@link ParticleSystem.destroy}), so a scene that destroys one system leaves\n * the others drawing and a system constructed afterwards reuses the already\n * compiled program instead of paying for a fresh one. The GPU resources behind\n * it are released by the backend when the renderer disconnects.\n */\nlet defaultRenderMode: ParticleRenderMode | null = null;\nconst getDefaultRenderMode = (): ParticleRenderMode => {\n defaultRenderMode ??= new QuadParticles();\n\n return defaultRenderMode;\n};\n\n/**\n * Options for {@link ParticleSystem}'s constructor - orthogonal config\n * that's independent of the texture source. Texture / frames / spritesheet\n * live in positional arguments to enforce mutual exclusivity at the type\n * level (you can't pass both a texture and a spritesheet by accident).\n */\nexport interface ParticleSystemOptions {\n /** Maximum particle count. Fixed at construction. Default 4096. */\n capacity?: number;\n /**\n * Direct GPU device. Lets advanced consumers wire a `GPUDevice` owned\n * outside an `Application` (or a mock device in tests). When omitted,\n * the backend reference is captured automatically on the first\n * {@link ParticleSystem.render} call - `WebGpuBackend` ⇒ GPU mode,\n * anything else (incl. WebGL2) ⇒ CPU mode.\n */\n device?: GPUDevice;\n /**\n * How this system's particles become vertices. Fixed at construction. A mode\n * with `gpuEligible === false` forces the system onto the CPU path -\n * silently, exactly like an update module without a `wgsl()` implementation,\n * and observable through {@link ParticleSystem.gpuMode}.\n *\n * **Ownership.** A mode passed here belongs to the system: the system\n * destroys it in {@link ParticleSystem.destroy}, which destroys the mode's\n * material and geometry and releases the GPU resources cached against them.\n * Pass one mode instance per system. Handing the same instance to two\n * systems is not supported - destroying either one pulls the material out\n * from under the other, which then silently rebuilds a fresh material and\n * pays for a fresh shader compile mid-life. Two systems that should share\n * one program simply omit this option; the default mode is shared for\n * exactly that reason and is not owned by any system.\n *\n * @default a process-wide shared {@link QuadParticles}\n */\n readonly render?: ParticleRenderMode;\n}\n\n/**\n * The central coordinator of the particle pipeline. `ParticleSystem` is a\n * {@link Drawable} that owns:\n *\n * - **Particle storage** - one channel per attribute (position, velocity,\n * scale, rotation, color, timing, ...), sized to a fixed capacity at\n * construction. Modules and render modes address it by name through a\n * {@link ParticleBatch}; user code brings particles into existence with\n * {@link emit}.\n * - **Spawn modules** - fill freshly emitted particles.\n * - **Update modules** - mutate the live range each frame (forces, color\n * blends, scale curves, drag, ...). Built-in modules ship both CPU and\n * WGSL implementations; custom modules can opt into GPU acceleration by\n * implementing `wgsl()`.\n * - **Death modules** - fire once per dying particle, before its slot is\n * recycled (sub-emitters, event hooks).\n *\n * **Auto-routing CPU vs GPU:** at first {@link update}, the system checks:\n * if a `WebGpuBackend` was supplied AND every registered update module has\n * `wgsl()` AND the render mode is GPU-eligible, the GPU path engages - a\n * composite compute pipeline runs\n * integration plus all module bodies in one dispatch and writes directly\n * into the renderer's instance buffer (no CPU readback). Otherwise the CPU\n * path runs the existing per-module `apply()` loops.\n *\n * **Per-frame order in {@link update} (CPU mode):**\n * 1. Run every spawn module.\n * 2. Integrate position from velocity, rotation from rotationSpeed, advance `elapsed`.\n * 3. Run every update module on the live range.\n * 4. Compact: scan `[0, liveCount)` forward, fire death modules on expired\n * slots, copy survivors down. `liveCount` shrinks to the survivor count.\n *\n * **Per-frame order in {@link update} (GPU mode):**\n * 1. Run every spawn module (CPU writes initial values into the spawn slot).\n * 2. Detect expiries on CPU (via `elapsed >= lifetime`); fire death modules;\n * set `lifetime[slot] = -1` sentinel + clear `alive[slot]` so the GPU\n * shader skips them. **No compaction** - slots are recycled on next spawn.\n * 3. Dispatch the composite compute pipeline. Integration + update modules\n * + pack-instances run in one pass; the instance buffer is written\n * directly. CPU SoA stays as-is for spawn writes.\n *\n * **Coordinate space:** particle positions are LOCAL to the system. The\n * system's `getGlobalTransform()` is applied on top during rendering - both\n * the WebGL2 and WebGPU shaders multiply `projection * translation * rotated`.\n * Setting world-space positions on individual particles double-translates.\n * Position the system itself via `system.setPosition(...)` and emit relative\n * to `(0, 0)`.\n *\n * **Pixel snapping:** {@link Drawable.pixelSnapMode} is intentionally ignored\n * for particle systems. Particle instances bake their own per-particle\n * transforms in the emitter/compute path rather than reading the shared\n * pixel-snap transform row, so a snap mode set on the system has no effect on\n * rendered output - snapping thousands of independently-moving sub-pixel\n * particles to the device grid is neither meaningful nor desirable.\n *\n * @example\n * // Backend-agnostic - runs CPU on WebGL2, GPU on WebGPU automatically.\n * const system = new ParticleSystem(loader.get('spark.png'), {\n * capacity: 8192,\n * });\n *\n * system.addSpawnModule(new RateSpawn({ rate: new Constant(60), ... }));\n * system.addUpdateModule(new ApplyForce(0, 980)); // gravity, GPU-eligible\n * system.addUpdateModule(new ColorOverLifetime(fireGradient));\n * scene.addChild(system);\n */\nexport class ParticleSystem extends Drawable implements ParticleEmitter {\n /** Maximum particle count this system will store. Fixed at construction. */\n public readonly capacity: number;\n\n /**\n * The simulation's channel storage. Handed to update modules and render modes\n * as a {@link ParticleBatch}; never exposed as a property of the system,\n * because outside those two callbacks its integrated values are not\n * backend-true.\n * @internal\n */\n public readonly _storage: ParticleStorage;\n\n private _writer: ParticleSlotWriter;\n\n private readonly _spawnModules: SpawnModule[] = [];\n private readonly _updateModules: UpdateModule[] = [];\n private readonly _deathModules: DeathModule[] = [];\n\n private _backend: RenderBackend | null = null;\n private readonly _device: GPUDevice | null = null;\n private _gpuState: ParticleGpuState | null = null;\n private _gpuMode = false;\n private _compiled = false;\n private _spawnHint = 0; // round-robin pointer for first-dead lookup in GPU mode\n /**\n * In GPU mode, slots whose CPU SoA values need re-uploading to the GPU\n * (newly spawned, or just-expired with lifetime sentinel). Cleared\n * after each compute dispatch. CPU never overwrites integrated GPU\n * state - only dirty slots flow CPU → GPU.\n */\n private readonly _gpuDirtySlots = new Set<number>();\n /**\n * Spawn lifetimes, in death order per slot, of the particles that expired\n * since the last batch the device staged for readback. The device's own\n * record cannot carry them: by the time the shader sees the particle, the CPU\n * has already overwritten its lifetime with the expiry sentinel. A slot can\n * appear more than once when it is recycled and dies again before the batch\n * is staged, so the lifetimes queue up per slot.\n */\n private _pendingDeathLifetimes = new Map<number, number[]>();\n\n /** Total entries across `_pendingDeathLifetimes`, which is what the dispatch reports. */\n private _pendingDeathCount = 0;\n\n /** Whether this system has already reported that its death backlog overflowed. */\n private _deathOverflowReported = false;\n /**\n * Slots handed out by `spawn()` while a recording window is open, or `null`\n * when nothing is recording. Lets callers identify freshly spawned particles\n * without diffing `liveCount`, which cannot see a recycled GPU slot.\n */\n private _spawnRecord: number[] | null = null;\n\n private readonly _renderMode: ParticleRenderMode;\n /** Whether {@link destroy} may destroy {@link _renderMode} - false for the shared default. */\n private readonly _ownsRenderMode: boolean;\n\n private _texture: Texture;\n private readonly _frames: Rectangle[] = [];\n private readonly _textureFrame: Rectangle = new Rectangle();\n private readonly _vertices: Float32Array = new Float32Array(4);\n private readonly _texCoords: Uint32Array = new Uint32Array(4);\n private _updateTexCoords = true;\n private _updateVertices = true;\n\n /** No texture - particles render as solid-color quads on a 1×1 white default. */\n public constructor(options?: ParticleSystemOptions);\n /** Single texture, no atlas - every particle uses the full texture as one frame. */\n public constructor(texture: Texture, options?: ParticleSystemOptions);\n /** Multi-frame atlas - each particle's `textureIndex` selects a frame. */\n public constructor(texture: Texture, frames: readonly Rectangle[], options?: ParticleSystemOptions);\n /** Spritesheet shorthand - texture + frames pulled from the sheet. */\n public constructor(spritesheet: Spritesheet, options?: ParticleSystemOptions);\n public constructor(\n sourceOrOptions?: Texture | Spritesheet | ParticleSystemOptions,\n framesOrOptions?: readonly Rectangle[] | ParticleSystemOptions,\n finalOptions?: ParticleSystemOptions,\n ) {\n super();\n\n // Disambiguate the four valid call shapes via instanceof checks.\n // The TS overloads above already prevent illegal combinations like\n // `(texture, sheet)` or `(sheet, frames)` at compile time; this\n // narrowing only sorts out the legal ones.\n let texture: Texture | null = null;\n let frames: readonly Rectangle[] | null = null;\n let options: ParticleSystemOptions;\n\n if (sourceOrOptions instanceof Texture) {\n texture = sourceOrOptions;\n\n if (Array.isArray(framesOrOptions)) {\n frames = framesOrOptions;\n options = finalOptions ?? {};\n } else {\n options = (framesOrOptions as ParticleSystemOptions | undefined) ?? {};\n }\n } else if (sourceOrOptions instanceof Spritesheet) {\n texture = sourceOrOptions.texture;\n frames = [...sourceOrOptions.frames.values()];\n options = (framesOrOptions as ParticleSystemOptions | undefined) ?? {};\n } else {\n options = sourceOrOptions ?? {};\n }\n\n const capacity = options.capacity ?? defaultCapacity;\n\n if (capacity <= 0 || !Number.isInteger(capacity)) {\n throw new Error(`ParticleSystem capacity must be a positive integer (got ${capacity}).`);\n }\n\n this.capacity = capacity;\n this._storage = new ParticleStorage(capacity);\n this._writer = new ParticleSlotWriter(this._storage);\n\n this._device = options.device ?? null;\n // A mode the caller supplied is this system's to destroy; the default is\n // shared with every other system that did not supply one, so it is not.\n this._ownsRenderMode = options.render !== undefined;\n this._renderMode = options.render ?? getDefaultRenderMode();\n this._texture = texture ?? getDefaultWhiteTexture();\n\n if (frames !== null) {\n for (const frame of frames) {\n this._frames.push(frame.clone());\n }\n }\n\n this.resetTextureFrame();\n }\n\n /**\n * The render mode this system's particles are drawn with. Fixed at\n * construction via `ParticleSystemOptions.render`; the backend renderers\n * read it every draw to learn the vertex layout, shader and draw model.\n *\n * Without that option this is the shared default mode - the same instance\n * every other defaulted system draws with, so do not destroy it or mutate\n * its material.\n */\n public get renderMode(): ParticleRenderMode {\n return this._renderMode;\n }\n\n public get texture(): Texture {\n return this._texture;\n }\n\n public set texture(texture: Texture) {\n this.setTexture(texture);\n }\n\n public get textureFrame(): Rectangle {\n return this._textureFrame;\n }\n\n public set textureFrame(frame: Rectangle) {\n this.setTextureFrame(frame);\n }\n\n /**\n * Atlas frames declared on this system, or empty when the texture is\n * used as a single frame. Each particle's {@link textureIndex} selects\n * an entry from this list; anything out of range shows frame 0.\n */\n public get frames(): readonly Rectangle[] {\n return this._frames;\n }\n\n /** `true` when the system declares more than one atlas frame. */\n public get hasAtlas(): boolean {\n return this._frames.length > 1;\n }\n\n public get vertices(): Float32Array {\n if (this._updateVertices) {\n const { x, y, width, height } = this._textureFrame;\n const offsetX = width / 2;\n const offsetY = height / 2;\n\n this._vertices[0] = x - offsetX;\n this._vertices[1] = y - offsetY;\n this._vertices[2] = width - offsetX;\n this._vertices[3] = height - offsetY;\n\n this._updateVertices = false;\n }\n\n return this._vertices;\n }\n\n public get texCoords(): Uint32Array {\n if (this._updateTexCoords) {\n const { width, height } = this._texture;\n const { left, top, right, bottom } = this._textureFrame;\n const minX = ((left / width) * 65535) & 65535;\n const minY = (((top / height) * 65535) & 65535) << 16;\n const maxX = ((right / width) * 65535) & 65535;\n const maxY = (((bottom / height) * 65535) & 65535) << 16;\n\n if (this._texture.flipY) {\n this._texCoords[0] = maxY | minX;\n this._texCoords[1] = maxY | maxX;\n this._texCoords[2] = minY | maxX;\n this._texCoords[3] = minY | minX;\n } else {\n this._texCoords[0] = minY | minX;\n this._texCoords[1] = minY | maxX;\n this._texCoords[2] = maxY | maxX;\n this._texCoords[3] = maxY | minX;\n }\n\n this._updateTexCoords = false;\n }\n\n return this._texCoords;\n }\n\n /** `true` when the system is running on the GPU compute pipeline. */\n public get gpuMode(): boolean {\n return this._gpuMode;\n }\n\n /** GPU-side state, or `null` in CPU mode. */\n public get gpuState(): ParticleGpuState | null {\n return this._gpuState;\n }\n\n /**\n * Upper bound of the slot range that can hold live particles.\n *\n * Exact on the CPU path: after each `update()` slots `[0, liveCount)` are all\n * alive. On the GPU path it is a high-water mark whose range can contain dead\n * holes that future emissions fill; {@link aliveCount} counts the live ones.\n */\n public get liveCount(): number {\n return this._storage.count;\n }\n\n /** Actual count of live particles. May be below {@link liveCount} on the GPU path. */\n public get aliveCount(): number {\n const { alive, count } = this._storage;\n let live = 0;\n\n for (let i = 0; i < count; i++) {\n if (alive[i] === 1) live++;\n }\n\n return live;\n }\n\n public get spawnModules(): readonly SpawnModule[] {\n return this._spawnModules;\n }\n\n public get updateModules(): readonly UpdateModule[] {\n return this._updateModules;\n }\n\n public get deathModules(): readonly DeathModule[] {\n return this._deathModules;\n }\n\n public setTexture(texture: Texture): this {\n if (this._texture !== texture) {\n this._texture = texture;\n this.resetTextureFrame();\n }\n\n return this;\n }\n\n public setTextureFrame(frame: Rectangle): this {\n this._textureFrame.copy(frame);\n this._updateTexCoords = true;\n this._updateVertices = true;\n\n this._setLocalBounds(0, 0, frame.width, frame.height);\n\n return this;\n }\n\n public resetTextureFrame(): this {\n return this.setTextureFrame(Rectangle.temp.set(0, 0, this._texture.width, this._texture.height));\n }\n\n public addSpawnModule(mod: SpawnModule): this {\n this._spawnModules.push(mod);\n\n return this;\n }\n\n /**\n * Registers an update module. Modules run in registration order, each seeing\n * what the previous ones did.\n *\n * Modules may be added and removed at any time, including mid-flight: the\n * next update rebuilds whatever the change invalidated. On the GPU path that\n * is the compute program alone - live particles keep the state the device has\n * been integrating. Adding a module without a `wgsl()` implementation to a\n * running GPU system is the one change that cannot preserve them: the\n * simulation moves to the CPU, which has no copy of the integrated state, so\n * the system clears its live particles rather than continuing from stale\n * values (see {@link clearParticles}).\n */\n public addUpdateModule(mod: UpdateModule): this {\n this._updateModules.push(mod);\n this._invalidateProgram();\n\n return this;\n }\n\n public addDeathModule(mod: DeathModule): this {\n const hadNone = this._deathModules.length === 0;\n\n this._deathModules.push(mod);\n\n // The GPU program only carries the death-reporting path when the system has\n // a death module, so gaining the first one rebuilds it.\n if (hadNone) {\n this._invalidateProgram();\n }\n\n return this;\n }\n\n public clearSpawnModules(): this {\n for (const mod of this._spawnModules) mod.destroy();\n\n this._spawnModules.length = 0;\n\n return this;\n }\n\n public clearUpdateModules(): this {\n for (const mod of this._updateModules) mod.destroy();\n\n this._updateModules.length = 0;\n this._invalidateProgram();\n\n return this;\n }\n\n public clearDeathModules(): this {\n for (const mod of this._deathModules) mod.destroy();\n\n this._deathModules.length = 0;\n this._invalidateProgram();\n\n return this;\n }\n\n /**\n * Brings one particle into existence and returns a writer for its initial\n * values, or `null` when the system is at {@link capacity}.\n *\n * The particle starts at the spawn defaults - origin, no velocity, unit\n * scale, no rotation, opaque white, frame 0, one second of life - so a caller\n * writes only what it varies. The returned writer is a cursor that the next\n * `emit()` rebinds, so it must not be stored.\n *\n * Emission is the only per-particle write that is true on every backend:\n * spawn values originate on the CPU and are uploaded from there, while\n * everything the simulation integrates afterwards lives wherever the\n * simulation runs.\n *\n * @example\n * ```ts\n * const particle = system.emit();\n *\n * if (particle) {\n * particle.position.set(120, 40);\n * particle.velocity.set(0, -80);\n * particle.lifetime = 2;\n * }\n * ```\n */\n public emit(): ParticleWriter | null {\n const slot = this._spawnSlot();\n\n if (slot < 0) {\n return null;\n }\n\n if (__DEV__) {\n // One writer per emission in development, so a writer kept past the next\n // emit() throws on use rather than filling the wrong particle. Production\n // keeps the single cursor: the check teaches the contract, it does not\n // enforce it at runtime cost.\n this._writer.retire();\n this._writer = new ParticleSlotWriter(this._storage);\n }\n\n return this._writer.bind(slot);\n }\n\n /**\n * Allocates one slot at the spawn defaults and returns its index, or `-1` at\n * capacity. Backs {@link emit}; the simulation's own machinery addresses\n * particles by slot, the public surface does not.\n * @internal\n */\n public _spawnSlot(): number {\n const slot = this._gpuMode ? this._spawnGpu() : this._spawnCpu();\n\n if (slot >= 0) {\n this._storage.reset(slot);\n }\n\n return slot;\n }\n\n /**\n * Begin recording the slots handed out by {@link spawn}.\n *\n * Callers that post-process freshly spawned particles cannot infer which\n * slots those are from {@link liveCount}: in GPU mode a spawn may recycle a\n * dead slot below the high-water mark, leaving the count unchanged, and the\n * reused slots are scattered rather than contiguous. Pass the returned token\n * back to {@link _endSpawnRecording}.\n *\n * @internal\n */\n public _beginSpawnRecording(): number[] | null {\n const previous = this._spawnRecord;\n\n this._spawnRecord = [];\n\n return previous;\n }\n\n /**\n * End the recording started by {@link _beginSpawnRecording} and return the\n * slots allocated during it. Slots are also handed to an enclosing recording\n * so a nested spawn stays visible to the outer window.\n *\n * @internal\n */\n public _endSpawnRecording(previous: number[] | null): readonly number[] {\n const recorded = this._spawnRecord ?? [];\n\n this._spawnRecord = previous;\n\n if (previous !== null) {\n for (const slot of recorded) {\n previous.push(slot);\n }\n }\n\n return recorded;\n }\n\n /**\n * Shifts the particles a sub-emitter just produced by `(x, y)`, so a child\n * spawner's distributions read as offsets from the death position.\n * @internal\n */\n public _offsetSpawned(slots: readonly number[], x: number, y: number): void {\n const { posX, posY } = this._storage;\n\n for (const slot of slots) {\n posX[slot] = posX[slot]! + x;\n posY[slot] = posY[slot]! + y;\n }\n }\n\n /** Resets the system to zero live particles without destroying it. */\n public clearParticles(): this {\n const storage = this._storage;\n\n storage.count = 0;\n this._spawnHint = 0;\n storage.alive.fill(0);\n storage.lifetime.fill(0);\n storage.elapsed.fill(0);\n\n return this;\n }\n\n /**\n * @internal\n *\n * Collect-hook: captures the active backend before this node is emitted so\n * the next `update()` can compile a GPU pipeline if the backend turned out\n * to be `WebGpuBackend`. Re-captures and rebuilds when the backend\n * reference changes (e.g. after device-loss recovery).\n */\n /** @internal */\n public override _collect(builder: RenderPlanBuilder, seq?: number): void {\n const backend = builder.backend;\n\n if (this._backend !== backend) {\n this._backend = backend;\n\n if (this._gpuState !== null) {\n this._gpuState.destroy();\n this._gpuState = null;\n }\n\n this._gpuMode = false;\n this._compiled = false;\n }\n\n super._collect(builder, seq);\n }\n\n /** Per-frame entry point. Routes to CPU or GPU pipeline based on auto-detection at first call. */\n public update(delta: Seconds): this {\n if (!this._compiled) {\n this._compile();\n }\n\n const dt = delta;\n\n // 1. Emit (CPU writes storage in both modes).\n for (let i = 0; i < this._spawnModules.length; i++) {\n this._spawnModules[i]!.apply(this, dt);\n }\n\n if (this._gpuMode) {\n this._updateGpu(dt);\n } else {\n this._updateCpu(dt);\n }\n\n return this;\n }\n\n public override destroy(): void {\n super.destroy();\n\n this.clearSpawnModules();\n this.clearUpdateModules();\n this.clearDeathModules();\n\n // Only a mode this system exclusively owns goes down with it. The shared\n // default is process-wide: destroying it here would tear the material,\n // geometry and compiled program out from under every other system still\n // drawing with it.\n if (this._ownsRenderMode) {\n this._renderMode.destroy();\n }\n\n if (this._gpuState !== null) {\n this._gpuState.destroy();\n this._gpuState = null;\n }\n\n for (const frame of this._frames) {\n frame.destroy();\n }\n this._frames.length = 0;\n\n this._gpuMode = false;\n this._compiled = false;\n this._storage.count = 0;\n this._storage.alive.fill(0);\n this._textureFrame.destroy();\n }\n\n /**\n * Marks the compiled program stale. The next update decides what that costs:\n * a GPU system that stays GPU-eligible rebuilds only its program, everything\n * else follows the transition rules in {@link _compile}.\n */\n private _invalidateProgram(): void {\n this._compiled = false;\n }\n\n private _compile(): void {\n this._compiled = true;\n\n const eligible = this._updateModules.every(m => typeof m.wgsl === 'function') && this._renderMode.gpuEligible;\n\n // Already running on the GPU: keep the buffers the device has been\n // integrating and swap the program, or - when the change made the system\n // CPU-only - drop the state and the particles with it, because the CPU\n // holds no copy of what the device computed.\n if (this._gpuState !== null) {\n if (eligible) {\n this._gpuState.setProgram(this._updateModules, this._deathModules.length > 0);\n\n return;\n }\n\n this._gpuState.destroy();\n this._gpuState = null;\n this._gpuMode = false;\n this._gpuDirtySlots.clear();\n this.clearParticles();\n\n return;\n }\n\n // Duck-typed `instanceof WebGpuBackend` - avoids importing the\n // backend class (which registers a renderer for ParticleSystem\n // and would create a circular dependency). WebGl2Backend has no\n // `device` field, so this naturally falls back to CPU mode.\n const backendDevice = (this._backend as { device?: GPUDevice } | null)?.device ?? null;\n const device = this._device ?? backendDevice;\n\n if (device === null) {\n return;\n }\n\n if (!eligible) {\n return;\n }\n\n this._gpuState = new ParticleGpuState(device, this.capacity, this._updateModules, this._frames, this._texture, this._deathModules.length > 0);\n this._gpuMode = true;\n\n // Mark every currently-alive slot dirty so the initial upload\n // matches CPU state; subsequent frames only push deltas.\n const { alive, count } = this._storage;\n\n for (let i = 0; i < count; i++) {\n if (alive[i] === 1) this._gpuDirtySlots.add(i);\n }\n }\n\n private _spawnCpu(): number {\n const storage = this._storage;\n\n if (storage.count >= this.capacity) {\n return -1;\n }\n\n const slot = storage.count++;\n\n storage.alive[slot] = 1;\n this._spawnRecord?.push(slot);\n\n return slot;\n }\n\n private _spawnGpu(): number {\n const capacity = this.capacity;\n const storage = this._storage;\n const alive = storage.alive;\n const start = this._spawnHint;\n\n // Search forward from hint, then wrap.\n for (let i = start; i < capacity; i++) {\n if (alive[i] === 0) {\n return this._claimGpuSlot(i, i + 1 === capacity ? 0 : i + 1);\n }\n }\n\n for (let i = 0; i < start; i++) {\n if (alive[i] === 0) {\n return this._claimGpuSlot(i, i + 1);\n }\n }\n\n return -1;\n }\n\n private _claimGpuSlot(slot: number, nextHint: number): number {\n const storage = this._storage;\n\n storage.alive[slot] = 1;\n this._spawnHint = nextHint;\n\n if (slot >= storage.count) {\n storage.count = slot + 1;\n }\n\n this._gpuDirtySlots.add(slot);\n this._spawnRecord?.push(slot);\n\n return slot;\n }\n\n private _updateCpu(dt: number): void {\n const storage = this._storage;\n const { posX, posY, velX, velY, rotations, rotationSpeeds, elapsed, lifetime, alive } = storage;\n const liveCount = storage.count;\n\n for (let i = 0; i < liveCount; i++) {\n posX[i] = posX[i]! + velX[i]! * dt;\n posY[i] = posY[i]! + velY[i]! * dt;\n rotations[i] = rotations[i]! + rotationSpeeds[i]! * dt;\n elapsed[i] = elapsed[i]! + dt;\n }\n\n for (let i = 0; i < this._updateModules.length; i++) {\n this._updateModules[i]!.apply(storage, dt);\n }\n\n // Compact: forward pass, report deaths on expired, copy survivors down.\n const deathModules = this._deathModules;\n let writeIndex = 0;\n\n for (let readIndex = 0; readIndex < storage.count; readIndex++) {\n if (elapsed[readIndex]! >= lifetime[readIndex]!) {\n if (deathModules.length > 0) {\n this._reportDeath(storage.snapshot(readIndex));\n }\n\n alive[readIndex] = 0;\n continue;\n }\n\n if (writeIndex !== readIndex) {\n storage.copySlot(readIndex, writeIndex);\n alive[writeIndex] = 1;\n }\n\n writeIndex++;\n }\n\n for (let i = writeIndex; i < storage.count; i++) {\n alive[i] = 0;\n }\n\n storage.count = writeIndex;\n }\n\n /** Hands one death snapshot to every registered death module, in registration order. */\n private _reportDeath(death: ParticleDeathContext): void {\n const deathModules = this._deathModules;\n\n for (let m = 0; m < deathModules.length; m++) {\n deathModules[m]!.onDeath(this, death);\n }\n }\n\n private _updateGpu(dt: number): void {\n // CPU advances its own copy of `elapsed` for expire detection only.\n // GPU's `timing[idx].x` is advanced independently inside the compute\n // shader; the two are never synced after spawn. They tick at the\n // same rate (both add `dt` per frame) so they stay equivalent in\n // practice (modulo numerical drift).\n const storage = this._storage;\n const { elapsed, lifetime, alive } = storage;\n const liveCount = storage.count;\n const reportsDeaths = this._deathModules.length > 0;\n\n for (let i = 0; i < liveCount; i++) {\n if (alive[i] === 0) continue;\n\n elapsed[i] = elapsed[i]! + dt;\n\n if (elapsed[i]! >= lifetime[i]!) {\n // The lifetime is about to become the expiry sentinel, so keep the one\n // the particle was spawned with: it is the CPU's own value, and the\n // record the device appends carries only what the device integrated.\n if (reportsDeaths) {\n const queued = this._pendingDeathLifetimes.get(i);\n\n if (queued === undefined) {\n this._pendingDeathLifetimes.set(i, [lifetime[i]!]);\n } else {\n queued.push(lifetime[i]!);\n }\n\n this._pendingDeathCount++;\n }\n\n alive[i] = 0;\n lifetime[i] = -1; // sentinel - the shader captures it, then skips\n\n // Only the sentinel goes up. A full slot upload would overwrite the\n // position and velocity the device integrated with the CPU's spawn-time\n // copy, which is precisely the staleness the death record avoids.\n this._gpuDirtySlots.delete(i);\n this._gpuState!.uploadExpiry(i);\n }\n }\n\n // Push dirty slots (new spawns + just-expired) to GPU. CPU is NOT\n // the source of truth for integrated position/velocity/etc. after\n // spawn - uploading the full live range every frame would wipe\n // out GPU's integrated state.\n if (this._gpuDirtySlots.size > 0) {\n this._gpuState!.uploadDirty(this, this._gpuDirtySlots);\n this._gpuDirtySlots.clear();\n }\n\n if (__DEV__ && this._pendingDeathCount > storage.capacity && !this._deathOverflowReported) {\n this._deathOverflowReported = true;\n logger.warn(\n `ParticleSystem: the device held back ${this._pendingDeathCount} unreported deaths, more than the system's capacity of ${storage.capacity}. ` +\n 'The excess is dropped: those particles expire without a death callback. Deaths queue on the device while readbacks are in flight, ' +\n 'so this means either the death callbacks are outpacing the readback or the system recycles slots faster than it can report them.',\n { source: 'particles' },\n );\n }\n\n // Dispatch over the pre-trim range: a slot that expired at the tail still\n // has to be visited once, or its death record is never appended.\n const staged = this._gpuState!.dispatch(dt, liveCount, this._pendingDeathCount);\n\n // Trim trailing dead slots for the next frame.\n let newLiveCount = storage.count;\n while (newLiveCount > 0 && alive[newLiveCount - 1] === 0) {\n newLiveCount--;\n }\n storage.count = newLiveCount;\n\n // Deaths the device could not stage stay queued here: they are appended\n // behind the ones already in the death buffer and travel with the batch\n // that does get staged.\n if (staged) {\n const pending = this._pendingDeathLifetimes;\n\n this._pendingDeathLifetimes = new Map();\n this._pendingDeathCount = 0;\n\n void this._drainDeaths(pending);\n }\n }\n\n /**\n * Delivers a staged batch of deaths once its readback has landed. Each record\n * carries what the device integrated; the lifetime comes from the CPU, which\n * is where it was written at spawn.\n */\n private async _drainDeaths(pending: Map<number, number[]>): Promise<void> {\n await this._gpuState?.readDeaths(records => {\n for (const record of records) {\n this._reportDeath({\n x: record.x,\n y: record.y,\n velocityX: record.velocityX,\n velocityY: record.velocityY,\n rotation: record.rotation,\n scaleX: record.scaleX,\n scaleY: record.scaleY,\n color: record.color,\n elapsed: record.elapsed,\n // Records are slot-ordered and, within a slot, in the order the\n // device appended them - which is the order the lifetimes queued.\n lifetime: pending.get(record.slot)?.shift() ?? 0,\n });\n }\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoxArea.d.ts","sourceRoot":"","sources":["../../../src/distributions/BoxArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;GAIG;AACH,qBAAa,OAAQ,YAAW,YAAY,CAAC,MAAM,CAAC;IAIzC,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,QAAQ,GAAG,MAAM;IAPhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAGhC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,QAAQ,GAAG,MAAiB;IAGpC,MAAM,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM;CAwBnD"}
|
|
@@ -1,48 +1,42 @@
|
|
|
1
|
-
import { Vector } from
|
|
1
|
+
import { Vector } from "@codexo/exojs";
|
|
2
2
|
|
|
3
|
+
//#region src/distributions/BoxArea.ts
|
|
3
4
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
out.set(this.maxX - (t - w - h), this.maxY);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
out.set(this.minX, this.maxY - (t - w * 2 - h));
|
|
42
|
-
}
|
|
43
|
-
return out;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
5
|
+
* Random point inside an axis-aligned box. With `mode: 'edge'` the result
|
|
6
|
+
* lies on the perimeter (uniform along all four edges combined); with
|
|
7
|
+
* `mode: 'volume'` (default) it's uniformly distributed across the area.
|
|
8
|
+
*/
|
|
9
|
+
var BoxArea = class {
|
|
10
|
+
minX;
|
|
11
|
+
maxX;
|
|
12
|
+
minY;
|
|
13
|
+
maxY;
|
|
14
|
+
mode;
|
|
15
|
+
_scratch = new Vector();
|
|
16
|
+
constructor(minX, maxX, minY, maxY, mode = "volume") {
|
|
17
|
+
this.minX = minX;
|
|
18
|
+
this.maxX = maxX;
|
|
19
|
+
this.minY = minY;
|
|
20
|
+
this.maxY = maxY;
|
|
21
|
+
this.mode = mode;
|
|
22
|
+
}
|
|
23
|
+
sample(out = this._scratch) {
|
|
24
|
+
if (this.mode === "volume") {
|
|
25
|
+
out.set(this.minX + Math.random() * (this.maxX - this.minX), this.minY + Math.random() * (this.maxY - this.minY));
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
const w = this.maxX - this.minX;
|
|
29
|
+
const h = this.maxY - this.minY;
|
|
30
|
+
const perimeter = (w + h) * 2;
|
|
31
|
+
const t = Math.random() * perimeter;
|
|
32
|
+
if (t < w) out.set(this.minX + t, this.minY);
|
|
33
|
+
else if (t < w + h) out.set(this.maxX, this.minY + (t - w));
|
|
34
|
+
else if (t < w * 2 + h) out.set(this.maxX - (t - w - h), this.maxY);
|
|
35
|
+
else out.set(this.minX, this.maxY - (t - w * 2 - h));
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
46
39
|
|
|
40
|
+
//#endregion
|
|
47
41
|
export { BoxArea };
|
|
48
|
-
//# sourceMappingURL=BoxArea.js.map
|
|
42
|
+
//# sourceMappingURL=BoxArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BoxArea.js","sources":["
|
|
1
|
+
{"version":3,"file":"BoxArea.js","names":[],"sources":["../../../src/distributions/BoxArea.ts"],"sourcesContent":["import { Vector } from '@codexo/exojs';\n\nimport type { Distribution } from './Distribution';\n\n/**\n * Random point inside an axis-aligned box. With `mode: 'edge'` the result\n * lies on the perimeter (uniform along all four edges combined); with\n * `mode: 'volume'` (default) it's uniformly distributed across the area.\n */\nexport class BoxArea implements Distribution<Vector> {\n private readonly _scratch = new Vector();\n\n public constructor(\n public minX: number,\n public maxX: number,\n public minY: number,\n public maxY: number,\n public mode: 'volume' | 'edge' = 'volume',\n ) {}\n\n public sample(out: Vector = this._scratch): Vector {\n if (this.mode === 'volume') {\n out.set(this.minX + Math.random() * (this.maxX - this.minX), this.minY + Math.random() * (this.maxY - this.minY));\n\n return out;\n }\n\n const w = this.maxX - this.minX;\n const h = this.maxY - this.minY;\n const perimeter = (w + h) * 2;\n const t = Math.random() * perimeter;\n\n if (t < w) {\n out.set(this.minX + t, this.minY);\n } else if (t < w + h) {\n out.set(this.maxX, this.minY + (t - w));\n } else if (t < w * 2 + h) {\n out.set(this.maxX - (t - w - h), this.maxY);\n } else {\n out.set(this.minX, this.maxY - (t - w * 2 - h));\n }\n\n return out;\n }\n}\n"],"mappings":";;;;;;;;AASA,IAAa,UAAb,MAAqD;CAI1C;CACA;CACA;CACA;CACA;CAPT,AAAiB,WAAW,IAAI,OAAO;CAEvC,AAAO,YACL,AAAO,MACP,AAAO,MACP,AAAO,MACP,AAAO,MACP,AAAO,OAA0B,UACjC;EALO;EACA;EACA;EACA;EACA;CACN;CAEH,AAAO,OAAO,MAAc,KAAK,UAAkB;EACjD,IAAI,KAAK,SAAS,UAAU;GAC1B,IAAI,IAAI,KAAK,OAAO,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,KAAK;GAEhH,OAAO;EACT;EAEA,MAAM,IAAI,KAAK,OAAO,KAAK;EAC3B,MAAM,IAAI,KAAK,OAAO,KAAK;EAC3B,MAAM,aAAa,IAAI,KAAK;EAC5B,MAAM,IAAI,KAAK,OAAO,IAAI;EAE1B,IAAI,IAAI,GACN,IAAI,IAAI,KAAK,OAAO,GAAG,KAAK,IAAI;OAC3B,IAAI,IAAI,IAAI,GACjB,IAAI,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,EAAE;OACjC,IAAI,IAAI,IAAI,IAAI,GACrB,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,IAAI,KAAK,IAAI;OAE1C,IAAI,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,EAAE;EAGhD,OAAO;CACT;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CircleArea.d.ts","sourceRoot":"","sources":["../../../src/distributions/CircleArea.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;;;;GAOG;AACH,qBAAa,UAAW,YAAW,YAAY,CAAC,MAAM,CAAC;IAI5C,OAAO,EAAE,MAAM;IACf,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,QAAQ,GAAG,MAAM;IANhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAGhC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,QAAQ,GAAG,MAAiB;IAGpC,MAAM,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM;CAQnD"}
|
|
@@ -1,33 +1,35 @@
|
|
|
1
|
-
import { Vector } from
|
|
1
|
+
import { Vector } from "@codexo/exojs";
|
|
2
2
|
|
|
3
|
+
//#region src/distributions/CircleArea.ts
|
|
3
4
|
const tau = Math.PI * 2;
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
6
|
+
* Random point on or inside a circle of radius `radius`, centred at
|
|
7
|
+
* `(centerX, centerY)`. With `mode: 'edge'` the result lies exactly on the
|
|
8
|
+
* circumference; with `mode: 'volume'` (default) it lies anywhere in the
|
|
9
|
+
* disk, with uniform area density (sqrt-of-random-radius distribution).
|
|
10
|
+
*
|
|
11
|
+
* Use as a spawn-position distribution for circular emitters.
|
|
12
|
+
*/
|
|
13
|
+
var CircleArea = class {
|
|
14
|
+
centerX;
|
|
15
|
+
centerY;
|
|
16
|
+
radius;
|
|
17
|
+
mode;
|
|
18
|
+
_scratch = new Vector();
|
|
19
|
+
constructor(centerX, centerY, radius, mode = "volume") {
|
|
20
|
+
this.centerX = centerX;
|
|
21
|
+
this.centerY = centerY;
|
|
22
|
+
this.radius = radius;
|
|
23
|
+
this.mode = mode;
|
|
24
|
+
}
|
|
25
|
+
sample(out = this._scratch) {
|
|
26
|
+
const angle = Math.random() * tau;
|
|
27
|
+
const r = this.mode === "edge" ? this.radius : this.radius * Math.sqrt(Math.random());
|
|
28
|
+
out.set(this.centerX + Math.cos(angle) * r, this.centerY + Math.sin(angle) * r);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
31
32
|
|
|
33
|
+
//#endregion
|
|
32
34
|
export { CircleArea };
|
|
33
|
-
//# sourceMappingURL=CircleArea.js.map
|
|
35
|
+
//# sourceMappingURL=CircleArea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CircleArea.js","sources":["
|
|
1
|
+
{"version":3,"file":"CircleArea.js","names":[],"sources":["../../../src/distributions/CircleArea.ts"],"sourcesContent":["import { Vector } from '@codexo/exojs';\n\nimport type { Distribution } from './Distribution';\n\nconst tau = Math.PI * 2;\n\n/**\n * Random point on or inside a circle of radius `radius`, centred at\n * `(centerX, centerY)`. With `mode: 'edge'` the result lies exactly on the\n * circumference; with `mode: 'volume'` (default) it lies anywhere in the\n * disk, with uniform area density (sqrt-of-random-radius distribution).\n *\n * Use as a spawn-position distribution for circular emitters.\n */\nexport class CircleArea implements Distribution<Vector> {\n private readonly _scratch = new Vector();\n\n public constructor(\n public centerX: number,\n public centerY: number,\n public radius: number,\n public mode: 'volume' | 'edge' = 'volume',\n ) {}\n\n public sample(out: Vector = this._scratch): Vector {\n const angle = Math.random() * tau;\n const r = this.mode === 'edge' ? this.radius : this.radius * Math.sqrt(Math.random());\n\n out.set(this.centerX + Math.cos(angle) * r, this.centerY + Math.sin(angle) * r);\n\n return out;\n }\n}\n"],"mappings":";;;AAIA,MAAM,MAAM,KAAK,KAAK;;;;;;;;;AAUtB,IAAa,aAAb,MAAwD;CAI7C;CACA;CACA;CACA;CANT,AAAiB,WAAW,IAAI,OAAO;CAEvC,AAAO,YACL,AAAO,SACP,AAAO,SACP,AAAO,QACP,AAAO,OAA0B,UACjC;EAJO;EACA;EACA;EACA;CACN;CAEH,AAAO,OAAO,MAAc,KAAK,UAAkB;EACjD,MAAM,QAAQ,KAAK,OAAO,IAAI;EAC9B,MAAM,IAAI,KAAK,SAAS,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK,KAAK,KAAK,OAAO,CAAC;EAEpF,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,KAAK,IAAI,GAAG,KAAK,UAAU,KAAK,IAAI,KAAK,IAAI,CAAC;EAE9E,OAAO;CACT;AACF"}
|
|
@@ -12,8 +12,8 @@ export interface ColorGradientKey {
|
|
|
12
12
|
* is cached so monotonically advancing `t` is O(1) amortised.
|
|
13
13
|
*
|
|
14
14
|
* Two output paths:
|
|
15
|
-
* - {@link evaluate}
|
|
16
|
-
* - {@link evaluateRgba}
|
|
15
|
+
* - {@link evaluate} - writes into a `Color` instance (own scratch by default).
|
|
16
|
+
* - {@link evaluateRgba} - returns the packed `0xAABBGGRR` u32 directly,
|
|
17
17
|
* skipping the Color object. Use this in tight per-particle inner loops
|
|
18
18
|
* that write into a `Uint32Array` instance buffer.
|
|
19
19
|
*
|
|
@@ -38,3 +38,4 @@ export declare class ColorGradient implements LifetimeFunction<Color> {
|
|
|
38
38
|
*/
|
|
39
39
|
evaluateRgba(t: number): number;
|
|
40
40
|
}
|
|
41
|
+
//# sourceMappingURL=ColorGradient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorGradient.d.ts","sourceRoot":"","sources":["../../../src/distributions/ColorGradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,sFAAsF;AACtF,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,KAAK,CAAC;CACd;AAID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAc,YAAW,gBAAgB,CAAC,KAAK,CAAC;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8B;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,YAAY,CAAK;gBAEN,IAAI,EAAE,SAAS,gBAAgB,EAAE;IAQ7C,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,KAAqB,GAAG,KAAK;IAkD7D;;;;OAIG;IACI,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;CAGvC"}
|
|
@@ -1,80 +1,75 @@
|
|
|
1
|
-
import { Color } from
|
|
1
|
+
import { Color } from "@codexo/exojs";
|
|
2
2
|
|
|
3
|
+
//#region src/distributions/ColorGradient.ts
|
|
3
4
|
const compareT = (a, b) => a.t - b.t;
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
* integer (`0xAABBGGRR`). Avoids the {@link Color} object on the hot
|
|
72
|
-
* path; suitable for direct write into a `Uint32Array` instance buffer.
|
|
73
|
-
*/
|
|
74
|
-
evaluateRgba(t) {
|
|
75
|
-
return this.evaluate(t, this._scratch).toRgba();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
6
|
+
* Piecewise-linear color gradient sampled by lifetime ratio `t` in `[0, 1]`.
|
|
7
|
+
* Keyframes are stored sorted by `t`; sampling outside the range returns
|
|
8
|
+
* the nearest endpoint color. Like {@link Curve}, the last accessed segment
|
|
9
|
+
* is cached so monotonically advancing `t` is O(1) amortised.
|
|
10
|
+
*
|
|
11
|
+
* Two output paths:
|
|
12
|
+
* - {@link evaluate} - writes into a `Color` instance (own scratch by default).
|
|
13
|
+
* - {@link evaluateRgba} - returns the packed `0xAABBGGRR` u32 directly,
|
|
14
|
+
* skipping the Color object. Use this in tight per-particle inner loops
|
|
15
|
+
* that write into a `Uint32Array` instance buffer.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* const fire = new ColorGradient([
|
|
19
|
+
* { t: 0, color: new Color(1, 1, 1, 1) }, // white
|
|
20
|
+
* { t: 0.3, color: new Color(1, 0.7, 0.1, 1) }, // orange
|
|
21
|
+
* { t: 0.7, color: new Color(0.4, 0.1, 0, 0.6) },
|
|
22
|
+
* { t: 1, color: new Color(0, 0, 0, 0) }, // transparent black
|
|
23
|
+
* ]);
|
|
24
|
+
*/
|
|
25
|
+
var ColorGradient = class {
|
|
26
|
+
_keys;
|
|
27
|
+
_scratch = new Color();
|
|
28
|
+
_lastSegment = 0;
|
|
29
|
+
constructor(keys) {
|
|
30
|
+
if (keys.length === 0) throw new Error("ColorGradient requires at least one keyframe.");
|
|
31
|
+
this._keys = [...keys].map((k) => ({
|
|
32
|
+
t: k.t,
|
|
33
|
+
color: k.color.clone()
|
|
34
|
+
})).sort(compareT);
|
|
35
|
+
}
|
|
36
|
+
evaluate(t, out = this._scratch) {
|
|
37
|
+
const keys = this._keys;
|
|
38
|
+
const last = keys.length - 1;
|
|
39
|
+
const first = keys[0];
|
|
40
|
+
const lastKey = keys[last];
|
|
41
|
+
if (first === void 0 || lastKey === void 0) return out;
|
|
42
|
+
if (t <= first.t) {
|
|
43
|
+
out.copy(first.color);
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
if (t >= lastKey.t) {
|
|
47
|
+
out.copy(lastKey.color);
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
let segment = this._lastSegment;
|
|
51
|
+
if (t < (keys[segment]?.t ?? 0)) segment = 0;
|
|
52
|
+
while (segment < last && t > (keys[segment + 1]?.t ?? Infinity)) segment++;
|
|
53
|
+
this._lastSegment = segment;
|
|
54
|
+
const lo = keys[segment];
|
|
55
|
+
const hi = keys[segment + 1];
|
|
56
|
+
if (lo === void 0 || hi === void 0) return out;
|
|
57
|
+
const a = lo.color;
|
|
58
|
+
const b = hi.color;
|
|
59
|
+
const ratio = (t - lo.t) / (hi.t - lo.t);
|
|
60
|
+
out.set(a.r + (b.r - a.r) * ratio, a.g + (b.g - a.g) * ratio, a.b + (b.b - a.b) * ratio, a.a + (b.a - a.a) * ratio);
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Returns the gradient sample at `t` packed into a single 32-bit RGBA
|
|
65
|
+
* integer (`0xAABBGGRR`). Avoids the {@link Color} object on the hot
|
|
66
|
+
* path; suitable for direct write into a `Uint32Array` instance buffer.
|
|
67
|
+
*/
|
|
68
|
+
evaluateRgba(t) {
|
|
69
|
+
return this.evaluate(t, this._scratch).toRgba8();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
78
72
|
|
|
73
|
+
//#endregion
|
|
79
74
|
export { ColorGradient };
|
|
80
|
-
//# sourceMappingURL=ColorGradient.js.map
|
|
75
|
+
//# sourceMappingURL=ColorGradient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorGradient.js","sources":["
|
|
1
|
+
{"version":3,"file":"ColorGradient.js","names":[],"sources":["../../../src/distributions/ColorGradient.ts"],"sourcesContent":["import { Color } from '@codexo/exojs';\n\nimport type { LifetimeFunction } from './Distribution';\n\n/** A keyframe in a {@link ColorGradient}: color at lifetime ratio `t` in `[0, 1]`. */\nexport interface ColorGradientKey {\n t: number;\n color: Color;\n}\n\nconst compareT = (a: ColorGradientKey, b: ColorGradientKey): number => a.t - b.t;\n\n/**\n * Piecewise-linear color gradient sampled by lifetime ratio `t` in `[0, 1]`.\n * Keyframes are stored sorted by `t`; sampling outside the range returns\n * the nearest endpoint color. Like {@link Curve}, the last accessed segment\n * is cached so monotonically advancing `t` is O(1) amortised.\n *\n * Two output paths:\n * - {@link evaluate} - writes into a `Color` instance (own scratch by default).\n * - {@link evaluateRgba} - returns the packed `0xAABBGGRR` u32 directly,\n * skipping the Color object. Use this in tight per-particle inner loops\n * that write into a `Uint32Array` instance buffer.\n *\n * @example\n * const fire = new ColorGradient([\n * { t: 0, color: new Color(1, 1, 1, 1) }, // white\n * { t: 0.3, color: new Color(1, 0.7, 0.1, 1) }, // orange\n * { t: 0.7, color: new Color(0.4, 0.1, 0, 0.6) },\n * { t: 1, color: new Color(0, 0, 0, 0) }, // transparent black\n * ]);\n */\nexport class ColorGradient implements LifetimeFunction<Color> {\n private readonly _keys: readonly ColorGradientKey[];\n private readonly _scratch = new Color();\n private _lastSegment = 0;\n\n public constructor(keys: readonly ColorGradientKey[]) {\n if (keys.length === 0) {\n throw new Error('ColorGradient requires at least one keyframe.');\n }\n\n this._keys = [...keys].map(k => ({ t: k.t, color: k.color.clone() })).sort(compareT);\n }\n\n public evaluate(t: number, out: Color = this._scratch): Color {\n const keys = this._keys;\n const last = keys.length - 1;\n const first = keys[0];\n const lastKey = keys[last];\n\n if (first === undefined || lastKey === undefined) {\n return out;\n }\n\n if (t <= first.t) {\n out.copy(first.color);\n\n return out;\n }\n\n if (t >= lastKey.t) {\n out.copy(lastKey.color);\n\n return out;\n }\n\n let segment = this._lastSegment;\n\n if (t < (keys[segment]?.t ?? 0)) {\n segment = 0;\n }\n\n while (segment < last && t > (keys[segment + 1]?.t ?? Infinity)) {\n segment++;\n }\n\n this._lastSegment = segment;\n\n const lo = keys[segment];\n const hi = keys[segment + 1];\n\n if (lo === undefined || hi === undefined) {\n return out;\n }\n\n const a = lo.color;\n const b = hi.color;\n const ratio = (t - lo.t) / (hi.t - lo.t);\n\n out.set(a.r + (b.r - a.r) * ratio, a.g + (b.g - a.g) * ratio, a.b + (b.b - a.b) * ratio, a.a + (b.a - a.a) * ratio);\n\n return out;\n }\n\n /**\n * Returns the gradient sample at `t` packed into a single 32-bit RGBA\n * integer (`0xAABBGGRR`). Avoids the {@link Color} object on the hot\n * path; suitable for direct write into a `Uint32Array` instance buffer.\n */\n public evaluateRgba(t: number): number {\n return this.evaluate(t, this._scratch).toRgba8();\n }\n}\n"],"mappings":";;;AAUA,MAAM,YAAY,GAAqB,MAAgC,EAAE,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;AAsB/E,IAAa,gBAAb,MAA8D;CAC5D,AAAiB;CACjB,AAAiB,WAAW,IAAI,MAAM;CACtC,AAAQ,eAAe;CAEvB,AAAO,YAAY,MAAmC;EACpD,IAAI,KAAK,WAAW,GAClB,MAAM,IAAI,MAAM,+CAA+C;EAGjE,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC,KAAI,OAAM;GAAE,GAAG,EAAE;GAAG,OAAO,EAAE,MAAM,MAAM;EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ;CACrF;CAEA,AAAO,SAAS,GAAW,MAAa,KAAK,UAAiB;EAC5D,MAAM,OAAO,KAAK;EAClB,MAAM,OAAO,KAAK,SAAS;EAC3B,MAAM,QAAQ,KAAK;EACnB,MAAM,UAAU,KAAK;EAErB,IAAI,UAAU,UAAa,YAAY,QACrC,OAAO;EAGT,IAAI,KAAK,MAAM,GAAG;GAChB,IAAI,KAAK,MAAM,KAAK;GAEpB,OAAO;EACT;EAEA,IAAI,KAAK,QAAQ,GAAG;GAClB,IAAI,KAAK,QAAQ,KAAK;GAEtB,OAAO;EACT;EAEA,IAAI,UAAU,KAAK;EAEnB,IAAI,KAAK,KAAK,QAAQ,EAAE,KAAK,IAC3B,UAAU;EAGZ,OAAO,UAAU,QAAQ,KAAK,KAAK,UAAU,EAAE,EAAE,KAAK,WACpD;EAGF,KAAK,eAAe;EAEpB,MAAM,KAAK,KAAK;EAChB,MAAM,KAAK,KAAK,UAAU;EAE1B,IAAI,OAAO,UAAa,OAAO,QAC7B,OAAO;EAGT,MAAM,IAAI,GAAG;EACb,MAAM,IAAI,GAAG;EACb,MAAM,SAAS,IAAI,GAAG,MAAM,GAAG,IAAI,GAAG;EAEtC,IAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,KAAK;EAElH,OAAO;CACT;;;;;;CAOA,AAAO,aAAa,GAAmB;EACrC,OAAO,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC,CAAC,QAAQ;CACjD;AACF"}
|
|
@@ -7,7 +7,7 @@ import type { Distribution } from './Distribution';
|
|
|
7
7
|
* screen-down coordinates) and spans `±halfAngle` radians around it. Speed
|
|
8
8
|
* is sampled uniformly in `[minSpeed, maxSpeed]`.
|
|
9
9
|
*
|
|
10
|
-
* Use for emission cones, explosions, fountain spread
|
|
10
|
+
* Use for emission cones, explosions, fountain spread - anywhere the
|
|
11
11
|
* direction has a preferred axis with bounded variance.
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
@@ -26,3 +26,4 @@ export declare class ConeDirection implements Distribution<Vector> {
|
|
|
26
26
|
/** Convenience: omnidirectional emission (full circle, 0..2π). */
|
|
27
27
|
static omni(minSpeed: number, maxSpeed: number): ConeDirection;
|
|
28
28
|
}
|
|
29
|
+
//# sourceMappingURL=ConeDirection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConeDirection.d.ts","sourceRoot":"","sources":["../../../src/distributions/ConeDirection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,aAAc,YAAW,YAAY,CAAC,MAAM,CAAC;IAI/C,cAAc,EAAE,MAAM;IACtB,SAAS,EAAE,MAAM;IACjB,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAGhC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM;IAGlB,MAAM,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM;IASlD,kEAAkE;WACpD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa;CAGtE"}
|