Screenshot Handling
⚠️ CRITICAL REQUIREMENT ⚠️
SAVING SCREENSHOTS TO PROJECT ROOT IS FORBIDDEN.
ALL screenshots MUST be saved to the screenshots/ folder. There are NO exceptions.
Validation Checklist
Before capturing ANY screenshot, verify:
- •✅
screenshots/folder exists (create withmkdir -p screenshots/) - •✅ Screenshot command includes
screenshots/in the path - •✅ Path format:
screenshots/filename.png(NOTfilename.png)
Correct vs Incorrect Examples
✅ CORRECT - Screenshots in screenshots/ folder:
- •
screenshots/mainmenu-verification.png - •
screenshots/timer-test.png - •
screenshots/game-over-state.png - •
screenshots/ui-validation.png
❌ INCORRECT - Screenshots in project root (FORBIDDEN):
- •
mainmenu-verification.png(project root) - •
timer-test.png(project root) - •
game-over-state.png(project root) - •
verification.png(project root)
If you discover screenshots in the project root, move them immediately to screenshots/ folder.
Screenshot path: Use project root or absolute path for the screenshot directory so CWD does not cause wrong locations. When saving to screenshots/, ensure CWD is project root.
Pre-completion (web tasks): For frontend/web tasks, do not skip browser verification; if agent-browser is loaded, at least one browser action (open, navigate, submit, or capture) must be performed before marking complete, unless documented as impossible (e.g. backend down) with fallback. For scaffold-only tasks, at least open the app URL and capture one screenshot to confirm the shell renders.
Overview
Screenshots should always be saved to a dedicated screenshots/ folder instead of the project root directory. This keeps the project root clean and organized, making it easier to manage and locate screenshot files.
Problem: Screenshots saved to project root create clutter and make it difficult to manage project files.
Solution: Always save screenshots to screenshots/ folder, creating it if it doesn't exist.
Required Behavior
ALWAYS save screenshots to the screenshots/ folder:
- •✅
screenshots/mainmenu-verification.png - •✅
screenshots/timer-test.png - •✅
screenshots/game-over-state.png - •❌
mainmenu-verification.png(project root) - •❌
timer-test.png(project root)
Folder Creation
Always ensure the screenshots/ folder exists before saving screenshots.
Bash/Shell
mkdir -p screenshots/ agent-browser screenshot screenshots/mainmenu-verification.png
Node.js/TypeScript
import fs from 'fs';
// Create folder if it doesn't exist
fs.mkdirSync('screenshots', { recursive: true });
// Then capture screenshot
await page.screenshot({ path: 'screenshots/mainmenu-verification.png' });
Python
import os
# Create folder if it doesn't exist
os.makedirs('screenshots', exist_ok=True)
# Then capture screenshot
page.screenshot(path='screenshots/mainmenu-verification.png')
Methods Covered
agent-browser Screenshot Commands
CRITICAL: ALWAYS create the screenshots/ folder FIRST, then specify the screenshots/ folder path:
# STEP 1: Create folder first (MANDATORY) mkdir -p screenshots/ # STEP 2: Capture screenshot to screenshots/ folder (path MUST include screenshots/) agent-browser screenshot screenshots/mainmenu-verification.png agent-browser screenshot screenshots/timer-test.png agent-browser screenshot screenshots/game-over-state.png # Full page screenshot (also in screenshots/ folder) agent-browser screenshot --full screenshots/full-page.png
❌ FORBIDDEN - Never save to project root:
# WRONG - Missing screenshots/ folder in path agent-browser screenshot mainmenu-verification.png # ❌ Saves to project root agent-browser screenshot verification.png # ❌ Saves to project root
✅ CORRECT - Always include screenshots/ in path:
# RIGHT - Includes screenshots/ folder in path mkdir -p screenshots/ # ✅ Create folder first agent-browser screenshot screenshots/mainmenu-verification.png # ✅ Saves to screenshots/
Reference: See agent-browser skill for complete screenshot command syntax.
Playwright Screenshot Methods
Always use screenshots/ folder path:
import { chromium } from 'playwright';
import fs from 'fs';
// Create folder if it doesn't exist
fs.mkdirSync('screenshots', { recursive: true });
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost:5173');
// Capture screenshot to screenshots/ folder
await page.screenshot({ path: 'screenshots/mainmenu-verification.png' });
// Full page screenshot
await page.screenshot({
path: 'screenshots/full-page.png',
fullPage: true
});
await browser.close();
Puppeteer Screenshot Methods
Always use screenshots/ folder path:
import puppeteer from 'puppeteer';
import fs from 'fs';
// Create folder if it doesn't exist
fs.mkdirSync('screenshots', { recursive: true });
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:5173');
// Capture screenshot to screenshots/ folder
await page.screenshot({ path: 'screenshots/mainmenu-verification.png' });
// Full page screenshot
await page.screenshot({
path: 'screenshots/full-page.png',
fullPage: true
});
await browser.close();
Other Screenshot Capture Tools
For any other screenshot capture method:
- •Create
screenshots/folder if it doesn't exist - •Always specify
screenshots/filename.pngas the output path - •Never save to project root
Naming Conventions
Use descriptive filenames with context:
- •✅
screenshots/mainmenu-verification.png- Clear purpose - •✅
screenshots/timer-test-10seconds.png- Includes test context - •✅
screenshots/game-over-state.png- Describes state - •✅
screenshots/ui-validation-mainmenu.png- Includes validation context - •✅
screenshots/2026-01-25-mainmenu.png- Includes date if needed - •❌
screenshots/screenshot.png- Too generic - •❌
screenshots/test.png- Not descriptive
Recommended patterns:
- •
screenshots/{feature}-{state}.png- e.g.,mainmenu-default.png - •
screenshots/{feature}-{test-context}.png- e.g.,timer-test-5seconds.png - •
screenshots/{validation-type}-{scene}.png- e.g.,ui-validation-mainmenu.png
Migration
When discovering screenshots in project root, move them to screenshots/ folder:
Manual Migration
# Create screenshots folder mkdir -p screenshots/ # Move existing screenshots from root to screenshots/ mv *.png screenshots/ 2>/dev/null || true # Or move specific files mv mainmenu-verification.png screenshots/ mv timer-test.png screenshots/
Automated Migration Script
#!/bin/bash
# migrate-screenshots.sh
# Create screenshots folder
mkdir -p screenshots/
# Find PNG files in project root (excluding node_modules, .git, etc.)
find . -maxdepth 1 -name "*.png" -type f ! -path "./node_modules/*" ! -path "./.git/*" -exec mv {} screenshots/ \;
echo "Screenshots migrated to screenshots/ folder"
Verification
After migration, verify screenshots are in the correct location:
# List screenshots in screenshots/ folder ls -la screenshots/ # Verify no PNG files remain in project root (excluding node_modules, .git, etc.) find . -maxdepth 1 -name "*.png" -type f ! -path "./node_modules/*" ! -path "./.git/*"
Troubleshooting
Screenshots Ended Up in Wrong Location
If you discover screenshots in the project root instead of screenshots/ folder:
- •
Verify the issue:
bash# Check for PNG files in project root find . -maxdepth 1 -name "*.png" -type f
- •
Create screenshots folder if missing:
bashmkdir -p screenshots/
- •
Move misplaced screenshots:
bash# Move all PNG files from root to screenshots/ mv *.png screenshots/ 2>/dev/null || true # Or move specific files mv mainmenu-verification.png screenshots/ mv timer-test.png screenshots/
- •
Verify migration:
bash# List screenshots in correct location ls -la screenshots/ # Verify no PNG files remain in project root find . -maxdepth 1 -name "*.png" -type f
- •
Prevent future issues:
- •Always run
mkdir -p screenshots/before capturing screenshots - •Always include
screenshots/in the screenshot path - •Review this skill's instructions before capturing screenshots
- •Always run
Common Mistakes
Mistake 1: Forgetting to create folder
# ❌ WRONG - Folder doesn't exist, screenshot may fail or save to root agent-browser screenshot screenshots/test.png # ✅ CORRECT - Create folder first mkdir -p screenshots/ agent-browser screenshot screenshots/test.png
Mistake 2: Missing screenshots/ in path
# ❌ WRONG - Path doesn't include screenshots/ agent-browser screenshot test.png # ✅ CORRECT - Path includes screenshots/ agent-browser screenshot screenshots/test.png
Mistake 3: Using relative path without screenshots/
# ❌ WRONG - Relative path without folder
page.screenshot({ path: 'verification.png' })
# ✅ CORRECT - Path includes screenshots/
page.screenshot({ path: 'screenshots/verification.png' })
Screenshot Freshness Verification
Verify Screenshots Are Current
Always verify screenshots are current before using them for verification:
# Force browser refresh before capturing verification screenshots agent-browser reload agent-browser wait 2000 # Wait for reload # Then capture screenshot agent-browser screenshot screenshots/verification.png
Timestamp Verification Techniques
Pattern 1: Check File Timestamp
# Check screenshot file timestamp ls -l screenshots/verification.png # Verify file was created recently (within last 10 seconds) file_age=$(($(date +%s) - $(stat -f %m screenshots/verification.png))) if [ $file_age -lt 10 ]; then echo "Screenshot is fresh" else echo "Screenshot may be stale" fi
Pattern 2: Timestamp in Filename
# Include timestamp in filename
timestamp=$(date +%Y%m%d_%H%M%S)
agent-browser screenshot "screenshots/verification-${timestamp}.png"
Pattern 3: Browser State Verification
# Verify browser state before screenshot
agent-browser eval "
const state = {
url: window.location.href,
timestamp: Date.now(),
testSeamReady: window.__TEST__?.ready || false
};
JSON.stringify(state)
"
# Capture screenshot
agent-browser screenshot screenshots/verification.png
Detecting Stale Screenshots
Check for stale screenshots:
# Check if screenshot exists and is recent
check_screenshot_freshness() {
local screenshot=$1
local max_age=30 # 30 seconds max age
if [ ! -f "$screenshot" ]; then
echo "Screenshot not found"
return 1
fi
local file_age=$(($(date +%s) - $(stat -f %m "$screenshot")))
if [ $file_age -gt $max_age ]; then
echo "Screenshot is stale (${file_age}s old)"
return 1
fi
echo "Screenshot is fresh"
return 0
}
Force Browser Refresh Before Capture
Always refresh browser before capturing verification screenshots:
# Force refresh before screenshot agent-browser reload agent-browser wait 2000 # Wait for reload # Verify HMR has applied changes (if applicable) agent-browser eval " const lastReload = window.__HMR_LAST_RELOAD__ || 0; const now = Date.now(); const timeSinceReload = now - lastReload; timeSinceReload < 5000 ? 'Recently reloaded' : 'Stale state' " # Then capture screenshot agent-browser screenshot screenshots/verification.png
Timing Considerations
When to Wait for Scene Transitions/Updates
Wait for scene transitions before capturing:
# Navigate to scene
agent-browser eval "window.__TEST__.commands.goToScene('GameScene')"
# Wait for transition (don't capture immediately)
agent-browser wait 500 # Wait for scene transition
# Wait for scene initialization
agent-browser eval "
new Promise((resolve) => {
const check = () => {
if (window.__TEST__?.ready) {
resolve(true);
} else {
setTimeout(check, 100);
}
};
check();
})
"
# Now capture screenshot
agent-browser screenshot screenshots/gamescene-ready.png
Verify HMR Has Applied Changes Before Screenshots
Always verify HMR has applied changes before capturing:
# Make code change (outside browser) # Wait for HMR to apply agent-browser eval " const lastReload = window.__HMR_LAST_RELOAD__ || 0; const now = Date.now(); const timeSinceReload = now - lastReload; timeSinceReload < 5000 ? 'HMR applied' : 'HMR not applied' " # If HMR not applied, force refresh if [ "$hmr_status" != "HMR applied" ]; then agent-browser reload agent-browser wait 2000 fi # Then capture screenshot agent-browser screenshot screenshots/after-change.png
Explicit Wait Patterns for Dynamic Content
Wait for dynamic content before capturing:
# Wait for content to load
agent-browser eval "
new Promise((resolve) => {
const check = () => {
if (document.querySelector('.content-loaded')) {
resolve(true);
} else {
setTimeout(check, 100);
}
};
check();
})
"
# Wait for animations to complete
agent-browser wait 1000 # Wait for animation
# Then capture screenshot
agent-browser screenshot screenshots/content-loaded.png
Pattern for Phaser Games:
# Wait for scene ready agent-browser eval "window.__TEST__?.ready || false" # Wait for game state initialized agent-browser eval " const state = window.__TEST__?.gameState?.(); state && state.initialized ? true : false " # Wait for any animations agent-browser wait 500 # Then capture screenshot agent-browser screenshot screenshots/game-ready.png
Batch Screenshot Operations
Patterns for Capturing Multiple Screenshots Efficiently
Pattern 1: Sequential Screenshots with Minimal Waits
# Capture multiple screenshots efficiently
mkdir -p screenshots/
# Screenshot 1: Main menu
agent-browser open "http://localhost:5173?scene=MainMenu"
agent-browser wait 1000
agent-browser screenshot screenshots/mainmenu.png
# Screenshot 2: Game scene (navigate and capture)
agent-browser eval "window.__TEST__.commands.goToScene('GameScene')"
agent-browser wait 500
agent-browser screenshot screenshots/gamescene.png
# Screenshot 3: Game over (trigger and capture)
agent-browser eval "window.__TEST__.commands.triggerGameOver()"
agent-browser wait 500
agent-browser screenshot screenshots/gameover.png
Pattern 2: Batch Screenshots with State Verification
# Capture screenshots with state verification
capture_screenshot_with_state() {
local scene=$1
local filename=$2
# Navigate to scene
agent-browser eval "window.__TEST__.commands.goToScene('$scene')"
agent-browser wait 500
# Verify state
agent-browser eval "window.__TEST__?.sceneKey === '$scene'"
# Capture screenshot
agent-browser screenshot "screenshots/$filename"
}
# Batch capture
capture_screenshot_with_state "MainMenu" "mainmenu.png"
capture_screenshot_with_state "GameScene" "gamescene.png"
capture_screenshot_with_state "GameOverScene" "gameover.png"
When to Use Comparison Screenshots (Before/After)
Use before/after screenshots for verification:
# Before screenshot agent-browser screenshot screenshots/before-change.png # Make change (code modification) # Wait for HMR agent-browser reload agent-browser wait 2000 # After screenshot agent-browser screenshot screenshots/after-change.png # Compare screenshots (using imgdiff or visual comparison)
When to Use Before/After:
- •Verifying code changes
- •Testing visual regressions
- •Documenting changes
- •Debugging layout issues
Caching Strategies to Avoid Redundant Captures
Pattern 1: Check Screenshot Age Before Capture
# Check if screenshot exists and is recent
should_capture_screenshot() {
local screenshot=$1
local max_age=60 # 60 seconds max age
if [ ! -f "$screenshot" ]; then
return 0 # Screenshot doesn't exist, should capture
fi
local file_age=$(($(date +%s) - $(stat -f %m "$screenshot")))
if [ $file_age -gt $max_age ]; then
return 0 # Screenshot is stale, should capture
fi
return 1 # Screenshot is fresh, skip capture
}
# Use caching
if should_capture_screenshot "screenshots/mainmenu.png"; then
agent-browser screenshot screenshots/mainmenu.png
else
echo "Using cached screenshot"
fi
Pattern 2: Hash-Based Caching
# Check if state has changed before capturing
get_state_hash() {
agent-browser eval "
const state = {
scene: window.__TEST__?.sceneKey,
score: window.__TEST__?.gameState?.()?.score
};
JSON.stringify(state)
" | md5sum | cut -d' ' -f1
}
# Capture only if state changed
current_hash=$(get_state_hash)
if [ "$current_hash" != "$last_hash" ]; then
agent-browser screenshot screenshots/state-${current_hash}.png
last_hash=$current_hash
fi
Pattern 3: Timestamp-Based Caching
# Cache screenshots with timestamps
capture_with_cache() {
local scene=$1
local cache_file="screenshots/.cache-${scene}.txt"
local screenshot="screenshots/${scene}.png"
# Check cache
if [ -f "$cache_file" ]; then
local cached_time=$(cat "$cache_file")
local current_time=$(date +%s)
local age=$((current_time - cached_time))
if [ $age -lt 30 ]; then
echo "Using cached screenshot for $scene"
return 0
fi
fi
# Capture new screenshot
agent-browser eval "window.__TEST__.commands.goToScene('$scene')"
agent-browser wait 500
agent-browser screenshot "$screenshot"
echo $(date +%s) > "$cache_file"
}
Best Practices
- •Always create folder first: Use
mkdir -p screenshots/or equivalent before capturing - •Use descriptive names: Include feature, state, or test context in filename
- •Consistent location: Always use
screenshots/folder, never project root - •Clean up root: Move any screenshots found in root to
screenshots/folder immediately - •Add to .gitignore: Consider adding
screenshots/*.pngto.gitignoreif screenshots are temporary - •Validate before completion: Verify all screenshots are in
screenshots/folder before marking task complete - •Verify freshness: Always refresh browser before capturing verification screenshots
- •Wait for transitions: Wait for scene transitions and HMR before capturing
- •Use batch operations: Capture multiple screenshots efficiently with minimal waits
- •Cache when appropriate: Use caching to avoid redundant captures
Examples
Example 1: UI Validation Screenshot
# Create folder mkdir -p screenshots/ # Capture main menu for UI validation agent-browser open http://localhost:5173 agent-browser wait 2000 agent-browser screenshot screenshots/ui-validation-mainmenu.png
Example 2: Timer Test Screenshot
# Create folder
mkdir -p screenshots/
# Navigate and capture timer state
agent-browser open http://localhost:5173
agent-browser eval "window.__TEST__.commands.goToScene('GameScene')"
agent-browser eval "window.__TEST__.commands.setTimer(5)"
agent-browser wait 1000
agent-browser screenshot screenshots/timer-test-5seconds.png
Example 3: Playwright Test Screenshot
import { test } from '@playwright/test';
import fs from 'fs';
test('capture main menu screenshot', async ({ page }) => {
// Create folder
fs.mkdirSync('screenshots', { recursive: true });
await page.goto('http://localhost:5173');
await page.waitForTimeout(2000);
// Capture to screenshots/ folder
await page.screenshot({ path: 'screenshots/mainmenu-test.png' });
});
Resources
- •
agent-browserskill - Browser automation and screenshot commands - •Project root should remain clean and organized
- •Screenshots in root should be moved to
screenshots/folder when discovered