Screenshot Loop

Generate UI → start dev server → screenshot at 1440x900, 1920x1080, 3440x1440 → review against gridalpha-terminal skill rules → i…

aquilesguerretta updated 2mo ago
Claude CodeGeneric
View source ↗
---
name: screenshot-loop
description: Generate UI → start dev server → screenshot at 1440x900, 1920x1080, 3440x1440 → review against gridalpha-terminal skill rules → iterate until all three viewports pass.
---

# Screenshot Loop

After generating any new UI surface or modifying an existing one, invoke
this loop to close the code → screenshot → critique cycle. Without
visual feedback you are flying blind; with it you catch your own slop
before CHROMA's pass or the review.

## What you are doing

GridAlpha's primary viewports are **1440×900** (typical terminal),
**1920×1080** (large desktop monitor), and **3440×1440** (ultrawide —
real trader monitors). Composition that reads correctly at 1440 can
look sparse and empty at 3440, and dense layouts that work at 3440 can
crush at 1440. You must check all three before declaring a phase done.

Mobile viewports are intentionally out of scope. GridAlpha is not
mobile-first.

## Steps

### 1. Confirm a dev server is running

Try the existing dev server first via the `mcp__Claude_Preview__*`
tools (they are usually configured in `.claude/launch.json`). If the
preview server is not running, start it:

preview_start name=GridAlpha Dev


If `preview_start` is unavailable for some reason, fall back to
launching `npm run dev` via the Bash tool with `run_in_background:true`
and wait ~3 seconds for Vite to boot.

### 2. Navigate to the surface under review

Use `playwright_navigate` (or `mcp__Claude_Preview__preview_eval` with
`window.history.pushState` + a popstate event) to land on the surface
you just changed. Dismiss the splash screen if it's present (it covers
the first ~2 seconds of cold load).

### 3. Capture screenshots at all three viewports

For each viewport in `[{ width: 1440, height: 900 }, { width: 1920, height: 1080 }, { width: 3440, height: 1440 }]`:

1. Resize the browser viewport (`playwright_resize` or
   `mcp__Claude_Preview__preview_resize`).
2. Wait ~500 ms for the layout to settle.
3. Capture (`playwright_screenshot` or
   `mcp__Claude_Preview__preview_screenshot`).
4. Save the image into the conversation with a clear caption — the
   model receives it as an image attachment and can read it.

### 4. Review each screenshot against the design rules

For every screenshot, run the following checks:

- **Task design intent** — does the rendered UI match the brief you
  were given? Spacing, hierarchy, content, density?
- **Antipatterns** — read
  `.claude/skills/gridalpha-terminal/references/terminal-antipatterns.md`.
  Any pill buttons, gradients, glassmorphism, neon-cyan accents,
  Roboto/system-ui fonts, box-shadow elevation, layout-altering
  animations? **Each is a defect.**
- **Composition** — read
  `.claude/skills/gridalpha-terminal/references/terminal-composition.md`.
  Is there exactly one focal element per screen (HERO)? Are the
  supporting sections in FLOW rhythm with consistent vertical spacing?
  Are data cards CONTAINED with the 1px top accent + 1px borders?
- **Density** — read
  `.claude/skills/gridalpha-terminal/references/terminal-density.md`.
  At 3440×1440 in particular, does the layout fill the viewport with
  meaningful information, or does it look sparse?
- **Tokens** — every color a `C.*` token, every spacing an `S.*`
  token, every radius an `R.*` token. No raw hex outside `tokens.ts`.

### 5. List the visual issues

Be specific. "The hero number looks small" is not actionable. "The
hero number is `HeroNumber size=80` at 3440×1440 and appears too
small relative to the supporting metrics" is.

### 6. Revise and re-loop

Fix the code, jump back to **Step 3**. Continue until all three
viewports pass every check.

### 7. Capture the final screenshots in your commit

After the loop converges, paste the final three screenshots into the
turn before you commit. They go into the commit context so future
agents (and CHROMA) can see what shipped.

## Error handling

### Dev server is not running

`preview_start` returns "Server failed to start" or the navigate call
404s. Run `npm run dev` via Bash (`run_in_background: true`) and wait
3 seconds before retrying. If the server is already running but on a
different port, update `.claude/launch.json`'s `port` entry locally
for this session only — do not commit a port change.

### Screenshot times out

The Vite renderer is heavy (Mapbox + Spline + Recharts). A 30 s
timeout on the first screenshot is **normal at 1440×900 and very
common at 1920+**. Procedure:

1. Retry once. ~1/3 of the time the second attempt succeeds.
2. If it times out again, the page may be stuck on the splash —
   dismiss with `document.body.click()` via `preview_eval`, then retry.
3. If it still times out, **fall back to DOM inspection**: use
   `preview_eval` to read `getComputedStyle()` on the target element
   and bounding-rect for layout. This produces the same defect
   signal (font size wrong, color wrong, position off) without
   requiring a captured pixel image. The Phase 4 and Phase 6 tests
   in `tools/screenshot-loop/` both used this fallback path for the
   1920+ viewports.

You are NOT blocked by a screenshot timeout. Continue the loop using
DOM inspection and visible-when-narrow screenshots.

### Port conflict

Default port `5173` is taken by another Vite project. Vite
auto-selects the next free port (5174, 5175, …). Read the dev
server's stdout to find the real port. Update `.claude/launch.json`
locally for this session only — do not commit the port change.

### Playwright MCP not loaded

If `playwright_screenshot` is not in the tool list, either:
- The Claude Code session was started before `.mcp.json` was added.
  Restart the session.
- The `@playwright/mcp` package failed to download. Run
  `npx -y @playwright/mcp@latest --help` once via Bash to warm the
  cache, then retry.

In the meantime, the `mcp__Claude_Preview__*` tools provide
`preview_screenshot` and `preview_resize` and are functionally
equivalent for this loop. Use them — the loop's value is in the
feedback signal, not in

Maintain Screenshot Loop?

Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.

[Screenshot Loop on getagentictools](https://getagentictools.com/loops/aquilesguerretta-screenshot-loop?ref=badge)
npx agentictools info loops/aquilesguerretta-screenshot-loop

The second line is the CLI lookup for this page — handy in READMEs and docs.