# Macos Window Visual QA

> Deterministic visual QA for macOS application windows and SwiftUI/AppKit views. Use when Codex must capture or inspect a specific native app window, reproduce layout defects, verify clipping, overlap, scrolling, alignment, responsive columns, or light/dark appearance, especially when earlier screenshot attempts cannot find the window or keep switching capture methods. Prefer a source-level fixed-size render with geometry assertions; otherwise identify and capture one exact live window, validate the artifact, and stop blind retries.

- Skill: `troicc/macos-window-visual-qa` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add troicc/macos-window-visual-qa`
- Raw SKILL.md: https://api.skillmd.com/api/skills/troicc/macos-window-visual-qa/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: troicc (https://skillmd.com/u/troicc)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/troicc/macos-window-visual-qa

---


# macOS Window Visual QA

Treat visual QA as a reproducible test, not a screenshot hunt. Produce an identified target, a valid image artifact, measurable layout evidence, and a concise verdict.

## Set the inspection contract

Before capturing anything, record:

- app, window, screen, route, or component under inspection;
- exact UI state and required test data;
- viewport size in points and appearance (`light` or `dark`);
- defects or invariants to check;
- evidence output directory.

Use the user's screenshot as the baseline when one exists. Inspect it first; do not recapture the same broken state merely to obtain your own copy.

## Choose one capture route

1. **Source-level render — preferred.** For an editable SwiftUI/AppKit project, render the real production view in a fixed-size `NSHostingView` attached to an `NSWindow`. Assert geometry in the same test and export PNG evidence. Read [references/swiftui-xctest-rendering.md](references/swiftui-xctest-rendering.md) before implementing this route.
2. **Exact live window.** Use this when window chrome, toolbar integration, launch state, focus, or a non-source app matters. Resolve the window before capture with [scripts/macos-window-capture](scripts/macos-window-capture).
3. **Existing artifact.** If the user supplied a screenshot and no post-change evidence is needed, inspect it directly with the image-viewing tool.

Do not use a full-screen screenshot as a substitute for a window-level request. Do not use browser capture for a native macOS window.

## Capture an exact live window

First probe candidates without writing an image:

```bash
zsh /absolute/path/to/scripts/macos-window-capture list --owner "App Name"
```

Run live-window probing with WindowServer access. In Codex's restricted shell, an empty result can be a sandbox artifact; if the app process is known to exist, rerun the same probe once with the tool's sandbox escalation instead of changing capture utilities.

Require a layer-0, on-screen candidate with plausible bounds. Refine ambiguous results with `--title-contains`, `--pid`, or use the reported `--window-id`. Prefer `--pid` for development builds without a stable app bundle name. A missing title can indicate unavailable Screen Recording metadata; PID and window ID remain usable.

Then capture once:

```bash
zsh /absolute/path/to/scripts/macos-window-capture capture \
  --owner "App Name" \
  --title-contains "Document or Page" \
  --output /absolute/evidence/window.png
```

The wrapper supplies an isolated Swift module cache, so it also works in restricted Codex shells. The script rejects zero matches, ambiguous matches, existing output paths, blank or invalid files, implausibly small captures, and dimension mismatches. Use `--window-id ID` when the target has already been resolved. Run `help` for all options.

## Enforce the retry budget

- Never rerun an unchanged failed capture command.
- Allow at most one attempt per distinct route before diagnosing the failure.
- If no candidate exists, verify app/process state and launch or navigate once. Probe again once; then stop.
- If a known process has no candidates in a restricted shell, request WindowServer access and repeat that probe once. This is a permission diagnosis, not a reason to switch tools.
- If capture fails while a valid candidate exists, treat Screen Recording permission as the likely blocker. Report it and request the required macOS permission; do not cycle through screenshot utilities.
- If the output is blank, corrupt, implausibly small, or the wrong dimensions, reject it. Fix the identified cause before another capture.
- Do not take repeated images hoping one will look right. Multiple captures are allowed only for a declared matrix such as light/dark, breakpoints, or before/after.

## Inspect and measure

After the capture command succeeds:

1. Open the PNG with the image-viewing tool. A successful command alone is not visual verification.
2. Confirm app/window identity, expected state, dimensions, and appearance.
3. Check content priority, clipping, overlap, occlusion, line wrapping, scrolling, icon/text centering, contrast, and loading/error states.
4. When source is available, turn every objective defect into an assertion: frame relationships, minimum readable width/height, scroll range, insets, hit target bounds, or visibility policy.
5. Verify all specified sizes and both appearances when relevant. Do not generalize from a single viewport.

Prefer frame conversion into one coordinate space before comparing geometry. Account for flipped AppKit coordinates explicitly.

## Completion gate

Do not claim the visual issue is fixed unless all are true:

- the exact production view or exact live target was captured;
- the PNG was validated and visually inspected;
- relevant geometry assertions pass;
- the required viewport/appearance matrix was checked;
- the evidence path and commands are reported;
- project-required tests and builds pass.

If any item is blocked, name the missing item and the single blocking condition. Never hide the blocker behind more screenshot attempts.

