Research: terminal color schemes for DropTerm’s Appearance settings

Date: 2026-10-02 Question: How should DropTerm represent, ship, and apply user-selectable terminal color schemes (16 ANSI colors, fg/bg, cursor, bright/dim variants), and how should they interact with the system light/dark preference?

TL;DR

Copy cosmic-term’s model — it is the same stack solving the same problem. cosmic-term (pop-os/cosmic-term, master 3ef31d7, 2026-10-01) represents a scheme as a serde struct ColorScheme (name, foreground, background, cursor, bright_foreground, dim_foreground, plus normal/bright/dim tables of 8 named colors each, all Option<HexColor>) defined in src/config.rs. User schemes live inside the cosmic-config config file as BTreeMap<ColorSchemeId, ColorScheme> — one map per dark/light kind — and the selected scheme per mode is a plain String name (syntax_theme_dark / syntax_theme_light). Schemes are applied by converting to alacritty_terminal::term::color::Colors (a [Option<Rgb>; 269]) and copying slots into each terminal on config change. DropTerm already vendors the last two steps (src/terminal/theme_source.rs, engine.rs::set_config), so the work is: a real ColorScheme type, a named scheme registry (built-ins compiled in — cosmic-term’s repo ships 30 importable RON files under color-schemes/), and a picker in the Appearance settings section instead of the raw color_scheme_dark/color_scheme_light strings currently buried in Advanced. Light/dark auto-switching already works end-to-end in DropTerm via libcosmic’s system_theme_update hooks — nothing new is needed there for a scheme list.

Note: util-linux terminal-colors.d(5) does not apply — it configures color output of CLI utilities (dmesg, ls, …), not terminal-emulator palettes. There is no freedesktop standard for emulator schemes; every emulator rolls its own format. The industry-consensus field set for a minimal-but-complete scheme is: name/metadata, foreground, background, 16 ANSI colors, cursor (+ optional cursor text), optional selection fg/bg, optional bright/dim variants (derivable).

What DropTerm does today

Findings

1. cosmic-term: scheme model, storage, and application

All paths below are pop-os/cosmic-term @ master 3ef31d750d3b09a73f266923b0d64c5df038cf9f (2026-10-01; Cargo.toml says version 1.9.0, license GPL-3.0-only, alacritty_terminal = "0.25.1", cosmic-text = "0.19", hex_color = "3", ron = "0.11" — same engine and color-text stack as DropTerm).

Types (src/config.rs):

Conversion to alacritty colors (src/terminal_theme.rs):

