evilfreelancer/screenshotting-gui/screenshotting-gui
Claude Code and agent skill by evilfreelancer/screenshotting-gui
- community
Checking that the SKILL.md file is still in the repository.
Use when you must produce clean, repeatable screenshots of a running GUI desktop application (an IDE like Cursor or VS Code, a native app, a browser window) for documentation, a course, a README, or a bug report - captured on an isolated Xvfb virtual display so synthetic input and captures never touch the operator's real desktop, scripted with python-Xlib (XTEST), and annotated (rounded highlight box, crop, arrow) with ImageMagick. Triggers include "take / redo a screenshot of an app's UI", "screenshot a menu or dialog in a specific state", "automate app screenshots for docs", "highlight a region on a screenshot". Not for grabbing the operator's live :0 desktop, and not for pure web-page shots (use a headless browser for those).
Install
npx vskill@latest install evilfreelancer/screenshotting-gui/screenshotting-guiSKILL.md
Screenshotting a GUI app
Produce documentation-grade screenshots of a running GUI application without a window manager and without touching the operator's screen. The app runs on a throwaway Xvfb display; you drive it to the exact state you want with synthetic X input, capture the frame, and annotate it.
Everything the model already knows (what X11, ImageMagick or a clipboard are) is omitted on purpose - this file is only the parts that are easy to get wrong.
The one rule that keeps it safe
Run on display `:99` (Xvfb), never `:0`. :0 is the operator's live desktop - clicking, typing and screenshotting it is a privacy and correctness disaster.
The subtle trap: xctl.py / xpaste.py default their own target to :99, but any GUI app you launch reads `$DISPLAY`. If $DISPLAY is still :0, the app opens on the real screen while your captures read :99 - winlist comes back empty and you capture a black frame. Always `export DISPLAY=:99` for the app launch, not just XCTL_DISPLAY.
Toolchain
Deterministic pieces live in scripts/ (run any with --help):
| Script | Role | |
|---|---|---|
scripts/xctl.py | Drive the app: move click key type scroll drag place shot winlist via python-Xlib XTEST. | |
scripts/xpaste.py | Serve UTF-8 on the CLIPBOARD so key ctrl+v pastes unicode / non-Latin text. | |
scripts/annotate.py | ImageMagick post-processing: box (rounded highlight), crop, vstack, arrow. |
Requirements: Xvfb, python3 + python-Xlib, ImageMagick (import, convert). Capture default is ImageMagick import (no extra dependency, no max-size ceiling). Fallback if ImageMagick is unavailable: python-Xlib root.get_image + Pillow (~2x faster, but needs Pillow and must tile a root above ~4.2 MP; pixel order is BGRX, not RGB).
Workflow
Find pixel coordinates from a winlist geometry plus a full shot you eyeball; without a window manager, screen coordinate = window origin + widget offset.
Driving the app - xctl.py
| Command | Purpose | ||
|---|---|---|---|
winlist | List mapped windows with class, name, geometry - find your target and its origin. | ||
move X Y | Move the pointer (origin = top-left of the display). | ||
click X Y [--button N] [--double] | Move then click (1 left, 2 middle, 3 right). | ||
key COMBO ... | Key chords: ctrl+shift+p, ctrl+v, Return, Escape, BackSpace. | ||
type TEXT | Type ASCII only (layout-correct via the live keymap). | ||
| `scroll up\ | down [N]` | Wheel N notches at the current pointer - move over the region first. | |
drag X1 Y1 X2 Y2 | Press-move-release - resize a panel by dragging its splitter. | ||
place SUBSTR X Y W H | Move+resize the first window matching name/class - fixes windows opened off-screen without a WM. | ||
shot OUT [--crop X Y W H] | Capture the display; crop to a region. |
Focus follows X input focus: click into the target widget before `type` or `ctrl+v`, or the keys go nowhere.
Unicode / non-Latin text - xpaste.py
type is ASCII-only by design. For Cyrillic or any symbol-heavy string (@, {}), never type it - paste it:
Annotating - annotate.py
Default accent #ff6b35, width 5, radius 14.
Gotchas
- `$DISPLAY` vs `$XCTL_DISPLAY`. The app reads
$DISPLAY; the scripts default to
:99. A mismatch silently launches the app on :0 while you capture :99 (empty winlist, black frames, and your keystrokes leaking to the real desktop). Export DISPLAY=:99 for the launch.
- No window manager is the simpler default. Without a WM there is no reparenting,
so screen coordinate = window origin + widget offset (clean math for place). Apps that need a WM for focus/stacking may want openbox/twm; try without first.
- Focus before keys. XTEST keystrokes and
ctrl+vroute to the focused window -
click the widget first.
- `scroll` ignores coordinates - it wheels at the current pointer;
movefirst. - Timing. Give the app ~1-2 s (heavy Electron/JVM apps 3-8 s) before
winlist;
give xpaste.py ~0.5-1 s to acquire the selection before ctrl+v, or you paste stale or empty clipboard.
- `type` skips non-ASCII (with a stderr warning) - use
xpaste.py. Shifted ASCII
(_ { } @ =) is handled.
- Blank-frame check. A real capture has non-zero pixel stddev; a near-black frame
means the app is not mapped or you shot the wrong display.
- `pkill -f xpaste.py` footgun - it also matches the killing shell's own command
line. Kill background helpers by numeric PID.
- UI coordinates drift between app versions and window sizes - never hardcode from
memory; winlist + a fresh full shot first.
- Reset app state between shots. For repo-mutating apps (an IDE agent editing
files), snapshot and restore - e.g. git -C <project> checkout . && git clean -fd.
Quick reference
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingSKILL.md
Popularity
- Repository stars
- 5
- 7-day trend score
- 9
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/evilfreelancer/screenshotting-gui/screenshotting-gui)