engine/y2k_aero library
The Y2K / Frutiger Aero family (spec §5.3 #10, enum y2kChrome, chip
label "Y2K Aero"; motion brief §2.3 "Y2K / chrome"): 2001–2008 glossy
optimism. Pure Dart: part of the generator, so every constant here is
part of the family's engine-v3 definition and must not change without a
version bump.
Two variants, drawn first on the background stream (so a seed keeps
its variant across palette retries and the Accessible lock):
- AERO (3 in 5, BackgroundKind.aeroSky): opaque, saturated gel keys — pearl or blue-lavender moonstone digits, frost or sea-glass function keys, blue and green gel operators — each with a hard white specular cap over its top 42 %, a deeper tone right under the cap and a light caustic at the bottom, under an azure sky with a lake horizon (Y2kScene.sky), over sunlit grass hills (Y2kScene.meadow) or deep in blue lagoon water with god rays (Y2kScene.water, the dark themes), with rising bubbles.
- CHROME (2 in 5, BackgroundKind.chromeHolo): satin-silver metal digits and titanium function keys in a light–dark–light chrome bezel, candy-gel operators, on pastel or black holographic foil with sparkles; heavy type with a slashed zero.
Keys are opaque where the label sits. The renderer paints each face as a vertical profile (y2kGelProfile / y2kMetalProfile) derived from the opaque face colour, plus white overlays (cap, sheen, hover, brushed streaks) and a lighter caustic. Inside the label zone (the middle 40 % of the height, y2kLabelZoneTop–y2kLabelZoneBottom) nothing darker than the profile's deep tone (floored at L 0.70, 0.735 under the Accessible lock) is drawn, and every label is darker than its face, so the label's worst backdrop is one of y2kLabelZoneSamples: the rest and pressed profiles blended in every proportion the renderer can show (validated as GuardrailRule.y2kLabelZone).
The press (motion brief "Y2K / chrome"): frame 1 swaps the body to the pressed face (y2kPressedFace: hue +20°, or an accent tint on the near-neutral pearl / silver / frost / titanium faces), flares the cap and slides it toward the finger; on release a specular band sweeps the face once, left to right.
Shared spec fields, as this family uses them:
| Field | Meaning here |
|---|---|
KeyStyleSpec.kind |
always KeyStyleKind.glass ("glossy"; faces are opaque) |
outlineWidthCdp |
AERO rim 1.00–1.50 dp; CHROME bezel ring 2.5–3.5 dp |
highlightPermille |
specular cap peak alpha (pressed + 0.10; ≥ 0.8 drawn on dark scenes) |
refractionPermille |
caustic glow alpha at the key's bottom (pressed × 1.8) |
edgeShadePermille |
depth of the deep tone under the cap (and the metal dark bands) |
shadowOffsetCdp / shadowBlurCdp |
the soft drop shadow (σ = blur / 2; offset ≤ 3 dp, blur ≥ 5 dp, so it stays within y2kEdgeShadowAlpha at a key's edge) |
stateLayerPermille |
0: the pressed cue is artwork, not a state layer |
Palette.background |
the Material chrome's surface (settings, history): the horizon haze (sky, meadow), the mid water (deep water) or the foil's base |
Palette.highlight |
the specular white, always opaque white |
Palette.shadow |
the drop-shadow colour and alpha |
Palette.accent |
= the focus ring (toolbar glyphs) |
KeyColors.edge |
AERO rim / CHROME hairline (≥ 3:1 on the scene under the lock) |
BackgroundSpec.colors |
six scene colours (y2k_aero_scene.dart lists the roles) |
angleTenths |
AERO sun azimuth; CHROME holo band angle |
pattern / patternColor / patternScaleCdp / patternOpacityPermille |
bubbles (AERO) or sparkles (CHROME): tint, size and layout seed, opacity |
driftPeriodMs |
on / off only (periods y2kAeroDriftMs, y2kChromeDriftMs) |
MotionSpec.fx / verb |
sheen / gloss (painted by the key face) |
Every draw comes from the generator's named sub-streams (palette and
its retry streams, background, shape, style, type, motion,
name), so a theme is a pure function of (seed, engineVersion,
accessible). The variant is a background draw, so a retry keeps it;
brightness is the first palette draw, so a retry may turn a light sky
into deep water (the shape, style, type and motion never change).
Classes
- Y2kGel
- One gel or candy colour: hue (tenths, may run past 3600 and wrap), lightness (thousandths; waterLMilli in the dark AERO scene), chroma as a share of the gamut (thousandths) capped at capMilli, and its weight.
Enums
Constants
- y2kAccentMinContrast → const double
-
Operator /
=vs digit: contrast ≥ y2kAccentMinContrast or min ΔEOK (normal + CVD) ≥ y2kAccentMinDeltaE (GuardrailRule.y2kAccentVsDigit). - y2kAccentMinDeltaE → const double
- y2kAccessibleDeepFloorMilli → const int
- y2kAccessibleFaceFloorMilli → const int
- y2kAccessibleFaceMinLMilli → const int
- y2kAccessibleLabelStartLMilli → const int
- y2kAeroDefinition → const FamilyDefinition
-
Y2K / Frutiger Aero (spec §5.3 #10; motion brief §2.3 "Y2K / chrome"):
opaque gel orbs or chrome-bezelled metal keys with a hard specular cap.
Press: effectsFast in, 439/0.75 out (seeded × {0.9, 1, 1.1}, ζ ± 0.05),
scale 0.96, a frame-1 hue +20° and cap flare, a specular sweep on
release; pop entry 0.88 → 1 on expressiveFast; sound
glass. The palette is built by buildY2kAeroCandidate. - y2kAeroDriftMs → const int
-
Drift period of each scene kind (constant:
driftPeriodMsonly says whether the scene drifts; a transition drops it to 0). -
y2kAeroGels
→ const List<
Y2kGel> - AERO gels: greens (0–2) and blues (3–5), every hue range ≥ 3° inside its 30° bucket (buckets 4–9).
-
y2kAeroLightSceneWeights
→ const List<
int> -
AERO light scenes:
[sky, meadow]weights (background stream). - y2kAeroRimCdp → const IntRange
- y2kBubbleMaxAlpha → const double
-
The bubble sprite's highest alpha (its rim over its body; the glint is
lower and never overlaps the rim): a bubble paints its tint at most at
this × the pattern opacity (
y2kBubbleBodyAlphain the scene painter lists the sprite). - Peak caustic alpha inside the label zone, as a share of the caustic's alpha (the oval's radial ramp where it meets the zone's bottom edge).
- y2kChromeBezelCdp → const IntRange
-
y2kChromeCandies
→ const List<
Y2kGel> - CHROME candies (buckets 0–4, 7, 9–11), lightness capped at 0.82 so a candy never matches a silver digit by lightness — except dandelion, which sits at L 0.84–0.88 (a darker yellow turns ochre) and stands apart from silver by its chroma and warmth (C ≈ 0.16 at 84–96°).
- y2kChromeDriftMs → const int
- y2kChromeFloorAlpha → const int
- CHROME: the pearl floor (the base colour over the bottom 15 % of the foil) at most at this alpha × 255.
- y2kDarkPanelGloss → const int
- y2kDarkShadowAlpha → const int
- The key drop shadow's alpha × 255 on a dark scene.
- y2kDeepFloorMilli → const int
- Floor of the deep tone under the cap × 1000 (standard / Accessible); the pressed deep tone may sit 25 lower.
- y2kEdgeDropMilli → const int
- AERO rim: the face 0.24 darker (y2kAeroEdge).
- y2kEdgeShadeRange → const IntRange
- y2kEqualsMinDeltaE → const double
-
=must stand this far (min ΔEOK, normal + CVD) from the operators before the shared rule's 0.05 (pre-separation, as in Neo-brutalism). - y2kFaceFloorMilli → const int
-
The validator's face floor × 1000 (standard / Accessible): a little
under the generator's, so the shared
=/ operator separation step has room (GuardrailRule.y2kLabelPolarity). - y2kFaceMaxLMilli → const int
- Highest key face lightness the generator moves a face to × 1000.
- y2kFaceMinLMilli → const int
- Lowest generated key face lightness × 1000 (standard / Accessible).
- y2kGelMinChroma → const double
-
A
=gel paler than this (OKLCH chroma) is a last resort. -
y2kGelStops
→ const List<
double> - Gel body profile stops (fractions of the key's height): M, M, T, F, M, B (y2kGelProfile).
- y2kGroundMinDeltaE → const double
- AERO light skies: the digit and function faces (and in a meadow the gel faces too: green gels melt into grass) at least this far (ΔEOK) from the ground band behind the keypad (GuardrailRule.y2kGround); the generator aims at y2kGroundTargetDeltaE.
- y2kGroundTargetDeltaE → const double
- y2kHighlightRange → const IntRange
- Renderer contract ranges (GuardrailRule.y2kGloss). The shadow's offset ≤ 3 dp and blur ≥ 5 dp keep it within y2kEdgeShadowAlpha just outside a key's edge.
- y2kLabelStartLMilli → const int
- Label search start lightness × 1000 (standard / Accessible).
- y2kLabelZoneBottom → const double
- y2kLabelZoneInset → const double
- y2kLabelZoneTop → const double
- The label zone: the middle 40 % of the key's height, inset 12 % at the sides. Only the opaque face profile and lighter overlays are drawn here.
- y2kLightPanelGloss → const int
- Display panel gloss alpha × 255 on a light / dark panel.
-
y2kMetalStops
→ const List<
double> - Metal body profile stops: sky, sky, D1 (the horizon line), F, M, D2, ground (y2kMetalProfile).
- y2kPanelDarkMaxMilli → const int
- y2kPanelLightMinMilli → const int
- Display panel lightness bands (GuardrailRule.y2kPanel): light panels ≥ 0.85, dark ≤ 0.24.
- y2kRefractionRange → const IntRange
- y2kShadowBlurCdp → const IntRange
- y2kShadowOffsetCdp → const IntRange
Properties
-
y2kWaterGels
→ List<
Y2kGel> -
The AERO gels in deep water: azure and cornflower (indices 4 and 5, at
their weights) become one cyan-leaning azure at L 0.80–0.82, so no
operator or
=shares the blue-lavender hue of the moonstone digits (L ≤ 0.755) and a blue gel stands clear of them by lightness while keeping its chroma (≈ 0.10–0.12; sRGB blues fade fast above L 0.8).final
Functions
-
buildY2kAeroCandidate(
int seed, FamilyDefinition def, int engineVersion, {int attempt = 0, bool accessible = false}) → ThemeSpec -
Builds one unvalidated Y2K / Frutiger Aero candidate (the generator
repairs and validates it, retries with
palette/retry/nand finally falls back to a Y2K hero). -
repairY2kAeroExtras(
Palette p, ThemeSpec spec, GuardrailLimits lim, List< int> bgs) → Palette? -
Family-specific repairs after labels and display texts (called from
repairThemefor ThemeFamily.y2kChrome specs only); null = unrepairable. Each key face is lifted to the gel floor and its label re-solved on its label zone (the face lifting 0.03 at a time when the label alone cannot reach the floor); AERO rims follow the final faces; under the Accessible lock every rim, and always the focus ring, is solved to 3:1 on the scene and the keys' shadow. -
validateY2kAero(
ThemeSpec spec, GuardrailLimits lim, List< int> bgs) → List<GuardrailViolation> -
The family-specific guardrails (called from
validateThemefor ThemeFamily.y2kChrome specs only);bgsare the scene samples. -
y2kAccentHueTenths(
Palette p) → int - The accent hue (tenths): the operator face's hue.
-
y2kAeroDisplayBackdrops(
ThemeSpec spec, List< int> surfaces, List<int> bgs) → List<int> ? -
Everything display text of
specmay be drawn on, fordisplayBackdrops: the opaque panel, the panel under its gloss band and (CHROME) under the gloss and the glare (y2kPanelSamples); display text never sits on the bare scene. -
y2kAeroEdge(
int face) → int -
The AERO rim of
face: 0.24 darker, chroma × 0.9 (≥ 0.035), turned 8° toward green on yellow-greens (an olive rim reads dirty). -
y2kAeroSceneSamples(
BackgroundSpec bg) → List< int> ? -
Guardrail background samples of a Y2K scene: every opaque colour a key,
label, rim, focus ring or the toolbar can sit over. H = the colour hull
of
colors[0..4](meshHullSamples: stops, pairwise ¼ / ½ / ¾ points and centroids — every gradient blend, hill and floor); the light overlay (colors[5]at its alpha: sun glow, flare ghosts, god rays, foil crease, all budgeted to stack ≤ that alpha) over H; CHROME's pearl floor over H; and the bubble / sparkle tint at its highest alpha (a bubble's rim over its body, y2kBubbleMaxAlpha; a sparkle is one path) over all of those. Null for malformed specs (the generic sampling then applies, and GuardrailRule.y2kScene fails). -
y2kCausticGlow(
int face) → int -
The caustic glow colour of
face: lighter, softer. -
y2kChromeEdge(
int digitHueTenths) → int - The CHROME bezel hairline: a dark neutral in the digit hue.
-
y2kDeep(
int face, int depthMilli, int floorMilli) → int -
The deep tone of
face: lightness lowered bydepthMilli/ 1000 but never belowfloorMilli/ 1000, chroma × 1.12. -
y2kDeepFloorFor(
{required bool accessible}) → int - The deep-tone floor × 1000 under the standard or Accessible lock.
-
y2kEdgeSamples(
List< int> bgs, int shadow) → List<int> -
What a key rim or the focus ring is seen against: the scene samples
bgs, plain and under the keys' ownshadow(y2kEdgeShadowAlpha). -
y2kEdgeShadowAlpha(
int shadow) → int - The key shadow's alpha × 255 just outside a key's edge, where its rim and the focus ring are seen: 0.9 of the drop shadow's alpha. The shadow is the face shifted down by the offset and blurred with σ = blur / 2, so directly under the bottom edge it covers Φ(offset / σ) ≤ Φ(3 / 2.5) ≈ 0.885 of its alpha for every style the generator draws (offset 2–3 dp, blur 5–8 dp).
-
y2kGelProfile(
int face, int depthMilli, int floorMilli) → List< int> -
The gel body colours at y2kGelStops for
face:M, M, T, F, M, Bwith M = F + 0.025, T the deep tone (y2kDeep,depthMillideep, floored atfloorMilli) and B = F + 0.06. -
y2kGroundSamples(
BackgroundSpec bg) → List< int> -
The ground band behind an AERO light keypad:
colors[3],colors[4]and their midpoint. Behind the keys the scene painter draws only these and their blends (the haze ramp ends at the keypad's top edge, a meadow's far field is the midpoint and its near hill's crest iscolors[3]; the lake glint, the sun's glow, flare ghosts and large bubbles stay beside the calculator), plus the micro-bubbles. -
y2kIsMeadow(
BackgroundSpec bg) → bool -
Whether an AERO light scene's ground (
colors[3]) is grass (a yellow- green to green hue) rather than a lake reflection. -
y2kLabelZoneSamples(
int face, {required int accentHueTenths, required int depthPermille, required int refractionPermille, bool metal = false, bool accessible = false}) → List< int> -
Every colour a label of a key with
facecan sit on inside the label zone, at rest and pressed: the body profile (y2kGelProfile or, formetalfaces, y2kMetalProfile) of the face and of its pressed face (y2kPressedFace ataccentHueTenths), each adjacent pair of stops that reaches into the zone blended at 0, ½ and 1, every rest / pressed pair blended at 0, ¼, ½, ¾ and 1 (the renderer fades the pressed body over the rest body with paint alpha), plus the caustic glow at its in-zone peak (refractionPermilleat rest, × 1.8 pressed). White overlays (cap, sheen, hover, streaks) only raise luminance, so they are not samples: labels are always darker than their faces. -
y2kLightCap(
BackgroundKind kind, {required bool dark}) → int -
Overlay caps per scene kind and brightness:
colors[5]alpha and the pattern opacity × 1000 (GuardrailRule.y2kScene). -
y2kMetalProfile(
int face, int depthMilli, int floorMilli) → List< int> -
The satin-metal body colours at y2kMetalStops for
face: a cool sky reflection, a dark horizon line D1 (floored like the gel's deep tone), the face, M, a dark band D2 and a warm ground reflection. -
y2kMix(
int a, int b, double t) → int -
a→battper channel in encoded sRGB (what gradients and paint alpha blend in), opaque. -
y2kPanelGlareAlpha(
int surface) → int -
The CHROME LCD glare streak's peak alpha × 255 for
surface: half the gloss (rounded up). -
y2kPanelGlossAlpha(
int surface) → int -
The display panel's gloss alpha × 255 for
surface. -
y2kPanelSamples(
int surface, {bool chrome = false}) → List< int> -
What display text sits on: the opaque panel, the panel under its gloss
band and, on a
chromeLCD, under the gloss with the glare streak crossing it (the lightest the panel gets). -
y2kPatternCap(
BackgroundKind kind, {required bool dark}) → int - Pattern opacity ceiling × 1000 (see y2kLightCap).
-
y2kPressedFace(
int face, int accentHueTenths) → int - The pressed face (frame-1 cue): lightness − 0.025; a coloured gel (C ≥ 0.06) keeps its chroma and turns +20°, a near-neutral face takes chroma 0.07 at the accent hue + 20°.
-
y2kSceneOf(
BackgroundSpec bg, {required bool dark}) → Y2kScene -
The scene of
bg(dark: the theme's brightness; AERO light scenes with a green ground are meadows). -
y2kTone(
int argb, int dLMilli, int cPermille) → int -
argbwith its OKLCH lightness moved bydLMilli/ 1000 and its chroma scaled bycPermille/ 1000 (hue kept), gamut-mapped. -
y2kVaporPair(
int a, int b) → bool -
CHROME candies that pair warm pink with cool aqua or blueberry
(bubblegum, grape, orchid × aqua, blueberry; strawberry × aqua):
Vaporwave's signature, so the
=pairing step skips them.