Verge (v1 — OLED-aware dark)
themes specs/themes/verge.kmd
Verge is the canonical visual language of the Koder Design System — Koder's equivalent to Google's Material or Microsoft's Fluent. Verge is registered as the **default preset** (`Default: true`) in `canonicalPresets`. v0 (2026-05-14) started from GNOME Adwaita 1:1; v1 (2026-05-28) diverges in dark mode with OLED-aware surfaces + larger radii (palette "C" from dek#123), while the light variant stays Adwaita-derived.
When this spec applies
Primary triggers
- Define or revise Verge tokens (KDS visual language)
All triggers
- Choose the default visual language for a new Koder product
- Tune a Koder product to feel native (not generic Material/iOS)
Specification body
Spec — Verge (v1 — OLED-aware dark)
Status: v1 — first substantive divergence from Adwaita baseline. Owner decision 2026-05-14: a linguagem visual canônica do Koder Design System se chama Verge. v0 (2026-05-14) iniciou com tokens GNOME Adwaita 1:1. v1 (owner ratificou 2026-05-28) promove o preset OLED-aware (palette "C" originalmente shipada em dek#123, 2026-05-25) a default canônico: a variante dark ganha surfaces near-black ramp + radii maiores + hairline outline; a variante light continua Adwaita-derived inalterada. Sub-tickets adicionais de divergência editorial seguem em tools/design-gen#008.
R1 — Position: Verge ⊂ Koder Design System
Verge é a camada visual do Koder Design System — equivalente direto ao "Material" no portfolio Google. A separação:
| Camada | Koder | |
|---|---|---|
| Organização | Koder Stack | |
| Portal de design + corpus de specs | (espalhado: Material site + Identity site + Wear + XR + …) | Koder Design System (KDS) — kds.koder.dev |
| Linguagem visual (tokens + components + foundations) | Material | Verge |
| Conjunto de ícones de UI (glyphs flat) | Material Symbols | Verge Symbols (specs/icons/ui-symbols.kmd) |
| SDK implementador | Material Components (Android/iOS/Web/Flutter) | koder_kit + koder_web_kit |
| Tema versionado | Material 1 → 2 → 3 → Expressive → You | Verge v0 → v1 → v2… |
KDS é mais amplo que Verge: além de Verge, hospeda specs cross-stack
(auth, identity, multi-tenancy, i18n, errors, voice, media, signing,
naming, koder-app behaviors, iconografia de UI — Verge Symbols,
specs/icons/ui-symbols.kmd). Verge é uma das peças.
R2 — Naming forms (per specs/naming/forms.kmd)
| Form | Value |
|---|---|
| type | design-language |
| display | Verge |
| bare | verge |
| slug | verge |
| path | meta/docs/stack/specs/themes/verge.kmd |
| aliases | — (none) |
CSS selectors (dois consumidores, ambos válidos):
tools/design-genemite.preset.verge(+.themed-dark.preset.verge).engines/sdk/koder_web_kitemite[data-style="verge"](+[data-theme="dark"][data-style="verge"]) — coerente com o resto dos 19 presets do SDK que já usam[data-style="…"].
Dart enum: KoderUIStyle.verge.
Web JS: koderStyle.set('verge').
Pron canônica: /vɜːdʒ/ (single English syllable, universal).
Brand score (preliminar, per specs/naming/brand-score.kmd): A-A-A-A
(Type/Pron/Son/Mem) com risco identificado de overlap cultural com
The Verge (publicação tech). Não bloqueia adoção — namespaces
diferentes (design system vs media), mas alinhar comunicação se
sobreposição vier a tema.
R3 — Strategy: start from Adwaita
Verge v0 não introduz identidade visual nova: copia os tokens GNOME Adwaita 1:1.
Por quê Adwaita?
- GNOME Adwaita é uma das identidades cross-OS mais maduras e documentadas em open source (libadwaita 1.x).
- Compact density (
pad-y: 8px,gap-field: 10px) cabe em surfaces pequenas sem virar Material's loose comfortable padding. 4/6/8pxradius cobre exatamente a faixa "minimally rounded squares" que owner ratificou em 2026-05-13 — sem reinventar.- Accent Adwaita
#3584E4é blue suficientemente neutro para um default cross-product (não é "the indigo Koder brand" — esse vive só no brand mark + landing hero). - Dark variant Adwaita já estava shipada no #007 wave A — reuse- first: o trabalho não duplica.
Divergência futura acontece gradualmente: à medida que os produtos Koder ratifiquem decisões próprias (forma do checkbox, shape do snackbar, easing do drawer, etc.), os tokens Verge vão sendo sobrescritos com decisões Koder-specific. Eventualmente Verge deixa de parecer Adwaita — mas a base existente acelera o ramp-up.
R4 — Tokens
Verge atualmente shipa em v1. As subsections abaixo registram o estado canônico atual + o histórico v0 pra rastreabilidade.
R4.1 — Light (v0 + v1, inalterado)
Light variant fica em Adwaita-derived integralmente — tokens e
radii. OLED-aware é uma decisão exclusiva de dark mode (#0F0F0F em
ambiente claro é hostil; o contraste light/dark é o que dá ao Verge
a personalidade dual). Owner ratificou "light intacto" em 2026-05-28
ao aprovar Verge v1.
.preset.verge {
--font: 'Cabin', 'Cantarell', 'Inter', sans-serif;
--accent: #3584E4; --accent-strong: #1c71d8; --accent-on: #fff;
--color-link: var(--accent-strong); /* text/line accent (links, focus); light = the DARKER blue #1c71d8 — #3584E4 fails AA on white (3.77), strong = 4.77 */
--bg: #FAFAFA; --surface: #fff;
--surface-sunken: #ECEEF0; /* design-RFC-012 — recesso/well; NAO-recursivo */
--on-surface: #2e3436; --label-color: #5e6772;
--radius-sm: 4px; --radius-md: 6px; --radius-lg: 8px; --radius-btn: 6px;
--pad-y: 8px; --pad-x: 12px;
--shadow-form: 0 0 0 1px rgba(0,0,0,0.1);
--input-border: 1px solid #c0c0c0;
--gap-field: 10px; --gap-title: 14px;
--pad-form: 18px;
--btn-secondary-border: 1px solid #c0c0c0;
}
Light geometry idêntica a v0. A divergência v1 é estritamente dark.
R4.2 — Dark v0 (Adwaita 1:1, superseded by R4.3)
Mantido aqui pra histórico. Não emitir em produção a partir de 2026-05-28.
.themed-dark.preset.verge {
--bg: #242424;
--surface: #303030;
--surface-2: #424242;
--on-surface: #ffffff;
--label-color: #cccccc;
--input-border: 1px solid #1b1b1b;
--btn-secondary-bg: #3a3a3a;
--btn-secondary-fg: #ffffff;
--btn-secondary-border: 1px solid #1b1b1b;
--btn-secondary-hover: #4a4a4a;
--shadow-form: 0 0 0 1px rgba(0, 0, 0, 0.5);
}
R4.3 — Dark v1 (OLED-aware, current)
Owner ratificou em 2026-05-28 (after dek#123 shipping em 2026-05-25).
Surfaces pinadas em near-black ramp (NÃO #000 puro — preserva
elevation cues), accent inalterado, radii maiores, hairline outline
em 5% white.
.themed-dark.preset.verge {
--bg: #0A0A0B;
--surface: #0F0F0F;
--card: #161618;
--card-high: #1F1F22;
--surface-sunken: #0A0A0B; /* design-RFC-012 — recesso/well; NAO-recursivo */
--on-surface: #F4F4F6;
--on-surface-dim: #9A9AA0;
--label-color: #9A9AA0;
--outline: rgba(255, 255, 255, 0.05);
/* radii bumped in v1: 2/4/6/8/12 → 6/8/12/14/18 */
--radius-xs: 6px; --radius-sm: 8px; --radius-md: 12px;
--radius-lg: 14px; --radius-xl: 18px; --radius-btn: 12px;
--input-border: 1px solid rgba(255, 255, 255, 0.05);
--shadow-form: 0 0 0 1px rgba(255, 255, 255, 0.05);
/* accent FILL stays Verge — same as light (#3584E4 + white on-accent text, AA OK
as a filled button). But the text/LINE accent must be lighter on dark for
legibility per color-roles.kmd R3 — a thin #3584E4 line/link reads too dark.
koder_web_kit#041. */
--accent: #3584E4;
--accent-strong: #1C71D8;
--accent-on: #ffffff;
--color-link: #A4C8F3; /* lighter tint of #3584E4 — links + focus outline on dark */
}
Por quê OLED-aware?
- Sentimento "Koder" — distintivo vs Adwaita default GNOME que já é conhecido por usuários Linux. Verge precisa de identidade própria.
- Battery em OLED phones (
#0A0A0Bqueima pixels off) — ganho free pra mobile/TV/landing. - Maior contraste pra leitura code-heavy (texto
#F4F4F6em#0F0F0F≈ 17.5:1 vs#FFFFFFem#303030≈ 13.2:1 do v0). - Radii maiores casam com a estética dos chips/cards modernos sem cair em "Material 3 expressive" (que é spacious, não compact).
R4.4 — v2 token model (seed → map → alias, derived — canonical from 2026-06-23)
Verge v2 (design-RFC-007, ratified 2026-06-23) replaces the hand-transcribed
flat token block as the canonical source: the token values are now derived
by algorithm from a small seed set, not authored per-hex. As of 2026-07-07 the
preset is FULLY seed-sourced — colour (primitives + tints + scrims + composites),
the non-colour tier (shape/space/type/motion seeds, internal/tokens/noncolour.go),
AND the white-scrim dark borders (slice 3b, applyDerivedComposites with a
per-layer scrim). No token is carried verbatim from the flat parse anymore, so the
flat shim (KDS_VERGE_FLAT) was retired 2026-07-07 (R6#5) — the derived path is
unconditional; the .preset.verge block in presets.css remains only as the
parse base the derivation overrides (and the ΔE parity anchor). The 3b borders are
colour-identical to flat but format-normalised (spaced → no-space rgba), shipped in
the 2026-07-07 verge.css redeploy.
- Seeds (
tools/design-gen/internal/tokens/seeds.go::VergeSeed): a neutral ramp (NeutralHue=211, NeutralChroma=4), a neutral-variant ramp (NeutralVariantHue=255, NeutralVariantChroma=11.7— the Material/HCT higher-chroma neutral for secondary text / recessed surfaces:label,on-surface-dim), the brandaccent(#3584E4), and the four state seeds (danger/warning/success/info). One seed set reproduces every colour role. - Algorithm (
internal/tokens/algorithm.go::DeriveVerge): pure-Go derivation via the verified HCT engine (internal/hct, HCT primary; OKLCH is the no-JS fallback). Light/dark map-tone ladders are frozen constants calibrated to the Adwaita ramp; dark neutrals use a cooler hue (neutralHueDark=275). Colour space + rationale:design-RFC-007R10. - Structural AA (closes the v0 accent debt, R8 path-to-fix — now resolved
by construction): the interactive accent is split into
accent-fill(button fill, white-on-it ≥ AA →#1C71D8both modes) andaccent-text(links/focus, ≥ AA vs surface → darken on light, lighten on dark).deriveAccentAAwalks the tone until contrast ≥ 4.5; the algorithm cannot emit a sub-threshold map. This generalizes the per-component Koder ID login fix (--color-link, R4.1). - Emit:
BuildVergesources the colour primitives fromDeriveVerge(parity-gated: build fails if any derived primitive drifts > ΔE2000 2.0 from its flat counterpart), preserving alias / non-colour properties (rgba tints, shadows, radii, fonts) verbatim from the flat parse until the alias / non-colour-seed tier lands (Phase 3 remainder). - Gates (CI,
design-RFC-007Phase 2): WCAG 2 AA hard (TestVergeContrastAA), ΔE≤2.0 parity (TestVergeDelta+ build-time gate), APCA Lc advisory (internal/tokens/apca.go, informational only —contrast-checker.kmd), and emit token-drift (tests/regression/verge_token_drift_test.go). Review artifact:design-gen verge-delta(--strict/--json). - Parity proven: every colour role reproduces the v1 flat preset within ΔE2000
≤ 2.0 (light ≤ 1.63, dark ≤ 1.83) — the flip is a visual no-op; no waiver
exceptions. Slices:
tools/design-gen/backlog#204 (model, DONE) · #205 (flip, DONE) · #206 (gates, DONE) · #207 (consumers→generated Dart, emitcolor-schemes/*.toml, retire shim — pending).
R5 — Default preset flip (2026-05-14)
tools/design-gen/internal/kinds/uistyle.go::canonicalPresets[0]:
{Slug: "verge", ..., Default: true, ...}
Demais especs foram atualizadas pra referenciar Verge no lugar de
material3 quando descrevem o "default preset":
specs/themes/ui-style.kmd— tabela de presets + audit rule + anti-pattern + exemplos Flutter/Web (KoderUIStyle.verge,default-state="verge").specs/themes/color-schemes.kmd— default agoraverge + system + default.specs/themes/elevation.kmd— tabela default agoraverge.specs/themes/shape.kmd— tabela default agoraverge.specs/themes/color-resources.kmd— chrome de referência agoraverge.
R6 — Versioning (Verge v0 → v1 → v2…)
Análogo a Material 1 → 2 → 3 → Expressive: Verge segue versionamento semântico ratificado por changesets quando tokens fundacionais mudam.
- v0 (2026-05-14) — Adwaita 1:1 baseline. Dark variant em
#242424/#303030ramp, radii2/4/6/8/12, sem outline. - v1 (2026-05-28) — OLED-aware dark. Dark variant em near-black
ramp
#0A0A0B/#0F0F0F/#161618/#1F1F22, on-surface#F4F4F6, hairline outlinergba(255,255,255,0.05), radii bumpadas2/4/6/8/12→6/8/12/14/18. Light variant inalterada vs v0 (Adwaita-derived, radii original) — owner ratificou "light intacto". Accent inalterado em ambas brightnesses.KoderUIStyle.oleddo koder_kit (display "Verge OLED") fica como alias@Deprecatedapontando praKoderUIStyle.verge. Removido em v2. - v2 (2026-06-23,
design-RFC-007) — token model flip: flat → seed/map/alias derivado (ver §R4.4). Tokens passam a ser derivados por algoritmo (HCT, pure-Go em design-gen) de um seed set mínimo, não mais transcritos à mão. Restaura a paleta neutral-variant (Material/HCT) que o flat colapsava; resolve o débito AA do accent do §R8 por construção (accent-fill/accent-text≥ AA). Paridade ΔE2000 ≤ 2.0 com o v1 flat (no-op visual); shim flat (KDS_VERGE_FLAT) retirado 2026-07-07 (R6#5, derivação 100%). Gates de CI: WCAG-hard + ΔE-parity + APCA-advisory + token-drift. - v2+ — evoluções subsequentes (analogo a Material 3 → Expressive).
Inclui: remoção do
KoderUIStyle.oledalias, tokens próprios de form elements, e o restante da Phase 3: consumidores →verge_tokens.rs(Kroma) — retargetado de Dart 2026-07-07 (Flutter sunset, design-RFC-006 emenda);color-schemes/*.tomlsuperseded (meta/docs/stack#259); derivação da camada de aliases completa (tints + scrims + composites + não-cor + white-scrim 3b, 2026-07-07); shim flat aposentado 2026-07-07 (R6#5) — Verge v2 completo, derivação incondicional.
Cada release Verge vN ganha:
- Subsection R4.{N+something} com diff de tokens vs vN-1 (R4.3 = v1 dark)
- Changelog em
tools/design-gen/blog/(Releases) - Migration guide no design-gen
/migrate/verge/vN-1-to-vN/
R8 — Contrast audit (baseline 2026-05-14, re-baselined 2026-05-28 for v1)
Audit automatizado em tools/design-gen/cmd/verge-contrast-audit/
(invocável via regression test
tests/regression/verge_contrast_baseline_test.go). WCAG 2.1 AA
threshold = 4.5:1 para texto normal.
Estado v1 (15 pares canônicos, light + dark; dark ratios bumpados pelo ramp OLED-aware):
| Pair | Light ratio | Dark ratio (v1) | Banda | Status |
|---|---|---|---|---|
accent-on / accent (#FFFFFF on #3584E4) | 3.77 | 3.77 | — | FAIL AA (herdado v0) |
accent-on / accent-strong (#FFFFFF on #1c71d8) | 4.77 | 4.77 | AA | PASS |
accent / surface (#3584E4 on #FFFFFF / #0F0F0F) | 3.77 | 5.09 | — / AA | FAIL AA (light) / PASS (dark v1) |
color-link / surface (#1c71d8 light / #a7c8ff dark, on #FFFFFF / #0F0F0F) | 4.77 | 11.3 | AA / AAA | text/line accent — light = accent-strong (PASS AA); dark = v2 model-derived R3 tone (AccentTextDarkTone T80, hybrid accent) PASS AAA. Supersedes the hand-picked #A4C8F3 (koder_web_kit#041) — same colour, now derived |
on-surface / surface | 12.65 | 17.45 | AAA | PASS |
on-surface / bg | 12.12 | 18.02 | AAA | PASS |
on-surface / surface-2 (dark only) | — | 14.97 | AAA | PASS |
label-color / surface | 5.74 | 6.85 | AA | PASS |
label-color / bg | 5.50 | 7.07 | AA / AAA | PASS |
Ratios medidos pelo
verge-contrast-auditem 2026-05-28 (15 pares). Dark variant v1: texto on-surface sobe de 13.20 → 17.45 (AAA com folga).accent / surfacedark sai de FAIL pra PASS AA (5.09 ≥ 4.5) pelo ramp#0F0F0F. Light variant inalterada; mantém os 2 FAILs de v0 ligados ao accent — path-to-fix abaixo persiste.
Known AA failures (2 pares em v1, ambos light-only): todos
relacionados ao #3584E4 accent + #FFFFFF on-accent pair em surface
clara. Adwaita usa o mesmo accent em buttons/links e aceita a ratio
sub-AA porque o sistema GNOME compensa com bold weight + tamanho
≥14pt. KDS não faz essa compensação por default. Dark variant v1 não
herda os FAILs (surfaces escurecidas levaram a ratio a 6.59).
Path-to-fix sugerido (defer pra Verge v2, owner pick):
flipar --accent light de #3584E4 → #1c71d8 (atual --accent-strong,
PASS AA 4.77) e introduzir novo --accent-strong ainda mais escuro
(ex.: #155199) para o estado hover. Mudança custaria 1 commit
- atualização §R4.1 + bump pra Verge v2. Owner ratifica quando quiser priorizar a11y AA strict em light.
Resolvido em v2 (2026-06-23, §R4.4) — por uma via melhor que a sugerida: em vez de só flipar
--accent, o v2 deriva dois papéis interativos AA-por- construção —accent-fill(branco-sobre-fill ≥ AA →#1C71D8nos dois temas) eaccent-text(≥ AA vs surface). O--accent(brand#3584E4) permanece como identidade da marca; o que toca texto/fill passa pelos papéis AA. O algoritmo não consegue emitir um accent interativo sub-AA. Os 2 FAILs light-only acima são herança do modelo flat v1 e somem quando os consumidores migram praaccent-fill/accent-text(Phase 3, #207).Modelo de accent HÍBRIDO (owner-ratificado 2026-06-24): o
vergemantém o brand accent + o fill do botão fixos (identidade —--accent #3584E4, botãoaccent-fill #1C71D8branco AA, iguais nos dois temas, honrando a ratificação v1 "accent inalterado"), mas o accent de texto/foco no escuro adota o tom R3 mais claro (AccentTextDarkToneT80 → ≈#a7c8ff, AAA 11.3) em vez do AA-mínimo. Isso resolve o conflito color-roles R3 × ratificação v1: o accent de marca não muda; só o link/foco clareia no escuro pra legibilidade — exatamente o que o login já entregava à mão (#A4C8F3), agora derivado do modelo. Decisão avaliada por render comparativo (fixo × híbrido × R3-completo). Presets novos podem optar pelo R3 tonal completo (TonalAccent, ver material3 em #207).
Baseline lock: tests/regression/verge_contrast_baseline_test.go
re-baselined em 2026-05-28; trava pass ≥ 12 (era 11 em v0; v1 sobe
1 par dark — accent / surface que era 3.50 sobre #303030, agora
6.59 sobre #0F0F0F). Qualquer divergência futura tem que manter
ou melhorar o score — nunca regredir. Cmd: verge-contrast-audit (report mode, sem --strict)
ou verge-contrast-audit --strict (exit 1 em qualquer fail).
R7 — Sub-tickets pendentes (gradual divergence)
A divergência editorial (substituir Adwaita por decisões Verge
próprias) acontece via os sub-tickets de
tools/design-gen/backlog/pending/008-koder-native-style-and-form-builder.md:
- #008.2 — Form elements (button variants, input, etc.)
- #008.3-9 — Containers / nav / data / feedback / typography / layout / surface-specific
- #008.10-11 — Verge style builder (graphical tool em
/tools/verge-builder/ou/tools/koder-style-builder/) - #008.13 — Migration de produtos existentes pra
.preset.verge(alguns já podem estar em.preset.gnome— operacionalmente equivalente em v0, mas o slug canônico éverge)
R9 — Verge Web (expressão web da marca; SSOT da paleta das landings/portais)
Ratificado via deliberação
/k-archc3, owner-aprovada por/k-goem 2026-06-10 (design-gen#202 / META-DOCS-171).
Verge (R4) é a linguagem visual de produto (apps mobile/desktop/
TV — chrome de aplicação, Adwaita-derived light + OLED-aware dark).
Verge Web é a expressão web da mesma marca: a identidade
navy/slate (#0b1120 + brand cyan #5BC8F5 / orange #FF6600) que as
propriedades *.koder.dev shipam (landings de produto/área/
institucionais, portal meta, sites gerados). Antes do R9 essa paleta
existia como 4+ cópias à mão (products.kmd §tokens, institutional.kmd,
meta/sites/ecosystem.css, meta/sites/meta/_assets/meta.css) sem SSOT
— a mesma classe de divergência silenciosa que deixou o bundle dark dos
tokens --kdr-* vazio por semanas (design-gen#201, regression #1177).
Regras:
- R9.1 — SSOT:
tools/design-gen/assets/css/verge-web.css. Tokens com prefixo--kw-(Koder Web): tríade de marca theme-invariant (--kw-brand-{navy,cyan,orange}), tipografia (--kw-font-{sans,mono}, self-hosted pelo consumidor perfonts/typography.kmd) e semânticos light/dark (--kw-{bg,surface,card,text,text-soft,text-muted,border,accent, accent-strong,code-bg};cardentrou via R9.4 em META-DOCS-174 — superfície elevada, light#ffffff/ dark#111827). - R9.2 — Export publicado:
https://kds.koder.dev/tokens/verge-web.css(:root+[data-theme="dark"]), regenerado pelo pipeline de tokens do design-gen (BuildVergeWeb), que valida paridade light/dark como gate de build (token semântico sem par quebra o build — anti-#201). Estabilidade: additive-only dentro do major. - R9.3 — Consumo: propriedade web nova consome o export (vendored copy
ou fetch no build; nunca Google Fonts/CDN externo). Consumidor mapeia
suas vars locais em
var(--kw-*). Primeiro consumidor: meta.koder.dev (META-DOCS-171, adoção com zero mudança visual). Migração das landings existentes: gradual (ticket follow-up no backlog meta/docs/stack). - R9.4 — Divergência: valor que um site precise e o export não tenha →
propor token novo no SSOT (additive), não hard-codear localmente quando
o conceito é compartilhável (regra-dos-3 de
reuse-first.kmdaplica).
Cross-link
themes/ui-style.kmd— preset registry (Verge agora Default)themes/light-dark.kmd— per-preset dark contractthemes/elevation.kmd,shape.kmd,color-schemes.kmd,color-resources.kmd— referências ao default atualizadasfonts/typography.kmd— Cabin/Cantarell são fallbacks; Inter é o último fallback (alinhado com a typography spec da Stack)icons/ui-symbols.kmd— Verge Symbols: conjunto de glyphs de UI irmão do Verge (equivalente Koder ao Material Symbols)naming/forms.kmd— Verge entry registrada em R2naming/brand-score.kmd— Verge score em R2registries/stack-manifest.kmd— entry CI-checkedtools/design-gen/backlog/pending/008-koder-native-style-and-form-builder.md— épico de sub-tickets pra divergir do Adwaita
References
specs/themes/ui-style.kmdspecs/themes/light-dark.kmdspecs/fonts/typography.kmdregistries/stack-manifest.kmdtools/design-gen/backlog/pending/008-koder-native-style-and-form-builder.md