DOM ENGINEV0.10.0FIZLET

SPRITE V0.10.0

fizlet/sprite

The character layer's drawing primitive. Pixel-art sprites written as data (rows of characters + a colour map whose values can be palette roles), baked once per (sprite, frame, scale, palette) into a bounded cache, then blitted with one drawImage. spriteSVG() / spriteURL() give the same pixels as an SVG for characters that live in the page instead of on a canvas; they stand alone, so a page that only places SVG characters never ships the canvas half.

fizlet/sprite · GZIP1,403 B1.4 KB of a 1.5 KB budget

Measured on this build: minified and gzipped with everything it imports, the way npm run size checks the budget in CI.

LIVE · NO LOOPOne sprite written as rows of characters, drawn at three scales in three palettes (side A, side B, hit flash), then the same pixels as an SVG image.
MODULES · hosted on this site
import { spriteSVG, spriteURL, sprites } from "https://coded-dot-design.github.io/fizlet/dist/sprite.js";
NPM · COMING SOON
npm install fizlet   # not published yet
import { spriteSVG, spriteURL, sprites } from "fizlet/sprite";
IN SHORT
const art = sprites({ bug: { colors: { b: "team" }, frames: [rows] } },
  { palettes: [{ team: "#39ffb0" }, { team: "#ff5c8f" }] });
art.draw(ctx, "bug", frame, x, y, angle, 3, side);
img.src = spriteURL(def, 0, palettes); // the same pixels as SVG

API

Every export, with its doc comment, read from the published type declarations of v0.10.0.

Paint type

A colour for a character: a hex, or a role name (team, enemy, hazard…) a palette fills.

export type Paint = string;

SpriteDef interface

export interface SpriteDef {
    /** Rows of characters, one per pixel (one frame), or a list of those (an animation). */
    frames?: string[] | string[][];
    /** Character → colour or role. Any character not listed is empty (use `.` by convention). */
    colors?: Record<string, Paint>;
    /** Pivot in sprite pixels (default: the centre). Draw places it at (x, y) and rotates about it. */
    ax?: number;
    ay?: number;
    /** A 1px rim around the silhouette (colour or role): readable on light and dark pages. */
    outline?: Paint;
    /** Vector sprite instead of pixels: its size, frame count and a painter, baked like the rest. */
    w?: number;
    h?: number;
    n?: number;
    paint?: (c: CanvasRenderingContext2D, frame: number, color: (p: Paint) => string) => void;
}

SpriteOptions interface

export interface SpriteOptions {
    /**
     * Palettes: role → hex. Index 0 is the default and fills roles the others leave out. The key `*`
     * paints every pixel one colour (a hit flash). Push more at runtime (max 32); `clear()` after
     * changing one in place.
     */
    palettes?: Record<string, string>[];
    /** Max baked tiles kept (default 256). The oldest is dropped when a new one is baked. */
    cap?: number;
    /** Tile factory (default: OffscreenCanvas, else a detached canvas). */
    canvas?: (w: number, h: number) => OffscreenCanvas | HTMLCanvasElement;
}

spriteSVG function

One sprite as an SVG string (crisp at any size), for characters placed in the page. Frames wrap.

export declare function spriteSVG(d: SpriteDef, frame?: number, palettes?: Palettes, palette?: number): string;

spriteURL const

spriteSVG() as a data URL, for an <img src> or a CSS background.

export declare const spriteURL: (d: SpriteDef, frame?: number, palettes?: Palettes, palette?: number) => string;

sprites function

Frames ≤ 64, palettes ≤ 32 and baked scales 1–8 per sprite: the cache key is one small integer.

export declare function sprites<K extends string>(defs: Record<K, SpriteDef>, o?: SpriteOptions): {
    ids: Record<K, number>;
    /** Width and height of each sprite in sprite pixels (outline not included), by id. */
    w: Float64Array<ArrayBuffer>;
    h: Float64Array<ArrayBuffer>;
    palettes: Record<string, string>[];
    tile: (id: number | K, frame?: number, scale?: number, palette?: number) => Tile;
    /**
     * Draw sprite `id` (number from `ids`, or its name) with its pivot at (x, y), turned by `angle`
     * radians, `scale` pixels per sprite pixel. Bakes on the first call; after that, no allocation.
     */
    draw(ctx: CanvasRenderingContext2D, id: number | K, frame: number, x: number, y: number, angle?: number, scale?: number, palette?: number): void;
    /** Baked tiles kept now. */
    readonly size: number;
    /** Tiles baked so far (cache misses). Flat in a steady scene. */
    readonly baked: number;
    /** Drop every baked tile (after changing a palette in place). */
    clear(): void;
};

Sprites type

export type Sprites = ReturnType<typeof sprites>;