feat(theme): make Boreal the distro default
Some checks failed
Check / eval (push) Has been cancelled

Seed theme-state.json and the downstream template from themes/boreal.json
(including border + empty settings). Point eval/schema fallbacks at Boreal
(theme.nix preset, plymouth and live-ISO splash colors, theme-shot, sync
error examples). Docs/TESTING and RECOVERY follow the new default.

Verified: state matches boreal palette; theme-contrast all pass.
preview.png for boreal still missing (picker plain-name; V3 capture).
This commit is contained in:
Bernardo Magri
2026-07-09 09:57:32 +01:00
parent 70501b566a
commit 351b7adb8e
13 changed files with 122 additions and 113 deletions

View File

@@ -28,15 +28,6 @@ in [`docs/ROADMAP.md`](../docs/ROADMAP.md); map in
## NEXT
### 42. Default theme → boreal (`VISION § B` / v1.0 bar)
Ship Boreal as the distro default instead of Tokyo Night: root
`theme-state.json`, `templates/downstream/theme-state.json` (and any
greeter/plymouth fallbacks that hardcode Tokyo Night when state is
missing). Preset already exists under `themes/boreal/`. Capture
`preview.png` if still missing so the picker looks first-class.
Cost: copy/apply palette into seed state files + grep for tokyo-night
defaults; V0 contrast, V1/V2 theme apply, V3 visual on hardware.
### 43. System Firmware — fwupd product surface (`VISION § A`)
`services.fwupd.enable` is already default-on and never auto-flashes,
but users only learn about `fwupdmgr` from a README sentence. Add a
@@ -131,10 +122,12 @@ implement. Bernardo moves accepted items into a tier.*
### v1.0 track — see `docs/VISION.md`
Product themes and the release bar live in **VISION**. Promoted to
**NEXT:** #42 boreal default · #43 System Firmware · #44 doctor
hardware. Remaining candidate promotions: fingerprint menu ·
first-boot tips · human rebuild errors · neon-glass quarantine.
Product themes and the release bar live in **VISION**. **NEXT:**
#43 System Firmware · #44 doctor hardware. #42 boreal default
shipped (seed state + eval fallbacks); still missing
`themes/boreal/preview.png` (picker plain-name until captured).
Remaining candidate promotions: fingerprint menu · first-boot tips ·
human rebuild errors · neon-glass quarantine.
### Pre-existing
@@ -283,11 +276,12 @@ first-boot tips · human rebuild errors · neon-glass quarantine.
### Theme polish / completeness (codebase exam 2026-07-09)
- **Missing theme picker previews + hand btop for identity themes**
`boreal`, `executive-slate`, and `neon-glass` lack `preview.png`
(picker falls back to plain-name rows) and `btop.theme` (generated
btop only). CSS/jsonc for boreal/executive-slate are otherwise
solid. Capture previews after neon-glass is fixed/quarantined.
Cost: asset capture + optional hand btop; V3 visual.
`boreal` (now the default — higher priority), `executive-slate`, and
`neon-glass` lack `preview.png` (picker plain-name rows) and
`btop.theme` (generated btop only). CSS/jsonc for boreal/executive-slate
are solid. Capture boreal preview ASAP for v1.0 bar; others after
neon-glass is fixed/quarantined. Cost: asset capture + optional hand
btop; V3 visual.
- **Generated Waybar missing identity-bar affordances**
Whole-swap bars ship `custom/powermenu` and a left logo → main menu;

View File

@@ -17,6 +17,13 @@ Template:
---
## 2026-07-09 — Default theme → Boreal (item #42)
- **Task:** NEXT #42 — distro default theme Tokyo Night → Boreal (`VISION § B` / v1.0 bar).
- **Did:** Seeded `theme-state.json` + `templates/downstream/theme-state.json` from `themes/boreal.json` (incl. border + settings). Eval fallbacks: `theme.nix` preset → boreal.json; plymouth + live ISO splash hex fallbacks; theme-shot / theme-sync examples; TESTING/RECOVERY wording.
- **Verified:** V0 — state JSON matches boreal palette/fonts; `check-theme-contrast` 24×7 pass; py_compile theme-sync. Full `nix flake check --no-build` started but not waited (slow ISO eval). No V2 apply / V3 session.
- **Pending:** `themes/boreal/preview.png` still missing (picker name-only) — left in PROPOSED theme polish; V2/V3 visual on hardware. Queue head now #43 Firmware.
- **Next suggestion:** #43 System Firmware or #44 doctor hardware.
## 2026-07-09 — Install contracts: swap=0 + unattended LUKS (workflow test run)
- **Task:** VISION § v1.0 install golden path — PROPOSED install P0s (NEXT head blocked: item 14 wait-cron, 20 `[human]`, 33 V3 visual, 41 hw). Test of VISION→BACKLOG→verify→commit loop.
- **Did:** (1) `nomarchy-install` passes `swapSize=0` when swap disabled (was always `"${SWAP_GB}G"``"0G"` still created `@swap`). (2) `disko-config.nix` treats `"0"` and `"0G"` as no-swap. (3) Unattended LUKS fail-closed: require `NOMARCHY_LUKS_PASSPHRASE` or `NOMARCHY_NO_LUKS=1`.

