Skip to content

ADR 0064: Deck indicator kinds — visual language, render layer, and semantic palette

Status: Accepted
Date: 2026-04-19

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”):

  1. Indicator kind — what to show the operator: “lamp of this class”, “deviation bar”, “short label”.
  2. Low-level graphics ops — line, fill, FormattedText in DrawingContext / Skia commands.
  3. Scene / metric tokens — viewport, grid step, padding of a whole instrument (e.g. semantic map); not a DeckPrimitiveKind row, 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 kindunified 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 DeckPrimitiveKind or 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