modules/home/coding-agents/common/skills/wayland-gui-debug/SKILL.md
Verify a rendering or window-chrome change in a GUI app unattended on Linux/Wayland under the niri compositor — enumerate windows and read output scale via niri msg --json, capture a specific window to a file with niri msg action screenshot-window --id, and probe exact pixel RGBA with ImageMagick. Use for layout/glyph/color/HiDPI rendering bugs where a screenshot or pixel value is the ground truth. For macOS use macos-gui-debug instead.
npx skillsauth add natsukium/dotfiles wayland-gui-debugInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Verify a rendering change by launching the app, finding its window
through the compositor, capturing that window to a file, and probing
pixels. On Wayland there is no cross-client "capture window N" API —
capture goes through the compositor, and under niri that is the
niri msg IPC, which can target a window by id directly. No external
screenshot tool is needed.
niri msg action arguments evolve between versions — niri msg action screenshot-window --help shows the flags your running niri actually
accepts.
ImageMagick (magick) and jq may not be on PATH. On Nix, run them
ad-hoc without installing:
nix run nixpkgs#imagemagick -- magick ..., nix run nixpkgs#jq -- ....
# windows: id, title, app_id, pid, focus, and logical window_size
niri msg --json windows | jq '.[] | {id, app_id, title, is_focused, size: .layout.window_size}'
# outputs: logical size/position and scale per monitor
niri msg --json outputs | jq 'to_entries[] | {output: .key, logical: .value.logical}'
layout.window_size is in logical pixels; the screenshot PNG is in
physical pixels — physical = logical × scale. A logical 960×600
window on a scale: 2.0 output captures as 1920×1200. Do this math
before claiming a size regression.id) before capturing — a crash leaves an empty list, a
clearer signal than a black frame.screenshot-window takes a window --id (no need to focus it) and a
--path (must be absolute); it writes the PNG there and also copies
to the clipboard.
WID=$(niri msg --json windows | jq '.[] | select(.app_id=="MyApp") | .id')
niri msg action screenshot-window --id "$WID" --path /tmp/win.png
# focused output instead of a single window:
niri msg action screenshot-screen --path /tmp/screen.png
--id targets the window even when it isn't focused. If you need it
focused for some other reason (e.g. it only renders when active),
niri msg action focus-window --id "$WID" first.screenshot-window by default
(--show-pointer to include); screenshot-screen includes it by
default (--show-pointer false to drop).screencapture -l strength, not Wayland's). Test transparency by
compositing over a known solid backdrop and reading the blended result,
or via the app's own rendering logs.# single pixel at (x,y), as "srgba(r,g,b,a)"
magick /tmp/win.png -format '%[pixel:p{120,80}]' info:
# dimensions + a few sample points
magick /tmp/win.png -format 'w=%w h=%h\n' info:
# average a region (coarse "is this the colour I expect" check)
magick /tmp/win.png -crop 20x20+100+100 +repage -resize 1x1 -format '%[pixel:p{0,0}]' info:
niri msg outputs.pkill -x myapp — match the exact process name. Never
pkill -f path/to/MyApp, which also matches helper/renderer processes
whose argv contains that path and can kill unrelated user sessions.If you need a raw framebuffer grab outside niri's path (e.g. capturing a
layer-shell surface niri won't target, or a whole output region),
grim works: nix run nixpkgs#grim -- -o <output> /tmp/out.png.
slurp, satty, and swappy are interactive — they block on a human,
so don't use them in unattended runs; compute regions from niri msg
geometry instead.
development
Verify a rendering or window-chrome change in any macOS GUI app unattended — find its CGWindowID via JXA, capture that window alone (with per-pixel alpha) using screencapture -l, and read exact RGBA via NSBitmapImageRep. Use for blur/opacity/corner-radius/glyph/color rendering bugs where a screenshot or pixel value is the ground truth. No Python and no Accessibility permission needed; for Linux/Wayland use wayland-gui-debug instead.
development
Clone and reuse GitHub/GitLab repositories under a single managed root (`ghq root`) instead of fetching files one-by-one via `gh api`/`WebFetch` or scratch-cloning into `/tmp`. Use this skill whenever investigating, reading, grepping, or referencing source code from any remote repository — even for a single file. Triggers include "look at X's source", "how does X implement Y", "check the X repo", "find Z in nixpkgs/react/linux/etc.", or any moment a remote repo URL appears and you need to read more than one file from it. Skip only for one-shot GitHub API operations that have no source code in them (PR comments, issue bodies, workflow runs — those belong to the `gh` skill).
tools
GitHub CLI for pull requests, issues, releases, workflows, and repository operations. Use for creating PRs, managing issues, viewing repository information, and accessing GitHub URLs.
tools
AST-based code search and transformation tool using tree-sitter. Use for structural pattern matching, refactoring deprecated APIs, detecting anti-patterns, migrating code between library versions, and enforcing coding standards.