# Red Bear OS — Default TUI Skin Palette
`redbear-tui-theme` is the **single source of truth** for the Red Bear brand colours used by every TUI application on Red Bear OS:
- `tlc` (file manager)
- `cub` (package manager)
- `redbear-info` (system dashboard)
- `redbear-netctl-console` (network control)
- `redbear-wifictl`, `redbear-btctl` (device control)
- `redbear-mtr`, `redbear-traceroute`, `redbear-nmap`, `redbear-hwutils` (diagnostics)
- any future TUI app
The palette is pure-Rust (no `ratatui` dep at the core), builds offline, and ships with both dark and light presets.
## Quick start
```toml
# Cargo.toml
[dependencies]
redbear-tui-theme = { path = "../../../tui/redbear-tui-theme/source" }
```
```rust
use redbear_tui_theme::{REDBEAR_DARK, Theme};
// Render a selection row.
let bg = REDBEAR_DARK.selection_bg; // #3652A0
let fg = REDBEAR_DARK.selection_fg; // #F4F4F4
// Or pick a theme from the environment (REDBEAR_TUI_THEME or COLORFGBG).
let theme = Theme::from_env();
```
## What's in the palette
The `Theme` struct has **33 slots** organized into six families:
| Surface | `background`, `surface`, `overlay_bg`, `title_bg`, `status_bg`, `gauge_bg` | 6 slots; 3-tier raised surface; chrome bars |
| Text | `text`, `muted`, `dim`, `border` | 4 slots; body text + de-emphasis |
| Accent | `accent`, `accent_soft`, `title_accent`, `pink` | 4 slots; brand red + secondary accents |
| Semantic | `success`, `warning`, `error`, `info` | 4 slots; status colours (must pair with glyphs) |
| File types | `directory`, `executable`, `symlink`, `device`, `device_warn`, `hidden` | 6 slots; tlc file-type colours |
| Selection | `selection_{bg,fg}`, `cursor_{bg,fg}`, `marked_{bg,fg}`, `buttonbar_{bg,fg}` | 8 slots; tlc selection/cursor/marked/buttonbar |
All 33 slots are sourced from the shared `Theme` — no consumer hard-codes brand hex values.
## Brand red
`#B52430` is the Red Bear OS brand red. It is **identical** in both dark and light themes. This matches the convention of macOS, KDE, GNOME, and Windows: the brand stays constant; only the background flips.
## WCAG 2.1 AA contrast (verified)
| `text` on `background` | 17.51 | 15.86 | AA-body ✓ |
| `text` on `accent` | 5.86 | 6.44 | AA-body ✓ |
| `muted` on `background` | 8.33 | 5.82 | AA-body ✓ |
| `border` on `background` | 4.53 | 2.27 | AA-body (dark) / AA-large (light) |
| `dim` on `background` | 2.91 | 3.81 | **Intentionally below AA-body** (de-emphasis) |
The only intentional AA-body failure is `dim`/`hidden`. By design: de-emphasis is the function. Apps must not use `dim` for body text.
## Color-blindness
- `success` vs `error`: distinguishable for all three common deficiencies.
- `warning` vs `error`: **confusable** for protanopia and deuteranopia. **Mitigation**: every warning must be accompanied by a `⚠` glyph prefix, every error by `✗`.
- `info` vs `success`: confusable for tritanopia. **Mitigation**: keep `info` and `success` on separate lines in status bars.
- `pink` is for highlights (favorites, active link). **Mitigation**: when used, also prepend `★` (U+2605).
Apps render these as styles with `Modifier::BOLD` on the semantic colours; the styles module (planned v0.2) will provide ready-made `success_style()`, `warning_style()`, etc. as one-liners.
## 256-color + 16-color fallback
For terminals that don't support truecolor, the `fallback` module provides:
- `fallback_256(rgb: Rgb) -> u8` — closest XTerm-256 index (0..=255)
- `fallback_16_name(rgb: Rgb) -> &'static str` — closest ANSI-16 name
`fallback_256` uses a weighted Euclidean distance in sRGB space (small luminance penalty to keep the returned colour visually close). Verified mappings:
| `background` | `#0E0E12` | 233 | Black |
| `text` | `#F4F4F4` | 255 | Bright White |
| `accent` | `#B52430` | 125 or 9 | Bright Red |
| `success` | `#74C793` | 114 | Bright Black |
| `warning` | `#FFBF57` | 215 | Bright Yellow |
## Migrating an existing TUI app
1. Add the dep to `Cargo.toml`:
```toml
redbear-tui-theme = { path = "../../../tui/redbear-tui-theme/source" }
```
2. Replace local `Color::Rgb(r, g, b)` constants with `REDBEAR_DARK.<slot>` (or `Rgb(r,g,b)` if you need a custom value).
3. Convert to your TUI lib's colour type: `ratatui::style::Color::Rgb(t.bg.0, t.bg.1, t.bg.2)`.
4. Replace any local `Theme` struct with `pub use redbear_tui_theme::Theme;`.
5. Add `redbear-tui-theme` to the cookbook's cascade list in `local/scripts/rebuild-cascade.sh`.
## Build
The crate has zero required dependencies. It builds offline:
```bash
cd local/recipes/tui/redbear-tui-theme/source
cargo build --release
cargo test # 11 unit tests (palette + fallback) + 1 doc test
```
The recipe lives at `local/recipes/tui/redbear-tui-theme/recipe.toml` and
stages the resulting `libredbear_tui_theme.rlib` into
`${COOKBOOK_STAGE}/usr/lib/` so the cookbook's repo artifact check passes.
The recipe is symlinked into the cookbook search path at
`recipes/tui/redbear-tui-theme` (per `local/AGENTS.md` "Local recipe priority
vs upstream WIP"). Downstream TUI apps depend on the crate via a Cargo
`path` dependency — they do **not** install it as a binary.
## Downstream consumers (as of 2026-06-13)
| `tlc` | ✅ wired | `tlc/source/Cargo.toml` adds `redbear-tui-theme = { path = "../../../tui/redbear-tui-theme/source" }`. The 22-field `Theme` struct in `src/terminal/color.rs` is preserved (TOML skin deserializer still works); `DEFAULT_THEME` and `LIGHT_THEME` are now built from the shared `REDBEAR_DARK`/`REDBEAR_LIGHT` via a const `as_color(rgb)` adapter. |
| `cub` | ✅ wired | `local/recipes/system/cub/source/cub/src/tui/theme.rs` is now a 33-field `RedBearTheme` newtype constructed from `redbear_tui_theme::REDBEAR_DARK` via a const `as_color(rgb)` adapter. The 19 `*_style()` methods are preserved as inherent methods; all 33 slots are sourced from the shared palette. 2 new tests verify byte-identical brand red and 19 non-empty styles. |
| `redbear-info` | 🚧 TODO | `local/recipes/system/redbear-info/source/src/tui.rs` uses the legacy ANSI-16 palette (`Color::Red`, `Color::DarkGray`, etc.). Migration is non-trivial because the file uses semantic colors only, not slot names. |
| `redbear-netctl-console` | 🚧 TODO | `local/recipes/system/redbear-netctl-console/source/src/ui.rs` uses the legacy ANSI-16 palette. Same migration story as `redbear-info`. |
## License
MIT — same as Red Bear OS.