Skip to main content

Tokens

Tokens are the stable contract between design, Compose, Views, and OEM brand systems. Cabin uses semantic tokens (intent) and component tokens (localized decisions), with OEM overlays that remap without forking.

Goals

  • One token source for both UI stacks (architecture).
  • Brand customization without editing component source (extension model).
  • Validation hooks for contrast, min sizes, and safety color locks.

Token layers

Reference (raw palettes, type ramps)

Semantic (primary, surface, space.md, motion.fast, …)

Component (button.padding.x, statusBar.iconSize, hvac.zoneGap, …)

Components consume component and semantic tokens — never raw reference hex values.

Planned naming

cabin.color.semantic.primary
cabin.color.semantic.onPrimary
cabin.color.semantic.charging
cabin.color.scheme.night.surface
cabin.type.role.status.size
cabin.size.touch.minimum
cabin.space.md
cabin.motion.fast.duration
cabin.component.media.transport.size
cabin.component.hvac.zone.gap

Exact schema ships in Phase 2 (cabin-tokens). Formats under consideration: Kotlin objects, Android resources generated from a single YAML/JSON source, or both.

Semantic tokens (categories)

CategoryExamples
Colorbrand, surface, domain accents, feedback
Typographyroles, weights, line heights
Spacingdensity scale
Sizingtouch minima, icon sizes
Motionduration, easing
Opacityscrims, disabled
Shapecorner radii (cabin tends toward modest radii)

Component tokens

Component tokens bind semantics to a widget without leaking brand decisions into Kotlin/XML repeatedly:

cabin.component.button.primary.containerColor → semantic.primary
cabin.component.button.primary.minSize → size.touch.minimum
cabin.component.status.warning.iconColor → semantic.warning

OEM theming without forks

Cabin baseline tokens
+
OEM overlay (brand primary, type family, radius)

Locked safety semantics (not overridable or only with explicit break-glass)
=
Product theme

Planned overlay sketch

// Planned
object OemBrandOverlay : CabinTokenOverlay {
override val primary = Color(0xFF0B6E4F) // example only
override val typographyFamily = CabinFontFamily.OemSans
// cannot override semantic.error meaning
}

Views (planned): generate values-oem/ overlays or runtime CabinTokenBridge.

Dual-stack resolution

StackResolution
ComposeCabinTheme.tokens / composition locals
ViewsTheme attributes + resource lookups generated from the same source

Parity tests assert identical resolved values for a fixture overlay.

Anti-bloat

  • Apps depend on cabin-tokens (small) even if they only need colors for a custom screen.
  • Do not ship full reference palettes for unused OEM brands in the default artifact — overlays are product-owned.

Acceptance criteria (Phase 2)

  • Single source generates Compose and Views consumables
  • Overlay mechanism documented and sampled
  • Safety color lock enforced in validation
  • Day/night schemes complete for core roles