Architecture Decision Records ​
Decisions behind @jolly-pixel/ui that are hard to reverse, surprising without context, or the result of a real trade-off. The package README indexes the guides and the API reference.
A choice confined to one component's API belongs in that component's API page, not here. Numbers are never reused: gaps are records that were merged into another one or moved to the API docs.
| # | Decision |
|---|---|
| 0001 | Custom elements are the public API, the facade only constructs them |
| 0002 | Controlled elements, stateful facade |
| 0003 | One shared field contract on a base class, not a mixin or controller |
| 0005 | disabled, readonly and lockedBy combine rather than override |
| 0007 | Tokens are declared once on scope hosts, using light-dark() |
| 0008 | Two token tiers: private ramps, public semantics |
| 0009 | Control backgrounds are alpha stops of one ink |
| 0010 | Non-text contrast is deliberately not met for control boundaries |
| 0011 | Roboto Mono is inlined as a base64 data URI, one weight |
| 0012 | Placement is separate from content |
| 0014 | jolly-color drops input[type="color"] |
| 0015 | Measurement is separate from display, ./stats is DOM-free, and metric sources are structural |
| 0016 | Built-in metrics and icons carry no privilege over registered ones |
| 0017 | ui declares a presence port and owns the presence schema |
| 0018 | Locks are advisory, live in the holder's presence, and only paint |
| 0020 | Keyboard ownership follows focus, and an open layer claims every key |
| 0021 | Structural math types, no three dependency |
| 0022 | Layout persists through derived keys and a stated reconciliation algorithm |
| 0023 | Field events are not cancelable, and carry the value alone |
| 0024 | No spec imports a component, so testable logic lives in plain modules |
| 0025 | Lit is a peer dependency and the barrel is never side-effect-free (superseded by 0041) |
| 0027 | The facade writes a math value component-wise, and an axis key is the domain identity |
| 0031 | jolly-log is an ambient feed, and jolly-toast stays deferred |
| 0033 | The layout snapshot is the only layout state, groups and columns included |
| 0037 | Colour is a tone on the glyph and an area on the pane, and a dialog's intent is not a tone |
| 0040 | A declarative binding reads through to its source and keeps no mirror |
| 0041 | Elements register through their own entry points, and the root registers none |
Scope boundary ​
ui owns anything expressible without knowing what a voxel, a layer or an asset is. Domain-coupled composites stay in editors and are built from these parts. Asset and object reference pickers, block and blockset libraries, 3D preview tiles, and curve and gradient editors are out of scope.
jolly-split and menubar or dropdown menus are deferred rather than rejected: no consumer in this repository names one, so there is nothing to validate a design against. jolly-context-menu left that list once a tree needed right-click row actions; it opens only at a point until a button menu has a consumer. jolly-toast stays deferred for a different reason: editors/voxel-map needed an ambient feed, not an alert, and got jolly-log instead. See ADR-0031.
Open questions ​
- Whether
jolly-treevirtualizes. Deferred until a consumer exceeds a few hundred nodes. - Whether pane state beyond order persists through Tweakpane-style
exportState/importState. Not built: no consumer to validate a serialisation format against. - Whether a central shortcut registry and user-rebindable shortcuts are needed, and where overrides persist. If built, spatial bindings match
event.code(soKeyWstays the physical key on AZERTY) and command bindings matchevent.key(so undo stays on the key labelled Z).@jolly-pixel/controlskey chords already match this way ("KeyQ"is a position,"z"a printed letter), so a registry would build on them. - Whether
jolly-flagsandjolly-layer-gridneed per-bit mixedness. A bitmask across a multi-selection genuinely is mixed bit by bit, whichFieldValue<number>cannot express. - Relative multi-edit is not expressible.
{ value: T }carries one absolute value; Unity applies a delta to each selected object instead, which would need a second detail shape and write-back path. - Whether
JollyFieldbecomes public. Promoting it is additive (ADR-0003).