@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":"ParticleGpuState.js","sources":["../../../../src/gpu/ParticleGpuState.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ParticleGpuState.js","names":["particleSimulateWgsl"],"sources":["../../../src/gpu/ParticleGpuState.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n\nimport type { Rectangle } from '@codexo/exojs';\nimport type { Texture } from '@codexo/exojs';\nimport type { ComputeBindGroupEntry } from '@codexo/exojs/renderer-sdk';\nimport { fillShaderSource, reflectComputeBindings, WebGpuComputePipeline, WebGpuStorageBuffer, WebGpuUniformBuffer } from '@codexo/exojs/renderer-sdk';\n\nimport type { UpdateModule } from '#modules/UpdateModule';\nimport type { WgslContribution, WgslUniformField } from '#modules/WgslContribution';\nimport { getWgslUniformByteSize } from '#modules/WgslContribution';\nimport type { ParticleSystem } from '#ParticleSystem';\n\nimport particleSimulateWgsl from './shaders/particle-simulate.wgsl';\n\n/**\n * GPU-side mirror of one {@link ParticleSystem}. Owns:\n *\n * - **8 packed storage buffers** for the per-particle SoA data:\n * positions/velocities/scales/rotInfo/timing as `vec2<f32>`, color and\n * textureIndex as `u32`, plus the instance output buffer. Sits at the\n * default WebGPU `maxStorageBuffersPerShaderStage = 8` limit. Built on\n * the shared {@link WebGpuStorageBuffer} SDK primitive.\n * - **Three uniform buffers** (sim state `dt`/`liveCount`, module configs -\n * concatenated per-module structs with WGSL std140-ish alignment - and\n * frame UVs, `array<vec4<f32>, N>` where N is the system's frame count or\n * 1 when no atlas is declared, each vec4 `(uvMinX, uvMinY, uvMaxX, uvMaxY)`\n * already flipY-adjusted), built on the shared {@link WebGpuUniformBuffer}\n * SDK primitive.\n * - **N 1D textures** for modules that use lookup tables (Curve / ColorGradient).\n * - **Composite compute pipeline** built once at construction by\n * concatenating the integration step + every registered module body +\n * the pack-instances step into a single shader, via the shared\n * {@link WebGpuComputePipeline} SDK primitive (two bind groups: group 0\n * holds uniforms + module lookup textures/samplers, group 1 holds the\n * 8 SoA storage buffers). The bind-group *layouts* are derived straight\n * from the shader's own `@group`/`@binding` declarations via\n * {@link reflectComputeBindings} - no hand-written binding list kept in\n * sync with the WGSL text by hand.\n *\n * The compute shader's pack-instances step reads `textureIndex[i]`, looks\n * up the matching frame UV, and writes a 40-byte interleaved record into\n * the instance output buffer (`STORAGE | VERTEX`). The renderer binds that\n * buffer directly as instanced vertex source - no readback.\n */\n\nconst workgroupSize = 64;\nconst instanceBytes = 40; // 5 x f32 + 1 x u32 + 4 x f32 (uvMin.xy, uvMax.xy)\n/** 8 x f32 (position, velocity, rotation, scale, elapsed) + 2 x u32 (color, slot). */\nconst deathRecordBytes = 40;\nconst deathStagingSlots = 3;\nconst minDeathStagingRecords = 32;\nconst deathRecordFloats = 10;\n\n/** One readback slot of the death staging ring. */\ninterface DeathStagingSlot {\n buffer: GPUBuffer;\n records: number;\n busy: boolean;\n}\n\n/** A copy that has been submitted into a staging slot and not yet delivered. */\ninterface StagedDeathBatch {\n slot: DeathStagingSlot;\n count: number;\n}\n\n/**\n * One particle's state as the compute shader captured it at death, plus the\n * slot it occupied. The slot orders the records; it never leaves the package.\n * @internal\n */\nexport interface ParticleDeathRecord {\n readonly x: number;\n readonly y: number;\n readonly velocityX: number;\n readonly velocityY: number;\n readonly rotation: number;\n readonly scaleX: number;\n readonly scaleY: number;\n readonly elapsed: number;\n readonly color: number;\n readonly slot: number;\n}\n\ninterface ModuleSlot {\n module: UpdateModule;\n contribution: WgslContribution;\n uniformByteOffset: number;\n uniformByteSize: number;\n}\n\nexport class ParticleGpuState {\n public readonly device: GPUDevice;\n public readonly capacity: number;\n\n /** GPU buffer holding interleaved per-instance vertex data, written by compute, read as VERTEX by the renderer. */\n public readonly instanceBuffer: GPUBuffer;\n\n private readonly _positions: WebGpuStorageBuffer;\n private readonly _velocities: WebGpuStorageBuffer;\n private readonly _scales: WebGpuStorageBuffer;\n private readonly _rotInfo: WebGpuStorageBuffer;\n private readonly _timing: WebGpuStorageBuffer;\n private readonly _color: WebGpuStorageBuffer;\n private readonly _instanceStorageBuffer: WebGpuStorageBuffer;\n\n /**\n * Death records the compute shader appended, plus the atomic append counter\n * in its first four bytes. Allocated only while the system has death modules,\n * so a system without them pays neither the memory nor the copy.\n *\n * Detecting a death and reporting one have separate lifetimes, and the path\n * between them has four stages: the shader appends here; records the copy has\n * not taken yet stay here as a device-side backlog; a copy moves a batch into\n * a staging slot; and the mapped batches are handed on in submission order.\n */\n private _deathBuffer: WebGpuStorageBuffer | null = null;\n private readonly _deathCounterReset = new Uint32Array(1);\n\n /**\n * Readback slots for the death buffer. A slot stays unavailable from the\n * submit that copies into it until its map resolves, so a single slot would\n * make every death that happens while a readback is in flight either a\n * validation error or a lost record. Three slots cover the queue depth a\n * frame loop runs at; a fourth death batch waits on the device instead.\n */\n private readonly _deathStaging: DeathStagingSlot[] = [];\n\n /** Copies submitted into a staging slot, oldest first, awaiting delivery. */\n private readonly _stagedDeaths: StagedDeathBatch[] = [];\n\n /**\n * Whether the death buffer holds records no readback has claimed yet. The\n * append counter is reset only once a copy has taken them, so a step that\n * finds no free staging slot leaves its records in place and the next step\n * appends behind them.\n */\n private _deathBufferDirty = false;\n\n /** Tail of the delivery chain, so batches are reported in submission order. */\n private _deathDelivery: Promise<void> = Promise.resolve();\n\n private readonly _simUniformBuffer: WebGpuUniformBuffer;\n private readonly _simUniformData: ArrayBuffer = new ArrayBuffer(16);\n private readonly _simUniformView: DataView;\n\n private _moduleUniformBuffer: WebGpuUniformBuffer | null = null;\n private _moduleUniformData: ArrayBuffer | null = null;\n private _moduleUniformView: DataView | null = null;\n private _moduleSlots: readonly ModuleSlot[] = [];\n\n private readonly _framesUniformBuffer: WebGpuUniformBuffer;\n private readonly _framesUniformData: ArrayBuffer;\n private readonly _framesUniformView: Float32Array;\n private readonly _frameCount: number;\n\n private readonly _moduleTextures = new Map<string, GPUTexture>();\n private readonly _samplerFiltering: GPUSampler;\n private readonly _samplerNonFiltering: GPUSampler;\n\n private _pipelineWrapper: WebGpuComputePipeline | null = null;\n private _bindGroup0: GPUBindGroup | null = null;\n private _bindGroup1: GPUBindGroup | null = null;\n private _reportsDeaths = false;\n private _destroyed = false;\n\n public constructor(\n device: GPUDevice,\n capacity: number,\n modules: readonly UpdateModule[],\n frames: readonly Rectangle[],\n texture: Texture,\n reportsDeaths = false,\n ) {\n this.device = device;\n this.capacity = capacity;\n\n this._frameCount = Math.max(1, frames.length);\n this._framesUniformData = new ArrayBuffer(this._frameCount * 16);\n this._framesUniformView = new Float32Array(this._framesUniformData);\n this._framesUniformBuffer = new WebGpuUniformBuffer(device, this._framesUniformData.byteLength, 'particle-frames-uniforms');\n this._writeFrames(frames, texture);\n\n const vec2Bytes = capacity * 8;\n const vec4Bytes = capacity * 16;\n const u32Bytes = capacity * 4;\n\n this._positions = new WebGpuStorageBuffer(device, vec2Bytes, 'particle-positions');\n this._velocities = new WebGpuStorageBuffer(device, vec2Bytes, 'particle-velocities');\n this._scales = new WebGpuStorageBuffer(device, vec2Bytes, 'particle-scales');\n // Rotation carries the atlas frame in its third lane: the default WebGPU\n // limit is 8 storage buffers per stage, and the death buffer needs the slot\n // a separate frame-index buffer used to hold. Module bodies address\n // rotInfo[idx].x / .y exactly as before.\n this._rotInfo = new WebGpuStorageBuffer(device, vec4Bytes, 'particle-rotInfo');\n this._timing = new WebGpuStorageBuffer(device, vec2Bytes, 'particle-timing');\n this._color = new WebGpuStorageBuffer(device, u32Bytes, 'particle-color');\n\n this._instanceStorageBuffer = new WebGpuStorageBuffer(device, capacity * instanceBytes, 'particle-instance-output', GPUBufferUsage.VERTEX);\n this.instanceBuffer = this._instanceStorageBuffer.buffer;\n\n this._simUniformView = new DataView(this._simUniformData);\n this._simUniformBuffer = new WebGpuUniformBuffer(device, 16, 'particle-sim-uniforms');\n\n // r32float textures aren't filterable in core WebGPU (would require\n // the optional `float32-filterable` feature). Use `nearest` for\n // r32float curve LUTs (256 taps is fine without interpolation) and\n // `linear` for rgba8unorm gradients which support filtering natively.\n this._samplerFiltering = device.createSampler({\n label: 'particle-lookup-sampler-filtering',\n minFilter: 'linear',\n magFilter: 'linear',\n addressModeU: 'clamp-to-edge',\n });\n this._samplerNonFiltering = device.createSampler({\n label: 'particle-lookup-sampler-non-filtering',\n minFilter: 'nearest',\n magFilter: 'nearest',\n addressModeU: 'clamp-to-edge',\n });\n\n this.setProgram(modules, reportsDeaths);\n }\n\n /**\n * Compiles the pipeline for `modules` and binds it to the buffers this state\n * already owns.\n *\n * The simulation lives in those buffers, not in the program, so changing the\n * module list rebuilds the shader, its uniforms and its lookup textures while\n * every live particle keeps the position and velocity the GPU last integrated.\n */\n public setProgram(modules: readonly UpdateModule[], reportsDeaths: boolean): void {\n for (const m of modules) {\n if (!m.wgsl) {\n throw new Error(`ParticleGpuState: module ${m.constructor.name} has no wgsl() - all registered UpdateModules must be GPU-eligible.`);\n }\n }\n\n this._destroyProgram();\n this._reportsDeaths = reportsDeaths;\n\n // Module uniform layout.\n const slots: ModuleSlot[] = [];\n let uniformOffset = 0;\n\n for (const m of modules) {\n const c = m.wgsl!();\n const fields = c.uniforms ?? [];\n const size = getWgslUniformByteSize(fields);\n\n uniformOffset = Math.ceil(uniformOffset / 16) * 16;\n\n slots.push({\n module: m,\n contribution: c,\n uniformByteOffset: uniformOffset,\n uniformByteSize: size,\n });\n\n uniformOffset += size;\n }\n\n const totalUniformBytes = Math.max(16, Math.ceil(uniformOffset / 16) * 16);\n\n this._moduleSlots = slots;\n\n if (uniformOffset > 0) {\n this._moduleUniformData = new ArrayBuffer(totalUniformBytes);\n this._moduleUniformView = new DataView(this._moduleUniformData);\n this._moduleUniformBuffer = new WebGpuUniformBuffer(this.device, totalUniformBytes, 'particle-module-uniforms');\n }\n\n if (reportsDeaths && this._deathBuffer === null) {\n // Four bytes of atomic append counter, then one record per slot: a frame\n // can at most report every particle the system holds.\n this._deathBuffer = new WebGpuStorageBuffer(this.device, 4 + this.capacity * deathRecordBytes, 'particle-deaths', GPUBufferUsage.COPY_SRC);\n }\n\n // Allocate textures for modules that need them.\n for (const slot of slots) {\n const c = slot.contribution;\n\n if (!c.textures) continue;\n\n for (const t of c.textures) {\n const tex = this.device.createTexture({\n label: `particle-tex-${c.key}-${t.name}`,\n size: { width: 256, height: 1, depthOrArrayLayers: 1 },\n format: t.format,\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\n dimension: '1d',\n });\n\n this._moduleTextures.set(`${c.key}_${t.name}`, tex);\n }\n }\n\n const wgsl = this._buildShader(slots);\n\n this._pipelineWrapper = WebGpuComputePipeline.create(this.device, {\n wgsl,\n workgroupSize,\n bindingGroups: reflectComputeBindings(wgsl, { nonFilteringResources: this._nonFilteringResourceNames(slots) }),\n label: 'particle-compute',\n });\n\n this._bindGroup0 = this._pipelineWrapper.createBindGroup(0, this._buildBindGroup0Entries(slots), 'particle-uniforms-bg');\n this._bindGroup1 = this._pipelineWrapper.createBindGroup(1, this._buildSoaBindGroupEntries(), 'particle-soa-bg');\n\n // Modules upload their lookup textures.\n for (const slot of slots) {\n if (!slot.module.uploadTextures) continue;\n\n const moduleTextures = new Map<string, GPUTexture>();\n\n for (const t of slot.contribution.textures ?? []) {\n const tex = this._moduleTextures.get(`${slot.contribution.key}_${t.name}`);\n\n if (tex !== undefined) {\n moduleTextures.set(t.name, tex);\n }\n }\n\n slot.module.uploadTextures(this.device, moduleTextures);\n }\n }\n\n /** Releases everything the current program owns, leaving the simulation buffers untouched. */\n private _destroyProgram(): void {\n this._moduleUniformBuffer?.destroy();\n this._moduleUniformBuffer = null;\n this._moduleUniformData = null;\n this._moduleUniformView = null;\n this._moduleSlots = [];\n\n for (const tex of this._moduleTextures.values()) {\n tex.destroy();\n }\n\n this._moduleTextures.clear();\n\n this._pipelineWrapper = null;\n this._bindGroup0 = null;\n this._bindGroup1 = null;\n }\n\n /**\n * Runs one simulation step over `[0, dispatchCount)`.\n *\n * `pendingDeaths` is how many expired particles the caller is still holding,\n * including the ones it marked for this step. The shader appends exactly one\n * record per marked particle, so the readback copies the used prefix of the\n * death buffer without first having to read its counter back - the count is\n * already known on this side.\n *\n * Returns whether a death batch was staged for readback. Deaths stay on the\n * device while every staging slot is in flight, so a step can report deaths\n * without staging any, and a later step can stage a batch spanning several\n * steps. A caller keeping per-death state has to hold it, and keep counting it\n * into `pendingDeaths`, until a step stages - then hand over all of it.\n */\n public dispatch(dt: number, dispatchCount: number, pendingDeaths = 0): boolean {\n const pipeline = this._pipelineWrapper;\n const bindGroup0 = this._bindGroup0;\n const bindGroup1 = this._bindGroup1;\n\n if (pipeline === null || bindGroup0 === null || bindGroup1 === null) {\n return false;\n }\n\n const simulating = dispatchCount > 0;\n const reporting = pendingDeaths > 0 && this._reportsDeaths && this._deathBuffer !== null;\n\n // A system whose last particles just expired has nothing left to simulate,\n // but its records still have to reach a staging slot - otherwise the last\n // deaths of a system are never delivered.\n if (!simulating && !reporting) {\n return false;\n }\n\n if (simulating) {\n this._writeSimUniforms(dt, dispatchCount);\n this._writeModuleUniforms(dt);\n }\n\n if (reporting && !this._deathBufferDirty) {\n this._deathCounterReset[0] = 0;\n this._deathBuffer!.write(this._deathCounterReset, 0);\n }\n\n const encoder = this.device.createCommandEncoder({ label: 'particle-compute' });\n\n if (simulating) {\n const pass = encoder.beginComputePass({ label: 'particle-compute-pass' });\n\n pipeline.dispatch(pass, dispatchCount, [bindGroup0, bindGroup1]);\n\n pass.end();\n }\n\n let staged = false;\n\n if (reporting) {\n this._deathBufferDirty = true;\n\n // The death buffer holds one record per slot. Records left over several\n // steps can exceed that when slots are recycled and die again, and appends\n // past the end are dropped by the device - so the copy must never claim\n // more than the buffer can hold.\n const count = Math.min(pendingDeaths, this.capacity);\n const slot = this._acquireDeathStaging(count);\n\n if (slot !== null) {\n encoder.copyBufferToBuffer(this._deathBuffer!.buffer, 4, slot.buffer, 0, count * deathRecordBytes);\n slot.busy = true;\n this._stagedDeaths.push({ slot, count });\n this._deathBufferDirty = false;\n staged = true;\n }\n }\n\n this.device.queue.submit([encoder.finish()]);\n\n return staged;\n }\n\n /**\n * Resolves the oldest staged death batch and hands its records to `receive`\n * once the copy has landed.\n *\n * The mapping is asynchronous by nature, so a death is delivered no earlier\n * than the frame after it happened. Batches are delivered in the order they\n * were submitted, and nothing blocks on a map: further steps keep staging\n * into other slots while one is in flight. A device that goes away mid-map\n * resolves to nothing rather than throwing: the deaths are lost with the\n * simulation that produced them.\n */\n public readDeaths(receive: (records: readonly ParticleDeathRecord[]) => void): Promise<void> {\n const batch = this._stagedDeaths.shift();\n\n if (batch === undefined || this._destroyed) {\n return Promise.resolve();\n }\n\n const previous = this._deathDelivery;\n let settled: () => void;\n\n // The chain only orders the batches. A death callback that throws must\n // reach its caller, but it must not leave the batches behind it waiting on\n // a rejected promise, so the successor waits on this separate handle.\n this._deathDelivery = new Promise<void>(resolve => {\n settled = resolve;\n });\n\n return this._deliverDeaths(batch, previous, receive).finally(() => settled());\n }\n\n private async _deliverDeaths(batch: StagedDeathBatch, previous: Promise<void>, receive: (records: readonly ParticleDeathRecord[]) => void): Promise<void> {\n const { slot, count } = batch;\n const bytes = count * deathRecordBytes;\n\n try {\n await slot.buffer.mapAsync(GPUMapMode.READ, 0, bytes);\n } catch {\n slot.busy = false;\n\n return;\n }\n\n if (this._destroyed) {\n slot.busy = false;\n\n return;\n }\n\n const records: ParticleDeathRecord[] = [];\n const mapped = slot.buffer.getMappedRange(0, bytes);\n const floats = new Float32Array(mapped);\n const uints = new Uint32Array(mapped);\n\n for (let i = 0; i < count; i++) {\n const base = i * deathRecordFloats;\n\n records.push({\n x: floats[base + 0]!,\n y: floats[base + 1]!,\n velocityX: floats[base + 2]!,\n velocityY: floats[base + 3]!,\n rotation: floats[base + 4]!,\n scaleX: floats[base + 5]!,\n scaleY: floats[base + 6]!,\n elapsed: floats[base + 7]!,\n color: uints[base + 8]!,\n slot: uints[base + 9]!,\n });\n }\n\n slot.buffer.unmap();\n // Released before waiting on the batch ahead: a slot held across that wait\n // would shrink the ring for no reason.\n slot.busy = false;\n\n // The shader appends through an atomic, so records arrive in whatever order\n // the workgroups finished. Slot order is reproducible and matches what the\n // CPU compaction pass would have reported.\n records.sort((a, b) => a.slot - b.slot);\n\n await previous;\n\n if (this._destroyed) {\n return;\n }\n\n receive(records);\n }\n\n /**\n * Claims a staging slot able to hold `records`, or null while every slot of\n * the ring is still in flight.\n */\n private _acquireDeathStaging(records: number): DeathStagingSlot | null {\n let reusable: DeathStagingSlot | null = null;\n\n for (const slot of this._deathStaging) {\n if (slot.busy) continue;\n\n if (slot.records >= records) {\n return slot;\n }\n\n reusable = slot;\n }\n\n if (reusable === null && this._deathStaging.length >= deathStagingSlots) {\n return null;\n }\n\n const size = Math.max(records, (reusable?.records ?? 0) * 2, minDeathStagingRecords);\n const buffer = this.device.createBuffer({\n label: 'particle-deaths-staging',\n size: size * deathRecordBytes,\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\n });\n\n if (reusable !== null) {\n reusable.buffer.destroy();\n reusable.buffer = buffer;\n reusable.records = size;\n\n return reusable;\n }\n\n const slot: DeathStagingSlot = { buffer, records: size, busy: false };\n\n this._deathStaging.push(slot);\n\n return slot;\n }\n\n private _releaseDeathStaging(): void {\n for (const slot of this._deathStaging) {\n slot.buffer.destroy();\n }\n\n this._deathStaging.length = 0;\n this._stagedDeaths.length = 0;\n this._deathBufferDirty = false;\n }\n\n public destroy(): void {\n this._destroyed = true;\n this._destroyProgram();\n\n this._positions.destroy();\n this._velocities.destroy();\n this._scales.destroy();\n this._rotInfo.destroy();\n this._timing.destroy();\n this._color.destroy();\n this._instanceStorageBuffer.destroy();\n this._simUniformBuffer.destroy();\n this._framesUniformBuffer.destroy();\n this._deathBuffer?.destroy();\n this._deathBuffer = null;\n this._releaseDeathStaging();\n }\n\n private _writeFrames(frames: readonly Rectangle[], texture: Texture): void {\n const view = this._framesUniformView;\n const w = texture.width;\n const h = texture.height;\n const flipY = texture.flipY;\n\n if (frames.length === 0) {\n // Single-frame fallback - full texture.\n view[0] = 0;\n view[1] = flipY ? 1 : 0;\n view[2] = 1;\n view[3] = flipY ? 0 : 1;\n } else {\n for (let i = 0; i < frames.length; i++) {\n const f = frames[i]!;\n const o = i * 4;\n const minU = f.left / w;\n const maxU = f.right / w;\n const topV = f.top / h;\n const bottomV = f.bottom / h;\n\n view[o + 0] = minU;\n view[o + 1] = flipY ? bottomV : topV;\n view[o + 2] = maxU;\n view[o + 3] = flipY ? topV : bottomV;\n }\n }\n\n this._framesUniformBuffer.write(this._framesUniformView);\n }\n\n /**\n * Push the listed CPU SoA slots to the GPU. Called by `ParticleSystem`\n * with newly-spawned slots and just-expired slots (lifetime sentinel).\n * Slots not in the dirty set are left alone - GPU keeps the integrated\n * state from previous compute dispatches.\n *\n * Each dirty slot triggers 7 small writes (one per SoA channel, via\n * {@link WebGpuStorageBuffer.write}). For typical spawn rates (≤200/s)\n * this is negligible (≤1400 calls/s); contiguous-range batching is a\n * future optimisation.\n */\n public uploadDirty(system: ParticleSystem, slots: Iterable<number>): void {\n const scratch2 = this._dirtyScratchVec2;\n const scratch4 = this._dirtyScratchVec4;\n const scratch1 = this._dirtyScratchU32;\n const storage = system._storage;\n\n for (const slot of slots) {\n const byteOffset2 = slot * 8;\n const byteOffset1 = slot * 4;\n\n scratch2[0] = storage.posX[slot]!;\n scratch2[1] = storage.posY[slot]!;\n this._positions.write(scratch2, byteOffset2);\n\n scratch2[0] = storage.velX[slot]!;\n scratch2[1] = storage.velY[slot]!;\n this._velocities.write(scratch2, byteOffset2);\n\n scratch2[0] = storage.scaleX[slot]!;\n scratch2[1] = storage.scaleY[slot]!;\n this._scales.write(scratch2, byteOffset2);\n\n scratch4[0] = storage.rotations[slot]!;\n scratch4[1] = storage.rotationSpeeds[slot]!;\n scratch4[2] = storage.frame[slot]!;\n scratch4[3] = 0;\n this._rotInfo.write(scratch4, slot * 16);\n\n scratch2[0] = storage.elapsed[slot]!;\n scratch2[1] = storage.lifetime[slot]!;\n this._timing.write(scratch2, byteOffset2);\n\n scratch1[0] = storage.color[slot]!;\n this._color.write(scratch1, byteOffset1);\n }\n }\n\n /**\n * Marks `slot` expired for the device without touching anything else about\n * it. Only the lifetime lane is written: a full slot upload would push the\n * CPU's stale position and velocity over the values the device integrated,\n * and those are exactly what the death record is supposed to carry.\n */\n public uploadExpiry(slot: number): void {\n this._expiryScratch[0] = -1;\n this._timing.write(this._expiryScratch, slot * 8 + 4);\n }\n\n private readonly _expiryScratch = new Float32Array(1);\n private readonly _dirtyScratchVec2 = new Float32Array(2);\n private readonly _dirtyScratchVec4 = new Float32Array(4);\n private readonly _dirtyScratchU32 = new Uint32Array(1);\n\n private _writeSimUniforms(dt: number, liveCount: number): void {\n this._simUniformView.setFloat32(0, dt, true);\n this._simUniformView.setUint32(4, liveCount, true);\n this._simUniformBuffer.write(this._simUniformView);\n }\n\n private _writeModuleUniforms(dt: number): void {\n if (this._moduleUniformView === null || this._moduleUniformBuffer === null || this._moduleUniformData === null) {\n return;\n }\n\n for (const slot of this._moduleSlots) {\n slot.module.writeUniforms?.(this._moduleUniformView, slot.uniformByteOffset, dt);\n }\n\n this._moduleUniformBuffer.write(this._moduleUniformView);\n }\n\n /**\n * WGSL variable names of module lookup textures/samplers whose format isn't natively\n * filterable (`r32float` Curve LUTs) - fed to {@link reflectComputeBindings} so it declares\n * `'unfilterable-float'`/`'non-filtering'` for those specific bindings instead of the default\n * `'float'`/`'filtering'`, an ambiguity the WGSL text itself can't resolve (see that\n * function's doc comment).\n */\n private _nonFilteringResourceNames(slots: readonly ModuleSlot[]): Set<string> {\n const names = new Set<string>();\n\n for (const slot of slots) {\n for (const t of slot.contribution.textures ?? []) {\n if (t.format === 'r32float') {\n names.add(`u_${slot.contribution.key}_${t.name}`);\n names.add(`u_${slot.contribution.key}_${t.name}_sampler`);\n }\n }\n }\n\n return names;\n }\n\n /** Group-0 bind-group entries, matching group 0's bindings (reflected from the shader text) one-to-one. */\n private _buildBindGroup0Entries(slots: readonly ModuleSlot[]): ComputeBindGroupEntry[] {\n const entries: ComputeBindGroupEntry[] = [\n { binding: 0, buffer: this._simUniformBuffer.buffer },\n { binding: 1, buffer: this._framesUniformBuffer.buffer },\n ];\n\n if (this._moduleUniformBuffer !== null) {\n entries.push({ binding: 2, buffer: this._moduleUniformBuffer.buffer });\n }\n\n let textureBindingIndex = this._moduleUniformBuffer !== null ? 3 : 2;\n\n for (const slot of slots) {\n for (const t of slot.contribution.textures ?? []) {\n const tex = this._moduleTextures.get(`${slot.contribution.key}_${t.name}`)!;\n const filterable = t.format !== 'r32float';\n const sampler = filterable ? this._samplerFiltering : this._samplerNonFiltering;\n\n entries.push({ binding: textureBindingIndex++, textureView: tex.createView({ dimension: '1d' }) });\n entries.push({ binding: textureBindingIndex++, sampler });\n }\n }\n\n return entries;\n }\n\n /** Group-1 bind-group entries: the 8 SoA storage buffers, matching group 1's bindings (reflected from the shader text) one-to-one. */\n private _buildSoaBindGroupEntries(): ComputeBindGroupEntry[] {\n const entries: ComputeBindGroupEntry[] = [\n { binding: 0, buffer: this._positions.buffer },\n { binding: 1, buffer: this._velocities.buffer },\n { binding: 2, buffer: this._scales.buffer },\n { binding: 3, buffer: this._rotInfo.buffer },\n { binding: 4, buffer: this._timing.buffer },\n { binding: 5, buffer: this._color.buffer },\n { binding: 6, buffer: this._instanceStorageBuffer.buffer },\n ];\n\n if (this._reportsDeaths && this._deathBuffer !== null) {\n entries.push({ binding: 7, buffer: this._deathBuffer.buffer });\n }\n\n return entries;\n }\n\n private _buildShader(slots: readonly ModuleSlot[]): string {\n const sections: string[] = [];\n\n sections.push(`\nstruct SimUniforms {\n dt: f32,\n liveCount: u32,\n _pad0: u32,\n _pad1: u32,\n}\n\nstruct FrameUniforms {\n frames: array<vec4<f32>, ${this._frameCount}>,\n}\n\n@group(0) @binding(0) var<uniform> sim: SimUniforms;\n@group(0) @binding(1) var<uniform> frameUv: FrameUniforms;\n `);\n\n const moduleStructFields: string[] = [];\n\n for (const slot of slots) {\n const c = slot.contribution;\n const fields = c.uniforms ?? [];\n\n if (fields.length === 0) {\n continue;\n }\n\n sections.push(this._renderModuleStruct(c.key, fields));\n moduleStructFields.push(`u_${c.key}: ${c.key}Uniforms,`);\n }\n\n if (moduleStructFields.length > 0) {\n sections.push(`\nstruct ModuleUniforms {\n${moduleStructFields.map(s => ` ${s}`).join('\\n')}\n}\n\n@group(0) @binding(2) var<uniform> modules: ModuleUniforms;\n `);\n }\n\n let textureBindingIndex = moduleStructFields.length > 0 ? 3 : 2;\n\n for (const slot of slots) {\n for (const t of slot.contribution.textures ?? []) {\n sections.push(`\n@group(0) @binding(${textureBindingIndex++}) var u_${slot.contribution.key}_${t.name}: texture_1d<f32>;\n@group(0) @binding(${textureBindingIndex++}) var u_${slot.contribution.key}_${t.name}_sampler: sampler;\n `);\n }\n }\n\n sections.push(`\n@group(1) @binding(0) var<storage, read_write> positions: array<vec2<f32>>;\n@group(1) @binding(1) var<storage, read_write> velocities: array<vec2<f32>>;\n@group(1) @binding(2) var<storage, read_write> scales: array<vec2<f32>>;\n@group(1) @binding(3) var<storage, read_write> rotInfo: array<vec4<f32>>;\n@group(1) @binding(4) var<storage, read_write> timing: array<vec2<f32>>;\n@group(1) @binding(5) var<storage, read_write> color: array<u32>;\n@group(1) @binding(6) var<storage, read_write> instanceOutput: array<u32>;\n `);\n\n if (this._reportsDeaths) {\n sections.push(`\nstruct DeathRecord {\n x: f32,\n y: f32,\n velocityX: f32,\n velocityY: f32,\n rotation: f32,\n scaleX: f32,\n scaleY: f32,\n elapsed: f32,\n color: u32,\n slot: u32,\n}\n\nstruct DeathBuffer {\n count: atomic<u32>,\n records: array<DeathRecord>,\n}\n\n@group(1) @binding(7) var<storage, read_write> deaths: DeathBuffer;\n `);\n }\n\n // Module preludes (helper functions/constants). Concatenated in\n // registration order; modules sharing the same key are emitted only\n // once (the contribution body strings are still inlined per-instance,\n // but the prelude function definitions can't be duplicated).\n const seenPreludeKeys = new Set<string>();\n\n for (const slot of slots) {\n const prelude = slot.contribution.prelude;\n\n if (prelude === undefined || prelude.trim() === '') continue;\n if (seenPreludeKeys.has(slot.contribution.key)) continue;\n\n seenPreludeKeys.add(slot.contribution.key);\n sections.push(prelude);\n }\n\n const moduleBodies = slots.map(s => s.contribution.body).join('\\n');\n\n sections.push(`\n${fillShaderSource(particleSimulateWgsl, { workgroupSize, moduleBodies, frameCount: this._frameCount, deathReport: this._deathReportSource() })} `);\n\n return sections.join('\\n\\n');\n }\n\n /**\n * The block that captures a particle's state the first time the shader sees\n * its expiry sentinel, or nothing when the system has no death modules.\n *\n * The CPU marks an expired particle with `lifetime = -1` and the shader\n * rewrites that to `-2` once captured, so exactly one record is appended per\n * death even though a dead slot is visited every frame until it is reused.\n */\n private _deathReportSource(): string {\n if (!this._reportsDeaths) {\n return '';\n }\n\n return `\n if (timing[idx].y > -1.5) {\n // The CPU found this particle expired from an elapsed time it had\n // already advanced for this frame, so the device owes it the matching\n // integration step before the snapshot is taken. Without it a death\n // reported from the GPU would sit one step behind the same death\n // reported from the CPU pipeline.\n positions[idx] = positions[idx] + velocities[idx] * dt;\n rotInfo[idx].x = rotInfo[idx].x + rotInfo[idx].y * dt;\n timing[idx].x = timing[idx].x + dt;\n\n let at = atomicAdd(&deaths.count, 1u);\n\n deaths.records[at].x = positions[idx].x;\n deaths.records[at].y = positions[idx].y;\n deaths.records[at].velocityX = velocities[idx].x;\n deaths.records[at].velocityY = velocities[idx].y;\n deaths.records[at].rotation = rotInfo[idx].x;\n deaths.records[at].scaleX = scales[idx].x;\n deaths.records[at].scaleY = scales[idx].y;\n deaths.records[at].elapsed = timing[idx].x;\n deaths.records[at].color = color[idx];\n deaths.records[at].slot = idx;\n\n timing[idx].y = -2.0;\n }`;\n }\n\n private _renderModuleStruct(key: string, fields: readonly WgslUniformField[]): string {\n const lines = fields.map(f => ` ${f.name}: ${f.type},`).join('\\n');\n\n return `struct ${key}Uniforms {\\n${lines}\\n}`;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/gpu/shaders/particle-simulate.wgsl
|
|
2
|
+
var particle_simulate_default = "@compute @workgroup_size({{workgroupSize}})\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let idx = gid.x;\n if (idx >= sim.liveCount) { return; }\n\n let dt = sim.dt;\n\n // Skip dead particles (lifetime sentinel < 0). Write zero-scale instance\n // so the renderer doesn't accidentally draw them. A sentinel of exactly -1\n // is a death the CPU has just marked and nobody has captured yet; the\n // death-report block (present only when the system has death modules)\n // snapshots it here, where the particle's last integrated state still\n // stands, and moves the sentinel to -2 so it reports once.\n if (timing[idx].y < 0.0) {\n{{deathReport}}\n let outBaseDead = idx * 10u;\n for (var k: u32 = 0u; k < 10u; k++) { instanceOutput[outBaseDead + k] = 0u; }\n return;\n }\n\n // Integration.\n positions[idx] = positions[idx] + velocities[idx] * dt;\n rotInfo[idx].x = rotInfo[idx].x + rotInfo[idx].y * dt;\n timing[idx].x = timing[idx].x + dt;\n\n // Module bodies (in registration order).\n{{moduleBodies}}\n\n // Resolve frame UVs. Anything that is not a valid explicit index shows\n // frame 0, which is what the CPU packer does and what a slot whose index\n // was never set already shows — `textureIndex` is zero-initialised.\n // Clamping to the last frame instead would be animation-hold semantics,\n // and this is a frame selector rather than an animation cursor.\n let rawFrameIndex = u32(rotInfo[idx].z);\n let frameIndex = select(0u, rawFrameIndex, rawFrameIndex < {{frameCount}}u);\n let frameUvBounds = frameUv.frames[frameIndex];\n\n // Pack interleaved instance data (10 u32s per particle):\n // x, y, scaleX, scaleY, rotation (f32×5) + color (u32) + uvMin.xy (f32×2) + uvMax.xy (f32×2)\n let outBase = idx * 10u;\n instanceOutput[outBase + 0u] = bitcast<u32>(positions[idx].x);\n instanceOutput[outBase + 1u] = bitcast<u32>(positions[idx].y);\n instanceOutput[outBase + 2u] = bitcast<u32>(scales[idx].x);\n instanceOutput[outBase + 3u] = bitcast<u32>(scales[idx].y);\n instanceOutput[outBase + 4u] = bitcast<u32>(rotInfo[idx].x);\n instanceOutput[outBase + 5u] = color[idx];\n instanceOutput[outBase + 6u] = bitcast<u32>(frameUvBounds.x);\n instanceOutput[outBase + 7u] = bitcast<u32>(frameUvBounds.y);\n instanceOutput[outBase + 8u] = bitcast<u32>(frameUvBounds.z);\n instanceOutput[outBase + 9u] = bitcast<u32>(frameUvBounds.w);\n}\n";
|
|
3
|
+
|
|
4
|
+
//#endregion
|
|
5
|
+
export { particle_simulate_default as default };
|
|
6
|
+
//# sourceMappingURL=particle-simulate.wgsl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"particle-simulate.wgsl.js","names":[],"sources":["../../../../src/gpu/shaders/particle-simulate.wgsl"],"sourcesContent":["export default \"@compute @workgroup_size({{workgroupSize}})\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\n let idx = gid.x;\\n if (idx >= sim.liveCount) { return; }\\n\\n let dt = sim.dt;\\n\\n // Skip dead particles (lifetime sentinel < 0). Write zero-scale instance\\n // so the renderer doesn't accidentally draw them. A sentinel of exactly -1\\n // is a death the CPU has just marked and nobody has captured yet; the\\n // death-report block (present only when the system has death modules)\\n // snapshots it here, where the particle's last integrated state still\\n // stands, and moves the sentinel to -2 so it reports once.\\n if (timing[idx].y < 0.0) {\\n{{deathReport}}\\n let outBaseDead = idx * 10u;\\n for (var k: u32 = 0u; k < 10u; k++) { instanceOutput[outBaseDead + k] = 0u; }\\n return;\\n }\\n\\n // Integration.\\n positions[idx] = positions[idx] + velocities[idx] * dt;\\n rotInfo[idx].x = rotInfo[idx].x + rotInfo[idx].y * dt;\\n timing[idx].x = timing[idx].x + dt;\\n\\n // Module bodies (in registration order).\\n{{moduleBodies}}\\n\\n // Resolve frame UVs. Anything that is not a valid explicit index shows\\n // frame 0, which is what the CPU packer does and what a slot whose index\\n // was never set already shows — `textureIndex` is zero-initialised.\\n // Clamping to the last frame instead would be animation-hold semantics,\\n // and this is a frame selector rather than an animation cursor.\\n let rawFrameIndex = u32(rotInfo[idx].z);\\n let frameIndex = select(0u, rawFrameIndex, rawFrameIndex < {{frameCount}}u);\\n let frameUvBounds = frameUv.frames[frameIndex];\\n\\n // Pack interleaved instance data (10 u32s per particle):\\n // x, y, scaleX, scaleY, rotation (f32×5) + color (u32) + uvMin.xy (f32×2) + uvMax.xy (f32×2)\\n let outBase = idx * 10u;\\n instanceOutput[outBase + 0u] = bitcast<u32>(positions[idx].x);\\n instanceOutput[outBase + 1u] = bitcast<u32>(positions[idx].y);\\n instanceOutput[outBase + 2u] = bitcast<u32>(scales[idx].x);\\n instanceOutput[outBase + 3u] = bitcast<u32>(scales[idx].y);\\n instanceOutput[outBase + 4u] = bitcast<u32>(rotInfo[idx].x);\\n instanceOutput[outBase + 5u] = color[idx];\\n instanceOutput[outBase + 6u] = bitcast<u32>(frameUvBounds.x);\\n instanceOutput[outBase + 7u] = bitcast<u32>(frameUvBounds.y);\\n instanceOutput[outBase + 8u] = bitcast<u32>(frameUvBounds.z);\\n instanceOutput[outBase + 9u] = bitcast<u32>(frameUvBounds.w);\\n}\\n\";"],"mappings":";AAAA,gCAAe"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,UAAU,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,32 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
1
|
+
import { BoxArea } from "./distributions/BoxArea.js";
|
|
2
|
+
import { CircleArea } from "./distributions/CircleArea.js";
|
|
3
|
+
import { ColorGradient } from "./distributions/ColorGradient.js";
|
|
4
|
+
import { ConeDirection } from "./distributions/ConeDirection.js";
|
|
5
|
+
import { Constant } from "./distributions/Constant.js";
|
|
6
|
+
import { Curve } from "./distributions/Curve.js";
|
|
7
|
+
import { LineSegment } from "./distributions/LineSegment.js";
|
|
8
|
+
import { Range } from "./distributions/Range.js";
|
|
9
|
+
import { VectorRange } from "./distributions/VectorRange.js";
|
|
10
|
+
import { UpdateModule } from "./modules/UpdateModule.js";
|
|
11
|
+
import { AlphaFadeOverLifetime } from "./modules/AlphaFadeOverLifetime.js";
|
|
12
|
+
import { ApplyForce } from "./modules/ApplyForce.js";
|
|
13
|
+
import { AttractToPoint } from "./modules/AttractToPoint.js";
|
|
14
|
+
import { SpawnModule } from "./modules/SpawnModule.js";
|
|
15
|
+
import { BurstSpawn } from "./modules/BurstSpawn.js";
|
|
16
|
+
import { ColorOverLifetime } from "./modules/ColorOverLifetime.js";
|
|
17
|
+
import { ColorOverSpeed } from "./modules/ColorOverSpeed.js";
|
|
18
|
+
import { DeathModule } from "./modules/DeathModule.js";
|
|
19
|
+
import { Drag } from "./modules/Drag.js";
|
|
20
|
+
import { OrbitalForce } from "./modules/OrbitalForce.js";
|
|
21
|
+
import { RateSpawn } from "./modules/RateSpawn.js";
|
|
22
|
+
import { RepelFromPoint } from "./modules/RepelFromPoint.js";
|
|
23
|
+
import { RotateOverLifetime } from "./modules/RotateOverLifetime.js";
|
|
24
|
+
import { ScaleOverLifetime } from "./modules/ScaleOverLifetime.js";
|
|
25
|
+
import { SpawnOnDeath } from "./modules/SpawnOnDeath.js";
|
|
26
|
+
import { Turbulence } from "./modules/Turbulence.js";
|
|
27
|
+
import { VelocityOverLifetime } from "./modules/VelocityOverLifetime.js";
|
|
28
|
+
import { getWgslFieldLayout, getWgslUniformByteSize } from "./modules/WgslContribution.js";
|
|
29
|
+
import { particlesBuildInfo } from "./particlesBuildInfo.js";
|
|
30
|
+
import { ParticleBufferLayout } from "./renderModes/ParticleBufferLayout.js";
|
|
31
|
+
import { ParticleMaterial } from "./renderModes/ParticleMaterial.js";
|
|
32
|
+
import { ParticleRenderMode } from "./renderModes/ParticleRenderMode.js";
|
|
33
|
+
import { QuadParticles } from "./renderModes/QuadParticles.js";
|
|
34
|
+
import { ParticleSystem } from "./ParticleSystem.js";
|
|
35
|
+
import { createParticlesExtension, particlesExtension } from "./particlesExtension.js";
|
|
36
|
+
import { MeshParticles } from "./renderModes/MeshParticles.js";
|
|
37
|
+
import { RibbonParticles } from "./renderModes/RibbonParticles.js";
|
|
38
|
+
|
|
39
|
+
export { AlphaFadeOverLifetime, ApplyForce, AttractToPoint, BoxArea, BurstSpawn, CircleArea, ColorGradient, ColorOverLifetime, ColorOverSpeed, ConeDirection, Constant, Curve, DeathModule, Drag, LineSegment, MeshParticles, OrbitalForce, ParticleBufferLayout, ParticleMaterial, ParticleRenderMode, ParticleSystem, QuadParticles, Range, RateSpawn, RepelFromPoint, RibbonParticles, RotateOverLifetime, ScaleOverLifetime, SpawnModule, SpawnOnDeath, Turbulence, UpdateModule, VectorRange, VelocityOverLifetime, createParticlesExtension, getWgslFieldLayout, getWgslUniformByteSize, particlesBuildInfo, particlesExtension };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Curve } from
|
|
2
|
-
import type {
|
|
1
|
+
import { Curve } from '#distributions/Curve';
|
|
2
|
+
import type { ParticleBatch } from '#ParticleStorage';
|
|
3
3
|
import { UpdateModule } from './UpdateModule';
|
|
4
4
|
import type { WgslContribution } from './WgslContribution';
|
|
5
5
|
/**
|
|
@@ -18,7 +18,8 @@ import type { WgslContribution } from './WgslContribution';
|
|
|
18
18
|
export declare class AlphaFadeOverLifetime extends UpdateModule {
|
|
19
19
|
curve: Curve;
|
|
20
20
|
constructor(curve?: Curve);
|
|
21
|
-
apply(
|
|
21
|
+
apply(particles: ParticleBatch, _dt: number): void;
|
|
22
22
|
wgsl(): WgslContribution;
|
|
23
23
|
uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void;
|
|
24
24
|
}
|
|
25
|
+
//# sourceMappingURL=AlphaFadeOverLifetime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AlphaFadeOverLifetime.d.ts","sourceRoot":"","sources":["../../../src/modules/AlphaFadeOverLifetime.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAsB,SAAQ,YAAY;IAC9C,KAAK,EAAE,KAAK,CAAC;gBAGlB,KAAK,GAAE,KAGL;IAMY,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAelD,IAAI,IAAI,gBAAgB;IAaxB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,IAAI;CAoBnG"}
|
|
@@ -1,64 +1,77 @@
|
|
|
1
|
-
import { Curve } from
|
|
2
|
-
import { UpdateModule } from
|
|
1
|
+
import { Curve } from "../distributions/Curve.js";
|
|
2
|
+
import { UpdateModule } from "./UpdateModule.js";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
//#region src/modules/AlphaFadeOverLifetime.ts
|
|
5
5
|
const lookupSize = 256;
|
|
6
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
|
-
|
|
7
|
+
* Fades only the alpha channel over a particle's lifetime, leaving RGB
|
|
8
|
+
* untouched. Pair with a spawn-time tint or a separate `ColorOverLifetime`
|
|
9
|
+
* to keep the color layer stable while controlling opacity from a single
|
|
10
|
+
* curve.
|
|
11
|
+
*
|
|
12
|
+
* The default curve `1 → 0` produces a linear fade-out. For a fade-in then
|
|
13
|
+
* fade-out, pass a curve like `[0,0]→[0.5,1]→[1,0]`.
|
|
14
|
+
*
|
|
15
|
+
* GPU-eligible: uploads the curve as a 256-tap 1D R32F texture; alpha is
|
|
16
|
+
* resampled per-particle in the compute shader and stitched into the
|
|
17
|
+
* existing color word with a single mask + shift.
|
|
18
|
+
*/
|
|
19
|
+
var AlphaFadeOverLifetime = class extends UpdateModule {
|
|
20
|
+
curve;
|
|
21
|
+
constructor(curve = new Curve([{
|
|
22
|
+
t: 0,
|
|
23
|
+
v: 1
|
|
24
|
+
}, {
|
|
25
|
+
t: 1,
|
|
26
|
+
v: 0
|
|
27
|
+
}])) {
|
|
28
|
+
super();
|
|
29
|
+
this.curve = curve;
|
|
30
|
+
}
|
|
31
|
+
apply(particles, _dt) {
|
|
32
|
+
const { elapsed, lifetime } = particles.timing;
|
|
33
|
+
const color = particles.color;
|
|
34
|
+
const liveCount = particles.count;
|
|
35
|
+
const curve = this.curve;
|
|
36
|
+
for (let i = 0; i < liveCount; i++) {
|
|
37
|
+
const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);
|
|
38
|
+
const a = curve.evaluate(t);
|
|
39
|
+
const alphaByte = Math.max(0, Math.min(1, a)) * 255 & 255;
|
|
40
|
+
color[i] = (color[i] ?? 0) & 16777215 | alphaByte << 24;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
wgsl() {
|
|
44
|
+
return {
|
|
45
|
+
key: "AlphaFadeOverLifetime",
|
|
46
|
+
textures: [{
|
|
47
|
+
name: "curve",
|
|
48
|
+
format: "r32float"
|
|
49
|
+
}],
|
|
50
|
+
body: `
|
|
43
51
|
let alphaT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);
|
|
44
52
|
let alphaSample = textureSampleLevel(u_AlphaFadeOverLifetime_curve, u_AlphaFadeOverLifetime_curve_sampler, alphaT, 0.0).r;
|
|
45
53
|
let alphaByte = u32(clamp(alphaSample, 0.0, 1.0) * 255.0) & 255u;
|
|
46
54
|
color[idx] = (color[idx] & 0x00ffffffu) | (alphaByte << 24u);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
uploadTextures(device, textures) {
|
|
59
|
+
const texture = textures.get("curve");
|
|
60
|
+
if (texture === void 0) return;
|
|
61
|
+
const data = new Float32Array(lookupSize);
|
|
62
|
+
for (let i = 0; i < lookupSize; i++) data[i] = this.curve.evaluate(i / 255);
|
|
63
|
+
device.queue.writeTexture({ texture }, data.buffer, {
|
|
64
|
+
offset: 0,
|
|
65
|
+
bytesPerRow: lookupSize * 4,
|
|
66
|
+
rowsPerImage: 1
|
|
67
|
+
}, {
|
|
68
|
+
width: lookupSize,
|
|
69
|
+
height: 1,
|
|
70
|
+
depthOrArrayLayers: 1
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
62
74
|
|
|
75
|
+
//#endregion
|
|
63
76
|
export { AlphaFadeOverLifetime };
|
|
64
|
-
//# sourceMappingURL=AlphaFadeOverLifetime.js.map
|
|
77
|
+
//# sourceMappingURL=AlphaFadeOverLifetime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AlphaFadeOverLifetime.js","sources":["
|
|
1
|
+
{"version":3,"file":"AlphaFadeOverLifetime.js","names":[],"sources":["../../../src/modules/AlphaFadeOverLifetime.ts"],"sourcesContent":["/// <reference types=\"@webgpu/types\" />\n\nimport { Curve } from '#distributions/Curve';\nimport type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\nconst lookupSize = 256;\n\n/**\n * Fades only the alpha channel over a particle's lifetime, leaving RGB\n * untouched. Pair with a spawn-time tint or a separate `ColorOverLifetime`\n * to keep the color layer stable while controlling opacity from a single\n * curve.\n *\n * The default curve `1 → 0` produces a linear fade-out. For a fade-in then\n * fade-out, pass a curve like `[0,0]→[0.5,1]→[1,0]`.\n *\n * GPU-eligible: uploads the curve as a 256-tap 1D R32F texture; alpha is\n * resampled per-particle in the compute shader and stitched into the\n * existing color word with a single mask + shift.\n */\nexport class AlphaFadeOverLifetime extends UpdateModule {\n public curve: Curve;\n\n public constructor(\n curve: Curve = new Curve([\n { t: 0, v: 1 },\n { t: 1, v: 0 },\n ]),\n ) {\n super();\n this.curve = curve;\n }\n\n public override apply(particles: ParticleBatch, _dt: number): void {\n const { elapsed, lifetime } = particles.timing;\n const color = particles.color;\n const liveCount = particles.count;\n const curve = this.curve;\n\n for (let i = 0; i < liveCount; i++) {\n const t = (elapsed[i] ?? 0) / (lifetime[i] ?? 1);\n const a = curve.evaluate(t);\n const alphaByte = (Math.max(0, Math.min(1, a)) * 255) & 255;\n\n color[i] = ((color[i] ?? 0) & 0x00ffffff) | (alphaByte << 24);\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'AlphaFadeOverLifetime',\n textures: [{ name: 'curve', format: 'r32float' }],\n body: `\n let alphaT = clamp(timing[idx].x / max(timing[idx].y, 0.000001), 0.0, 1.0);\n let alphaSample = textureSampleLevel(u_AlphaFadeOverLifetime_curve, u_AlphaFadeOverLifetime_curve_sampler, alphaT, 0.0).r;\n let alphaByte = u32(clamp(alphaSample, 0.0, 1.0) * 255.0) & 255u;\n color[idx] = (color[idx] & 0x00ffffffu) | (alphaByte << 24u);\n `,\n };\n }\n\n public override uploadTextures(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): void {\n const texture = textures.get('curve');\n\n if (texture === undefined) {\n return;\n }\n\n const data = new Float32Array(lookupSize);\n\n for (let i = 0; i < lookupSize; i++) {\n data[i] = this.curve.evaluate(i / (lookupSize - 1));\n }\n\n device.queue.writeTexture(\n { texture },\n data.buffer,\n { offset: 0, bytesPerRow: lookupSize * 4, rowsPerImage: 1 },\n { width: lookupSize, height: 1, depthOrArrayLayers: 1 },\n );\n }\n}\n"],"mappings":";;;;AAQA,MAAM,aAAa;;;;;;;;;;;;;;AAenB,IAAa,wBAAb,cAA2C,aAAa;CACtD,AAAO;CAEP,AAAO,YACL,QAAe,IAAI,MAAM,CACvB;EAAE,GAAG;EAAG,GAAG;CAAE,GACb;EAAE,GAAG;EAAG,GAAG;CAAE,CACf,CAAC,GACD;EACA,MAAM;EACN,KAAK,QAAQ;CACf;CAEA,AAAgB,MAAM,WAA0B,KAAmB;EACjE,MAAM,EAAE,SAAS,aAAa,UAAU;EACxC,MAAM,QAAQ,UAAU;EACxB,MAAM,YAAY,UAAU;EAC5B,MAAM,QAAQ,KAAK;EAEnB,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;GAClC,MAAM,KAAK,QAAQ,MAAM,MAAM,SAAS,MAAM;GAC9C,MAAM,IAAI,MAAM,SAAS,CAAC;GAC1B,MAAM,YAAa,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,MAAO;GAExD,MAAM,MAAO,MAAM,MAAM,KAAK,WAAe,aAAa;EAC5D;CACF;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CAAC;IAAE,MAAM;IAAS,QAAQ;GAAW,CAAC;GAChD,MAAM;;;;;;EAMR;CACF;CAEA,AAAgB,eAAe,QAAmB,UAAiD;EACjG,MAAM,UAAU,SAAS,IAAI,OAAO;EAEpC,IAAI,YAAY,QACd;EAGF,MAAM,OAAO,IAAI,aAAa,UAAU;EAExC,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAC9B,KAAK,KAAK,KAAK,MAAM,SAAS,IAAK,GAAe;EAGpD,OAAO,MAAM,aACX,EAAE,QAAQ,GACV,KAAK,QACL;GAAE,QAAQ;GAAG,aAAa,aAAa;GAAG,cAAc;EAAE,GAC1D;GAAE,OAAO;GAAY,QAAQ;GAAG,oBAAoB;EAAE,CACxD;CACF;AACF"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ParticleBatch } from '#ParticleStorage';
|
|
2
2
|
import { UpdateModule } from './UpdateModule';
|
|
3
3
|
import type { WgslContribution } from './WgslContribution';
|
|
4
4
|
/**
|
|
5
5
|
* Adds a constant 2D acceleration to every live particle's velocity each
|
|
6
6
|
* frame. Use for gravity (`new ApplyForce(0, 980)`), wind, or any uniform
|
|
7
|
-
* force field. Force is applied to all particles equally
|
|
7
|
+
* force field. Force is applied to all particles equally - for per-particle
|
|
8
8
|
* variation, layer multiple ApplyForce modules with different gates.
|
|
9
9
|
*
|
|
10
10
|
* GPU-eligible: implements {@link UpdateModule.wgsl} so this module runs in
|
|
@@ -14,7 +14,8 @@ export declare class ApplyForce extends UpdateModule {
|
|
|
14
14
|
accelerationX: number;
|
|
15
15
|
accelerationY: number;
|
|
16
16
|
constructor(accelerationX: number, accelerationY: number);
|
|
17
|
-
apply(
|
|
17
|
+
apply(particles: ParticleBatch, dt: number): void;
|
|
18
18
|
wgsl(): WgslContribution;
|
|
19
19
|
writeUniforms(view: DataView, offset: number): void;
|
|
20
20
|
}
|
|
21
|
+
//# sourceMappingURL=ApplyForce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApplyForce.d.ts","sourceRoot":"","sources":["../../../src/modules/ApplyForce.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D;;;;;;;;GAQG;AACH,qBAAa,UAAW,SAAQ,YAAY;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;gBAEV,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM;IAM/C,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAYjD,IAAI,IAAI,gBAAgB;IAaxB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAIpE"}
|
|
@@ -1,48 +1,54 @@
|
|
|
1
|
-
import { UpdateModule } from
|
|
1
|
+
import { UpdateModule } from "./UpdateModule.js";
|
|
2
2
|
|
|
3
|
+
//#region src/modules/ApplyForce.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
|
-
|
|
5
|
+
* Adds a constant 2D acceleration to every live particle's velocity each
|
|
6
|
+
* frame. Use for gravity (`new ApplyForce(0, 980)`), wind, or any uniform
|
|
7
|
+
* force field. Force is applied to all particles equally - for per-particle
|
|
8
|
+
* variation, layer multiple ApplyForce modules with different gates.
|
|
9
|
+
*
|
|
10
|
+
* GPU-eligible: implements {@link UpdateModule.wgsl} so this module runs in
|
|
11
|
+
* the system's compute shader on WebGPU backends with no CPU readback.
|
|
12
|
+
*/
|
|
13
|
+
var ApplyForce = class extends UpdateModule {
|
|
14
|
+
accelerationX;
|
|
15
|
+
accelerationY;
|
|
16
|
+
constructor(accelerationX, accelerationY) {
|
|
17
|
+
super();
|
|
18
|
+
this.accelerationX = accelerationX;
|
|
19
|
+
this.accelerationY = accelerationY;
|
|
20
|
+
}
|
|
21
|
+
apply(particles, dt) {
|
|
22
|
+
const { x: velX, y: velY } = particles.velocity;
|
|
23
|
+
const liveCount = particles.count;
|
|
24
|
+
const ax = this.accelerationX * dt;
|
|
25
|
+
const ay = this.accelerationY * dt;
|
|
26
|
+
for (let i = 0; i < liveCount; i++) {
|
|
27
|
+
velX[i] = (velX[i] ?? 0) + ax;
|
|
28
|
+
velY[i] = (velY[i] ?? 0) + ay;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
wgsl() {
|
|
32
|
+
return {
|
|
33
|
+
key: "ApplyForce",
|
|
34
|
+
uniforms: [{
|
|
35
|
+
name: "ax",
|
|
36
|
+
type: "f32"
|
|
37
|
+
}, {
|
|
38
|
+
name: "ay",
|
|
39
|
+
type: "f32"
|
|
40
|
+
}],
|
|
41
|
+
body: `
|
|
37
42
|
velocities[idx] = velocities[idx] + vec2<f32>(modules.u_ApplyForce.ax, modules.u_ApplyForce.ay) * dt;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
43
|
+
`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
writeUniforms(view, offset) {
|
|
47
|
+
view.setFloat32(offset + 0, this.accelerationX, true);
|
|
48
|
+
view.setFloat32(offset + 4, this.accelerationY, true);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
46
51
|
|
|
52
|
+
//#endregion
|
|
47
53
|
export { ApplyForce };
|
|
48
|
-
//# sourceMappingURL=ApplyForce.js.map
|
|
54
|
+
//# sourceMappingURL=ApplyForce.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApplyForce.js","sources":["
|
|
1
|
+
{"version":3,"file":"ApplyForce.js","names":[],"sources":["../../../src/modules/ApplyForce.ts"],"sourcesContent":["import type { ParticleBatch } from '#ParticleStorage';\n\nimport { UpdateModule } from './UpdateModule';\nimport type { WgslContribution } from './WgslContribution';\n\n/**\n * Adds a constant 2D acceleration to every live particle's velocity each\n * frame. Use for gravity (`new ApplyForce(0, 980)`), wind, or any uniform\n * force field. Force is applied to all particles equally - for per-particle\n * variation, layer multiple ApplyForce modules with different gates.\n *\n * GPU-eligible: implements {@link UpdateModule.wgsl} so this module runs in\n * the system's compute shader on WebGPU backends with no CPU readback.\n */\nexport class ApplyForce extends UpdateModule {\n public accelerationX: number;\n public accelerationY: number;\n\n public constructor(accelerationX: number, accelerationY: number) {\n super();\n this.accelerationX = accelerationX;\n this.accelerationY = accelerationY;\n }\n\n public override apply(particles: ParticleBatch, dt: number): void {\n const { x: velX, y: velY } = particles.velocity;\n const liveCount = particles.count;\n const ax = this.accelerationX * dt;\n const ay = this.accelerationY * dt;\n\n for (let i = 0; i < liveCount; i++) {\n velX[i] = (velX[i] ?? 0) + ax;\n velY[i] = (velY[i] ?? 0) + ay;\n }\n }\n\n public override wgsl(): WgslContribution {\n return {\n key: 'ApplyForce',\n uniforms: [\n { name: 'ax', type: 'f32' },\n { name: 'ay', type: 'f32' },\n ],\n body: `\n velocities[idx] = velocities[idx] + vec2<f32>(modules.u_ApplyForce.ax, modules.u_ApplyForce.ay) * dt;\n `,\n };\n }\n\n public override writeUniforms(view: DataView, offset: number): void {\n view.setFloat32(offset + 0, this.accelerationX, true);\n view.setFloat32(offset + 4, this.accelerationY, true);\n }\n}\n"],"mappings":";;;;;;;;;;;;AAcA,IAAa,aAAb,cAAgC,aAAa;CAC3C,AAAO;CACP,AAAO;CAEP,AAAO,YAAY,eAAuB,eAAuB;EAC/D,MAAM;EACN,KAAK,gBAAgB;EACrB,KAAK,gBAAgB;CACvB;CAEA,AAAgB,MAAM,WAA0B,IAAkB;EAChE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,UAAU;EACvC,MAAM,YAAY,UAAU;EAC5B,MAAM,KAAK,KAAK,gBAAgB;EAChC,MAAM,KAAK,KAAK,gBAAgB;EAEhC,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,KAAK;GAClC,KAAK,MAAM,KAAK,MAAM,KAAK;GAC3B,KAAK,MAAM,KAAK,MAAM,KAAK;EAC7B;CACF;CAEA,AAAgB,OAAyB;EACvC,OAAO;GACL,KAAK;GACL,UAAU,CACR;IAAE,MAAM;IAAM,MAAM;GAAM,GAC1B;IAAE,MAAM;IAAM,MAAM;GAAM,CAC5B;GACA,MAAM;;;EAGR;CACF;CAEA,AAAgB,cAAc,MAAgB,QAAsB;EAClE,KAAK,WAAW,SAAS,GAAG,KAAK,eAAe,IAAI;EACpD,KAAK,WAAW,SAAS,GAAG,KAAK,eAAe,IAAI;CACtD;AACF"}
|