How to Automate Visual Checks Using Screenshots in Archify
Archify's built-in visual-check utility programmatically renders HTML artifacts in headless Chrome, captures multi-viewport screenshots, and generates structured receipts for automated UI validation.
The visual check automation system in the tt-a1i/archify repository provides a complete, scriptable solution for verifying that HTML diagrams and components render correctly across device sizes and color themes. This guide covers the architecture, execution flow, and practical integration patterns.
How the Visual Check System Works
The implementation lives in archify/bin/visual-check.mjs and consists of four coordinated components:
- Viewport definitions — Fixed size arrays for containment testing and final screenshot capture
- Side-car generation — Structured output folder with JSON receipt, contact-sheet HTML, and PNG files
- Chrome driver — Lightweight CDP client that spawns headless Chrome and controls rendering
- Orchestration — Main
runVisualCheck()function that wires everything together
Viewport Configuration
Two viewport arrays control the automated screenshot capture behavior:
// archify/bin/visual-check.mjs lines 8-13
const VISUAL_CHECK_VIEWPORTS = [
{ width: 1920, height: 1080, name: 'desktop' },
{ width: 1440, height: 900, name: 'laptop' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 375, height: 667, name: 'mobile' }
];
// archify/bin/visual-check.mjs lines 15-18
const CAPTURE_VIEWPORTS = [
{ width: 1440, height: 900 } // Primary screenshot size
];
VISUAL_CHECK_VIEWPORTS validates containment (no overflow) across four standard devices. CAPTURE_VIEWPORTS determines which dimensions receive actual PNG screenshots in both light and dark themes.
Side-Car Output Structure
For every processed artifact, sidecarPaths() (lines 54-70) creates a .visual-check folder containing:
| File | Purpose |
|---|---|
*.visual-check.json |
Machine-readable receipt with metrics and status |
*.visual-check.html |
Human-readable contact-sheet gallery |
*.visual-check.{width}x{height}.{theme}.png |
Actual screenshot files |
File naming follows the pattern: diagram.visual-check.1440x900.light.png.
Chrome Driver Implementation
The ChromeVisualBrowser class uses a minimal CDP (Chrome DevTools Protocol) client called PipeCdp:
// From archify/bin/visual-check.mjs lines 35-44, 84-108
class ChromeVisualBrowser {
async inspect({ url, width, height, theme, screenshot }) {
// Spawns headless Chrome, forces static UI state,
// captures metrics, optionally records screenshot
}
}
The inspect() method:
- Emulates the requested viewport dimensions
- Forces light or dark theme via CSS injection
- Returns containment metrics (
innerWidth,scrollWidth,scrollHeight) - Writes PNG data when
screenshot: trueis passed
Execution Flow: Step by Step
The runVisualCheck() function orchestrates the complete visual check automation pipeline:
- Chrome discovery —
findChrome()checksARCHIFY_CHROMEenv var or searches standard install paths; returns exit code2if unavailable - Side-car preparation —
sidecarPaths()andbaseReceipt()initialize output structure - Containment pass — Iterates
VISUAL_CHECK_VIEWPORTSto collect overflow metrics (no screenshots) - Screenshot pass — Iterates
CAPTURE_VIEWPORTS× 2 themes to write PNG files - Immutability check — Re-hashes original artifact; aborts on mismatch
- Result aggregation — Computes
containment.status("pass" or "fail") and buildscaptures.screenshotsarray - Atomic writes — Uses
writeAtomic()for receipt and contact-sheet; cleans up partial files on failure
CLI Usage for Visual Checks
Run the built-in command directly:
node ./archify/bin/visual-check.mjs ./examples/archify-repo.html
Expected output files:
archify-repo.visual-check.json
archify-repo.visual-check.html
archify-repo.visual-check.1440x900.light.png
archify-repo.visual-check.1440x900.dark.png
Exit codes indicate results:
0— All viewports contained, screenshots captured successfully1— Overflow detected or screenshot failure2— Chrome not found (skipped)
Programmatic Visual Check Integration
Import runVisualCheck() for build script automation:
// build-script.mjs
import { runVisualCheck } from './archify/bin/visual-check.mjs';
async function validateArtifacts(files) {
for (const file of files) {
const { exitCode, receipt } = await runVisualCheck({
artifactPath: file,
// Optional: specify Chrome binary path
// chromePath: process.env.ARCHIFY_CHROME
});
if (exitCode !== 0) {
console.error(`Visual check failed for ${file}`);
process.exit(1);
}
console.log(`✓ ${file}: ${receipt.containment.status}`);
}
}
The returned receipt object contains:
receipt.containment.status— "pass" or "fail"receipt.containment.viewports— Array of per-viewport metricsreceipt.captures.screenshots— Array with PNG filenames and metadata
CI/CD Integration for Automated Screenshots
GitHub Actions workflow example:
name: Visual Check
on: [push, pull_request]
jobs:
visual-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Chrome
uses: browser-actions/setup-chrome@v1
- name: Run visual checks
run: |
node ./archify/bin/visual-check.mjs ./examples/archify-repo.html
- name: Verify containment
run: |
jq -e '.containment.status == "pass"' \
archify-repo.visual-check.json
The jq command gates the pipeline: any overflow failure aborts the workflow.
Contact Sheet Generation
The contactSheetHtml() function (invoked during orchestration) produces a minimal HTML gallery displaying:
- Each screenshot with its viewport dimensions
- Light/dark theme variants
- Pass/fail containment labels
- Links to full-resolution PNG files
Open *.visual-check.html in any browser for immediate visual inspection of automated screenshot results.
Environment Variables
| Variable | Purpose |
|---|---|
ARCHIFY_CHROME |
Override path to Chrome/Chromium binary |
Standard CI |
Detected automatically; triggers non-interactive output |
Summary
- Archify's visual check automation renders HTML in headless Chrome and captures structured screenshots
- Four viewport sizes validate containment; one primary size generates theme-variant PNGs
- Side-car outputs include JSON receipt, HTML contact sheet, and screenshot files
- Exit codes (
0,1,2) integrate cleanly with CI pipelines - Programmatic API via
runVisualCheck()enables custom build workflows
Frequently Asked Questions
How does Archify handle missing Chrome installations?
The findChrome() function first checks the ARCHIFY_CHROME environment variable, then searches common system paths. If Chrome is unavailable, runVisualCheck() returns exit code 2, writes a receipt with status: "skipped", and does not throw—allowing CI pipelines to continue optionally.
Can I customize which viewports get screenshots?
The CAPTURE_VIEWPORTS array in archify/bin/visual-check.mjs (lines 15-18) controls screenshot dimensions. Modify this constant before running the CLI, or call runVisualCheck() from a wrapper script that patches the configuration. Containment validation always uses the full VISUAL_CHECK_VIEWPORTS set.
What triggers a containment failure?
A viewport fails containment when scrollWidth > innerWidth or scrollHeight > innerHeight, indicating content overflow. The receipt's containment.viewports[n].ok field is false for that viewport, and the aggregate containment.status becomes "fail" unless all viewports report ok: true.
How are screenshot files named and organized?
sidecarPaths() generates paths following the pattern {basename}.visual-check.{width}x{height}.{theme}.png alongside {basename}.visual-check.json and {basename}.visual-check.html. All files reside in the same directory as the original artifact, not a separate folder.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →