SHAPES const
Shapes a kind can draw as (a streak trails its velocity: sparks, drips).
export declare const SHAPES: readonly ["square", "disc", "ring", "frame", "word", "smoke", "streak"];
FX V0.10.0
fizlet/fxExplosions that land. One fixed pool of particles (struct-of-arrays, no allocation), drawn on a canvas: square debris, flashes, shock rings, spinning square rings, smoke, scorch marks and pop words, plus screen shake. blast() is the DOM VIRUS / Battlefield hero recipe. Gravity (gravity, px/s²) pulls each kind by its own share. Particle kinds are data (shape, drag, gravity, how they leave an emitter): emitter(fx, KINDS) registers the built-in bubble, spark, drip and debris (or your own) and sprays them; a page that never calls it never ships it. Visual only: its own random (seeded from Math.random), never the simulation's seeded random.
Measured on this build: minified and gzipped with everything it imports, the way npm run size checks the budget in CI.
import { SHAPES, BUBBLE, SPARK, DRIP, … } from "https://coded-dot-design.github.io/fizlet/dist/fx.js";npm install fizlet # not published yet
import { SHAPES, BUBBLE, SPARK, DRIP, … } from "fizlet/fx";const fx = effects({ cap: 420 });
fx.blast(x, y, 1.2); // flash, rings, debris, scorch
fx.step(dt); fx.draw(ctx); // pooled: never allocatesEvery export, with its doc comment, read from the published type declarations of v0.10.0.
SHAPES constShapes a kind can draw as (a streak trails its velocity: sparks, drips).
export declare const SHAPES: readonly ["square", "disc", "ring", "frame", "word", "smoke", "streak"];
Kind interfaceA particle kind, as data. Ranges are [min, max]; speed and size scale with emit's scale.
export interface Kind {
shape: (typeof SHAPES)[number];
/** Velocity lost per second, as a fraction (1.4 is the blast's smoke and flashes). */
drag: number;
/** Share of the pool's gravity (0: none; negative floats up, like a bubble). */
gravity: number;
/** Emit direction in radians (-π/2 is up) and the spread around it (2π: all round). */
angle: number;
spread: number;
speed: readonly [number, number];
size: readonly [number, number];
life: readonly [number, number];
}
BUBBLE constexport declare const BUBBLE: Kind;
SPARK constexport declare const SPARK: Kind;
DRIP constexport declare const DRIP: Kind;
DEBRIS_KIND constexport declare const DEBRIS_KIND: Kind;
KINDS constAll four by name: emitter(fx, KINDS), or pick some (emitter(fx, { bubble: BUBBLE })).
export declare const KINDS: {
bubble: Kind;
spark: Kind;
drip: Kind;
debris: Kind;
};
FxOptions interfaceexport interface FxOptions {
/** Max live particles (default 420). New ones are refused (and counted in `dropped`) when full. */
cap?: number;
/** Colour table, at most 256; particles store an index (default: the Battlefield blast palette). */
colors?: string[];
/** Word table for pop words (index into it), at most 256. */
words?: string[];
/** Max scorch marks kept on the ground (default 36; 0 turns them off). */
scorch?: number;
/** Gravity in px/s² down (default 0); each kind takes its own share of it. */
gravity?: number;
}
effects functionOverload policy: particles are decorative, so a full pool refuses new ones and counts them in dropped; a blast stops its per-particle work as soon as the pool is full. Invalid input (non-finite numbers, a life that would never end) is refused and counted the same way.
export declare function effects(o?: FxOptions): {
colors: string[];
words: string[];
spawn: (k: number, x: number, y: number, vx: number, vy: number, size: number, life: number, c: number, rot?: number, spin?: number, w?: number) => boolean;
readonly live: number;
readonly shake: number;
/** Particles refused so far: pool full, or invalid input. Decorative, so they may drop; counted. */
readonly dropped: number;
/** Set gravity in px/s² down (each kind takes its own share; read it back from your own state). */
gravity: number;
/** The pool itself, for emitter() and other helpers in this file. Not public API. */
raw: {
f: Float32Array<ArrayBuffer>[];
kind: Uint8Array<ArrayBuffer>;
col: Uint8Array<ArrayBuffer>;
word: Uint8Array<ArrayBuffer>;
st: Float64Array<ArrayBuffer>;
K: Float32Array<ArrayBuffer>;
cap: number;
rnd: (a: number, b: number) => number;
};
/** Add screen shake (decays on its own; read `shake` when drawing). */
kick(amount: number): void;
/** Pop word (index into `words`), drifting up. */
word(x: number, y: number, w: number, c: number, size?: number): void;
/** The hero explosion: flash, fireball, shock ring, spinning square ring, debris, smoke, scorch. */
blast(x: number, y: number, power?: number, tint?: number): undefined;
/** Advance every particle (call once per frame or per step). */
step(dt: number): void;
/** Scorch marks under everything; call before drawing the actors. */
drawGround(ctx: CanvasRenderingContext2D, light?: boolean): void;
/** Every live particle, on top of the actors. */
draw(ctx: CanvasRenderingContext2D, light?: boolean): void;
clear(): void;
};
Effects typeexport type Effects = ReturnType<typeof effects>;
emitter functionNamed particle kinds on a pool: const { ids, emit } = emitter(fx, KINDS), then emit(ids.bubble, x, y, 12). Its own export, so a page that never sprays kinds never ships it. At most 26 kinds per pool (ids 6-31); a second emitter on the same pool adds after the first.
export declare function emitter<N extends string>(fx: Effects, kinds: Record<N, Kind>): {
ids: Record<N, number>;
/**
* `n` particles of kind `k` from (x, y), as that kind's data says: direction, spread, speed, size
* and life (speed and size times `scale`). Colours are picked from `c`...`c + cn - 1`. Bounded: it
* stops at capacity and counts the rest in `dropped`. Writes the arrays directly: nothing boxes.
*/
emit(k: number, x: number, y: number, n: number, c?: number, cn?: number, scale?: number): undefined;
};