JS engine
pixfx-wasm is the engine as plain JavaScript bindings: list effects, read their metadata, spawn instances, step them and read their pixels. You decide how to draw them.
Use it to draw with WebGL or WebGPU, in a worker, or to test pixels. To simply show effects on a canvas, the canvas renderer does the drawing for you.
Build
wasm-pack build crates/pixfx-wasm --target web --out-dir pkg
import init, { Fx, effects, meta } from "./pkg/pixfx_wasm.js";
await init();
Example
const fx = new Fx("fire/campfire", { seed: 1 });
canvas.width = fx.width();
canvas.height = fx.height();
const ctx = canvas.getContext("2d");
let last = performance.now();
function frame(now) {
fx.update(Math.max(0, now - last) / 1000); // never step backwards
last = now;
fx.draw("both");
ctx.putImageData(new ImageData(fx.rgba(), fx.width(), fx.height()), 0, 0);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
Functions
effects() → string[]
Every effect id, in registry order.
meta(id) → object
{id, name, desc, tags, size: [w, h], origin: [x, y], glowMargin, duration, loop, fps, seed}. Throws unknown effect "..." for an id not in the registry. Fields are described in Concepts.
Fx
A live effect on its own canvas: meta.size plus margin empty pixels on every side, with the effect's origin at meta.origin + margin.
new Fx(id, opts?)
opts is undefined, null or a plain object with the common options, the effect's own options, and:
| Option | Meaning |
|---|---|
margin | Whole number from 0 to 4096: empty pixels round the canvas. 0 (the default) eases light out at the edge so frames match the sprite sheet; meta(id).glowMargin fits the effect's glow and fades nothing. |
Options are checked once, here. A field of the wrong type throws an error naming it, for example option flip must be a boolean or option palette[2]: not a #rgb, #rrggbb or #rrggbbaa colour. x and y are refused: an Fx always draws at its own origin. Keys whose value is undefined are skipped.
Methods
| Method | Does |
|---|---|
update(dt) | Advance by dt seconds (at most 0.25, in 1/120 s sub-steps). Throws for NaN, a missing argument or a negative step, and leaves the instance unchanged. |
draw(layer) | Clear the canvas and draw "back", "front" or "both" at the current time. |
stop() | Let it end: loops fade out, one-shots are cut short. |
done() | True once a stopped instance has faded, or a one-shot has finished. |
t() | Seconds since the instance started. |
width(), height() | Canvas size in pixels, margin included. |
originX(), originY() | Where the effect's origin sits on the canvas. Draw the canvas at (x - originX(), y - originY()) to place the effect at (x, y). |
free() | Release the instance's wasm memory (wasm-bindgen). |
Reading pixels
After draw(), read the frame in the form that suits your renderer:
| Method | Returns |
|---|---|
rgba() | A Uint8ClampedArray copy, width × height × 4: both layers composited over transparency, ready for new ImageData(px, w, h). |
color() | A Uint32Array copy of the colour layer, one ABGR word per pixel, row-major. |
light() | A Uint32Array copy of the light layer, one xBGR word per pixel (top byte unused). |
colorRgbaPtr() | Address in wasm memory of the colour layer as straight-alpha RGBA8 bytes. No copy. |
lightRgbaPtr() | Address of the light layer as RGBA8: lit pixels r, g, b, 255, unlit 0, 0, 0, 0, to draw additively. No copy. |
The pointer methods avoid a copy per frame. View the bytes before the next call on the same instance; they share one buffer, so lightRgbaPtr() overwrites what colorRgbaPtr() wrote.
import init, { Fx } from "./pkg/pixfx_wasm.js";
const wasm = await init();
const ptr = fx.colorRgbaPtr();
const bytes = new Uint8ClampedArray(wasm.memory.buffer, ptr, fx.width() * fx.height() * 4);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, fx.width(), fx.height(), gl.RGBA, gl.UNSIGNED_BYTE, bytes);
Make a new view each frame: wasm memory can grow, which detaches old views.
Rust side
The bindings are a thin layer over plain Rust, which other crates use directly: pixfx_wasm::Player (an instance plus its canvas) and pixfx_wasm::parse_options (JS object to typed Options and margin). pixfx-canvas is built on both.
Demo
wasm-pack build crates/pixfx-wasm --target web --out-dir demo/pkg
cd crates/pixfx-wasm/demo && python3 -m http.server 8765 --bind 127.0.0.1