Skip to content

v0.106.0 — New character sheet: the 5e sheet

Shipped 2026-09-22 — built on version/0.106.0; the merge hash and tag are in the changelog. The sixteenth of the releases the near-term roadmap sequences from the August 2026 heuristic evaluation, and part two of the new character sheet; the roadmap page is the 5e sheet. Module API 1.40.0; dnd5e 0.17.0. The developer page is Character Sheet Renderer.

The first real sheet on v0.105.0's seam. The module ships the component and the platform ships the frame: the fillable 5e sheet's three pages, drawn by dnd5e from @purple-cat/sheet-kit, writing only through SheetApi.edit.

The sheet (in the module)

  • The geometry is the printed form's (N5.1) — scripts/extractLayout.mjs reads the fillable sheet's 334 widgets and writes layout.json: every field's rectangle, the 45 boxes the sheet draws, each page's columns and reading order. The PDF is not committed; the layout is (NS-D3).
  • Three pages as reflowing grids (N5.2), matching the form at 612 px and stacking three → two → one column below it, in the form's reading order.
  • The module's own chrome (N5.3): containers, labels and frames matching the boxes, every colour a --vtt-* token, a Retro variant and a plain one. One sheet, both editions.
  • Homes for the homeless fields (N5.4) under metadata.dnd5e.*, declared so the write path, history and the importer know them.
  • Every field with its editor (N5.5) over a pure view model; rollable and acknowledged (N5.6); print (N5.7).

What the platform learned (Module API 1.40.0)

The seam's corrections, from building the first real sheet on it: SheetApi.rest (the quick view's rest flow behind the API, the host asking the prompts the sheet did not answer), SheetApi.equipment with a live equipment prop, treasury.claim, openPicker('attack', attackId) to edit an attack in place and openPicker('ability-scores') for the platform's generation modal (NS-D10's Regenerate), and CharacterSheetSchema.metadataFields / metadataNamespace — a system's own fields, declared: the write path type-checks them, the history diff descends into the metadata bag and labels each leaf by the module's own label, and the importer asks the model for them by path. Plus _ownerName on GET /api/characters/:id, for the sheet's Player box.

The kit gained the reflow (Page's reflow steps, measured at the container, with rows that lengthen) and --sk-region-padding.

The playtest (NS.14)

The desktop pass found the sheet's alignment and sizing, fixed in the module, and two platform bugs worth naming:

  • The character page reached its sheet only through the ⋯ menu, while the Character context showed a button. It is the same button in both places now.
  • Undocking the sheet drew nothing: FloatingContextWindow's switch had no case for sheet. contextSwitchCoverage.test.ts holds both switches to the ContextType union so the next context cannot reach only one of them.

A physical phone is still owed, as v0.98.0's M.11 is.