ADR 0064: Deck indicator kinds — visual language, render layer, and semantic palette¶
Status: Accepted
Date: 2026-04-19
Related ADRs¶
| ADR | Role |
|---|---|
| 0063 § kinds | DeckPrimitiveKind, Presence / Dark Cockpit |
| 0055 | Render pipeline stage |
| 0021 | Dark Cockpit |
| 0046 | layout invariants |
| 0066 | cockpit palette vs IDE chrome |
Summary¶
- Deck indicator kinds: unified rendering + semantic palette.
DeckPrimitiveKind— catalog of kinds; no extra architectural layer.
Code: Cockpit/PrimitivesKit/ — annunciator, lamps, semantic map tokens.
Context¶
0063 § indicator kinds fixes the product taxonomy of indicator kinds: Lamp, Bar, Sign, Readout, etc. — signal shape in a deck cell or Skia instrument fragment.
In parallel, code and conversation mixed meanings (formerly tied to “primitive”):
- Indicator kind — what to show the operator: “lamp of this class”, “deviation bar”, “short label”.
- Low-level graphics ops — line, fill,
FormattedTextinDrawingContext/ Skia commands. - Scene / metric tokens — viewport, grid step, padding of a whole instrument (e.g. semantic map); not a
DeckPrimitiveKindrow, but shared layout constants.
Without explicit separation, features duplicate colors and geometry in XAML, VM, and render code: attention goes to competing shades and “Christmas tree” UI, not task and state hierarchy (0021 §6). We need a norm: one visual language per indicator kind and one render library that implements it.
Decision¶
1) Indicator kinds are high-level with unified graphics¶
An indicator kind per 0063 is an atomic glance: UI data is which kind (DeckPrimitiveKind and state profile) plus minimal payload (legend text, severity, readout number, etc.), not “draw rectangle #rrggbb”.
Invariant: for each indicator kind + state semantics (e.g. Lamp + ok / caution / unavailable) the product has exactly one consistent graphic embodiment in the cockpit (shape, border weight, label typography, semantic color — see §3). Arbitrary per-screen styling is not allowed: the operator spends attention on style, not state.
Features and deck compositors pass kind semantics into the render library, not low-level graphics op lists.
2) Render library for indicator kinds (shared with 0055)¶
To uphold §1 in code, use a shared render library (repo: Cockpit/PrimitivesKit/, Render stage per 0055):
- per supported kind (or narrow family, e.g. annunciator Lamp) — one “how to draw” implementation: functions/types taking
DrawingContext(and bounds if needed), no duplicated logic in controls and instruments; - for Skia pipeline, same contract as draw instructions with the same semantics, without copy-paste colors/metrics from Avalonia XAML.
Boundary: render library does not replace instrument compositor (Intent → Declutter → Layout) or business logic; it only implements agreed appearance from semantic inputs.
Folder name PrimitivesKit is collective; see lexicon and §4 for whole-scene metrics.
3) Unified color language (semantic palette)¶
Color in the cockpit for deck indicators and instruments reads as meaning (readiness level, deviation severity, informational), not decoration.
Invariants:
- palette defined by semantic roles (e.g. nominal, attention, info, unavailable), not arbitrary hex per feature;
- aligned with Dark Cockpit (0021, 0063 § Presence): in nominal state do not multiply bright pixels and animation “for beauty”;
- for a11y (not color alone) — extensions of the same semantics (icon, hatch), not a second “palette” without rules.
Concrete token values may live in theme/resources, but role → display mapping stays single and aligned with §2. EICAS W/C/A vs everyday Error/Warning/Information and AnnunciatorLampLevel — table in 0021 §5.
4) Indicator kind vs whole-scene tokens¶
Indicator kind and boundary with instruments — 0063 § primitive vs instrument (section title uses historical “primitive”; meaning is indicator kind vs instrument).
Layout / composition metrics (instrument viewport, graph level step, scene padding) are not deck indicator kinds; code may use layout tokens, instrument geometry to avoid confusion with DeckPrimitiveKind.
Non-goals (current phase)¶
- Full public render API contract for third-party plugins (0063 open questions).
- Entire cockpit palette in one TOML before theme stabilizes.
- No exceptions: local experiments behind flags are allowed but must not define a second “canon” without ADR review.
Consequences¶
- Product discussion and review use: indicator kind → unified render (§2) → composition in instrument/deck — without an extra intermediate “layer” in architecture.
- Duplicated lamp/readout colors/geometry is technical debt until moved to §2 and §3 palette.
- Prefer indicator kind / signal shape in text; “primitive” only when citing
DeckPrimitiveKindor legacy 0063 section titles.
Alternatives (brief)¶
| Option | Downside |
|---|---|
| Markdown guidelines only, no ADR | No stable reference in architecture policy |
One huge theme.json without render layer |
Semantics spread across bindings; palette drifts |
| Forbid any numbers outside PrimitivesKit | Too rigid for prototypes; §4 separation is enough |