capturing-tk-screenshots-headless
Skill0 starsChanged 6 days agoMITView on GitHub
Use when a Tkinter, Thonny, IDLE or other Tk/X11 desktop GUI must be run, seen or screenshotted in a headless Linux sandbox or CI with no monitor - "no display name and no $DISPLAY environment variable", black or overlapping captures, checking UI/editor themes, fonts, glyphs or emoji rendering, or showing a person what a widget looks like.
In this repository10 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- concept-parableSkill
- opencode-apiSkill
- opencode-buildSkill
- opencode-cliSkill
- provider-onboardingSkill
- pygameturboSkill
- thonny-pluginSkill
- timestampSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 15
Run the GUI on a virtual X server (Xvfb) and capture with ImageMagick import.
- Very specific: line 18
Use a Python that has tkinter: python -c "import tkinter".
- Distinctive: line 48
Keep scratch files out of the project.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Capturing Tk screenshots headless
Overview
Run the GUI on a virtual X server (Xvfb) and capture with ImageMagick import. There is no window manager: no title bars, every window opens at 0,0, and import -window <id> copies whatever is on screen in that window's rectangle, including other windows covering it.
Before you start
- Use a Python that has tkinter:
python -c "import tkinter". Sandbox systempython3often lacks it; a venv with Thonny orpython3-tkhas it. - Tools:
Xvfb,xvfb-run,import,convert(ImageMagick). Often missing:xdotool,xwininfo,scrot. Don't plan on them.
Recipe A: your own widget or test window
xvfb-run -a -s "-screen 0 1600x1200x24" PY capture.pyimport subprocess, tkinter as tk
root = tk.Tk(); root.withdraw()
wins = [make_window_1(root), make_window_2(root)] # your Toplevels
for i, w in enumerate(wins, 1):
for o in wins: # show ONE window at a time
o.deiconify() if o is w else o.withdraw()
root.update(); root.after(300); root.update() # let Tk finish drawing
subprocess.run(["import", "-window", str(w.winfo_id()), f"win{i}.png"], check=True)
root.destroy()Skip mainloop() in capture scripts; update() draws everything.
Recipe B: a real application (Thonny, IDLE, ...)
Xvfb :77 -screen 0 1200x800x24 &(explicit display number, screen = desired image size).- Give the app a throwaway config dir with theme, font size and window geometry preset to fill the screen at 0,0 (most apps take a config-directory environment variable or option; check the app's docs). An empty config dir often opens a first-run or welcome dialog instead of the main window: preset the settings that skip it. Never touch the user's real config.
- Open a file with real content so themes, syntax colors and fonts are visible.
- Launch with
DISPLAY=:77 ... &, then wait for it to settle instead of sleeping a guessed time:python3 scripts/grab_stable.py :77 out.png(waits until the screen is non-blank and stops changing, tolerates a blinking cursor;--crop WxH+X+Y,--timeout). - Kill the app, then Xvfb. Read the app's log for "Could not find ..." warnings.
Always
- Open every PNG yourself (whatever image-viewing tool your harness has) before reporting, and describe what it actually shows: a capture that ran without errors can still be black, half-drawn or the wrong window.
- Keep scratch files out of the project; hand finished images to the person with your harness's file-sharing mechanism.
- Captures are 1:1 pixels at Tk's 1x rendering.
- Running in Claude Code? Also read
claude-code.mdfor its tool names and container notes.
Common mistakes
| Symptom | Cause / fix |
| Black or another window inside a capture | Windows overlap at 0,0: show one at a time, or place with geometry("+X+Y") and crop -window root |
| Capture of a half-built window | Missing update()/after(), or fixed sleep too short: use grab_stable.py |
| App ignored the theme | Wrong theme name or UI vs editor theme mixed up; check log |
| App at an offset on a black screen | Geometry not preset; screen size not matched |
| Emoji gray/outline, extra blank cell after ⬅️ | Tk 8.6 draws no color emoji; U+FE0F takes a cell. fc-list ":charset=274c" family shows which font supplies a glyph |
OSError: AF_UNIX path too long at launch | The app's socket path (under a long config or runtime dir) exceeds the ~108-byte limit: use a shorter dir, or set XDG_RUNTIME_DIR to one |
| Fonts differ from the user's OS | Sandbox fonts (e.g. DejaVu) ≠ Windows Consolas/Segoe; say so |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

