UI Style
Eixo "estilo de interface" ortogonal ao "esquema de cores" já existente (`themes/light-dark.kmd`). Define vocabulário abstrato em tokens (style, corner-radius, density, font-stack, elevation, motion) e 19 presets canônicos (Material 3, GNOME, macOS, Windows 11, etc.) que cada SDK Koder traduz pro idioma nativo (ThemeData no Flutter, CSS custom properties no Web). App Desktop/Web Koder expõe `KoderUIStylePicker` em Settings § Appearance.
Distinto e ortogonal ao esquema de cores (
themes/light-dark.kmd): esquema de cores pinta as superfícies; estilo de interface define como as superfícies são desenhadas (forma, espaço, peso, animação). A matrizcor × estiloproduz a paleta visual do app.
Goals
- Variedade visual sem multiplicar widget trees — todo preset
permanece em Material/CSS puros do SDK
- Linguagem abstrata que viaja entre Flutter e Web — mesmo preset
no koderkit e no koderweb_kit
- Eixo ortogonal ao color scheme — usuário pode ter "Material 3 +
Dracula" ou "GNOME + Solarized"
- Default Material 3 (status quo) com switch explícito pelo usuário
em Settings § Appearance
Vocabulário abstrato (tokens)
Todo preset declara seus valores nestes tokens. Cada SDK traduz pro idioma nativo.
| Token | Tipo | Valores |
|---|---|---|
style |
enum | nome do preset (material3, gnome, macos, ...) |
accent |
color | hex #RRGGBB |
accent_strong |
color | hex (hover/pressed state) |
surface |
color | background dos containers |
on_surface |
color | text sobre surface |
surface_variant |
color | secondary background |
corner_radius_xs |
length (px) | corners minúsculos (chips, badges) |
corner_radius_sm |
length | corners pequenos (buttons) |
corner_radius_md |
length | corners médios (cards) |
corner_radius_lg |
length | corners grandes (dialogs) |
corner_radius_xl |
length | corners enormes (sheets) |
density |
enum | compact / comfortable / spacious |
font_stack |
string | CSS font-family ou Flutter fontFamily |
font_weight_regular |
int | typically 400 |
font_weight_medium |
int | typically 500 |
font_weight_bold |
int | typically 700 |
elevation_0..5 |
shadow | sombra/elevação por nível Material |
motion_instant |
duration | <100ms — ripple, focus |
motion_fast |
duration | 100-300ms — hover, switch |
motion_medium |
duration | 300-500ms — page transition |
motion_slow |
duration | 500ms+ — coordinated multi-element |
Os 19 presets canônicos
Grupo A — OS look-alikes (10)
| # | Preset | Corner radius | Density | Font stack | Notas |
|---|---|---|---|---|---|
| 0 | verge |
sm4, md6, lg=8 | compact | CabinCantarellInter | Verge v0 — Default desde 2026-05-14 — Adwaita-based, diverge gradualmente (#008). Spec: verge.kmd |
| 1 | material3 |
sm8, md12, lg=24 | comfortable | Inter/Roboto | Google M3 (era default até 2026-05-14) |
| 2 | material2 |
sm4, md4, lg=4 | comfortable | Roboto | useMaterial3: false |
| 3 | gnome |
sm4, md6, lg=8 | compact | Cantarell-like, Inter | Adwaita-inspired, accent #3584E4 |
| 4 | kde_breeze |
sm2, md2, lg=4 | compact | Inter | accent azul-aço #3DAEE9 |
| 5 | yaru |
sm4, md6, lg=8 | compact | Inter | Ubuntu — base GNOME + accent #E95420 (laranja) |
| 6 | macos_sonoma |
sm6, md10, lg=14 | comfortable | SF Pro-like, Inter | rounded windows, vibrancy via BackdropFilter |
| 7 | windows_11 |
sm4, md8, lg=12 | comfortable | Segoe UI-like, Inter | Mica simulada via gradient + blur |
| 8 | ios_cupertino |
sm10, md14, lg=20 | comfortable | SF Pro-like, Inter | capsule shapes, system blue |
| 9 | windows_95 |
sm0, md0, lg=0 | compact | Tahoma-like, monospace | borders 3D hard-edge — exige CustomPaint |
| 10 | aqua_classic |
sm8, md12, lg=16 | comfortable | Lucida Grande-like | gradients + brilho — CustomPaint |
Grupo B — Aesthetic personalities (9)
| # | Preset | Corner radius | Density | Font stack | Notas |
|---|---|---|---|---|---|
| 11 | terminal_classic |
sm0, md0, lg=0 | compact | JetBrains Mono | verde fósforo CRT no preto, scanlines via ShaderMask |
| 12 | brutalist |
sm0, md0, lg=0 | compact | JetBrains Mono / Inter | sharp edges, hi-contrast |
| 13 | newspaper |
sm2, md4, lg=6 | spacious | Source Serif Pro | sépia, tipografia serif |
| 14 | minimalist_mono |
sm4, md6, lg=8 | spacious | Inter | um accent só, branco/preto |
| 15 | compact_power_user |
sm2, md4, lg=6 | compact | Inter (small) | density max, padding mínimo |
| 16 | bauhaus |
sm0, md0, lg=0 | comfortable | Futura-like, Inter | sans geométrica, primárias |
| 17 | cyberpunk_neon |
sm2, md4, lg=8 | comfortable | JetBrains Mono | dark + neon, glow via BoxShadow |
| 18 | synthwave |
sm4, md8, lg=12 | comfortable | Inter | gradients magenta→ciano, sun-grid bordas |
| 19 | glassmorphism |
sm8, md12, lg=20 | comfortable | Inter | BackdropFilter blur em surfaces |
Skeuomorphic Vintage foi cortado do escopo original (20 presets) por custo de assets duplicado por surface (texturas couromadeirametal). Pode entrar como preset 20 numa v2 com asset bundle compartilhado. Neumorphism (Soft UI) considerado e mantido em v2 — exige
CustomPaintem Flutter (custo médio); mais tarde.
Agrupamento por variante + default por surface (#130)
Eixo de apresentação no portal
kds.koder.dev/style/: os presets são agrupados pela variante (surface × targetdevariants/taxonomy.kmd) em que se aplicam, e cada variante declara um preset default. Responde à pergunta real "que estilo eu uso em Desktop Linux / Android / TV?". Cada preset ganha dois campos derivados:
surfaces— eixo grosso já existente (mobile|desktop|tv|web).default_for— subconjunto de variantes onde o preset é o default.
O eixo de variantes do KDS coalescente é fechado em 8 buckets (web é target-agnóstico; desktop/mobile dividem por SO; tv e tui-cli são únicos):
Decisão do owner (2026-06-09, supersede os pins por-SO de 2026-05-11): o Verge é o default em TODAS as variantes — a UI Koder é Koder-native em toda superfície, não imita o SO host. Os look-alikes de SO continuam como presets selecionáveis (só não são mais o default).
| Variante | Default canônico | Origem da decisão |
|---|---|---|
web |
verge |
Linguagem própria Koder |
desktop-linux |
verge |
Owner (2026-06-09) — Koder-native (era gnome até 2026-06-09) |
desktop-windows |
verge |
Owner (2026-06-09) — Koder-native (era fluent_design) |
desktop-macos |
verge |
Owner (2026-06-09) — Koder-native (era macos_sonoma) |
mobile-android |
verge |
Owner (2026-06-09) — Koder-native (era material_expressive) |
mobile-ios |
verge |
Owner (2026-06-09) — Koder-native (era ios_cupertino) |
tv |
verge |
Owner (2026-06-09) — Koder-native (era android_tv) |
tui-cli |
verge |
Owner (2026-06-09) — Koder-native (era terminal_classic) |
Regra de validação (auditável): cada uma das 8 variantes tem exatamente um preset com aquela variante em default_for. Fonte de verdade no código: tools/design-gen/internal/kinds/uistyle.go (defaultPresetByVariant + variantOverride/variantExtra para a aplicabilidade fina); teste de invariante em uistyle_test.go.
Tradução por SDK
Flutter (engines/sdk/koder_kit v0.6.0+)
import 'package:koder_kit/koder_kit.dart';
// Em main() ou tema do app:
final ui = KoderUIStyle.verge; // default; ou .material3, .gnome, .macosSonoma, etc.
final theme = koderTheme(
brightness: Brightness.dark,
style: ui, // novo param em v0.6.0
colorScheme: dracula, // ortogonal — color scheme separado
);
MaterialApp(theme: theme, ...)Web (engines/sdk/koder_web_kit v0.3.0+)
:root[data-style="material3"] {
--kdr-radius-sm: 8px;
--kdr-radius-md: 12px;
--kdr-radius-lg: 24px;
--kdr-density: 1.0;
}
:root[data-style="gnome"] {
--kdr-radius-sm: 4px;
--kdr-radius-md: 6px;
--kdr-radius-lg: 8px;
--kdr-density: 0.9;
}JavaScript:
import { koderStyle } from 'koder-web-kit';
koderStyle.set('gnome'); // muda atributo + persiste
koderStyle.subscribe(s => ); // reage a mudançasUI de seleção
Settings § Appearance (per specs/settings/patterns.kmd group appearance):
Flutter:
KoderSettingsTile(
key: 'ui_style',
label: l10n.settings.uiStyle,
control: KoderSettingsControl.dropdown(
options: KoderUIStyle.values,
builder: (style) => KoderUIStyleOption(style), // mostra preview
),
defaultState: KoderUIStyle.verge,
persistenceKey: 'koder.ui_style',
)Web:
<koder-settings-tile
key="ui_style"
label="Interface style"
control="dropdown"
default-state="verge"
persistence-key="koder.ui_style">
<koder-style-picker></koder-style-picker>
</koder-settings-tile>KoderUIStylePicker (Flutter) e <koder-style-picker> (Web) renderizam um grid de cards com preview ao vivo (mini-UI 200×120px) de cada preset, permitindo seleção visual antes de aplicar.
Audit
/k-audit ui-style <module> (via koder-spec-audit) verifica:
- App Desktop/Web tem Settings § Appearance (delegado pra
settings/patterns.kmdaudit) - Settings § Appearance contém o tile
ui_style(key obrigatória) - Tile usa
KoderUIStylePickerou<koder-style-picker>— não custom defaultStateéKoderUIStyle.verge(não pode hardcodar outro) — flipado 2026-05-14 dematerial3pravergeperverge.kmdR5persistenceKeyé exatamentekoder.ui_style(sync cross-device futuro)
Anti-patterns
Don't:
- Implementar UI style local — não criar novo enum/factory; sempre
importar
KoderUIStyledo koder_kit - Hardcodar default fora de
verge— quebra expectativa do user (default flipado 2026-05-14 dematerial3pravergeperverge.kmd) - Pular
KoderUIStylePicker— picker não-padrão quebra preview aovivo
- Adicionar preset novo sem update desta spec + audit script
Do:
- Usar enum + factory canônicos — extensão futura é uniforme
- Manter ortogonalidade com color scheme — não consolidar nas duas
coisas como uma só
- Cortar presets pra v1 se algum não couber em pure Material/CSS
(registrar em "v2 backlog" da spec)
Conflitos com outras specs
specs/themes/light-dark.kmd: ortogonal —light-dark.kmddefineThemeMode(lightdarksystem);ui-style.kmddefinestyledentro do mode. Compostas livremente.specs/settings/patterns.kmd: dependência —ui_styletile moraem group
appearancedeclarado lá.
Origem
Spec criada durante o ticket KSTACK-101 ETAPA 2.2. Origem do trabalho: pedido do usuário em 2026-05-01 ("trocar estilo da interface no kterm"); descoberta no path: feature deveria ser cross-stack, não local. 19 presets escolhidos via decisão Q-Específica (premissa Quality > Speed permite incluir custos médios como NeumorphismWin95Aqua).