A compact, self-describing ID scheme for procedurally composed grid shapes (geometric marks/logo icons) — plus a library and CLI to generate and render them from that ID, no lookup table required.
A shape ID decodes offline: BS-{cols}X{rows}-{payload}{checksum}, one
base62 character per grid cell (row-major), each character encoding that
cell's primitive type, rotation, and inversion. Most shapes fit this
one-character-per-cell form; when a cell's encoded value needs more room,
encodeShapeId automatically switches to the wider
BS2-{cols}X{rows}-{payload}{checksum} form (2 characters per cell) —
you'll see both prefixes in the gallery below. See
openspec/roadmap.md for the full format rationale.
npm install bitshaperEvery mark below is rendered straight from its shape ID — no assets, just the ID string.
Together these cover all 10 primitives currently in the registry:
empty, fill, fillet, bulge, circle, wedge, cap,
pinwheel-arc, step, ogee.
import {
decodeShapeId,
encodeShapeId,
renderShape,
generateShapeId,
} from "bitshaper";
// Decode a shape ID into its grid definition
const shapeDef = decodeShapeId("BS-2X2-GIMKE");
// { cols: 2, rows: 2, cells: [...] }
// Render a shape ID straight to an SVG string
const svg = renderShape("BS-2X2-GIMKE");
// Encode a grid definition back into its canonical ID
const id = encodeShapeId(shapeDef); // "BS-2X2-GIMKE"
// Deterministically generate a new shape ID from a seed
const generatedId = generateShapeId("my-seed", { cols: 3, rows: 3 });# Decode and render a shape ID to an SVG file
bitshaper render "BS-2X2-GIMKE" -o diamond.svg
bitshaper render "BS-2X2-GIMKE" -o diamond.svg --fill "#1d4ed8"
# Deterministically generate and render a shape from a seed
bitshaper generate --seed my-seed --grid 3x3 -o generated.svg
# List every curated catalog entry
bitshaper listSee docs/architecture.md for where code lives
and docs/code-standards.md for how it's
written. This project uses spec-driven development via
OpenSpec for changes under src/.