Files
Nomarchy/tools/theme-shot.nix
Bernardo Magri fb75c3dedf
All checks were successful
Check / eval (push) Successful in 3m2s
feat(tools): 1080p themed-desktop capture harness + first polish findings (item 28c)
tools/theme-shot.nix: boots the full themed desktop headlessly
(software-GL Hyprland, THEME env picks the slug) at 1920x1080 and
QMP-dumps desktop.png + menu.png (rofi root open) — the review
artifact for slice (c). Two fixes over the 2026-06-19 spike:
home-manager.useGlobalPkgs (the HM submodule otherwise misses the
overlay) and the menu shot via hyprctl dispatch exec. Maintainer tool,
deliberately not a checks.* gate. Known gap in the header: the
wallpaper needs ~/.nomarchy seeded in the guest.

First full-res review (tokyo-night) added to the item-28 punch list:
rofi root menu is ~760px of mostly empty row space (candidate:
right-aligned SUPER+CTRL hints from keybinds.nix), full-color Papirus
menu icons vs the all-monochrome bar glyphs is a [human] identity
call, bar right-cluster group margins confirmed at full res, and the
bar's alpha(text,.5) dim states should become the @muted role now
that 28b floors guarantee its legibility. Whole-swap bar module
parity verified textually — no drift.

Verified: harness end-to-end green (screenshots read back); evals
from tools/ via the relative flake path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:00:28 +01:00

67 lines
3.0 KiB
Nix

# Themed-desktop capture harness (item 28 slice c) — boots the full
# desktop headlessly (software-GL Hyprland) at 1920x1080 and QMP-dumps
# two screenshots into $out: desktop.png and menu.png (rofi root open).
# Maintainer tool, NOT a checks.* gate (a full-desktop VM is far too
# heavy for CI). Impure: THEME env picks the theme slug.
# THEME=<slug> nix build --impure -f tools/theme-shot.nix --no-link --print-out-paths
# Known gap: the wallpaper does not paint — nomarchy-theme-sync resolves
# state from ~/.nomarchy at runtime, absent in the guest; seed it
# (cp the flake to ~nomarchy/.nomarchy in testScript) if the wallpaper
# matters to the shot. Bar + menus render fully.
let
flake = builtins.getFlake ("git+file://" + toString ../.);
inherit (flake.inputs) nixpkgs home-manager;
pkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [ flake.overlays.default ];
config.allowUnfree = true;
};
slug = let s = builtins.getEnv "THEME"; in if s == "" then "tokyo-night" else s;
in
pkgs.testers.runNixOSTest {
name = "theme-shot-${slug}";
node.pkgsReadOnly = false; # nomarchy sets nixpkgs.config
node.specialArgs = { username = "nomarchy"; };
nodes.machine = { pkgs, lib, ... }: {
imports = [ flake.nixosModules.nomarchy home-manager.nixosModules.home-manager ];
virtualisation.memorySize = 4096;
virtualisation.cores = 4;
# Software GL for Hyprland (GLES/aquamarine) without a host GPU.
hardware.graphics.enable = true;
environment.variables.LIBGL_ALWAYS_SOFTWARE = "1";
boot.initrd.availableKernelModules = [ "virtio_gpu" ];
virtualisation.qemu.options = [ "-vga none" "-device virtio-gpu-pci,xres=1920,yres=1080" ];
users.users.nomarchy = {
isNormalUser = true;
password = "test";
extraGroups = [ "wheel" "video" ];
};
nomarchy.system.stateFile = flake + "/themes/${slug}.json";
services.greetd.settings.initial_session = {
command = "start-hyprland";
user = "nomarchy";
};
home-manager.useGlobalPkgs = true; # HM must see the overlay'd node pkgs
home-manager.users.nomarchy = {
imports = [ flake.homeModules.nomarchy ];
nomarchy.stateFile = flake + "/themes/${slug}.json";
nomarchy.idle.enable = false; # no lock/dpms during the shot
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.wait_for_file("/run/user/1000/hypr", 180)
machine.sleep(12)
# Paint the wallpaper explicitly (awww timing was flaky in the spike).
machine.execute("su - nomarchy -c 'XDG_RUNTIME_DIR=/run/user/1000 nomarchy-theme-sync wallpaper' >/dev/null 2>&1")
machine.sleep(18)
machine.screenshot("desktop")
# Open the root menu for the polish review.
hy = "su - nomarchy -c 'XDG_RUNTIME_DIR=/run/user/1000 HYPRLAND_INSTANCE_SIGNATURE=$(ls /run/user/1000/hypr | head -1) hyprctl dispatch exec"
machine.execute(hy + " nomarchy-menu' >/dev/null 2>&1")
machine.sleep(8)
machine.screenshot("menu")
'';
}