View File

@@ -25,7 +25,7 @@ The same picker lives in the menu: **System Rollback** lists the
recent desktop generations — pick one and it activates.
Or simply apply a theme you know is good: `nomarchy-theme-sync apply
tokyo-night`. If a switch failed halfway, the state file is written
boreal` (or any preset). If a switch failed halfway, the state file is written
*before* the rebuild — fix the cause and re-run
`home-manager switch --flake ~/.nomarchy` (or `home-update`).

View File

@@ -65,13 +65,13 @@ Work through these in order; each one exercises a different layer.
| # | Check | Verifies |
|---|---|---|
| 1 | Boots to Hyprland with Tokyo Night wallpaper visible | greetd autologin, awww, session start |
| 1 | Boots to Hyprland with the default theme wallpaper visible (Boreal) | greetd autologin, awww, session start |
| 2 | Waybar shows at top, themed (blue accent on dark) | HM waybar module, palette baking |
| 3 | `SUPER+Return` opens Ghostty with Tokyo Night colors | terminal default, ANSI palette |
| 3 | `SUPER+Return` opens Ghostty with the default theme colors (Boreal) | terminal default, ANSI palette |
| 4 | `btop` in the terminal is themed | per-theme asset baking |
| 5 | `nomarchy-theme-sync list` prints 21 presets | package, baked themes dir |
| 6 | `nomarchy-theme-sync apply gruvbox` → state written, `home-manager switch` runs, desktop re-themes, wallpaper changes | the whole engine: state write, pure eval, HM rebuild, wallpaper hook |
| 7 | `SUPER+SHIFT+T` cycles wallpapers instantly (try `tokyo-night`: 4 of them) | the runtime wallpaper path |
| 7 | `SUPER+SHIFT+T` cycles wallpapers instantly (try `tokyo-night` for 4, or `boreal` for its set) | the runtime wallpaper path |
| 8 | `nomarchy-theme-sync apply summer-night` → after the switch the bar has its own identity (light bar, different styling) | whole-swap waybar.css assets |
| 9 | Open a GTK app — dark theme matching the palette | Stylix layer |
| 10 | `home-manager generations` lists one generation per theme change; activating an older one rolls the theme back | atomicity / rollback story |

View File

@@ -37,7 +37,7 @@ judgment; agents prepare, do not advance `v1`):
| Bar | Done looks like |
|-----|-----------------|
| **Install golden path** | Offline (or documented online) install → first boot themed desktop; swap=0 and unattended LUKS contracts correct |
| **Default identity** | Boreal (or chosen default) is the seed theme; picker has preview |
| **Default identity** | Boreal is the seed theme (shipped 2026-07-09); picker should have `preview.png` |
| **Day-2 confidence** | Doctor covers real failure modes; firmware and fingerprint are discoverable without reading the README |
| **Hardware story** | `docs/HARDWARE.md` matches code; option-docs green; i2c/ddcci documented |
| **Honesty** | No “done” claims past verified tier; HARDWARE-QUEUE cleared or consciously deferred |

View File

@@ -6,14 +6,14 @@
let
# ISO boot branding: the Nomarchy monogram recolored to the palette accent,
# centred on the theme base. Built from the vendored vector logo and the
# live theme-state.json (tokyo-night by default). The same composed image
# live theme-state.json (Boreal by default). The same composed image
# backs both the isolinux (BIOS) splash and the GRUB (UEFI) theme below, so
# the two boot paths match.
state = builtins.fromJSON (builtins.readFile ../theme-state.json);
isoColor = key: fallback: lib.removePrefix "#" ((state.colors or { }).${key} or fallback);
accent = isoColor "accent" "7aa2f7";
base = isoColor "base" "1a1b26";
subtext = isoColor "subtext" "787c99";
accent = isoColor "accent" "B79BE8";
base = isoColor "base" "21272F";
subtext = isoColor "subtext" "97A3B2";
isoSplash = pkgs.runCommand "nomarchy-iso-splash.png"
{ nativeBuildInputs = [ pkgs.imagemagick pkgs.librsvg ]; } ''

View File

@@ -22,10 +22,10 @@ let
# Defaults guarantee evaluation succeeds on a sparse or older state
# file (e.g. one written before a schema field was added). The shipped
# Tokyo Night preset provides the color/ansi fallbacks; the path is
# Boreal preset provides the color/ansi fallbacks; the path is
# relative to this module, so it resolves inside Nomarchy's own flake
# source even when consumed downstream.
preset = builtins.fromJSON (builtins.readFile ../../themes/tokyo-night.json);
preset = builtins.fromJSON (builtins.readFile ../../themes/boreal.json);
defaults = preset // {
fonts = {
@@ -132,7 +132,7 @@ let
${toString cfg.stateFile} is a snapshot of it). The tool prints
the same report with per-field fixes: `nomarchy-theme-sync
validate`. Re-applying any preset resets all appearance fields:
`nomarchy-theme-sync apply tokyo-night`.'';
`nomarchy-theme-sync apply boreal`.'';
# A border value is a palette key (look it up in colors) unless it's
# already a literal hex; unknown keys fall through to the raw string.

View File

@@ -33,7 +33,7 @@
description = ''
theme-state.json for the system-side consumers (currently the
Plymouth splash background). lib.mkFlake wires it automatically
from your flake; null falls back to the Tokyo Night base color.
from your flake; null falls back to the Boreal base color.
'';
};

View File

@@ -15,14 +15,15 @@ let
then builtins.fromJSON (builtins.readFile cfg.stateFile)
else { };
colorOf = key: fallback: lib.removePrefix "#" ((state.colors or { }).${key} or fallback);
base = colorOf "base" "#1a1b26";
# Fallbacks match the distro default theme (Boreal) when stateFile is null.
base = colorOf "base" "#21272F";
# Splash elements are recolored from the palette so they read on any
# base, light or dark: foreground glyphs → text, field/track boxes →
# surface (raised from base in both polarities), the progress fill →
# accent. The shipped art is a fixed navy that vanished on dark themes.
text = colorOf "text" "#a9b1d6";
surface = colorOf "surface" "#32344a";
accent = colorOf "accent" "#7aa2f7";
text = colorOf "text" "#D3DAE0";
surface = colorOf "surface" "#303A46";
accent = colorOf "accent" "#B79BE8";
magick = lib.getExe' pkgs.imagemagick "magick";
# Plymouth's Window.SetBackgroundTopColor takes three floats in

View File

@@ -208,7 +208,7 @@ def validate_state(state) -> tuple:
if not isinstance(state, dict):
err("top level", "must be a JSON object",
"re-apply a preset: nomarchy-theme-sync apply tokyo-night")
"re-apply a preset: nomarchy-theme-sync apply boreal")
return errors, warnings
for k in state:
@@ -221,7 +221,7 @@ def validate_state(state) -> tuple:
("icons", "an icon theme name (or \"\" for pick-by-mode)")):
v = state.get(field)
if v is not None and not isinstance(v, str):
err(field, f"must be a string ({want}), got {v!r}", 'quote it, e.g. "tokyo-night"')
err(field, f"must be a string ({want}), got {v!r}", 'quote it, e.g. "boreal"')
mode = state.get("mode")
if mode is not None and mode not in ("dark", "light"):

View File

@@ -1,55 +1,61 @@
{
"version": 1,
"name": "Tokyo Night",
"slug": "tokyo-night",
"name": "Boreal",
"slug": "boreal",
"mode": "dark",
"wallpaper": "",
"colors": {
"base": "#1a1b26",
"mantle": "#161720",
"surface": "#32344a",
"overlay": "#444b6a",
"text": "#a9b1d6",
"subtext": "#787c99",
"muted": "#444b6a",
"accent": "#7aa2f7",
"accentAlt": "#ad8ee6",
"good": "#9ece6a",
"warn": "#e0af68",
"bad": "#f7768e"
"base": "#21272F",
"mantle": "#1A1F26",
"surface": "#303A46",
"overlay": "#404D5C",
"text": "#D3DAE0",
"subtext": "#97A3B2",
"muted": "#5E6A78",
"accent": "#B79BE8",
"accentAlt": "#86C7C0",
"good": "#A3CF88",
"warn": "#E6C384",
"bad": "#E2818A"
},
"border": {
"active": "accent",
"inactive": "overlay"
},
"ansi": [
"#32344a",
"#f7768e",
"#9ece6a",
"#e0af68",
"#7aa2f7",
"#ad8ee6",
"#449dab",
"#787c99",
"#444b6a",
"#ff7a93",
"#b9f27c",
"#ff9e64",
"#7da6ff",
"#bb9af7",
"#0db9d7",
"#acb0d0"
"#2E3742",
"#E2818A",
"#A3CF88",
"#E6C384",
"#86A9E0",
"#B79BE8",
"#86C7C0",
"#D3DAE0",
"#5E6A78",
"#EC98A0",
"#B4DB9C",
"#EFCF98",
"#9DBBEC",
"#C6AEEF",
"#99D6CF",
"#E8EDF2"
],
"fonts": {
"mono": "JetBrainsMono Nerd Font",
"mono": "GeistMono Nerd Font",
"ui": "Inter",
"size": 11
},
"ui": {
"gapsIn": 5,
"gapsOut": 12,
"borderSize": 2,
"rounding": 10,
"gapsIn": 6,
"gapsOut": 14,
"borderSize": 3,
"rounding": 12,
"iconSize": 44,
"activeOpacity": 1.0,
"inactiveOpacity": 0.95,
"terminalOpacity": 0.96,
"inactiveOpacity": 0.93,
"terminalOpacity": 0.9,
"blur": true,
"shadow": true
}
},
"settings": {}
}

View File

@@ -1,58 +1,59 @@
{
"version": 1,
"name": "Tokyo Night",
"slug": "tokyo-night",
"name": "Boreal",
"slug": "boreal",
"mode": "dark",
"wallpaper": "",
"colors": {
"base": "#1a1b26",
"mantle": "#161720",
"surface": "#32344a",
"overlay": "#444b6a",
"text": "#a9b1d6",
"subtext": "#787c99",
"muted": "#444b6a",
"accent": "#7aa2f7",
"accentAlt": "#ad8ee6",
"good": "#9ece6a",
"warn": "#e0af68",
"bad": "#f7768e"
"base": "#21272F",
"mantle": "#1A1F26",
"surface": "#303A46",
"overlay": "#404D5C",
"text": "#D3DAE0",
"subtext": "#97A3B2",
"muted": "#5E6A78",
"accent": "#B79BE8",
"accentAlt": "#86C7C0",
"good": "#A3CF88",
"warn": "#E6C384",
"bad": "#E2818A"
},
"border": {
"active": "accent",
"inactive": "overlay"
},
"ansi": [
"#32344a",
"#f7768e",
"#9ece6a",
"#e0af68",
"#7aa2f7",
"#ad8ee6",
"#449dab",
"#787c99",
"#444b6a",
"#ff7a93",
"#b9f27c",
"#ff9e64",
"#7da6ff",
"#bb9af7",
"#0db9d7",
"#acb0d0"
"#2E3742",
"#E2818A",
"#A3CF88",
"#E6C384",
"#86A9E0",
"#B79BE8",
"#86C7C0",
"#D3DAE0",
"#5E6A78",
"#EC98A0",
"#B4DB9C",
"#EFCF98",
"#9DBBEC",
"#C6AEEF",
"#99D6CF",
"#E8EDF2"
],
"fonts": {
"mono": "JetBrainsMono Nerd Font",
"mono": "GeistMono Nerd Font",
"ui": "Inter",
"size": 11
},
"ui": {
"gapsIn": 5,
"gapsOut": 12,
"borderSize": 2,
"rounding": 10,
"gapsIn": 6,
"gapsOut": 14,
"borderSize": 3,
"rounding": 12,
"iconSize": 44,
"activeOpacity": 1.0,
"inactiveOpacity": 0.95,
"terminalOpacity": 0.96,
"inactiveOpacity": 0.93,
"terminalOpacity": 0.9,
"blur": true,
"shadow": true
},

View File

@@ -17,7 +17,7 @@ let
overlays = [ flake.overlays.default ];
config.allowUnfree = true;
};
slug = let s = builtins.getEnv "THEME"; in if s == "" then "tokyo-night" else s;
slug = let s = builtins.getEnv "THEME"; in if s == "" then "boreal" else s;
in
pkgs.testers.runNixOSTest {
name = "theme-shot-${slug}";