Foundations
Why this isn't just "themed Material"
Short answer: Odyssey starts from Material 3 — same 37 colour roles, same shape/elevation/typography scaffolding — because M3 Expressive is a genuinely good foundation, not a bar to escape. What makes a screen read as a specific bank, not a generic app, lives entirely in the layer above that scaffolding. This page shows what that layer is, live.
What's identical to stock Material 3
No fork, no divergent grid, no invented spacing system. Same 37 M3 colour roles (plus one Odyssey addition, success, since M3 ships none). Same shape/elevation/type scale conventions. A component library built straight on M3 gets you a correctly-structured app — Foundations covers this half in full. It just doesn't get you a bank's identity, because M3 was never designed to carry one on its own.
The five things layered on top
Brandprint-driven palette
One seed (a logo's dominant colour, converted to OKLCH) generates all 37 roles deterministically — a real client's exact hex, not a picker's closest preset.
Glass + signature motif
Per-brand translucency recipe and a named background pattern (sonar rings, coastal arcs, grid-spark, shield guilloché) — the thing that makes a card art panel or hero recognisably this bank at a glance.
Glow-based elevation
Dark mode lifts surfaces with a tint of the brand colour, not a flat black shadow that goes invisible against an already-dark background.
Per-brand motion signature
A CTA's sheen-sweep timing is derived from the brand's own easing/duration tokens — a calmer bank's buttons move slower than a snappier one's, not one fixed animation for everyone.
Content + feedback tone
Typography pairing, Arabic-first RTL (not retrofitted), Arabic-Indic numerals as an independent lever, and haptic/sound feedback weighted to the brand's declared personality.
The same three pieces, side by side
Left: a stock Material 3 baseline scheme (Google's own default seed, #6750A4) — correct, accessible, and completely generic. Right: the exact same three UI pieces, live-themed as Triton via tokens/themes.css — nothing on the right is a mockup; toggle Foundations to any of the four reference brands and every one of these five layers moves with it.
Material 3 baseline
Default seed colour, Roboto, no glass/motif/glow
Available balance
12,480.50
LYD · •••• 4821
Neptune Odyssey — Triton
Same 37 M3 roles, generated from Triton's brandprint seed
Available balance
12,480.50
LYD · •••• 4821
Feature by feature
| Dimension | Material 3 baseline | Neptune Odyssey |
|---|---|---|
| Colour | One seed hue, Google's tonal palette algorithm | Any brand's real hex → OKLCH seed → all 37 roles, contrast-checked per brand |
| Elevation (dark) | Flat black shadow — often invisible on a dark surface | Glow tinted toward the brand primary — reads as ambient light, not a cast shadow |
| Motion | One default easing/duration for every app | Per-brand signature timing (a CTA's sheen/nudge cycle is derived from the brand's own motion tokens) |
| Background texture | Flat surface colour | A named signature motif per brand (sonar rings / coastal arcs / grid-spark / guilloché) at brand-tuned strength |
| Typography | Roboto, one weight ramp | Per-brand display + text + numeral face pairing, with a dedicated Arabic face swap under RTL — not a fallback font |
| Numerals | Tied to locale | Independent lever — Arabic-Indic digits under an English UI or vice versa, a real requirement for Gulf/Libyan banking apps |
| Feedback | None built in | Haptic weight + sound-cue hooks, tuned per brand's declared content tone |
| Platform reach | Android-first origin | Same brandprint resolves identically on Flutter, web (React/Vue/Svelte/Laravel), byte-pinned in tests |
Proof it's not a reskin bolted on top
A reskin would mean the identity layer is optional decoration a component can ship without. It isn't: neptune_flutter_ui's CI gate literally greps every widget file for a literal colour, radius, or font — the rulebook calls a screen that reads M3 roles correctly but ships no gradient, glass, motif, glow or brand type "a grey Material mockup, not done." A recent full-suite audit checked all 89 web components against Flutter's 149 classes for capability gaps and found exactly one (a missing app-bar layout variant, fixed) — the two implementations aren't approximating each other, they're the same design system twice.
| Glass | NeptuneGlass, NptIdentity.glassTint() |
| Motif | NeptuneMotifLayer |
| Glow elevation | NptIdentity.elevation1..5 |
| Motion signature | NptMotion, derived per brand in NeptuneCta |
| Feedback tone | NptFeedback, hapticWeightFor() |