playwright-visual-testing
Fast visual testing and screenshot automation for breathe-together-v2. Use when you need to capture screenshots of the 3D scene, compare visual changes before/after code modifications, or test different Leva configurations. Provides branch-aware filenames for easy comparison. Works with all viewports (desktop, tablet, mobile).
When & Why to Use This Skill
This Claude skill automates high-speed visual testing and screenshot capture using Playwright, specifically optimized for 3D web environments. It streamlines visual regression analysis by providing branch-aware naming, multi-viewport support, and dynamic Leva configuration injection, allowing developers to precisely compare UI changes and validate visual consistency across different code states.
Use Cases
- Visual Regression Testing: Capture 'before' and 'after' screenshots during the development cycle to identify and fix unintended visual bugs or regressions.
- Cross-Device UI Verification: Automatically generate and compare screenshots across desktop, tablet, and mobile viewports to ensure responsive design integrity.
- Visual Parameter Experimentation: Use Leva configuration overrides to test different material properties, lighting, or colors in real-time and document the results via automated screenshots.
- AI-Assisted Design Review: Provide Claude with structured screenshot outputs to facilitate automated visual audits and receive recommendations for updating code defaults based on experimental results.
| name | playwright-visual-testing |
|---|---|
| description | Fast visual testing and screenshot automation for breathe-together-v2. Use when you need to capture screenshots of the 3D scene, compare visual changes before/after code modifications, or test different Leva configurations. Provides branch-aware filenames for easy comparison. Works with all viewports (desktop, tablet, mobile). |
Playwright Visual Testing
Fast screenshot automation with branch-aware naming and Leva config injection.
Quick Start
# Basic screenshot (desktop viewport)
npm run screenshot
# All viewports (desktop, tablet, mobile)
npm run screenshot:all
# With Leva config override
LEVA_CONFIG='{"ior": 1.8, "glassDepth": 0.4}' npm run screenshot
# Before/after comparison
SCREENSHOT_TAG="before" npm run screenshot
# ... make changes ...
SCREENSHOT_TAG="after" npm run screenshot
Screenshot List Output
After each screenshot, the script displays recent screenshots from the current branch:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Recent Screenshots for Current Branch
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[demo] desktop 2.0MB 1s ago screenshots/...desktop_demo_20260106-193814.png
[demo] mobile 0.3MB 6s ago screenshots/...mobile_demo_20260106-193814.png
[demo] tablet 0.8MB 5s ago screenshots/...tablet_demo_20260106-193814.png
[before] desktop 2.0MB 2m ago screenshots/...desktop_before_20260106-193612.png
[after] desktop 2.0MB 1m ago screenshots/...desktop_after_20260106-193658.png
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This makes it easy for Claude to see available screenshots for comparison.
Naming Convention
Screenshots are saved with branch-aware names:
./screenshots/<branch>_<viewport>_[tag]_<timestamp>.png
Example: claude-fix-glass-effect_desktop_before_20260106-143052.png
Environment Variables
| Variable | Description | Default |
|---|---|---|
LEVA_CONFIG |
JSON string of Leva control overrides | - |
SCREENSHOT_TAG |
Tag to append to filename | - |
SCREENSHOT_OUTPUT |
Override output path completely | Auto-generated |
NO_MODALS |
Set to false to show modals |
true |
ELEMENT_SELECTOR |
CSS selector for element screenshot | canvas |
Workflows
Visual Change Comparison
# 1. Capture baseline
SCREENSHOT_TAG="before" npm run screenshot
# 2. Make code changes...
# 3. Capture new state
SCREENSHOT_TAG="after" npm run screenshot
# 4. Compare files in ./screenshots/
Multi-Config Testing
Test different visual configurations quickly:
SCREENSHOT_TAG="default" npm run screenshot
LEVA_CONFIG='{"ior": 2.0}' SCREENSHOT_TAG="high-ior" npm run screenshot
LEVA_CONFIG='{"ior": 1.2}' SCREENSHOT_TAG="low-ior" npm run screenshot
Updating Code Defaults from Leva Experiments
When you find better visual configurations through Leva experimentation, update the code defaults:
# 1. Test different Leva configs
LEVA_CONFIG='{"starColor": "#ffc940", "lineOpacity": 0.3}' SCREENSHOT_TAG="golden-stars" npm run screenshot
# 2. Compare results and identify improvements
# (Claude reads screenshots and determines golden-stars config is better)
# 3. Update code defaults in the component file
# Edit src/entities/environment/ConstellationStars.tsx:
# starColor = '#ffc940', // updated from '#ffefc2'
# lineOpacity = 0.3, // updated from 0.85
# 4. Capture new baseline with updated defaults
SCREENSHOT_TAG="updated-defaults" npm run screenshot
# 5. Verify improvements persist without Leva overrides
Workflow Pattern:
- Experiment - Use
LEVA_CONFIGto test different visual parameters - Document - Screenshot script logs the exact Leva config used
- Compare - Review screenshots to identify improvements
- Update - Change code defaults in component files (not just Leva)
- Verify - Confirm new defaults work without overrides
Why Update Code Defaults?
- Leva configs are temporary - code defaults are permanent
- Ensures consistent visuals in production (dev mode disabled)
- Makes improvements discoverable to other developers
- Reduces need for runtime configuration
Real Example - Constellation Stars Improvement:
# Initial state: pale white stars, bright lines
SCREENSHOT_TAG="before" npm run screenshot
# Experiment with golden color and subtle lines
LEVA_CONFIG='{"starColor": "#ffc940", "lineOpacity": 0.3}' SCREENSHOT_TAG="golden" npm run screenshot
# Compare screenshots → golden version is better
# Update src/entities/environment/ConstellationStars.tsx:
# starColor = '#ffc940', // was '#ffefc2'
# lineOpacity = 0.3, // was 0.85
# Verify new defaults
SCREENSHOT_TAG="after" npm run screenshot
# Result: Golden stars with subtle lines, no Leva override needed
Element Screenshots
Target specific UI elements:
# Canvas only
ELEMENT_SELECTOR="canvas" npm run screenshot:element
# Phase display
ELEMENT_SELECTOR=".phase-display" npm run screenshot:element
# Custom selector
ELEMENT_SELECTOR="[data-testid='controls']" npm run screenshot:element
AI-Assisted Review
Claude can easily see available screenshots from the list output and read them for comparison:
User: SCREENSHOT_TAG="before" npm run screenshot
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Screenshot Configuration
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Viewport: desktop
Tag: before
Output: ./screenshots/claude-branch_desktop_before_20260106-193612.png
Leva Config: (using code defaults)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
User: [Makes code changes]
User: SCREENSHOT_TAG="after" npm run screenshot
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Screenshot Configuration
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Viewport: desktop
Tag: after
Output: ./screenshots/claude-branch_desktop_after_20260106-193658.png
Leva Config: (using code defaults)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Recent Screenshots for Current Branch
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[after] desktop 2.0MB 1s ago screenshots/...desktop_after_20260106-193658.png
[before] desktop 2.0MB 2m ago screenshots/...desktop_before_20260106-193612.png
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
User: Compare the before and after screenshots
Claude: [Reads both screenshots from the list]
- Before: Pale white constellation stars, bright connecting lines
- After: Golden stars (#ffc940) with subtle lines (opacity 0.3)
- The golden color creates better contrast against the dark background
- Recommendation: Update code defaults to golden configuration
The screenshot list and configuration logging make it easy to:
- See exactly what parameters were used for each screenshot
- Identify before/after pairs by tag
- Find recent screenshots by age (1s ago, 5m ago, 1h ago)
- Compare across viewports (desktop, tablet, mobile)
- Reproduce exact configurations from the logged Leva config
Leva Controls Reference
See references/leva-controls.md for commonly used controls.
Key controls for visual testing:
ior- Glass refraction (1.0-2.5)glassDepth- Glass thickness (0.0-1.0)shardMaterialType- Material style (polished, frosted, cel, bubble, chromatic)showShardShells- Toggle outer shellsenableBloom- Toggle bloom effectbloomIntensity- Bloom strength (0-2)
Implementation Details
Screenshot Ready Signal
The app emits [SCREENSHOT_READY] to console when shards are fully rendered.
Tests wait for this signal before capturing.
Modal Hiding
Modals are hidden via CSS injection to capture clean scene screenshots.
Set NO_MODALS=false to capture with modals visible.
Leva Bridge
window.__LEVA_SET__ and window.__LEVA_GET__ are exposed for programmatic
control injection. Only available when dev mode is enabled.
Screenshot Configuration Logging
Each screenshot run logs complete configuration for reproducibility:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Screenshot Configuration
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Viewport: desktop
Tag: golden-stars
Output: ./screenshots/claude-branch_desktop_golden-stars_20260106-195711.png
Leva Config: {
"starColor": "#ffc940",
"lineOpacity": 0.3
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This makes it easy to:
- Reproduce screenshots with exact same config
- Document what parameters were tested
- Share configurations with team members
- Track which Leva configs led to code default updates