aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-29 10:05:08 +0200
committerDanilo M. <danix@danix.xyz>2026-09-29 10:05:08 +0200
commit266cb5655217293f733e22d677169d93e497e400 (patch)
tree9cb0ad1aceab4684c00147166a9de471cbf5d09f /docs/superpowers
downloadgrub-theme-udt-266cb5655217293f733e22d677169d93e497e400.tar.gz
grub-theme-udt-266cb5655217293f733e22d677169d93e497e400.zip
Add design spec, GPLv2 license
Design for a udt-themed GRUB theme: wallpaper snapshot background, left panel echoing sddm-theme-udt, theme.txt.in rendered by udt-palette, and a stdlib build script that assembles the installable theme. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docs/superpowers')
-rw-r--r--docs/superpowers/specs/2026-09-29-grub-theme-udt-design.md132
1 files changed, 132 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-09-29-grub-theme-udt-design.md b/docs/superpowers/specs/2026-09-29-grub-theme-udt-design.md
new file mode 100644
index 0000000..a9c522d
--- /dev/null
+++ b/docs/superpowers/specs/2026-09-29-grub-theme-udt-design.md
@@ -0,0 +1,132 @@
+# grub-theme-udt design
+
+A GRUB 2 theme for the unified-desktop-theme (udt) family. Colours come from
+the active udt scheme; the background is a snapshot of the current wallpaper;
+the layout echoes sddm-theme-udt's left panel.
+
+## Constraints
+
+- GRUB reads `/boot` before anything else is mounted, so the installed theme is
+ a **copy**, never a symlink into `/home`.
+- Installing is root's job. Nothing in this repo or in udt writes under `/boot`
+ or `/etc`; udt's `install.sh` only prints the root commands.
+- Nothing at boot can read the wallpaper-tracking accent, so the theme uses the
+ scheme's fixed `accent` role.
+- `theme.txt` has no include mechanism, so it is a template rendered whole.
+- Target: GRUB 2.14, x86_64-efi. 2.14 supports `desktop-image-scale-method`.
+- GRUB's image readers are limited: no progressive JPEG, no interlaced PNG, no
+ webp. Anything GRUB loads is written by `build` in a format it can read.
+- Minimal dependencies: Python stdlib, `grub-mkfont`, `fc-match`, `magick`,
+ all already installed.
+
+## Layout
+
+- **Background:** `desktop-image: "background.jpg"` with
+ `desktop-image-scale-method: "crop"`, so any mode (including 2560x1080) is
+ filled without distortion. `desktop-color` is `@BG@`, shown if the image fails
+ to load.
+- **Panel:** a `+ image` component at `left = 0`, `top = 0`, `width = 25%`,
+ `height = 100%`, file `panel.png`: a small RGBA PNG of `bg_alt` at about 85%
+ alpha. GRUB scales the image to the component and alpha-blends it over the
+ wallpaper. Square corners, as in SDDM.
+- **Inside the panel,** top to bottom:
+ - title `+ label`: the `NAME` from `/etc/os-release`, colour `@FG@`,
+ Noto Sans Bold;
+ - `+ boot_menu`: `item_color = @FG_DIM@`, `selected_item_color = @FG@`,
+ Noto Sans Regular, no icons (`icon_width = 0`);
+ - `+ label` with `id = "__timeout__"`, colour `@FG_FAINT@`;
+ - `+ progress_bar` with `id = "__timeout__"`, `fg_color = @ACCENT@`,
+ `bg_color = @SURFACE@`, a few pixels high.
+- **Selected item:** `selected_item_pixmap_style = "select_*.png"`. The `w`
+ slice is a 4px `accent` bar, the `c` and `e` slices are solid `surface`.
+- **Console:** `terminal-box: "terminal_box_*.png"`, all nine slices solid
+ `bg_deep`; `terminal-font` is Inconsolata Nerd Font Mono.
+
+Menu entry icons are out of scope. GRUB would look for `icons/<class>.png` per
+entry class; adding them later is additive.
+
+## Files
+
+| Path | Tracked | Role |
+|---|---|---|
+| `theme.txt.in` | yes | the template, `@ROLE@` placeholders |
+| `theme.txt` | no | rendered by udt-palette |
+| `build` | yes | stdlib Python script, assembles `build/udt/` |
+| `build/udt/` | no | the complete theme, what root copies |
+| `README.md`, `LICENSE` | yes | GPLv2 only |
+| `.gitignore` | yes | `theme.txt`, `build/` |
+
+## Placeholders
+
+udt-palette substitutes these in `theme.txt.in`, each as `#rrggbb`:
+
+`@BG@ @BG_ALT@ @BG_DEEP@ @SURFACE@ @FG@ @FG_DIM@ @FG_FAINT@ @ACCENT@`
+
+plus `@SCHEME@`, the scheme name, used in a header comment.
+
+The template carries one machine-readable comment line that `build` parses to
+get the colours it needs for the PNGs, so there is no second template:
+
+ # udt: bg_alt=@BG_ALT@ bg_deep=@BG_DEEP@ surface=@SURFACE@ accent=@ACCENT@
+
+GRUB ignores comment lines.
+
+## Data flow
+
+1. udt's `install.sh` runs udt-palette, which renders `theme.txt.in` to
+ `theme.txt` in this repo (the gen function and TARGETS line are owned by
+ the udt session).
+2. udt's `install.sh` runs `./build` here (skipped if the repo is not cloned).
+3. `build`:
+ - reads `theme.txt`, fails if any `@...@` remains or the `# udt:` line is
+ missing;
+ - substitutes the title from `/etc/os-release` into `build/udt/theme.txt`;
+ - writes `panel.png`, `select_{w,c,e}.png`, `terminal_box_{nw,n,ne,w,c,e,sw,s,se}.png`
+ with an in-script PNG encoder (`zlib` + `struct`, 8-bit RGBA, not
+ interlaced);
+ - builds the `.pf2` fonts with `grub-mkfont`, resolving the TTF paths with
+ `fc-match -f '%{file}'`; rebuilt only when missing, since fonts do not
+ change with the scheme;
+ - converts `~/.cache/udt/wpaper` (following the symlink) with `magick` to a
+ baseline, non-interlaced `background.jpg`, capped at 2560px on the long
+ side, metadata stripped.
+4. udt's `install.sh` prints the root commands:
+
+ rm -rf /boot/grub/themes/udt && cp -r <repo>/build/udt /boot/grub/themes/
+ # once: set GRUB_THEME="/boot/grub/themes/udt/theme.txt" in /etc/default/grub
+ grub-mkconfig -o /boot/grub/grub.cfg
+
+ The copy must be rerun after a scheme or wallpaper change. `grub-mkconfig`
+ is needed only when `GRUB_THEME` changes.
+
+## Fonts
+
+| Use | Source | Size |
+|---|---|---|
+| title | Noto Sans Bold | 32 |
+| menu items, countdown | Noto Sans Regular | 24 |
+| console | Inconsolata Nerd Font Mono | 18 |
+
+Font names in `theme.txt.in` must match what `grub-mkfont` records (family,
+style, size), e.g. `"Noto Sans Regular 24"`; `build` checks the generated
+names against the template.
+
+## Errors
+
+`build` exits non-zero with a one-line message when: `theme.txt` is missing
+or unrendered, the wallpaper link is missing, `magick`/`grub-mkfont`/`fc-match`
+is absent, or `fc-match` resolves to a fallback font rather than the requested
+family. Nothing is written to `build/udt/` until all inputs are valid, so a
+failed build never leaves a half theme for root to copy.
+
+## Testing
+
+- `./build --selftest`: encodes PNGs, decodes them back with `zlib`, checks
+ pixel values against the input colours; checks placeholder detection.
+- Visual check before install: `grub-emu` is not packaged here, so the check
+ is a real boot. The previous `GRUB_THEME` line is the rollback.
+
+## Notes for the user
+
+`/etc/default/grub` has `GRUB_GFXMODE=2560x1080×32` with a Unicode `×`, so
+GRUB likely rejects that mode and falls back to 1920x1080. Replace with `x`.