Skip to content

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.

When this spec applies

Primary triggers

All triggers

Specification body

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 verge + system + default (flipado 2026-05-14 de material3 per verge.kmd R5).

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)

TokenUso
bgBackground principal de janelas/scaffold
bg_altBackground secundário (cards, sheets)
bg_insetBackground de áreas inset (input, code block)
fgTexto primário sobre bg
fg_mutedTexto secundário (labels, captions)
fg_subtleTexto desabilitado/placeholder
borderBordas de containers
border_strongBordas com ênfase (focus, selected)
accentCor de marca/ação primária
accent_strongHover/pressed state do accent
accent_onTexto sobre superfície accent
errorEstado de erro (banner, border, text)
error_bgBackground sutil de erro
warningEstado de aviso
warning_bgBackground sutil de warning
successEstado de sucesso
success_bgBackground sutil de sucesso
infoEstado informacional
info_bgBackground sutil de info
selectionBackground de seleção de texto
selection_fgTexto sobre selection
linkCor de hyperlink
link_visitedCor de hyperlink já visitado

Tokens de syntax highlighting

TokenUso
syntax_keywordPalavras-chave da linguagem (if, class, def)
syntax_keyword_opOperadores keyword-like (and, or, not)
syntax_stringLiterais string
syntax_string_specialEscape sequences, interpolation markers
syntax_numberLiterais numéricos (int, float, hex)
syntax_booleantrue, false, nil, null
syntax_commentComentários
syntax_doc_commentDoc comments (#: em Koda)
syntax_functionDefinição de função
syntax_function_callChamada de função
syntax_methodMétodo de classe/instância
syntax_classDefinição de classe/tipo
syntax_typeReferência a tipo
syntax_intrinsicIntrínsecos da linguagem (self, super)
syntax_macroMacro/preprocessor
syntax_constantConstantes (MAX_SIZE, PI)
syntax_variableVariável local
syntax_parameterParâmetro de função
syntax_propertyPropriedade de objeto/dict
syntax_punctuation{}, [], (), ,, ;
syntax_operator+, -, *, ==, <
syntax_tagTag XML/HTML
syntax_attributeAtributo de tag
syntax_errorErros de syntax/lint inline

Tokens de terminal palette

16 cores ANSI (8 normal + 8 bright):

TokenANSI
ansi_black0
ansi_red1
ansi_green2
ansi_yellow3
ansi_blue4
ansi_magenta5
ansi_cyan6
ansi_white7
ansi_bright_black8
ansi_bright_red9
ansi_bright_green10
ansi_bright_yellow11
ansi_bright_blue12
ansi_bright_magenta13
ansi_bright_cyan14
ansi_bright_white15

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)

#PresetVariantesOrigemNotas
1defaultlight, darkKoderNeutros próprios. Default de fábrica.
2solarizedlight, darkEthan Schoonover (2011)AAA contrast por construção
3draculadark, light*Zeno Rocha (2013)*light derivado pela Koder
4norddark, lightArctic Ice Studio (2016)Polar Night / Snow Storm
5gruvboxlight, darkPavel Pertsev (2014)Retro warm
6tokyo_nightdark, lightEnkia (2020)Variantes Night/Storm/Day
7monokaidark, light*Jon Skinner (Sublime, 2006)*light derivado
8onelight, darkAtom (2015)One Light / One Dark
9catppuccinlight (Latte), dark (Mocha)Catppuccin org (2021)Frappé/Macchiato disponíveis
10high_contrastlight, darkKoder (a11y)WCAG AAA estrito; obrigatório como opção em todo app
11terminal_phosphordarkKoder (CRT-style)Verde fósforo no preto, casa com ui-style: terminal_classic
12githublight, darkGitHub (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).

Presetbg.darkfg.darkaccent.darkOrigem oficial
solarized.dark#002B36#839496#268BD2https://ethanschoonover.com/solarized/
dracula.dark#282A36#F8F8F2#BD93F9https://draculatheme.com/contribute
nord.dark#2E3440#D8DEE9#88C0D0https://www.nordtheme.com/docs/colors-and-palettes
gruvbox.dark#282828#EBDBB2#83A598https://github.com/morhetz/gruvbox
tokyo_night.dark#1A1B26#A9B1D6#7AA2F7https://github.com/enkia/tokyo-night-vscode-theme
monokai.dark#272822#F8F8F2#A6E22Ehttps://monokai.pro/
one.dark#282C34#ABB2BF#61AFEFhttps://github.com/atom/one-dark-syntax
catppuccin.mocha#1E1E2E#CDD6F4#89B4FAhttps://catppuccin.com/palette
github.dark#0D1117#C9D1D9#58A6FFhttps://primer.style/foundations/color
high_contrast.dark#000000#FFFFFF#FFFF00Koder (WCAG AAA)
terminal_phosphor.dark#000000#33FF33#33FF33Koder (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

References