engine/claymorphism library
The Claymorphism family (spec §5.3 #7; motion brief §2.3 "Claymorphism"; design: inflated, matte, soft-touch plasticine). 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.
- Keys are big puffy squircles on an opaque, multi-pastel face, with
three stacked depth cues the guardrails check are visible: a soft
drop shadow tinted from the key's own hue (
KeyColors.edge, never grey, GuardrailRule.clayShadowTint; deep and dense on night bodies so it still reads there), a white top-left highlight that lifts every face by ≥ 0.025 L (Palette.highlight, GuardrailRule.clayHighlight) and a darker bottom-right inner shade (KeyStyleSpec.edgeShadePermille, clayInnerShade). - Lightness ladder (both brightnesses): digits 0.915–0.950 >
function keys 0.80–0.86 (light ones as low as ~0.75 after they are
pushed below the body) > candy operators 0.68–0.78 > the deep gummy
=0.46–0.54 (0.40–0.44 under the Accessible lock). Light bodies (L 0.855–0.895; butter 0.880–0.895) sit between the digits and the function keys; night bodies (plum, indigo, midnight, berry at L 0.20–0.26) sit ≥ 0.15 below every key (GuardrailRule.clayKeyBody), and the night=keeps ≥ 2.8:1 against the body. - Variants: candy (contrasting triples, 45 %), tonal (one-colour
plasticine sets, 30 %) and night (25 %). The candy-hue rule
(clayCandyHue) keeps operators, function keys and spheres out of
75–130° (spreading the moved hues past the band edges rather than
piling them on one colour); the
=rule (clayEqualsHue) keeps the gummy out of 35–150° and the dull teal / petrol band and turns a red=beside a green operator grape; night operators turn kelly green to jade (clayNightOperatorHue); night spheres turn red-orange / amber to berry and green / teal / cyan to violet, berry or cobalt jewels (clayNightSphereHue): no mustard, olive, moss, brown or slate. - Display: a puffy pillow card in the opaque surface colour (the recessed tray is retired: at phone size it read as an LCD well or a Neumorphism inset); display text only ever sits on it.
- Scene (BackgroundKind.claySoft): a soft pastel or night-clay
wash with two clay spheres.
colorsholds exactly nine opaque colours:[0]base (the keypad body, =Palette.background),[1]top wash,[2..4]sphere A lit / body / shade,[5..7]sphere B lit / body / shade,[8]sphere shadow core.angleTenthsis the size balance between the spheres (0–750, step 150). Static (no drift).
Every draw comes from the generator's named sub-streams (style first,
then palette and its retry streams, background, shape, type,
motion, name), so a theme is a pure function of (seed,
engineVersion, accessible).
Enums
- ClayVariant
- The three sub-variants.
Constants
- clayAccessibleEqualsLMilli → const IntRange
- clayAccessibleNightBodyLMilli → const IntRange
- Accessible lock: night bodies are remapped linearly onto this range.
- clayAccessibleOperatorMinLMilli → const int
-
Accessible lock: operator lightness floor and the
=range (× 1000). - clayBodyChromaFloorMilli → const int
- Light body chroma floor (thousandths): rose and lavender bodies below it read dusty.
- clayButterAnchor → const int
- The butter anchor's index in clayLightBodyHues. At the shared body lightness and relative chroma (capped at 0.060) a 90–100° body reads khaki or manila, so butter takes its own lightness (clayButterLMilli) and absolute chroma (clayButterChromaMilli), mapped linearly from the same draws: a clean pastel yellow.
- clayButterChromaMilli → const IntRange
- clayButterLMilli → const IntRange
- clayCandyKeyBand → const IntRange
- Candy-hue rule for operators, function keys and spheres: hues inside clayCandyKeyBand move past the nearer of clayCandyKeyTargets (by half their depth into the band, at most clayCandyKeyPush).
- clayCandyKeyPush → const int
- clayCandyKeyTargets → const (int, int)
-
clayCandySchemes
→ const List<
Weighted< (int, int, int)> > -
(operator, function,
=) hue offsets from the body hue (tenths): candy and night themes. - clayCoolMilkShiftTenths → const int
- clayCreamHueTenths → const IntRange
- Cream digit hues (tenths), and the shift that turns cream into cool milk on warm (peach / butter) bodies (→ 245–265°).
- clayDigitAboveBodyMilli → const int
- Light digits sit at least this far above the body (L × 1000).
- clayDigitHueJitter → const int
- clayDigitMaxLMilli → const int
- Digit lightness cap (× 1000): the highlight stays visible (lift ≥ 0.025).
- clayEqJitter → const int
- clayEqualsBand → const IntRange
-
Candy-hue rule for
=(both modes, normal and accessible): no moss, olive or mustard gummy. Moved hues land at 5–25° (red) or 156–176° (emerald). - clayEqualsChromaMilli → const int
-
=chroma floor (both modes): at least min(clayEqualsChromaMilli / 1000, clayEqualsChromaRel / 1000 × maxChroma), so the key stays a saturated gummy. - clayEqualsChromaRel → const int
- clayEqualsDullBand → const IntRange
-
=hues inside clayEqualsDullBand (165–245°, teal to petrol: sRGB holds only C 0.07–0.12 there at the=lightness, so the gummy comes out drab) move past the nearer of clayEqualsDullTargets — emerald (156°) and cobalt (256°) — by half their depth into the band, at most clayEqualsDullPushDown down (never below 150°) or clayEqualsDullPushUp up; past the other one when the nearer target lies within clayEqualsOpGap of the operator hue or (night) within clayNightEqualsBodyGap of the body hue (clayEqualsDullHue). - clayEqualsDullPushDown → const int
- clayEqualsDullPushUp → const int
- clayEqualsDullTargets → const (int, int)
- clayEqualsOpGap → const int
- clayEqualsPush → const int
- clayEqualsTargets → const (int, int)
- clayFnJitter → const int
- clayFocusShadowPermille → const int
- The focus ring is also solved against each key group's own drop shadow at this fraction (× 1000) of its alpha over every scene colour a key can sit on (clayFocusShadowBackdrops): the ring is drawn 2–4 dp outside the key, where the soft shadow still covers up to ~62 % (depth 6 dp, blur 14 dp on a 64 dp key).
- clayFunctionBelowBodyMilli → const int
- Light function keys sit at least this far below the body (L × 1000).
- clayFunctionMinCvdDeltaE → const double
- Light function keys keep at least this colour-blind ΔEOK (the minimum over normal vision and the three dichromacies) from the body.
- clayGrapeEquals → const IntRange
- clayGreenOperatorBand → const IntRange
-
A green operator (hue in clayGreenOperatorBand) with a red
=(hue in clayRedEqualsBand, wrapping) reads as Christmas: the=turns grape (clayGrapeEquals, spread by its place in the red band). - clayHighlightAlpha → const IntRange
- White highlight alpha (0xA0–0xC8), step 10.
- clayInnerShadePermille → const IntRange
- Inner bottom-right shade depth (L × 1000), step 10.
- clayLabelZoneInset → const double
- The label zone of a clay key: its face deflated by this fraction of the rest short side. Inside it the renderer paints only the face colour (the highlight, cover ramp and inner shade end at 0.20 s).
- clayLightBlobChromaMilli → const IntRange
- clayLightBlobLMilli → const IntRange
- Light sphere bodies: lightness offset from the base and absolute chroma (× 1000), so they read as solid objects.
-
clayLightBodyHues
→ const List<
Weighted< IntRange> > - Light body hue anchors (tenths) and weights. Index 1 (peach) and 4 (butter) are warm: their cream digits turn cool milk.
- clayLightRanges → const RoleRanges
- Light ranges (candy and tonal). Hues come from the scheme tables.
- clayLightSphereWarmBand → const IntRange
- Light spheres with a hue in clayLightSphereWarmBand (35–75°: tan and biscuit at low chroma) get at least min(clayLightSphereWarmChromaMilli, 0.9 × maxChroma): apricot, not cardboard.
- clayLightSphereWarmChromaMilli → const int
-
clayLightVariantWeights
→ const List<
int> -
Light themes:
[candy, tonal]weights. - clayMinHighlightLift → const double
- The smallest lightness lift the highlight must give every face.
- claymorphismDefinition → const FamilyDefinition
-
Claymorphism (spec §5.3 #7; motion brief §2.3 "Claymorphism"): opaque
squircle keys with a coloured drop shadow, an inner top-left highlight
and an inner bottom-right shade. Press: a bottom-anchored squash
(X 1.04 / Y 0.92) on 1755/0.85, the shadow 40 % smaller from frame 1, a
visible tall-and-thin rebound on 322/0.65; the display pops glyphs in
from 0.86; sound
pop, haptic soft · 0.8. The palette is built by buildClaymorphismCandidate. - clayNightBlobChromaCapMilli → const int
- clayNightBlobChromaFloorMilli → const int
- clayNightBlobChromaRel → const IntRange
- clayNightBlobLMilli → const IntRange
- Night sphere bodies: absolute lightness and relative chroma (× 1000, capped at clayNightBlobChromaCapMilli, at least min(clayNightBlobChromaFloorMilli, 0.9 × maxChroma)): glowing jewel clay 0.15–0.26 L above the body, never a dark smudge.
- clayNightBodyChromaFloorMilli → const int
- Night body chroma floor (thousandths): below it berry and plum bodies read aubergine-brown (C 0.06 is in gamut for every night anchor at L 0.20).
-
clayNightBodyHues
→ const List<
Weighted< IntRange> > - Night body hue anchors: hues whose maximum chroma at the shadow lightness (L 0.11–0.17) is ≥ 0.05, so night shadows stay coloured.
- clayNightEqualsBodyGap → const int
- clayNightEqualsMaxLMilli → const int
- clayNightEqualsMinContrast → const double
-
Normal-mode night
=keys keep at least clayNightEqualsMinContrast against the body, lifted 0.01 L at a time up to clayNightEqualsMaxLMilli (× 1000): the most important key never sinks into the clay. - clayNightJade → const IntRange
- clayNightKellyBand → const IntRange
- Night operators in clayNightKellyBand (kelly green on a plum or berry body reads as Christmas) move to jade (clayNightJade, spread by their place in the band).
- clayNightMinKeyAboveBodyMilli → const int
- Night keys sit at least this far above the body (L × 1000).
- clayNightRanges → const RoleRanges
- Night ranges.
-
clayNightShadowAlpha
→ const List<
int> - clayNightShadowDrop → const double
- Night drop shadows: lightness clayNightShadowL (the body less 0.14, at least 0.07) and chroma ≥ clayNightShadowMinChroma (capped by the gamut); a hue qualifies when maxChroma there is ≥ that too.
- clayNightShadowMinChroma → const double
- clayNightShadowMinL → const double
- clayNightSphereBodyGap → const int
- clayNightSphereGap → const int
- clayNightSphereJewelBand → const IntRange
- Night spheres: green, teal and cyan hues (clayNightSphereJewelBand) read bottle-green, moss or slate on night clay, so they move to the first of clayNightSphereJewels (violet, berry, cobalt; spread by their depth into the band) that keeps clayNightSphereBodyGap from the body hue and clayNightSphereGap from the other sphere (clayNightSphereHue).
-
clayNightSphereJewels
→ const List<
IntRange> - clayNightSphereWarmBand → const IntRange
- Night spheres: a red-orange / apricot / amber hue at L 0.40–0.46 is maroon or brown, so hues in clayNightSphereWarmBand turn to berry (clayNightSphereWarmTarget minus a fifth of their depth into the band: 330–345°), like hero 72's sphere under coral operators.
- clayNightSphereWarmTarget → const int
- clayOpJitter → const int
-
Hue jitter (± tenths) of candy and night operators, function keys and
=. - clayPanelShadePermille → const int
- The pillow card's shaded rim: clayInnerShade of the surface at this depth (× 1000), a little softer than a key's.
-
clayPanelWeights
→ const List<
int> -
Display panel weights
[pillow, tray]: the recessed tray is retired (weight 0: at phone size it read as an LCD well or a Neumorphism inset). The palette stream still makes the draw, so every later palette draw keeps its place. - clayPillowChromaMilli → const IntRange
- clayPillowChromaRel → const int
- Light pillow chroma: clayPillowChromaRel / 1000 × the body chroma, clamped to clayPillowChromaMilli (× 1000), so the card is a pale tint of the body, never grey.
- clayPillowMaxLMilli → const int
- Light pillow lightness cap (× 1000).
- clayPressedShadowPermille → const int
- The pressed drop shadow: offset and blur × this (× 1000) — "the shadow is 40 % smaller from frame 1".
- clayRedEqualsBand → const IntRange
-
claySceneMixPairs
→ const List<
(int, int)> - The index pairs whose encoded-sRGB ½ mixes claymorphismSceneSamples adds to the nine stops (the gradients' midpoints a key, label or ring can sit over).
-
clayShadowAlpha
→ const List<
int> - Drop-shadow alpha per KeyGroup (digit, operator, equals, function). Night shadows are denser: on a body at L 0.20–0.26 a lighter one cannot be seen.
- clayShadowAlphaMax → const int
- clayShadowAlphaMin → const int
- Lowest and highest drop-shadow alpha the guardrail accepts.
- clayShadowBlurCdp → const IntRange
- Drop-shadow blur radius, dp × 100, step 200.
- clayShadowCdp → const IntRange
- Drop-shadow offset at rest (= the motion depth), dp × 100, step 100.
- claySphereJitter → const int
- Hue jitter (± tenths) of the sphere hues and of non-cream digits.
- claySquashStretchPermille → const int
- Squash stretch at full press (X 1.04; Y is the motion scale 0.92).
- clayTonalJitter → const int
- Hue jitter (± tenths) of all three tonal key hues.
-
clayTonalSchemes
→ const List<
Weighted< (int, int, int)> > -
(operator, function,
=) hue offsets from the body hue (tenths): tonal themes (function keys on the far side of the operators). - clayTopWashLightMilli → const int
- Top wash: lightness above the base (× 1000).
- clayTopWashNightMilli → const int
- clayWarmFunctionBand → const IntRange
- Function keys with a hue in clayWarmFunctionBand (40–75°: café au lait at low chroma) get at least min(clayWarmFunctionChromaMilli, 0.95 × maxChroma).
- clayWarmFunctionChromaMilli → const int
Functions
-
buildClaymorphismCandidate(
int seed, FamilyDefinition def, int engineVersion, {int attempt = 0, bool accessible = false}) → ThemeSpec -
Builds one unvalidated Claymorphism candidate (the generator repairs
and validates it, retries with
palette/retry/nand finally falls back to a Claymorphism hero). -
clayCandyHue(
int hue, IntRange band, (int, int) targets, int pivot, {int maxPush = 0}) → int -
The candy-hue rule:
hueinsidebandleaves it on the side of whichever oftargetsis circularly nearerpivot(the hue itself for candy and night themes, the body hue for tonal ones; ties go to the first). It lands on the target pushed away from the band by half the hue's depth into the band from that side, at mostmaxPush— so the band stays empty without piling every moved hue onto one colour. Pure integer tenths. -
clayDropShadow(
int face, {required int bodyHueTenths, required bool dark, required KeyGroup group, double baseL = 0, double baseC = 0, BileRule bile = BileRule.v2}) → int -
A key group's drop-shadow colour (
KeyColors.edge): coloured, darker than the body, never grey, bile-safe.bodyHueTenths,baseLandbaseCdescribe the body (colors[0]). GuardrailRule.clayShadowTint accepts alpha clayShadowAlphaMin–clayShadowAlphaMax, chroma ≥ min(0.040, 0.75 × maxChroma) (night ≥ 0.035) and a hue within 40° of the key's own (bile-applied; at night the clayNightShadowHue reference, which falls back to the body hue for faces with no chroma at the shadow lightness). -
clayEqualsDullHue(
int hue, int opHue, {int? nightBodyHue}) → int -
The
=fold out of the dull teal / petrol band (both modes):hue(tenths) inside clayEqualsDullBand lands past the nearer of clayEqualsDullTargets (by half its depth into the band, at most clayEqualsDullPushDown / clayEqualsDullPushUp), or past the other one when the nearer target lies within clayEqualsOpGap ofopHueor (givennightBodyHue) within clayNightEqualsBodyGap of the night body hue. Pure integer tenths. -
clayEqualsHue(
int hue, int opHue, {int? pivot, int? nightBodyHue}) → int -
The full
=hue rule after the scheme draw: the candy band (clayEqualsBand, leaving on the side ofpivot, or the other side when that lands within clayEqualsOpGap ofopHue), the dull band (clayEqualsDullHue) and grape for a red=beside a green operator (clayGrapeEquals). Pure integer tenths. -
clayFocusShadowBackdrops(
List< int> colors) → List<int> - The scene colours a key (hence its drop shadow and the focus ring drawn round it) can sit on: the base, the top wash and their mix, sphere B (lit, body, shade and their mixes) and the spheres' shadow core (and its mix with the base). Sphere A stays behind the toolbar, the card or a gutter, never under the keypad.
-
clayFocusShadowSamples(
Palette p, List< int> colors) → List<int> - Every colour the focus ring can cross where it runs over a key's own drop shadow: each key group's shadow at clayFocusShadowPermille of its alpha over each of clayFocusShadowBackdrops (40 colours). The generator, the validator and the repair share it.
-
clayHighlightAlphaFor(
int face, int highlight) → int -
The highlight alpha the renderer actually paints on
face(and the guardrail checks): thePalette.highlightalpha × 1.0 (face L ≥ 0.80), 0.75 (≥ 0.62), 0.55 (≥ 0.40) or 0.35 (darker, e.g. a night pillow). -
clayHighlightComposite(
int face, int highlight) → int -
faceunder the painted highlight (white at clayHighlightAlphaFor), opaque: the lit top-left rim of a clay key. -
clayInnerShade(
int face, int depthPermille) → int -
The inner bottom-right shade of
face: L −depthPermille/ 1000, chroma × 1.12 (gamut-mapped), opaque. -
clayLabelRingColor(
KeyColors k, int edgeShadePermille, int highlight) → int - The colour a clay function label must also reach the label floor on: the inner shade for labels darker than the face, the highlight composite for lighter ones.
-
claymorphismDisplayBackdrops(
ThemeSpec spec, List< int> surfaces, List<int> bgs) → List<int> ? - Clay display text only ever sits on the opaque pillow card (the renderer's cover is opaque over every part of the padded display box text can use), so the surface is its only backdrop.
-
claymorphismSceneSamples(
BackgroundSpec bg) → List< int> ? - Guardrail background samples of a BackgroundKind.claySoft scene: its nine stops plus the ½ mixes of claySceneMixPairs (22 colours). Null unless the scene has exactly nine colours.
-
clayNightOperatorHue(
int hue) → int - Night operators: kelly green (clayNightKellyBand) turns jade (clayNightJade). Pure integer tenths.
-
clayNightShadowHue(
int face, int bodyHueTenths, double l, {BileRule bile = BileRule.v2}) → int -
The night drop-shadow hue (tenths) for
faceat shadow lightnessl: the face hue (bile-applied) when the face has C ≥ 0.035 and maxChroma(l, hue) ≥ clayNightShadowMinChroma, else the body hue turned 10° at a time toward 270° (≤ 6 steps) until maxChroma(l, hue) reaches it. -
clayNightShadowL(
double baseL) → double -
The night drop-shadow lightness for a body of lightness
baseL. -
clayNightSphereHue(
int hue, int bodyHue, {int? other}) → int -
The night sphere hue rule after the candy rule: red-orange / amber
(clayNightSphereWarmBand) turns berry; green, teal and cyan
(clayNightSphereJewelBand) take the first jewel of
clayNightSphereJewels at least clayNightSphereBodyGap from
bodyHueand (givenother, the other sphere's hue) clayNightSphereGap from it — else the jewel that misses those gaps by the least. Pure integer tenths. -
clayPanelRaised(
ThemeSpec spec) → bool -
Whether the display panel of
specis the raised pillow: its surface is lighter than the body. GuardrailRule.clayPanel requires it (the recessed tray is retired). -
repairClaymorphismExtras(
Palette p, ThemeSpec spec, GuardrailLimits lim, List< int> bgs) → Palette? -
Family repairs after labels and display texts (called from
repairThemefor ThemeFamily.claymorphism specs only): lifts light digits / darkens light function keys off the body, raises the highlight, re-solves the function label on its ring, recomputes every drop shadow from the final faces and re-solves the focus ring over them. Null when unrepairable. -
validateClaymorphism(
ThemeSpec spec, GuardrailLimits lim, List< int> bgs) → List<GuardrailViolation> -
The family guardrails (called from
validateThemefor ThemeFamily.claymorphism specs only): coloured, darker drop shadows (GuardrailRule.clayShadowTint), keys standing off the body (GuardrailRule.clayKeyBody), a visible highlight on every face (GuardrailRule.clayHighlight), function labels legible where they cross the shade ring (GuardrailRule.clayLabelRing), the focus ring where it crosses a key's own drop shadow (GuardrailRule.focusRing, "over key shadow"), an opaque, distinct display panel (GuardrailRule.clayPanel) and the renderer contract (GuardrailRule.clayStyle).