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.mjsreads the fillable sheet's 334 widgets and writeslayout.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 forsheet.contextSwitchCoverage.test.tsholds both switches to theContextTypeunion so the next context cannot reach only one of them.
A physical phone is still owed, as v0.98.0's M.11 is.