How to Switch Between Dark and Light#
Every one of the 24 targets renders both modes, and every role in semantics.yaml/ anchors/*.yaml resolves under both — but “the artifact exists” and “your terminal is showing it” are two different problems.
This covers the switch itself: how mode is selected, which tools honor that selection automatically, and how to get each application to actually pick up its light half.
Two independent --mode flags#
Irix has two unrelated things both called --mode, and confusing them is the most common way to be surprised:
The four interactive CLIs —
colorcode,promptcode,kittyhud,themecode— resolve a runtime mode throughirix.term.resolve_mode, with a fixed precedence:An explicit
--mode {dark,light}flag, if given.$IRIX_MODE, if set.dark, otherwise.
An invalid value from either source prints one warning to stderr and falls back to
dark— color-mode selection is never allowed to crash a shell prompt.irix generate/irix check/irix deploytake their own--mode {dark,light,both}(defaultboth). This selects which mode’s artifacts to render, diff, or copy — it has nothing to do with$IRIX_MODE, doesn’t read it, and isn’t read by it. Setting$IRIX_MODE=lightin your environment has zero effect onirix generate; you’d passirix generate --mode lightexplicitly.
IRIX_MODE=light uv run promptcode --path . --fmt plain # picks up $IRIX_MODE
uv run promptcode --path . --fmt ansi --mode dark # explicit flag wins regardless
uv run irix generate kitty --mode light # unrelated flag, unrelated tool
For an interactive session, the simplest approach is exporting it once:
export IRIX_MODE=light
and every colorcode/promptcode/kittyhud/themecode invocation in that shell follows, with no per-command flag needed.
Getting each application to switch#
$IRIX_MODE only changes what the four live CLIs render on the spot.
Every deployed artifact is a static file, so an application that isn’t one of those four CLIs needs its own nudge — some via a config line, some via native in-app switching.
None of this is automated by irix itself; the target engine’s job ends at “both files exist on disk.”
kitty — no built-in light switch.
irix deploy kittywriteskitty.conf(the file kitty loads) andkitty-light.confside by side, but nothing points from one to the other. If you want an easy toggle rather than re-deploying, restructure yourkitty.confaround kitty’s ownincludedirective instead of lettingirix deployown the whole file:# kitty.conf include current-theme.conf
then symlink
current-theme.confat whichever ofkitty.conf’s rendered content (copied aside, sinceirix deploystill wants to write the realkitty.conf) orkitty-light.confyou want live, and reload withkitty @ load-configorctrl+shift+F5.vim —
out/editors/irix.vimis the dual-mode-single-artifact case: one file, both halves.:colorscheme irixpicks it up once; after that, plain vim’s own:set background=dark/:set background=lightselects the half — no second file, no redeploy.sublime — deployed as two separate files,
irix-dark.sublime-color-schemeandirix-light.sublime-color-scheme, both landing inPackages/User/. Switch viaPreferences → Color Scheme → Irix Dark(orIrix Light) — Sublime’s own scheme picker, no config file to hand-edit.vscode — same shape as sublime: two independent theme files, no automatic pairing. Switch via VS Code’s own
Preferences: Color Themepicker (Ctrl+K Ctrl+T) once both are installed as described in Editors.lsd —
colors.yamlandcolors-light.yamldeploy side by side, but lsd only ever reads the file literally namedcolors.yaml. Switching means overwriting that name — e.g.cp colors-light.yaml colors.yamlinside$XDG_CONFIG_HOME/lsd/— there’s no lsd config key to point at an alternate filename.cssvars — the other single-artifact case:
:rootholds the light values, a.darkclass block overrides them. Toggle by adding/removing thedarkclass on<html>or<body>, no file swap at all.Everything else generate-only (starship, delta, fzf, zshcolors, dircolors, the gpl/slack/ gsheets/pymodule targets, …) is a plain two-file pair with no shared switch — you re-source or re-paste whichever mode’s file you want active. How to Deploy Each Target has the exact destination and activation line for each.
The legibility guarantee#
Per-mode isn’t just “same addresses, different palette lookup” everywhere.
A handful of semantics.yaml/anchors/*.yaml roles carry a {dark: ..., light: ...} override instead of one shared address, because Radix’s sign1/sign2 rung — calibrated for a dark surface — falls below the WCAG AA contrast floor against a light background for a few roles (accent, keyword, comment, and others).
Dark addresses are untouched; only the light half of those roles moved one or two rungs deeper on the same hue until it cleared the floor.
tests/test_legibility.py is the enforcement side of that fix — a frozen ledger of every text-ish role’s measured contrast, in both modes, that fails loudly on any drift in either direction.
The full rationale, the before/after contrast numbers, and how the ledger works are in the architecture reference; this page only needs you to know the guarantee exists — every light artifact is legible by measurement, not by eye.