算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
visual-feedback-loop【设计与创意】AI agent visual feedback loop for any web app. Use when iterating on visual code (UI, canvas, 3D, SVG, charts, animations) and you need to SEE the rendered result to evaluate quality. Covers: dev-screenshot API pattern (GET trigger → SSE → client capture → POST back → file saved), parameterized rendering, metadata sidecars, visual regression with pix…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Capture, inspect, and compare visual output from a running web app during iterative development.
Agent (CLI) Server Browser
|--- GET /api/dev-screenshot -->|--- SSE "capture" ----------->|
| ?param=value | |-- capture canvas
| |<-- POST { dataUrl } ---------|
| | writes:
| | .screenshots/{UTC}.webp
| | .screenshots/{UTC}.json (metadata)
| | .screenshots/latest.webp (convenience copy)
|<-- { ok, path, latest } ------|
Agent can't access the browser directly. Server relays: GET triggers → SSE notifies browser → browser captures and POSTs back → GET resolves.
Capture current view:
curl http://localhost:3000/api/dev-screenshot
Capture with params (app-specific — browser client interprets them):
curl 'http://localhost:3000/api/dev-screenshot?component=header&theme=dark'
curl 'http://localhost:3000/api/dev-screenshot?letter=б&depth=0.8'
Then read the result. Response includes path (timestamped file) and latest (convenience copy):
Read .screenshots/latest.webp
Compare against a ground truth screenshot using ImageMagick:
magick compare -metric RMSE .screenshots/ground-truth.webp .screenshots/latest.webp .screenshots/diff.webp
RMSE output: 0.01 = ~1% difference (rendering noise), 0.03+ = visible change. Save diff image for inspection.
Each screenshot gets a JSON sidecar with the same UTC timestamp:
{
"timestamp": "2026-02-25T08:22:12.655Z",
"git": { "commit": "0a5726f", "dirty": true },
"params": { "letter": "о", "chamferModel": "membrane", "cameraView": "front" },
"format": "webp",
"file": "2026-02-25T08-22-12-655Z.webp"
}
Use this to trace which code state + params produced a screenshot — critical when iterating across multiple code changes.
curl '...?letter=о' → note the {UTC}.webp filenamecurl '...?letter=о'magick compare -metric RMSE .screenshots/{ground-truth}.webp .screenshots/latest.webp .screenshots/diff.webpConsole fallback: await window.__takeDevScreenshot()
Read .screenshots/latest.webp after capture. Never assume the render is correct.{ ok: false, error: "..." }.globalThis so it survives module reloads. EventSource auto-reconnects on the client. If screenshots still fail after code changes, ask user to refresh.useEffect capture stale module references. After code changes to rendering logic, always ask user to hard refresh (Cmd+Shift+R on macOS, Ctrl+Shift+R on Windows/Linux).| Symptom | Fix |
|---|---|
| Timeout: browser did not respond | Open/refresh app in browser |
| 409: already in progress | Wait for timeout (10s) |
| Black/empty image | Refresh browser tab |
| Works once, then times out | HMR broke SSE — refresh tab (rare if using globalThis pattern) |
| Code changes not reflected in screenshots | HMR doesn't update offscreen renderers — hard refresh (Cmd+Shift+R on macOS, Ctrl+Shift+R on Windows/Linux) |
| Comparing screenshots from different code states | Check JSON sidecar for git commit + dirty flag |
See references/errors.md for full error reference.
The pattern is framework-agnostic — it only requires an HTTP server with GET/POST routes and SSE. The reference implementation uses Next.js, but the same approach works with Express, Fastify, Hono, Vite dev server plugins, or any Node.js HTTP server.
See references/setup-nextjs.md for a complete Next.js implementation (API route, SSE listener, WebMCP registration). Adapt the route handler to your framework — the client-side SSE listener and capture logic are identical regardless of server framework.