Color Schemes

themes specs/themes/color-schemes.kmd

Catálogo canônico de **esquemas de cor** (paletas) da Koder Stack — terceiro eixo da matriz visual (`ui-style × light-dark × color-scheme`), ortogonal aos dois primeiros. Define vocabulário semântico de tokens (bg, fg, accent, error, syntax_*, ansi_*) e ≥10 presets canônicos (default Koder neutros + Solarized, Dracula, Nord, Gruvbox, Tokyo Night, Monokai, One, Catppuccin, High Contrast). Cada preset declara hex pra cada token semântico, AAA contrast validado, e variantes light/dark quando aplicável. Cross-render: o mesmo preset aplica em UI, syntax highlighting, e terminal palette.

Quando esta spec se aplica

Triggers primários

Todos os triggers

Corpo da especificação

Spec — Color Schemes

Terceiro eixo, ortogonal aos dois primeiros:

  • themes/ui-style.kmd define forma/densidade/movimento (style)
  • themes/light-dark.kmd define comportamento do toggle light/dark
  • themes/color-schemes.kmd (este) define a paleta que pinta tudo

A matriz (ui-style × light-dark × color-scheme) é a paleta visual completa de uma instalação Koder. Default material3 + system + default.

Goals

  1. Catálogo canônico — usuário escolhe entre presets pré-validados, sem inventar paletas ad-hoc
  2. AAA contrast validado em cada preset (WCAG)
  3. Cross-render — mesmo preset pinta UI, syntax highlighting e terminal palette com critério unificado
  4. Eixo ortogonal — color scheme é independente de ui-style; usuário pode combinar gnome + dracula ou material3 + solarized
  5. Default Koder neutrosdefault_light e default_dark (color scheme de fábrica) são paletas próprias da Koder, não alias de scheme de terceiro

Vocabulário de tokens

Todo preset declara estes tokens. Cada SDK traduz pro idioma nativo (CSS custom properties no Web, ColorScheme no Flutter, ANSI codes em terminal).

Tokens semânticos (UI surface)

Token Uso
bg Background principal de janelas/scaffold
bg_alt Background secundário (cards, sheets)
bg_inset Background de áreas inset (input, code block)
fg Texto primário sobre bg
fg_muted Texto secundário (labels, captions)
fg_subtle Texto desabilitado/placeholder
border Bordas de containers
border_strong Bordas com ênfase (focus, selected)
accent Cor de marca/ação primária
accent_strong Hover/pressed state do accent
accent_on Texto sobre superfície accent
error Estado de erro (banner, border, text)
error_bg Background sutil de erro
warning Estado de aviso
warning_bg Background sutil de warning
success Estado de sucesso
success_bg Background sutil de sucesso
info Estado informacional
info_bg Background sutil de info
selection Background de seleção de texto
selection_fg Texto sobre selection
link Cor de hyperlink
link_visited Cor de hyperlink já visitado

Tokens de syntax highlighting

