workshop

← all creations

Ledger Scribe

sprites · created 2026-08-29

34×26 pixel sprite — a bookkeeping clerk whose posture and tally columns read how well the ledger balances, from steady strokes to a snapped quill.

pixel-artcanvas

A bookkeeping clerk hunched over an open ledger, with the books doing the storytelling: even, upright strokes and two matched tally columns when debits equal credits; a lower hunch and faster scribbling as one column outgrows the other; and — once it won’t reconcile — a snapped quill and spilled ink pooling across the page. Nods to a system design deep-dive on payment ledgers and why double-entry accounting is really just an invariant check running in production.

Reuse

Render at integer scales with nearest-neighbor filtering or the edges smear. balanced plays at 1.5 fps, drifting at 4 fps, broken at 1 fps (ANIMATIONS in the module carries all three).

Source

No .aseprite — the canonical source is source/ledger-scribe.mjs: a framework-free ES module holding the clerk as a character map (one char per pixel, palette at the top). Edit the grid and regenerate everything with:

node source/render.mjs

(needs site/node_modules installed — the script resolves Playwright from there.) That one command rewrites export/, media/, thumb.png, and the demo’s bundled copy of the module, so nothing drifts.

How the frames are built

One static CLERK grid — hair, glasses, collar, torso, reaching arm — is painted at a per-frame clerkTop offset plus a hunch that pushes everything from the collar down further forward as the ledger drifts, the same posture-reads-a-metric trick as warehouse-duck’s waterline. The ledger itself (desk, open page, two tally columns, quill, ink) is drawn entirely from numbers rather than a second sprite: each frame’s debit and credit counts are literally the pixel heights of two columns growing up from the page’s baseline, so a balanced ledger draws two equal stacks and a drifting one visibly pulls apart. While writing, the quill is a short interpolated stroke from the clerk’s wrist to the debit column’s current height; once quill: 'snapped', both pieces drop onto the page instead and an ink pool spreads from the spine outward with ink.

Gotchas

Port notes

paintFrame is grid-walking plus a handful of arithmetic overlays with no DOM dependency beyond a 2D context — same shape as warehouse-duck’s — so a DragonRuby port translates directly: keep the grid as strings, map cells to args.outputs.solids, or just consume scribe-sheet.png as a spritesheet with source_x = frame * 34.