M1: initial scaffold — pipeline, specs, source, Dockerfile

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul O'Reilly
2026-04-17 23:52:40 +12:00
commit 8584def154
22 changed files with 1413 additions and 0 deletions

77
spec/screenshot.md Normal file
View File

@@ -0,0 +1,77 @@
# Screenshot Spec (WE-S)
## Overview
Captures full-page screenshots of a URL at desktop and mobile viewport sizes
using Playwright (Chromium). Screenshots are saved as PNG files to the output
screenshots directory.
## Responsibilities
- Launch a Playwright Chromium browser
- Capture a full-page desktop screenshot (1440×900 viewport)
- Capture a full-page mobile screenshot (375×812 viewport, mobile UA)
- Save both as PNG to the screenshots directory
- Return the browser instance for DOM analysis reuse
Delegates to: Playwright
## Dependencies
Read [pipeline.md](pipeline.md) for output directory layout.
## Data Model
### Viewport configs
```js
const DESKTOP = { width: 1440, height: 900, deviceScaleFactor: 1 };
const MOBILE = { width: 375, height: 812, deviceScaleFactor: 2, isMobile: true,
hasTouch: true, userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0...' };
```
### Output
```
screenshots/desktop.png — full-page, lossless PNG
screenshots/mobile.png — full-page, lossless PNG, 2× pixel density
```
## Requirements
**WE-S-1:** Navigate to the URL and wait for `networkidle` before capturing.
Why: Ensures lazy-loaded content and web fonts are rendered.
**WE-S-2:** Capture a full-page screenshot (not just the visible viewport).
Why: Full-page screenshots let Claude see below-the-fold content.
**WE-S-3:** Desktop viewport: 1440×900, deviceScaleFactor 1, no mobile emulation.
**WE-S-4:** Mobile viewport: 375×812, deviceScaleFactor 2, mobile UA, touch enabled.
The mobile UA string should identify as an iPhone running Safari to maximise
site responsiveness compatibility.
**WE-S-5:** Save format: PNG (lossless). Do not use JPEG.
Why: Lossless preserves fine text and UI details important for design critique.
**WE-S-6:** The function must accept an already-open Playwright browser instance
(not launch its own) so the caller can reuse the session for DOM extraction.
**WE-S-7:** Both screenshots must be saved before returning.
## Scenarios
### Scenario: Happy path
**Given:** Valid browser instance, reachable URL, writable screenshots dir
**When:** `captureScreenshots(browser, url, screenshotsDir)` is called
**Then:** `desktop.png` and `mobile.png` exist in `screenshotsDir`, both non-zero bytes
### Scenario: Navigation timeout
**Given:** URL that times out (server unresponsive)
**When:** Page navigation exceeds 30s
**Then:** Error is thrown with the URL and "navigation timeout" in the message
### Scenario: Page with no content
**Given:** URL that returns an empty 200 response
**When:** Screenshots are captured
**Then:** Screenshots are saved (may be blank); no error is thrown