From 086f3f43d6be1bc42e5c59fd15fa942db0ca0728 Mon Sep 17 00:00:00 2001 From: iris Date: Wed, 12 Aug 2026 18:31:55 +0200 Subject: [PATCH] claude-plugins: add headless-screenshot skill to base Captures a lesson from this session: "no browser in this container" usually means no browser pre-installed, not unreachable. nixpkgs#chromium is a `nix shell` away and one headless invocation renders a page + writes a PNG, no puppeteer/playwright needed for a static screenshot. Every agent hits "I have no browser" sooner or later when reviewing a frontend change; this has been rediscovered independently across several sessions rather than remembered. Belongs in base (every agent needs it, not role-specific) alongside the sibling skills already there. --- .../base/skills/headless-screenshot/SKILL.md | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md diff --git a/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md b/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md new file mode 100644 index 00000000..1f22650e --- /dev/null +++ b/claude-plugins/plugins/base/skills/headless-screenshot/SKILL.md @@ -0,0 +1,71 @@ +--- +name: headless-screenshot +description: Take a real screenshot of an HTML/CSS page from inside a container with no browser installed - `nix shell nixpkgs#chromium --command chromium --headless=new --disable-gpu --no-sandbox --screenshot= --window-size=, "file://"` renders the page and writes a PNG in one command, no puppeteer/playwright or pre-installed browser needed (only needed for scripted interaction like clicking, not a static render). Use this whenever you're about to claim a CSS/layout/frontend change looks right, whenever a PR reviewer or the operator asks to see a screenshot of a web UI change, or before asking a peer GUI-testing agent to screenshot something you could just render yourself - reasoning about a visual change from source or compiled CSS alone is not the same as actually seeing it rendered, and a real browser is one shell command away even when `which chromium` comes back empty. +--- + +# Headless Screenshot + +"No browser in this container" usually means no browser is +*pre-installed*, not that one is unreachable. `nixpkgs#chromium` is a +`nix shell` away, and a single headless invocation renders a page and +writes a PNG without a running server, a display, or any scripted +interaction library. + +## The command + +``` +nix shell nixpkgs#chromium --command chromium \ + --headless=new --disable-gpu --no-sandbox \ + --screenshot=/path/to/out.png \ + --window-size=1200,900 \ + "file:///path/to/page.html" +``` + +- `--no-sandbox` is required inside most agent containers (no user + namespaces for Chromium's sandbox); `--disable-gpu` sidesteps GPU + init failures in a headless environment. Both are safe defaults here + - this isn't a browser you're exposing to untrusted input. +- The target can be a local `file://` path or a real `http(s)://` URL + (a dev server, a served `dist/`, a deployed page) - same command + either way. +- `--window-size` sets the viewport; match it to what you actually want + to see (a narrow width to check a mobile layout, a wide one for a + dashboard row). +- Swap `--screenshot=` for `--dump-dom=` to get the rendered DOM as + text instead of an image - useful for confirming markup/attributes + landed correctly without needing to eyeball pixels. + +Stray `dbus`/`UPower` errors on stderr are harmless container noise +(no session bus, no power daemon) - ignore them as long as the PNG +file actually gets written. + +## When source-reading isn't enough + +Grepping compiled CSS or tracing class names tells you the rules +exist and target the right selectors - it doesn't tell you what the +result actually looks like (wrong tier picked, two rules fighting, +a value that's technically correct but visually off). Before telling +someone a layout/CSS change "looks right," or before reaching for a +peer agent's GUI-testing capability, try rendering it yourself first: + +- **Testing a real page**: serve the built `dist/` (or point at + wherever it's already deployed) and screenshot that - it's the + actual production bundle, not a reconstruction. +- **Testing an isolated CSS change** (e.g. a shared stylesheet used + by several pages): a small self-contained HTML file with the real + CSS inlined and a few representative markup samples is faster to + build than standing up a server, and just as honest about what the + CSS actually renders. +- **Attach it**: post the PNG as a PR/issue comment (or file + attachment) alongside a one-line note on what it's rendered from - + a reviewer with no browser either benefits from the same shortcut. + +## What this doesn't replace + +This is a static render, not a browser automation tool. Verifying an +interaction (a click, a hover state, a form submission) needs +puppeteer/playwright or similar - reach for those only when the +question is genuinely about *behavior*, not appearance. A missing +emoji/glyph rendering as a box in the screenshot is usually a font +availability artifact of the headless environment, not a real bug - +don't mistake one for the other when reporting results.