算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
headless-capture【设计与创意】Capture screenshots/recordings of desktop or web apps for visual verification. Works across Linux, macOS, and Windows. Supports Tauri, Electron, native desktop apps (via Xvfb/screencapture/gdigrab), and web apps (via Playwright). Use proactively after UI changes so the human can verify without running the app locally.
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
name: headless-capture description: Capture screenshots/recordings of desktop or web apps for visual verification. Works across Linux, macOS, and Windows. Supports Tauri, Electron, native desktop apps (via Xvfb/screencapture/gdigrab), and web apps (via Playwright). Use proactively after UI changes so the human can verify without running the app locally. triggers:
Capture screenshots and recordings of desktop or web applications for visual verification. This skill helps remote agents show their UI work to humans who aren't watching the screen live.
This skill is about delivering visual artifacts to a human for verification. It is not an agent-vision feedback loop; for browser automation and self-correction, prefer Playwright/CDP-style tooling directly.
Proactively suggest captures when:
Don't use this skill when:
| App Type | Linux | macOS | Windows |
|---|---|---|---|
| Web apps (Vite, Next.js, etc.) | Playwright | Playwright | Playwright |
| Tauri | Xvfb + import/ffmpeg | screencapture + ffmpeg | nircmd + ffmpeg |
| Electron | Xvfb + import/ffmpeg | screencapture + ffmpeg | nircmd + ffmpeg |
| Native GTK/Qt/etc. | Xvfb + import/ffmpeg | screencapture + ffmpeg | nircmd + ffmpeg |
| VS Code extension | Xvfb + downloaded VS Code | adapt (Xvfb shape) | adapt (Xvfb shape) |
Playwright is the preferred path for web apps — it's simpler, cross-platform, and doesn't need a virtual display.
| App type | Template | Recipe |
|---|---|---|
| Tauri / Electron / GTK / Qt / generic X11 (own binary) | templates/capture.mjs | recipes/tauri.md |
| VS Code extension (hosted by a downloaded VS Code) | templates/capture-vscode-extension.mjs | recipes/vscode-extension.md |
| Web apps | templates/capture.mjs (Playwright path) | — |
Own-binary apps (Tauri/Electron/GTK/Qt) differ only by values (binary path, window name, env hints, build command) → one generic template. A VS Code extension diverges structurally (download the editor, run in Extension Development Host mode, seed a user-data-dir to auto-open the panel) → its own template. A new variant earns its own template only when it adds lifecycle steps, not when it only changes values.
Capture script (scripts/capture.mjs) — unified script that:
artifacts/captures/SessionStart hook (Linux/Claude Code on the web) — installs toolchain automatically
Wrapper scripts in package.json for easy invocation
.gitignore entry for artifacts
First, determine OS and app type:
// OS detection
const platform = process.platform; // 'linux', 'darwin', 'win32'
// App type detection - check in order:
// 1. Web app: package.json has vite/next/nuxt/astro/remix OR user specifies URL
// 2. VS Code extension: package.json has engines.vscode + contributes
// 3. Tauri: src-tauri/Cargo.toml exists
// 4. Electron: package.json has "electron" dependency
// 5. Native: ask user for binary path
A VS Code extension has no URL and isn't your own binary — the "app" is a
real VS Code (Electron) editor hosting your extension. It needs the dedicated
templates/capture-vscode-extension.mjs + recipes/vscode-extension.md, not the
generic capture.mjs. If you can't tell the app type, ask the user — don't guess.
Web apps (Playwright path):
npm install -D playwright @playwright/testDesktop apps (platform-native path):
| OS | Display | Screenshot | Recording | Input |
|---|---|---|---|---|
| Linux | Xvfb (virtual) | import -window root | ffmpeg -f x11grab | xdotool |
| macOS | Real display | screencapture -x | ffmpeg -f avfoundation | cliclick / AppleScript |
| Windows | Real display | PowerShell or nircmd | ffmpeg -f gdigrab | nircmd / AutoHotkey |
Use AskUserQuestion for:
Don't ask about things you can decide yourself.
Copy templates/session-start.sh to .claude/hooks/session-start.sh. Register in .claude/settings.json:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"
}
]
}
]
}
}
The hook is gated on $CLAUDE_CODE_REMOTE / $CURSOR_AGENT so it only runs in remote agent sessions, not on a local Linux dev machine. It falls back to sudo when the container runs as a non-root user.
Cursor Cloud Agent caveat: Cursor does not run SessionStart hooks. Install the toolchain explicitly there — run session-start.sh directly with CURSOR_AGENT=1, or call it from a build/test step.
For macOS/Windows, document manual install in README instead of a hook.
Web / own-binary apps (Tauri/Electron/GTK/Qt) — copy templates/capture.mjs
to scripts/capture.mjs and customize (see recipes/tauri.md for the own-binary
swap-ins):
APP_TYPE: 'web', 'tauri', 'electron', or 'native'WEB_URL: dev server URL for web apps (e.g., http://localhost:5173)APP_BINARY: path to desktop app binaryWINDOW_NAME: for desktop app window detectionensureBinary() for desktop appsOn Linux the desktop path defaults to 1920x1080, resizes the window to fill the
virtual screen (no window manager under Xvfb to maximize it), and captures the
window region rather than the whole screen — so the screen background doesn't
bleed in as a black strip. It falls back to root capture when xdotool is absent.
VS Code extension — copy templates/capture-vscode-extension.mjs to
scripts/capture-vscode.mjs and fill in EXTENSION_MAIN, BUILD_CMD,
AUTO_OPEN_SETTINGS, and (optionally) the tour coords. See
recipes/vscode-extension.md. If you only changed the extension's webview
content (not the editor chrome), prefer Playwright against the webview HTML or
over CDP — it's faster and more reliable than full-editor capture.
{
"scripts": {
"capture": "node scripts/capture.mjs screenshot",
"capture:record": "node scripts/capture.mjs record",
"capture:web": "node scripts/capture.mjs screenshot --web",
"capture:web:record": "node scripts/capture.mjs record --web"
}
}
Add to .gitignore:
artifacts/captures/
For web apps:
npm run devnpm run capture:webFor desktop apps:
npm run capture--settle.WINDOW_NAME matches, or the app isn't launching on the capture display.xdotool coords are hitting title-bar chrome instead of the UI.Getting the artifact in front of the human proves the loop works end to end.
SendUserFile with the PNG/MP4 and a one-line caption. Paths under artifacts/captures/ work even though they are gitignored.artifacts/captures/ (see below). PNG for stills; MP4 for recordings (inlines reliably). Avoid GIF in chat — it often hangs while loading.If the artifact is broken (blank/wrong) after the obvious fixes, send what you have anyway with a note on what went wrong rather than reporting success.
Capture scripts write to artifacts/captures/, which is gitignored. That's
fine for generation, but do not Read or reference a gitignored path directly —
Cursor chat shows "Waiting for upload…" forever. Copy it to the harness's
public artifact dir first, then Read that path:
mkdir -p /opt/cursor/artifacts/screenshots
cp artifacts/captures/my-shot.png /opt/cursor/artifacts/screenshots/
# then Read /opt/cursor/artifacts/screenshots/my-shot.png
Don't reference artifacts/captures/… in markdown image syntax — those URLs
aren't reachable from chat. Optional: bake the copy step into the capture script
via a PUBLIC_ARTIFACT_DIR env var pointing at the public dir.
Add a section explaining:
brew install ffmpeg cliclick, Windows: choco install ffmpeg nircmd)After modifying UI files, proactively offer to capture:
I've updated the login form styling. Would you like me to capture a screenshot so you can verify the changes?
If the user has previously accepted captures in the session, just do it:
I've updated the button colors. Here's a screenshot of the result:
[attach screenshot]
:99, override with CAPTURE_DISPLAYbrew install ffmpeg cliclickscreencapture -x for silent screenshotschoco install ffmpeg nircmd or winget install ffmpegAdd-Type can capture screen without external toolsnpm install -D playwrightnpx playwright install chromiumThe default record mode grabs a settled, idle window — no input during the clip. Validate that first; only reach for tours if the user wants navigation in the deliverable (clicking tabs, opening menus, etc.).
ffmpeg -f x11grab, then drive clicks with xdotool during the grab.xdotool windowmove <id> 0 0) and calibrate Y: mousemove --window coords are relative to the decorated window, not the webview. Low Y often lands on the title bar / app logo, so the tour looks frozen on one view. Take a calibration screenshot before scripting clicks.Cursor chat stuck on "Waiting for upload…":
artifacts/captures/…) or used markdown
. Copy to /opt/cursor/artifacts/screenshots/ and Read
that path instead (see step 9).Blank captures (desktop apps):
--settle time (default 3s)Playwright can't connect:
waitForSelector or increase timeoutPermission denied (macOS):
Display collision (Linux):
:99CAPTURE_DISPLAY=:98 or another numberRecording shows nothing:
DISPLAY env var matches Xvfbxdotool coords on decorated windows (Linux tours):
Window-name mismatch (Linux):
--name finds nothing, the script falls back to capturing the root display, which is fine.Tauri build deps (Linux):
cargo build fails with gdk-3.0 not found or similar, install: libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev libcurl4-openssl-dev libssl-dev pkg-config.EGL / DRI3 warnings (Linux):
Lingering processes:
apt-get without root:
apt-get install -y ffmpeg imagemagick xdotool x11-utils xvfb.templates/capture.mjs — unified capture script (web + own-binary desktop)templates/capture-vscode-extension.mjs — VS Code extension capture (downloads VS Code, EDH mode)templates/session-start.sh — Linux SessionStart hookrecipes/tauri.md — own-binary (Tauri/Electron/GTK/Qt) swap-insrecipes/vscode-extension.md — VS Code extension lifecycle + calibration