UI Style

mandatory

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 matriz cor × estilo produz a paleta visual do app.

Goals

  1. Variedade visual sem multiplicar widget trees — todo preset

    permanece em Material/CSS puros do SDK

  2. Linguagem abstrata que viaja entre Flutter e Web — mesmo preset

    no koderkit e no koderweb_kit

  3. Eixo ortogonal ao color scheme — usuário pode ter "Material 3 +

    Dracula" ou "GNOME + Solarized"

  4. 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 CustomPaint em 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 × target de variants/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ças

UI 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:

  1. App Desktop/Web tem Settings § Appearance (delegado pra

    settings/patterns.kmd audit)

  2. Settings § Appearance contém o tile ui_style (key obrigatória)
  3. Tile usa KoderUIStylePicker ou <koder-style-picker> — não custom
  4. defaultState é KoderUIStyle.verge (não pode hardcodar outro) — flipado 2026-05-14 de material3 pra verge per verge.kmd R5
  5. persistenceKey é exatamente koder.ui_style (sync cross-device futuro)

Anti-patterns

Don't:

  1. Implementar UI style local — não criar novo enum/factory; sempre

    importar KoderUIStyle do koder_kit

  2. Hardcodar default fora de verge — quebra expectativa do user (default flipado 2026-05-14 de material3 pra verge per verge.kmd)
  3. Pular KoderUIStylePicker — picker não-padrão quebra preview ao

    vivo

  4. Adicionar preset novo sem update desta spec + audit script

Do:

  1. Usar enum + factory canônicos — extensão futura é uniforme
  2. Manter ortogonalidade com color scheme — não consolidar nas duas

    coisas como uma só

  3. 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.kmd define

    ThemeMode (lightdarksystem); ui-style.kmd define style dentro do mode. Compostas livremente.

  • specs/settings/patterns.kmd: dependência — ui_style tile mora

    em group appearance declarado 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).