# Visual QA Diff Process in ai-website-cloner-template: How to Compare Screenshots for Pixel-Perfect Clones

> Explore the visual QA diff process in ai-website-cloner-template. Learn how to compare screenshots pixel-by-pixel for perfect website clones. Validate your results effectively.

- Repository: [JCodesMore/ai-website-cloner-template](https://github.com/JCodesMore/ai-website-cloner-template)
- Tags: how-to-guide
- Published: 2026-06-24

---

**The visual QA diff process performs a pixel-by-pixel comparison between the original website and the generated clone at desktop (1440px) and mobile (390px) viewports, using screenshots stored in `docs/design-references/` and validated against the Phase 5 checklist defined in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md).**

The **ai-website-cloner-template** repository defines a rigorous **visual QA diff** as the final validation gate in its cloning pipeline. According to the source documentation, this process ensures that the generated Next.js application is visually indistinguishable from the target site by comparing full-page screenshots side-by-side and iterating until zero pixel differences remain.

## What Is the Visual QA Diff Process?

The visual QA diff constitutes **Phase 5** of the cloning workflow, executed immediately after the builders merge their worktrees and the Next.js app compiles. As documented in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md), this phase involves:

- Capturing full-page screenshots of the **original** site stored during Phase 1 reconnaissance
- Capturing identical screenshots of the **clone** after running `npm run build`
- Comparing each section top-to-bottom at **1440px desktop** and **390px mobile** viewports
- Tracing every mismatch to its source spec file in `docs/research/components/` and rebuilding until the discrepancy resolves

The process enforces **pixel-perfect fidelity**—any stray margin, incorrect color value, or missing hover state captured in the diff triggers a rebuild of the offending component.

## Where the Visual QA Process Is Defined

The canonical definition of the visual QA diff process lives in two locations within the repository:

- **[`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md)** (line 12): Contains the detailed Phase 5 instructions and the mandatory checklist
- **[`README.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/README.md)** (section "Assembly & QA", line 94): Provides the high-level pipeline overview mentioning the side-by-side screenshot comparison

Component specifications referenced during the diff are located at `docs/research/components/*.spec.md`, while screenshot assets reside in `docs/design-references/`.

## How to Capture Screenshots for Comparison

### Capturing Original Site Screenshots

During **Phase 1 – Reconnaissance**, capture baseline screenshots of the live target using a headless browser and store them in `docs/design-references/`:

```javascript
// scripts/capture-original.mjs
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  
  // Desktop viewport
  await page.setViewportSize({ width: 1440, height: 900 });
  await page.goto('https://target-website.com', { waitUntil: 'networkidle' });
  await page.screenshot({ 
    path: 'docs/design-references/original-desktop.png', 
    fullPage: true 
  });
  
  // Mobile viewport
  await page.setViewportSize({ width: 390, height: 800 });
  await page.goto('https://target-website.com', { waitUntil: 'networkidle' });
  await page.screenshot({ 
    path: 'docs/design-references/original-mobile.png', 
    fullPage: true 
  });
  
  await browser.close();
})();

```

### Capturing Clone Screenshots

After building the clone, launch the dev server and capture the same viewports:

```javascript
// scripts/clone-screenshot.mjs
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();

  // Desktop viewport
  await page.setViewportSize({ width: 1440, height: 900 });
  await page.goto('http://localhost:3000', { waitUntil: 'networkidle' });
  await page.screenshot({ 
    path: 'docs/design-references/clone-desktop.png', 
    fullPage: true 
  });

  // Mobile viewport
  await page.setViewportSize({ width: 390, height: 800 });
  await page.goto('http://localhost:3000', { waitUntil: 'networkidle' });
  await page.screenshot({ 
    path: 'docs/design-references/clone-mobile.png', 
    fullPage: true 
  });

  await browser.close();
})();

```

Run the capture after starting the development server:

```bash
npm run dev &
node scripts/clone-screenshot.mjs

```

## How to Compare Screenshots

### Manual Side-by-Side Comparison

For manual validation, open the paired PNG files (original vs. clone) side-by-side in any image diff tool. Supported options include **ImageMagick**, VS Code’s built-in image diff viewer, or GUI tools like **Beyond Compare**.

### Automated Pixel-Match Diff

For CI/CD pipelines, automate the comparison using `pixelmatch` to generate diff images with highlighted mismatches:

