engine/neumorphism library
The Neumorphism (Soft UI) palette builder (spec §5.3 #4; docs/m4-design.md §C; research theme-engine.md recommendation 7 and §7.2). Pure Dart: part of the generator, so every value here is part of the family's engine-v2 definition and must not change without a version bump.
Classic neumorphism fails WCAG because its keys are the background colour and their only edge is a blurred shadow (neumorphism.io's default reaches 1.41:1). This builder keeps the look and adds:
- Surface: a monochrome, low-chroma base (light L 0.88–0.94, dark L 0.20–0.28, C ≤ 0.02) that is the background and every digit and function face.
- Shadows: a light and a dark shadow derived in OKLCH from the
surface (same hue; light L + 0.04–0.08 (dark themes + 0.03–0.06),
dark L − 0.10–0.18 (dark themes − 0.08–0.12), C + 0.01), stored as
palette.highlight/palette.shadow. The Accessible lock deepens the dark shadow. - Rim: a 1–1.5 dp stroke on the shadow side, its colour solved by
OKLCH lightness bisection to the least change that reaches ≥ 3:1
against the surface (WCAG 1.4.11), stored as every group's
KeyColors.edge. - Labels: near-black / near-white ink solved to ≥ 4.5:1 (7:1 under the Accessible lock and on dark faces), function keys in an accent-tinted ink.
- Operators: an accent label on the surface face, or a tinted
accent face ≥ 0.10 lightness from it (seeded), always with a label
weight ≥ key weight + 200 — the recorded non-colour cue
(OperatorCue.weight).
=is a full accent face. - Pressed: besides the shadow swap, surface-faced keys show their label in the accent colour (solved ≥ the label floor on the surface) and the rim closes all round; accent-labelled operators swap to the digit ink.
Classes
- SoftShadowRanges
- Soft-shadow lightness offsets from the surface (× 1000 of OKLCH L).
Enums
- SoftOperatorStyle
- How the operators of a Neumorphism theme stand out (both add the heavier glyph).
Constants
- softDarkShadows → const SoftShadowRanges
- Dark themes: little headroom for highlights, so a smaller one.
- softLightShadows → const SoftShadowRanges
- Light themes (research §7.2.2).
-
softRimWidthsCdp
→ const List<
int> -
Rim widths (dp × 100) the style stream picks from; the Accessible lock
always takes the widest. Inside
softRimWidthMinCdp–softRimWidthMaxCdp(guardrails.dart).
Functions
-
buildNeumorphicCandidate(
int seed, FamilyDefinition def, int engineVersion, {required String paletteTag, required bool accessible}) → ThemeSpec -
One unvalidated Neumorphism candidate for
seed(the generator adds repair, retries and the hero fallback).paletteTagis the palette stream of this attempt (palette, thenpalette/retry/n). -
softOperatorStyleOf(
ThemeSpec spec) → SoftOperatorStyle -
Whether
spec(a soft-style theme) gives operators an accent label on the surface face rather than a tinted face. -
softRimFor(
int surface, {double target = ratioLarge}) → int -
The rim colour for
surface: same hue, chroma + 0.01, the least lightness change from the surface that reachestargetagainst it.