API reference
Every public class, method, and event in @codexo/exojs. Generated from source.
classUpdateModule
Per-frame, per-batch mutator. Operates on the live particles through their named channels - typically a single tight loop over `[0, particles.count)` that reads and writes the channel arrays it needs. Implementations must always provide a CPU `apply()`. To make a module GPU-eligible (executed inside the system's composite compute shader on WebGPU backends), additionally implement wgsl and writeUniforms. Modules that declare a WgslContribution may also opt to declare a 1D texture binding via the `textures` field (used by `Curve` / `ColorGradient`-driven modules) - in which case uploadTextures runs once at compile time to upload the data. Implementation pattern (CPU-only module): ```ts class MyModule extends UpdateModule { apply(particles, dt) { const { x: velX, y: velY } = particles.velocity; for (let i = 0; i < particles.count; i++) { velX[i] *= 0.99; velY[i] *= 0.99; } } } ``` Implementation pattern (GPU-eligible module): ```ts class MyForce extends UpdateModule { constructor(public ax: number, public ay: number) { super(); } apply(particles, dt) { const { x: velX, y: velY } = particles.velocity; for (let i = 0; i < particles.count; i++) { velX[i] += this.ax * dt; velY[i] += this.ay * dt; } } wgsl(): WgslContribution { return { key: 'MyForce', uniforms: [{ name: 'ax', type: 'f32' }, { name: 'ay', type: 'f32' }], body: `velX[idx] += u_MyForce.ax * dt; velY[idx] += u_MyForce.ay * dt;`, }; } writeUniforms(view, offset) { view.setFloat32(offset + 0, this.ax, true); view.setFloat32(offset + 4, this.ay, true); } } ``` If *any* registered update module on a system lacks `wgsl()`, the system forces CPU mode regardless of backend - preserving the contract that `apply()` is always honoured. Built-in modules ship both implementations; custom modules can opt into GPU acceleration at their authors' discretion. Update modules run after integration each frame. Multiple modules execute in registration order; later modules see the effects of earlier ones.
import { UpdateModule } from '@codexo/exojs-particles'Per-frame, per-batch mutator. Operates on the live particles through their named channels - typically a single tight loop over `[0, particles.count)` that reads and writes the channel arrays it needs.
Implementations must always provide a CPU `apply()`. To make a module GPU-eligible (executed inside the system's composite compute shader on WebGPU backends), additionally implement wgsl and writeUniforms. Modules that declare a WgslContribution may also opt to declare a 1D texture binding via the `textures` field (used by `Curve` / `ColorGradient`-driven modules) - in which case uploadTextures runs once at compile time to upload the data.
Implementation pattern (CPU-only module):
```ts class MyModule extends UpdateModule { apply(particles, dt) { const { x: velX, y: velY } = particles.velocity; for (let i = 0; i < particles.count; i++) { velX[i] *= 0.99; velY[i] *= 0.99; } } } ```
Implementation pattern (GPU-eligible module):
```ts class MyForce extends UpdateModule { constructor(public ax: number, public ay: number) { super(); }
apply(particles, dt) { const { x: velX, y: velY } = particles.velocity; for (let i = 0; i < particles.count; i++) { velX[i] += this.ax * dt; velY[i] += this.ay * dt; } }
wgsl(): WgslContribution { return { key: 'MyForce', uniforms: [{ name: 'ax', type: 'f32' }, { name: 'ay', type: 'f32' }], body: `velX[idx] += u_MyForce.ax * dt; velY[idx] += u_MyForce.ay * dt;`, }; }
writeUniforms(view, offset) { view.setFloat32(offset + 0, this.ax, true); view.setFloat32(offset + 4, this.ay, true); } } ```
If *any* registered update module on a system lacks `wgsl()`, the system forces CPU mode regardless of backend - preserving the contract that `apply()` is always honoured. Built-in modules ship both implementations; custom modules can opt into GPU acceleration at their authors' discretion.
Update modules run after integration each frame. Multiple modules execute in registration order; later modules see the effects of earlier ones.
new(): UpdateModuledestroy(): voiduploadTextures?(device: GPUDevice, textures: ReadonlyMap<string, GPUTexture>): voidwriteUniforms?(view: DataView, byteOffset: number, dt: number): void