```javascript
// scripts/visual-diff.mjs
import { readFile } from 'fs/promises';
import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';
import { writeFile } from 'fs/promises';

async function diffImages(aPath, bPath, outPath) {
  const [aBuf, bBuf] = await Promise.all([readFile(aPath), readFile(bPath)]);
  const imgA = PNG.sync.read(aBuf);
  const imgB = PNG.sync.read(bBuf);
  const { width, height } = imgA;
  const diff = new PNG({ width, height });

  const mismatched = pixelmatch(
    imgA.data,
    imgB.data,
    diff.data,
    width,
    height,
    { threshold: 0.1 }
  );

  await writeFile(outPath, PNG.sync.write(diff));
  console.log(`✖ ${mismatched} pixels differ – diff saved to ${outPath}`);
}

await diffImages(
  'docs/design-references/original-desktop.png',
  'docs/design-references/clone-desktop.png',
  'docs/design-references/diff-desktop.png'
);

```

If `mismatched` returns **0**, the visual QA for that viewport passes. Any non-zero value requires revisiting the corresponding component spec in `docs/research/components/` and rebuilding.

## The Visual QA Checklist

The template enforces a concrete checklist before declaring the clone complete. As defined in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md) (line 32), the auditor must verify:

1. Every component has a corresponding [`.spec.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.spec.md) file
2. All CSS values originate from `getComputedStyle()` extraction
3. Interaction models (hover, scroll, tab) are documented
4. All component states are captured
5. Responsive layouts are documented for both viewports
6. Zero pixel differences exist at desktop (1440px)
7. Zero pixel differences exist at mobile (390px)

Implement this checklist programmatically using a TypeScript helper:

```typescript
// scripts/qa-checklist.ts
type ChecklistItem = { label: string; done: boolean };

export const visualQaChecklist: ChecklistItem[] = [
  { label: 'Spec file written for each component', done: false },
  { label: 'All CSS values taken from getComputedStyle()', done: false },
  { label: 'Interaction model documented', done: false },
  { label: 'All component states captured', done: false },
  { label: 'Responsive layouts documented', done: false },
  { label: 'Zero pixel differences at desktop', done: false },
  { label: 'Zero pixel differences at mobile', done: false },
];

export function reportChecklist() {
  visualQaChecklist.forEach(i => console.log(`[${i.done ? 'x' : ' '}] ${i.label}`));
}

```

Execute `node scripts/qa-checklist.ts` at the end of Phase 5 to confirm every item is ticked before finalizing the build.

## Summary

- The **visual QA diff process** is Phase 5 of the ai-website-cloner-template pipeline, defined in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md)
- Comparisons occur at **1440px desktop** and **390px mobile** viewports using screenshots stored in `docs/design-references/`
- **Pixelmatch** or manual tools perform pixel-by-pixel validation between original and clone screenshots
- The **Phase 5 checklist** mandates zero pixel differences and complete component documentation before the clone passes QA
- Discrepancies trace back to `docs/research/components/*.spec.md` files for deterministic rework

## Frequently Asked Questions

### What viewport sizes does the visual QA diff process use?

The process mandates validation at two canonical viewports: **1440px width for desktop** and **390px width for mobile**, as specified in [`.windsurf/workflows/clone-website.md`](https://github.com/JCodesMore/ai-website-cloner-template/blob/main/.windsurf/workflows/clone-website.md). These dimensions represent standard breakpoints that ensure responsive fidelity across devices.

### Where are the screenshots stored during the visual QA process?

Original site screenshots captured during Phase 1 reconnaissance and clone screenshots taken after `npm run build` both reside in **`docs/design-references/`**. This directory serves as the single source of truth for all visual comparison assets.

### Which tools automate the screenshot comparison?

The repository supports **Playwright** or **Puppeteer** for headless screenshot capture, and **pixelmatch** (a Node.js library) for generating diff images with highlighted pixel deviations. For manual review, ImageMagick, VS Code image diff, or Beyond Compare are compatible alternatives.

### How do you resolve visual discrepancies found during the diff?

When the diff detects mismatched pixels, trace the visual defect to its source **component spec** in `docs/research/components/<Component>.spec.md`. Re-run the extraction script for that component to update the spec with corrected CSS values, rebuild the component, and re-run `npm run build` until the screenshot comparison returns zero differences.