engine/families library

Theme families (spec §5.3) and what each may generate (spec §5.2): allowed shapes, styles, fonts, backgrounds and effects with integer weights, harmony schemes, OKLCH role ranges for dark and light themes (research theme-engine.md §5.3) and motion tokens plus their seeded ranges (motion brief §2.3, §2.5).

Everything here is part of engineVersion: changing a weight, range or list order changes generated themes.

Classes

BileRule
The "disliked colour" rule (research §5.4, MCU DislikeAnalyzer): hues in loTenths, hiTenths with chroma above minChroma and lightness below maxL read as bile / olive and are rotated to lowTarget (hues below the band's middle) or highTarget.
ChromaRange
Chroma range: absolute (thousandths of OKLCH chroma) or relative (thousandths of maxChroma(L, h), then an absolute cap in thousandths).
FamilyDefinition
Everything the generator needs to know about a family.
FontIds
Stable font ids (match BundledFont.id in lib/themes/render/fonts.dart).
IntRange
Inclusive integer range.
MotionRanges
RoleRange
OKLCH lightness (thousandths) + chroma range for one role.
RoleRanges
Role ranges for one brightness (research §5.3).
Weighted<T>
A value with an integer sampling weight.

Enums

HarmonyScheme
Colour-harmony schemes as OKLCH hue offsets (research §5.2).
ThemeFamily
Theme families. id is the stable 5-bit number used in share codes and JSON — never use index. Ids 30 (reserved) and 31 (hero, see share_code.dart) are never families.

Constants

m3ExpressiveDefinition → const FamilyDefinition
Material 3 Expressive (spec §5.3 #1; motion brief §2.3 row 1): tonal palettes, shape-morphing keys (full round → 30 % of the short side), scale 0.97, +10 % state layer snapped in frame 1, pop entry.
neoPopDarkRangesV2 → const RoleRanges
Engine v2 NeoPOP dark ranges (review: khaki function keys, pastel accents): near-neutral function faces (C ≤ 0.015) and operator / = lightness at the hue's chroma cusp ± 0.06, clamped to 0.62–0.80.
neoPopDefinition → const FamilyDefinition
NeoPOP (spec §5.3 #3; motion brief §2.3 row 3): dark base, bright flat colours, hard extruded edges; the face translates (+d, +d) with d = 3–5 dp (seeded), no tint, release haptic, drop entry.
neumorphismDarkRanges → const RoleRanges
Neumorphism dark ranges (research §7.2): a charcoal base (L 0.20–0.28, C ≤ 0.02); tinted operator faces ≥ 0.10 lighter than it; a light accent = with dark ink.
neumorphismDefinition → const FamilyDefinition
Neumorphism / Soft UI (spec §5.3 #4; motion brief §2.3 row 4; docs/m4-design.md §C). Keys are the surface itself, lifted by a light (top-left) and dark (bottom-right) soft shadow pair derived in OKLCH from it, plus the contrast fixes classic neumorphism lacks (research recommendation 7): a 1–1.5 dp rim on the shadow side solved to ≥ 3:1 against the surface, labels ≥ 4.5:1 (7:1 accessible), operators with an accent face or accent label and a heavier glyph (recorded as OperatorCue.weight), and a pressed state that also swaps the label colour and closes the rim (validated: GuardrailRule.softPressedLabel).
neumorphismLightRanges → const RoleRanges
Neumorphism light ranges (research theme-engine.md §7.2): a near-white monochrome base (L 0.88–0.94, C ≤ 0.02) that is also every digit and function face; operators either keep it (accent labels) or take a tinted face ≥ 0.10 darker; = is a full accent face. Mid-band bases (L 0.46–0.67) are avoided: they cannot carry 7:1 labels.
retroDefinition → const FamilyDefinition
Retro hardware (spec §5.3 #5; motion brief §2.3 "Retro hardware"; docs/m4-design.md §B): a 90s desk or pocket calculator. Keycaps with a top-highlight / bottom-shadow bevel that swaps on touch-down (frame 1) and 2–3 dp of travel (seeded, whole dp), hardPress in and 1200/0.7 out; a 7-segment LCD (or VFD) display drawn by an in-house segment painter (TypeSpec.lcd), segments on 30 ms / off 50 ms; sound beep (desk themes sometimes mech_clicky), haptic rigid plus a release tick. Operators always carry a heavier label (OperatorCue.weight). The palette is built by buildRetroCandidate (retro.dart).
retroDeskRanges → const RoleRanges
Retro desk (beige / cream body) ranges: cream digit keys above the body (or dark-brown ones, see retro.dart), dark grey function keys, muted accent operators and a stronger accent =.
retroPocketRanges → const RoleRanges
Retro pocket (black / charcoal body) ranges: graphite digit keys at least 0.08 above the body, a function step lighter, muted accent operators and a stronger accent = (docs/m4-design.md §B). Only the lightness / chroma ranges are read (by buildRetroCandidate); hues come from the Retro tables in retro.dart.
standardDarkRanges → const RoleRanges
Standard dark ranges (research §5.3).
standardLightRanges → const RoleRanges
Standard light ranges (research §5.3).
standardLightRangesV2 → const RoleRanges
Seeded motion variation (motion brief §2.5). pressIn is never varied. Engine v2 light ranges (review: digit keys vanished into light backgrounds, function keys merged with digits): background 965–990, digits 870–925 and ≥ 0.04 below the background, function keys 780–850 and ≥ 0.05 below the digits; digit chroma still capped at 0.03.

Properties

familyDefinitions → Map<ThemeFamily, FamilyDefinition>
Definitions for every family (disabled ones are placeholders).
final
familyDefinitionsByVersion → Map<int, Map<ThemeFamily, FamilyDefinition>>
The generator definitions of every shipped family, per engine version (design doc "Rules": ThemeSpec is a pure function of (seed, family, engineVersion)). A version's map is frozen once released: a change to any definition, or shipping another family, is a new version entry plus a new golden fixture. Families missing from a version's map are refused by the generator, the feed and share codes at that version.
final
latestDefinedEngineVersion → int
The newest engine version with definitions.
no setter

Functions

familyDefinitionAt(ThemeFamily family, int engineVersion) → FamilyDefinition?
family's definition at engineVersion, or null when that version did not ship it (or is unknown).
familyShippedAt(ThemeFamily family, int engineVersion) → bool
Whether engineVersion generates family.
pickWeightedValue<T>(Rng rng, List<Weighted<T>> options) → T
Picks from options by integer weight (research §9.5).
placeholderFamilyDefinition(ThemeFamily family, MotionSpec motion, {required KeyShapeKind shape, required KeyStyleKind style, required SoundPackId sound, MotionRanges motionRanges = const MotionRanges()}) → FamilyDefinition
A disabled family: motion tokens from the brief, generic everything else. Filled in when the family ships.