The shipped RON files: the repo tree has 30 files under color-schemes/*.ron (COSMIC Dark/Light, Dracula, Gruvbox Dark, Solarized Dark/Light, Tango Dark/Light, Selenized ×4, Modus ×4, Rose Pine ×3, Pop Dark, Rxvt, XTerm, Linux Console, OneHalfDark, Everforest, Seashells, seal-brown-amber, …). Notably nothing in src/ reads that directory (grep for read_dir/include over the tree: zero hits) — at master they are an import source for users (Settings → Color Schemes → import file dialog, src/main.rs ~L2115-2150 ron::de::from_reader::<_, ColorScheme>) and the contribution point for new schemes (recent commits: “Add seal brown and amber terminal color scheme” f9d893b8, 2025-12-20). The two COSMIC RONs have no background field (matching the unset-Background behavior), while third-party ones like Dracula.ron set background: "#1e1f29".

Application at runtime (src/terminal.rs, src/terminal_box.rs):

Light/dark switching (src/main.rs):

Could DropTerm reuse a crate? No — ColorScheme lives in cosmic-term’s binary crate (not published), and there is no shared scheme crate; libcosmic’s cosmic-theme is the toolkit palette, not ANSI schemes. The options are vendor the ~150 lines of config.rs types + terminal_theme.rs conversions (DropTerm already vendored the palettes; both projects are GPL-3.0-only), or write a compatible struct from scratch.

2. alacritty_terminal 0.25.1: the color model we embed

From the local cargo registry (…/registry/src/index.crates.io-…/alacritty_terminal-0.25.1/src/term/color.rs, Apache-2.0):

3. Alacritty’s colors: TOML format

Primary source: extra/man/alacritty.5.scd @ alacritty master (https://github.com/alacritty/alacritty/blob/master/extra/man/alacritty.5.scd, “# COLORS” section at L294+). Field inventory:

4. Industry conventions for named schemes

Emulator Scheme fields Selected via Light/dark
Alacritty (§3) primary (fg/bg/dim/bright fg), 16 colors, optional dim table, cursor/vi cursor, selection, search/hints, indexed theme TOML + import, or inline colors: no auto light/dark; users keep two files
kitty foreground, background, cursor, selection_foreground, selection_background, color0-color15 (+ optional cursor_text_color, etc.) themes kitten; a theme is “just a .conf file” copied to ~/.config/kitty/current-theme.conf + include in kitty.conf auto: dark-theme.auto.conf / light-theme.auto.conf / no-preference-theme.auto.conf (kitty ≥ 0.38.0) chosen from the OS color scheme; changes live
GNOME Terminal profile keys: palette (16 hex strings), foreground-color, background-color, bold-color(+-same-as-fg), cursor-colors-set + cursor-background/foreground-color, highlight-colors-set + highlight-background/foreground-color, use-theme-colors dconf profile; built-in palettes in the “Colors” tab picker use-theme-colors follows the GTK theme
iTerm2 .itermcolors plist: Ansi 0-15 Color, Background/Foreground/Bold/Cursor/Cursor Text/Selection/Selected Text Color (+ Link), each a dict of Red/Green/Blue Component floats 0..1 “Color Presets…” menu; import/export files; preset name from filename profiles may carry separate light & dark color sets (“Use separate colors for light and dark mode”)
Windows Terminal schemes[] JSON object: name, cursorColor, selectionBackground (both optional), background, foreground, 16 colors black..white + brightBlack..brightWhite (uses purple, not magenta) per-profile colorScheme string in settings.json no scheme-level dark/light pairing; themes app / manual
base16 / tinted scheme:, author:, base00-base0F (00-07 = bg→fg ramp; base02 selection bg, base05 fg/caret; 08-0F = accents mapped to ANSI by templates) templates per app; tinty CLI scheme is one variant; families ship dark+light as separate files

Sources: kitty themes docs (https://sw.kovidgoyal.net/kitty/kittens/themes/ — mechanism, user-theme override by name in ~/.config/kitty/themes, auto light/dark section) and theme-file shape (kitty-themes repo, 413 .conf files; themes/Solarized_Dark.conf sets background/foreground/cursor/ selection_background/selection_foreground/color0-15 plus `## name:/## author:/

license:/## blurb:` metadata headers; option defaults in

kitty/options/definition.py L2523-2800). GNOME Terminal src/org.gnome.Terminal.gschema.xml @ gitlab master (keys and defaults quoted at L141-200, L315+, L346). iTerm2 https://iterm2.com/documentation-preferences-profiles-colors.html + a sample .itermcolors from mbadolato/iTerm2-Color-Schemes (key list above). Windows Terminal https://learn.microsoft.com/en-us/windows/terminal/customize-settings/color-schemes and fragment extensions (https://learn.microsoft.com/en-us/windows/terminal/json-fragment-extensions — a fragment scheme “must define a name … and every color in the color table”). base16: styling.md in chriskempson/base16 (role table) and tinted-theming/base16-schemes solarized-dark.yaml; the successor spec tinted8 (tinted-theming/home specs/tinted8/styling.md, 0.2.0-beta) adds variant: dark|light, scheme.slug, and inherits for syntax/ui.

Minimal-but-complete field set (the intersection everyone agrees on, plus what our engine can consume): name (+ ideally author/license metadata), foreground, background, 16 ANSI colors, cursor (cursor-text optional), and optionally selection fg/bg and dim/bright variants. cosmic-term’s ColorScheme = exactly this minus selection; alacritty’s = this plus search/hints/indexed; WT requires name + all 16 and treats cursor/selection as optional.

5. How a scheme list is usually shipped

Four patterns, all in active use:

  1. Compiled-in built-ins — cosmic-term’s two hardcoded palettes; Windows Terminal’s schemes inside defaults.json; kitty’s embedded themes (overridable by a same-named file in ~/.config/kitty/themes). Pros: no I/O, versioned with the app, always present for fallback.
  2. A repo of importable files — alacritty-theme (177 TOMLs), kitty-themes (413), cosmic-term’s color-schemes/ (30 RONs, imported via file dialog), iTerm2’s preset gallery. The app doesn’t scan them; users import.
  3. User files auto-discovered from a config dir — kitty’s ~/.config/kitty/themes/*.conf (overrides builtins by theme name); WT fragments in defined locations. This is the hand-editable, dotfiles-friendly option.
  4. Schemes stored inside the app config — cosmic-term’s color_schemes_dark/light maps in the cosmic-config entry (created via its editor UI or import); WT’s schemes[] in settings.json. No fs watching, atomic saves, but schemes aren’t shareable files without import/export.

freedesktop/XDG note: the only XDG-adjacent convention, terminal-colors.d(5) (util-linux 2.42.4, https://man.archlinux.org/man/terminal-colors.d.5.en), configures “output colorization for various utilities” — disable/enable/scheme files for CLI tools like dmesg, keyed per utility and $TERM*. It is consumed by util-linux utilities, not terminal emulators, and its scheme files map logical names (e.g. error`) to ANSI sequences — nothing to do with a 256-color palette. Do not adopt or claim compatibility with it for DropTerm’s scheme files. Emulator schemes have no standard location; the closest convention is “files in a subdir of the app’s XDG config dir” (kitty).

6. System light/dark mode + libcosmic (pinned rev 08a09e3)

Verified in the local checkout (~/.cargo/git/checkouts/libcosmic-41009aea1d72760b/08a09e3/, i.e. pop-os/libcosmic @ 08a09e3):

What applies to DropTerm

Phase 1 — named built-ins + picker (no new subsystems):

  1. Adopt cosmic-term’s ColorScheme/ColorSchemeAnsi/ColorSchemeKind types (vendor ~150 lines from src/config.rs @ 3ef31d7, keeping the SPDX/copyright header like theme_source.rs already does). Field list is in §1; it is a strict superset of what dropterm’s engine consumes today and a subset of alacritty’s TOML, so importing alacritty-style themes later is lossless-ish (search/hints colors dropped).
  2. Keep the conversion tail already vendored: add cosmic-term’s From<&ColorScheme> for Colors to theme_source.rs and route the existing cosmic_dark()/cosmic_light() through ColorScheme (their palettes are byte-identical to color-schemes/COSMIC Dark.ron / COSMIC Light.ron, which conveniently have no background field — preserving the follow-COSMIC-theme background behavior).
  3. Ship a curated set of built-ins compiled in (include_str! + ron::from_str into a once_cell/const table, or code-generated). Directly reusable: the 30 RONs in cosmic-term’s color-schemes/ (GPL-3.0-only, same as DropTerm — see licensing below). A scheme with a background field overrides the COSMIC window background — that’s the desired behavior for e.g. Dracula; WINDOW_BG_COLOR remains the fallback for the two COSMIC schemes (and refresh_window_bg_color() already keeps it fresh).
  4. UI: move scheme selection into the Appearance section as a dropdown (one choice for dark mode, one for light — or a single choice + “COSMIC Dark/Light for the other mode” if the settings spec prefers fewer rows). The existing color_scheme_dark/color_scheme_light: String config fields stay as-is — they already store the scheme name, and active_colors() already falls back gracefully on unknown names. That keeps DropTermConfig at #[version = 1] with no migration.
  5. Light/dark: nothing to build. system_theme_update / system_theme_mode_update → apply_config_to_tabs() already re-resolve active_colors() on OS flips. (If an explicit app theme override is ever wanted, copy cosmic-edit/cosmic-term’s AppTheme tri-state + set_theme, and consult config.color_scheme_kind() instead of raw is_dark().)
  6. Tests: round-trip ColorScheme ↔ Colors over all color::COUNT slots exactly like cosmic-term’s export() assert; unit-test name lookup, fallback-on-unknown-name, and that COSMIC built-ins leave Background unset.

Phase 2 — user schemes (pick one):

Selection colors: leave out of v1 — cosmic-term has none either (fg/bg swap, with an upstream TODO). If added later, they are engine/widget-level (render-time override like alacritty’s selection {text, background}), not NamedColor slots, so the scheme struct can grow selection_foreground/background: Option<HexColor> without touching alacritty_terminal types.

Licensing

Unverified / open questions

Sources