Preview capture
Skill markdavidgan/apple-dev-skills/src/skills/preview-capture
Render named SwiftUI #Previews to PNG at canonical device resolution for design-contract verification, with an automatic simulator-capability check and a documented fallback for machines that cannot or must not run the simulator. Use to produce capture proof for a design contract's §9 frames.From its SKILL.md
npx -y skills add markdavidgan/apple-dev-skills --skill preview-captureAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.6 KB, ~1.5k tokens by cl100k_base, as published. Nobody here has run it
Preview Capture
Purpose: Turn a design contract's canonical
#Previewframes into committed PNGs that a reviewer can diff against the mockup. Trigger: A plan written withdesign-contractrequires capture proof, and you need to render#Previews to images.
A design contract's §9 maps each canonical frame to a named #Preview. This skill renders those previews to captures/<PreviewName>.png so fidelity becomes reviewable. It first decides whether this machine may render at all — because "looks capable" is not the same as "is allowed."
When to Use
- Do use to generate capture proof for
design-contract§9 frames before opening a PR. - Do use to refresh captures after a UI change touches a contracted frame.
- Don't use for ad-hoc screenshots of a running app (that's
ios-simulate), or when there is no design contract.
Command Reference
/preview-capture # Render every contracted #Preview in the touched files
/preview-capture <PreviewName> ... # Render specific named previews
Step 1: Gauge simulator capability (REQUIRED — run first)
You cannot reliably probe "will the simulator crash this machine" from hardware. A Mac that meets every spec can still destabilize on boot. Therefore an explicit opt-out always wins over any hardware probe — a passing probe must never re-enable a machine a human has marked unsafe.
Resolve capability with this precedence ladder:
# --- simulator-capability ladder -------------------------------------------
# Echoes one of: forbidden | unavailable | insufficient | capable
cap_marker_present() {
[ -f ".claude/NO_SIMULATOR.md" ] || [ -n "${AETHER_NO_SIMULATOR:-}" ] || \
[ -f "$HOME/.config/no-simulator" ]
}
min_free_ram_gb=8
min_free_disk_gb=15
if cap_marker_present; then
echo "forbidden" # human/policy opt-out — AUTHORITATIVE, stop here
elif [ "$(uname -s)" != "Darwin" ]; then
echo "unavailable" # simulators are macOS-only
elif ! xcode-select -p >/dev/null 2>&1; then
echo "unavailable" # no Xcode toolchain
elif ! xcrun simctl list runtimes 2>/dev/null | grep -qiE "iOS|watchOS|visionOS"; then
echo "unavailable" # no installed simulator runtime
else
ram_gb=$(( $(sysctl -n hw.memsize) / 1073741824 ))
disk_gb=$(df -g . | awk 'NR==2 {print $4}')
if [ "$ram_gb" -lt "$min_free_ram_gb" ] || [ "${disk_gb:-0}" -lt "$min_free_disk_gb" ]; then
echo "insufficient" # meets neither RAM nor disk floor
else
echo "capable"
fi
fi
# ---------------------------------------------------------------------------
Interpretation:
| Result | Meaning | Action |
|---|---|---|
forbidden | A marker (.claude/NO_SIMULATOR.md, AETHER_NO_SIMULATOR, ~/.config/no-simulator) opts this machine out | Go to Step 3 (fallback). Never override. |
unavailable | Not macOS, no Xcode, or no installed runtime | Go to Step 3. Cannot render here. |
insufficient | Below the RAM/disk floor | Go to Step 3; warn the user the machine is under-resourced. |
capable | Probe passed and no opt-out | Go to Step 2. |
The hardware probe is a convenience that catches obvious "no Xcode" cases. The marker is the authority. If you are unsure, treat as
forbidden.
Step 2: Render previews (capable machines)
Use Xcode's preview-to-image path. Each #Preview named in the contract's §9 renders at the canonical device resolution recorded in the contract (e.g. iPhone 17 Pro Max).
# Boot the canonical device once (see ios-simulate for device selection)
xcrun simctl boot "<canonical-device>" 2>/dev/null || true
# Render each contracted preview to captures/. Prefer the project's own
# preview-render target/script if present; otherwise drive the simulator and
# screenshot the rendered preview.
xcrun simctl io booted screenshot "<app>/docs/vision/captures/<PreviewName>.png"
Commit the PNGs alongside the implementing change. One PNG per §9 frame, named exactly the §9 Preview name so the reviewer can map 1:1.
Never run iOS UI tests as part of this — capture is a render, not a test pass. (See ios-test for why UI-test execution is gated.)
Step 3: Fallback (forbidden / unavailable / insufficient)
When this machine may not render, the gate substitutes rather than disappears:
- CI gate = archive build. Run the project's archive/export (e.g.
make export-test-<app>/xcodebuild archive). This catches Swift 6 strict concurrency, signing, asset-catalog, and Live Activity encoding failures that a debug render would not — it is a stronger correctness gate than a simulator screenshot. - Visual proof = a human render. The
#Previews remain mandatory in code (they cost nothing and a teammate renders them in Xcode or checks a TestFlight build on device). That person drops the PNGs intocaptures/<PreviewName>.png. - Honesty rule. The agent must NOT fabricate captures and must NOT claim visual parity it cannot see. It states plainly: "previews compile and archive passes; visual parity pending a teammate's Xcode render."
Record in the plan which captures are agent-produced vs. pending-human, so the PR reviewer knows what is actually verified.
Error Handling
| Error | Cause | Fix |
|---|---|---|
Ladder returns capable on a known-bad machine | Marker missing | Create .claude/NO_SIMULATOR.md (or set AETHER_NO_SIMULATOR=1); the marker is authoritative |
xcrun simctl hangs / crashes the host | Machine destabilizes despite passing specs | Add the opt-out marker and use Step 3 permanently for that machine |
| Capture name ≠ §9 Preview name | Hand-named file | Rename to match §9 exactly; the reviewer maps captures→frames by name |
| Blank/black capture | Simulator not booted, or preview compile error | Boot the device; confirm the #Preview compiles in the archive build |
Cross-References
- Defines the §9 frames and capture gate:
design-contract - Consumes the captures for fidelity diffing:
verify-against-spec(Visual Fidelity agent) - Device selection, simctl workflows:
ios-simulate - Why UI tests are gated separately:
ios-test
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.