Theme centralization: - theme/colors.json is now the single source of truth for the palette. - New theme/generate-theme.py renders, at install time, the three derived artifacts into ~/.config: colors.css (waybar/wofi @import), mako config, and hyprlock-colors.conf (hyprlang $tn_* variables). - theme/colors.css removed from the repo (now generated); install.sh calls the generator instead of the old inline mako snippet. - hyprlock.conf sources the generated color file and uses $tn_* variables instead of hardcoded rgba() values. - Generator covered by theme/test_generate_theme.py. Bluetooth: - Added waybar built-in bluetooth module (config.jsonc + style.css), with bluez/bluez-utils in packages.txt. Includes design spec and implementation plan under docs/superpowers/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.5 KiB
Theme Centralization & Bluetooth Module — Design
Date: 2026-06-07 Status: Approved (pending spec review)
Summary
Two independent enhancements to the niri dotfiles:
- Theme centralization — collapse the duplicated color palette into a single
source of truth (
theme/colors.json) and generate all derived configs from it at install time. Bringhyprlockunder the shared palette. Leavealacrittyuntouched (out of scope). - Bluetooth module — add a waybar bluetooth indicator using the
already-installed
blueman/bluezstack.
Motivation
CLAUDE.md mandates a single source of truth and warns against duplicating
configs / hardcoding colors in multiple places. Current state violates this:
theme/colors.css(@define-colorpalette) andtheme/colors.json(same palette as JSON) both hand-maintain the same 12 colors. Changing a color requires editing both files.hyprlock/hyprlock.confhardcodes 7rgba(...)colors, every one of which already exists in the palette.
Already-correct (not changed by this work):
- waybar (
waybar/style.css) and wofi (wofi/style.css)@importcolors.css. - mako config is generated from
colors.jsonbyinstall.sh.
Scope
In scope: unify the two palette files into one source; generate colors.css,
the mako config, and a hyprlock color file from it; convert hyprlock.conf to
reference the shared palette; add a waybar bluetooth module.
Out of scope: alacritty terminal colors (needs a full 16-color normal+bright set the palette does not currently model — deferred); any change to the Tomorrow Night palette values themselves; GTK theming (handled by Materia).
Approach
Chosen approach A: theme/colors.json is the single source of truth;
everything else is generated at install time. This extends the existing Python
generation block already in install.sh (which generates the mako config).
Rejected: parsing colors.css as the source (fragile regex), and introducing a
new neutral source format (YAGNI for this scope, discards working JSON+Python).
Detailed Design
1. Single source of truth
theme/colors.json remains the only hand-edited palette file. It holds the 12
base colors (already present). The hand-maintained theme/colors.css is
deleted from the repo; it becomes a generated artifact.
2. Generator: theme/generate-theme.py
A new standalone script, invoked by install.sh, replacing the current inline
Python mako snippet. Reads theme/colors.json and writes three artifacts
directly into ~/.config (written, not symlinked — matching how mako is handled
today):
~/.config/theme/colors.css—@define-colorblock for all 12 base colors, plus the three alpha variants (tn-bg-a90,tn-bg-a95,tn-bg-a96) computed from thebackgroundcolor at opacities 0.90 / 0.95 / 0.96. This is what waybar and wofi already@import; their files do not change.~/.config/mako/config— same output as the current inline snippet.~/.config/theme/hyprlock-colors.conf— hyprlang variable declarations, one per needed color, e.g.$tn_fg = rgba(c5c8c6ff). Hex fromcolors.jsonis converted to hyprlock'srgba(RRGGBBAA)form withAA = ff.
The generator must be idempotent and safe to re-run (overwrites its outputs).
3. hyprlock.conf
- Add
source = ~/.config/theme/hyprlock-colors.confnear the top. - Replace the 7 hardcoded
rgba(...)values with the matching$tn_*variables. Color → variable mapping (from current values):rgba(c5c8c6ff)→$tn_fg(foreground)rgba(969896ff)→$tn_fg_dim(foreground_dim)rgba(282a2eff)→$tn_bg_alt(background_alt)rgba(81a2beff)→$tn_blue(blue)rgba(cc6666ff)→$tn_red(red)rgba(b5bd68ff)→$tn_green(green)
hyprlock.confstays a hand-edited, symlinked file; only its colors come from the generated source file.
Risk + fallback: hyprlock v0.9.5 uses the hyprlang parser, which documents
support for $variables and source=. This is verified by documentation, not
empirically (no dry-run flag; launching hyprlock grabs the screen). The
implementation plan MUST include an explicit parse test (lock once and confirm
colors render, or launch with --grace 0 and watch --verbose for parse
errors). Fallback if source=/variables misbehave: generate the entire
hyprlock.conf from a hyprlock/hyprlock.conf.tmpl template with color
placeholders, instead of using source=. Same single-source outcome, more
generation.
4. install.sh changes
- Remove the inline
python3 - <<'PYEOF' ... PYEOFmako block. - Add a call to
python3 theme/generate-theme.pyafter configs are linked. - Remove the
ln -sf .../theme/colors.css ~/.config/theme/colors.cssline (colors.css is now generated into that path, not symlinked). - Ensure
~/.config/themeexists before generation (already created).
5. Bluetooth waybar module
waybar/config.jsonc: add"bluetooth"tomodules-right(placed next tonetwork), with abluetoothmodule block:format,format-connected,format-disabledusing Nerd Font glyphs.on-click:blueman-manager.
waybar/style.css: add a#bluetoothpadding rule (consistent with the other right-side modules) plus a connected-state accent color using a palette variable (e.g.@tn-blue).- Dependencies:
blueman+bluez/bluez-utils(blueman pulls bluez). Confirmpackages.txtlists what's needed; the waybar bluetooth module requires thebluezdaemon running.
Testing / Verification
- Generator: run
python3 theme/generate-theme.py; diff generated~/.config/theme/colors.cssagainst the previous hand-written file to confirm identical palette + alpha variants. Confirm mako config output unchanged. - waybar/wofi: restart waybar (
waybar-restart), confirm no CSS errors and colors render. Open wofi, confirm styling intact. - hyprlock: parse test per the fallback note above; confirm lock screen colors match before/after.
- Bluetooth: confirm module appears, reflects adapter state, and
blueman-manageropens on click. - Idempotency: re-run
install.sh; confirm no errors and stable output.
Rollout Notes
- Generated files (
~/.config/theme/colors.css,~/.config/theme/hyprlock-colors.conf) are not committed and not symlinked — consistent with the existing mako generation. The committedtheme/colors.cssis removed in this change. - The two features (theme, bluetooth) are independent and can be implemented and verified separately.