Token Uso
syntax_keyword Palavras-chave da linguagem (if, class, def)
syntax_keyword_op Operadores keyword-like (and, or, not)
syntax_string Literais string
syntax_string_special Escape sequences, interpolation markers
syntax_number Literais numéricos (int, float, hex)
syntax_boolean true, false, nil, null
syntax_comment Comentários
syntax_doc_comment Doc comments (#: em Koda)
syntax_function Definição de função
syntax_function_call Chamada de função
syntax_method Método de classe/instância
syntax_class Definição de classe/tipo
syntax_type Referência a tipo
syntax_intrinsic Intrínsecos da linguagem (self, super)
syntax_macro Macro/preprocessor
syntax_constant Constantes (MAX_SIZE, PI)
syntax_variable Variável local
syntax_parameter Parâmetro de função
syntax_property Propriedade de objeto/dict
syntax_punctuation {}, [], (), ,, ;
syntax_operator +, -, *, ==, <
syntax_tag Tag XML/HTML
syntax_attribute Atributo de tag
syntax_error Erros de syntax/lint inline

Tokens de terminal palette

16 cores ANSI (8 normal + 8 bright):

Token ANSI
ansi_black 0
ansi_red 1
ansi_green 2
ansi_yellow 3
ansi_blue 4
ansi_magenta 5
ansi_cyan 6
ansi_white 7
ansi_bright_black 8
ansi_bright_red 9
ansi_bright_green 10
ansi_bright_yellow 11
ansi_bright_blue 12
ansi_bright_magenta 13
ansi_bright_cyan 14
ansi_bright_white 15

Plus terminal_bg, terminal_fg, terminal_cursor, terminal_selection_bg.

Catálogo de presets canônicos

Princípio de variantes

Todo preset declara uma ou duas variantes:

  • light — usado quando data-theme=light (ou ThemeMode.light)
  • dark — usado quando data-theme=dark (ou ThemeMode.dark)

Se o preset original é "dark only" (ex: Dracula, Monokai original), a Koder fornece variante derivada _light mantendo a alma da paleta ou marca explicitamente dark_only: true no preset.

A combinação efetiva é resolvida por:

effective = color_scheme.variant[light_or_dark]

Lista canônica (≥10 presets)

# Preset Variantes Origem Notas
1 default light, dark Koder Neutros próprios. Default de fábrica.
2 solarized light, dark Ethan Schoonover (2011) AAA contrast por construção
3 dracula dark, light* Zeno Rocha (2013) *light derivado pela Koder
4 nord dark, light Arctic Ice Studio (2016) Polar Night / Snow Storm
5 gruvbox light, dark Pavel Pertsev (2014) Retro warm
6 tokyo_night dark, light Enkia (2020) Variantes Night/Storm/Day
7 monokai dark, light* Jon Skinner (Sublime, 2006) *light derivado
8 one light, dark Atom (2015) One Light / One Dark
9 catppuccin light (Latte), dark (Mocha) Catppuccin org (2021) Frappé/Macchiato disponíveis
10 high_contrast light, dark Koder (a11y) WCAG AAA estrito; obrigatório como opção em todo app
11 terminal_phosphor dark Koder (CRT-style) Verde fósforo no preto, casa com ui-style: terminal_classic
12 github light, dark GitHub (2020) Familiar pra devs externos

Exemplo de declaração — default (Koder neutros)

[color_schemes.default.light]
bg = "#FFFFFF"
bg_alt = "#F7F8FA"
bg_inset = "#EEF0F4"
fg = "#0B1220"
fg_muted = "#445063"
fg_subtle = "#8893A6"
border = "#D9DEE6"
border_strong = "#A7B0C0"
accent = "#3B5BFD"
accent_strong = "#2944D9"
accent_on = "#FFFFFF"
error = "#C62828"
error_bg = "#FDECEA"
warning = "#A66300"
warning_bg = "#FFF4D6"
success = "#1F7A3A"
success_bg = "#E5F4EA"
info = "#0B6BCB"
info_bg = "#E3F0FB"
selection = "#C6D6FF"
selection_fg = "#0B1220"
link = "#3B5BFD"
link_visited = "#7444C4"

# syntax
syntax_keyword = "#7444C4"
syntax_string = "#1F7A3A"
syntax_number = "#A66300"
syntax_boolean = "#A66300"
syntax_comment = "#8893A6"
syntax_doc_comment = "#5E6B82"
syntax_function = "#0B6BCB"
syntax_function_call = "#0B6BCB"
syntax_class = "#C62828"
syntax_type = "#C62828"
syntax_intrinsic = "#7444C4"
syntax_constant = "#A66300"
syntax_operator = "#445063"
syntax_punctuation = "#445063"

# terminal
terminal_bg = "#FFFFFF"
terminal_fg = "#0B1220"
terminal_cursor = "#3B5BFD"
terminal_selection_bg = "#C6D6FF"
ansi_black = "#0B1220"
ansi_red = "#C62828"
ansi_green = "#1F7A3A"
ansi_yellow = "#A66300"
ansi_blue = "#0B6BCB"
ansi_magenta = "#7444C4"
ansi_cyan = "#0E7C86"
ansi_white = "#D9DEE6"
ansi_bright_black = "#445063"
ansi_bright_red = "#E53935"
ansi_bright_green = "#2E9F4F"
ansi_bright_yellow = "#C28200"
ansi_bright_blue = "#1F86E0"
ansi_bright_magenta = "#9061D6"
ansi_bright_cyan = "#16A0AB"
ansi_bright_white = "#FFFFFF"

[color_schemes.default.dark]
bg = "#0B1220"
bg_alt = "#121A2C"
bg_inset = "#0A0F1C"
fg = "#E7ECF5"
fg_muted = "#A7B0C0"
fg_subtle = "#6A7388"
border = "#212B41"
border_strong = "#3A4660"
accent = "#7E97FF"
accent_strong = "#A8B9FF"
accent_on = "#0B1220"
error = "#FF6E6E"
error_bg = "#3A1B1B"
warning = "#FFC36A"
warning_bg = "#3A2A0F"
success = "#7FE0A0"
success_bg = "#0F2E1B"
info = "#7BC4FF"
info_bg = "#0F2438"
selection = "#2A3D7A"
selection_fg = "#E7ECF5"
link = "#7E97FF"
link_visited = "#B79EFF"

# syntax (escurecido equivalente)
syntax_keyword = "#B79EFF"
syntax_string = "#7FE0A0"
syntax_number = "#FFC36A"
syntax_boolean = "#FFC36A"
syntax_comment = "#6A7388"
syntax_doc_comment = "#8893A6"
syntax_function = "#7BC4FF"
syntax_function_call = "#7BC4FF"
syntax_class = "#FF6E6E"
syntax_type = "#FF6E6E"
syntax_intrinsic = "#B79EFF"
syntax_constant = "#FFC36A"
syntax_operator = "#A7B0C0"
syntax_punctuation = "#A7B0C0"

# terminal
terminal_bg = "#0B1220"
terminal_fg = "#E7ECF5"
terminal_cursor = "#7E97FF"
terminal_selection_bg = "#2A3D7A"
ansi_black = "#212B41"
ansi_red = "#FF6E6E"
ansi_green = "#7FE0A0"
ansi_yellow = "#FFC36A"
ansi_blue = "#7BC4FF"
ansi_magenta = "#B79EFF"
ansi_cyan = "#5FD3DD"
ansi_white = "#A7B0C0"
ansi_bright_black = "#3A4660"
ansi_bright_red = "#FF8A8A"
ansi_bright_green = "#A0EEB6"
ansi_bright_yellow = "#FFD79A"
ansi_bright_blue = "#A1D6FF"
ansi_bright_magenta = "#CFBFFF"
ansi_bright_cyan = "#88E1E8"
ansi_bright_white = "#FFFFFF"

Exemplos de outros presets (referência por pares hex)

Nota: Solarized, Dracula, Nord, Gruvbox, etc. usam os hex oficiais da spec original do autor pra bg/fg/accent etc.; mapping pros tokens Koder é determinístico. Escopo deste spec é declarar a tabela; os hex completos vivem em meta/docs/stack/specs/themes/color-schemes/<preset>.toml (sub-arquivos a serem criados em ticket follow-up).

Preset bg.dark fg.dark accent.dark Origem oficial
solarized.dark #002B36 #839496 #268BD2 https://ethanschoonover.com/solarized/
dracula.dark #282A36 #F8F8F2 #BD93F9 https://draculatheme.com/contribute
nord.dark #2E3440 #D8DEE9 #88C0D0 https://www.nordtheme.com/docs/colors-and-palettes
gruvbox.dark #282828 #EBDBB2 #83A598 https://github.com/morhetz/gruvbox
tokyo_night.dark #1A1B26 #A9B1D6 #7AA2F7 https://github.com/enkia/tokyo-night-vscode-theme
monokai.dark #272822 #F8F8F2 #A6E22E https://monokai.pro/
one.dark #282C34 #ABB2BF #61AFEF https://github.com/atom/one-dark-syntax
catppuccin.mocha #1E1E2E #CDD6F4 #89B4FA https://catppuccin.com/palette
github.dark #0D1117 #C9D1D9 #58A6FF https://primer.style/foundations/color
high_contrast.dark #000000 #FFFFFF #FFFF00 Koder (WCAG AAA)
terminal_phosphor.dark #000000 #33FF33 #33FF33 Koder (CRT)

Cross-render contract

O mesmo preset aplica em 3 surfaces:

1. UI (web + Flutter)

  • koder_web_kit v0.4+ expõe CSS custom properties (--bg, --accent, etc.) populadas pelo preset selecionado
  • koder_kit Flutter v0.18+ expõe KoderColorScheme que produz ColorScheme Material a partir dos tokens

2. Syntax highlighting

  • dev/koder-design-vscode extension lê color-schemes/<preset>.toml e gera tokenColors pro VSCode
  • kterm (Koder terminal) lê os 16 ANSI codes + syntax tokens via TextMate grammar
  • Editor/IDE Koder futuro consome via mesma source

3. Terminal palette

  • 16 ANSI codes diretos
  • Cursor + selection bg
  • kterm aplica via escape codes OSC 4

AAA contrast

Cada preset declara contrast_validation no frontmatter do sub-arquivo:

contrast_validation = {
  "fg/bg" = 7.0,             # AAA Normal text (≥7.0)
  "fg_muted/bg" = 4.5,       # AA (≥4.5)
  "accent_on/accent" = 4.5,  # AA
  "error/error_bg" = 4.5,
  "warning/warning_bg" = 4.5,
}

Audit script (color-schemes-audit.sh) roda axe-color-contrast em cada combinação relevante. Falha = build break.

high_contrast é o único com todos ratios ≥ 7.0 (AAA estrito).

Picker em Settings

App Koder Desktop/Web expõe KoderColorSchemePicker em Settings § Appearance, ao lado do KoderUIStylePicker. O usuário pode combinar livremente.

KoderApp(
  uiStyle: gnome,           // forma
  colorScheme: dracula,     // paleta — ortogonal
  themeMode: ThemeMode.system,  // light/dark
)

Persistência

Mesma chave do tema light/dark, expandida:

localStorage.setItem('koder.appearance', JSON.stringify({
  ui_style: 'gnome',
  color_scheme: 'dracula',
  theme_mode: 'system',
}))

Audit deterministico

color-schemes-audit.sh verifica:

  1. Cada preset listado tem sub-arquivo TOML em themes/color-schemes/<preset>.toml
  2. Cada sub-arquivo declara todos os tokens semânticos + syntax + ANSI
  3. Hex válidos (#RRGGBB)
  4. Contrast ratios cumprem AA/AAA conforme variante
  5. high_contrast cumpre AAA em todos os pares relevantes
  • themes/ui-style.kmd — eixo ortogonal (forma vs cor)
  • themes/light-dark.kmd — eixo ortogonal (toggle behavior)
  • code/languages/koda-style.kmd — declara token grammar; este spec pinta os tokens
  • rfcs/design-RFC-001 § Facets — color schemes pertence ao facet Visual
  • policies/design-governance.kmd — review process pra novo preset

Referências