---
name: browser-screenshot-tooling
description: "How Claude captures rendered Evolution screenshots — browser-tools/shot.js (Playwright), dev login, image-size flags"
metadata: 
  node_type: memory
  type: reference
  originSessionId: 0dd434bc-8ce0-4ad3-8630-5739f5603fa8
  modified: 2026-07-20T03:02:00.427Z
---

Claude can *see* rendered Evolution pages via `/config/workspace/browser-tools/` —
a Playwright + headless-Chromium tool, `shot.js`. Chromium launches on demand and
tears down on exit (container is RAM-tight). Verified working end-to-end 2026-07-19.

**Usage:** `cd /config/workspace/browser-tools && node shot.js <app-path-or-url> [opts]`
then Read the PNG/JPEG it writes to `shots/` (git-ignored).

Key opts: `--env dev|live` (default dev), `--full`, `--selector <css>` (element-only),
`--jpeg [q]` / `--quality N` (default 80), `--scale <n>` (<1 = fewer pixels →
smaller file AND fewer AI tokens), `--fresh` (re-auth), `--no-login`, `--out`.

**Image size — two independent levers, both native (no reduce-script, no per-image
AI cost):** file bytes are set by JPEG/quality (docs-site concern); AI-token cost is
set by *pixel dimensions* not bytes, so use `--scale` to cut tokens. Docs sweet spot:
`--jpeg 82` (~1.5 MB PNG → ~50–280 KB, crisp). Default output stays lossless PNG.

**Login is TWO-stage** (username/password → company/tenant select); shot.js handles
both and caches the session in `.auth/<env>.json`. Selectors baked in: user
`input[name="username"]`, pass `input[name="password"]`, submit `input[name="login"]`,
success `#navdiv, a[href="logoff.php"]`, error `h2[style*="color:red"]`, company form
`#companySelectForm` (sets `#company`). The flow redirects login→login2→app; DOM reads
must wait for a settle selector or they hit "Execution context was destroyed" (fixed
via `settleOn()`).

**Dev web login** (shane.evolutionerp.com.au/evolution, tenant `85-1384947162` =
"MASTER TEST COMPANY"): user `claude@evolutionerp.com.au`, pass
`M15QL2023!_DEV3NV26`. Source of truth = `evolution/.env` defines `evoClaudeUser` /
`evoClaudePasswd`. NOTE: this is the *web* login; the same string is also the prod
DB password (see [[prod_mysql_access]]) — coincidence, they're separate systems.
**Cred source of truth = `evolution/.env` `evoClaudeUser` / `evoClaudePasswd`.**
`browser-tools/.env` EVO_DEV_USER/PASS are currently BLANK — don't trust them, and
don't grep for those names expecting values. shot.js reads env vars, so either export
`EVO_DEV_USER`/`EVO_DEV_PASS` inline from the evolution/.env values or let
`regen-docs.sh` derive them (it now `sed`-extracts evoClaudeUser/evoClaudePasswd from
`evolution/.env` at runtime — no hardcoded/duplicated secret). **Dev-only for now**; live (my.evolutionerp.com.au) stays blank until a
prod `claude` user exists — will mimic prod user creds then. For live, confirm before
any action beyond viewing/screenshotting.

**One-time setup after redeploy:** `codeserver-setup/install.sh` (root) does the
`npm install` + `playwright install --with-deps chromium` into shared `/ms-playwright`
(PLAYWRIGHT_BROWSERS_PATH). See [[codeserver_setup_scripts]]. shot.js self-defaults
that path if present.

Good pairing with [[feature_release_docs_policy]] — screenshots for docs pages.

**Reporting docs screenshots:** `browser-tools/regen-docs.sh` regenerates all
`evolution/docs/reporting/images/**` at **2560x1440 (1440P/QHD)** in one pass — this
is the standard docs resolution as of 2026-07-20 (was 1920x1080); shot.js default
viewport is also 2560x1440. Config array of
`out|app-path|shot.js-flags`). Gotchas baked in: (a) date-driven reports default to
FY-to-date (near-empty this early in the AU FY) — drive them to **FY2023/24** which is
the richest test-data year (1708 committed invoices, 53k GL postings; salesByRep/
salesByRepCustomers `#qbrYear::2023-07-01`+`#qbrRun`, invoicesByRep/Summary
`#ibrYear`+`#ibrRun`, finRevenue `#revFy::2023`+`#revRun`, finGst `#gstFy::2023`,
finPL fill `#plDate1/#plDate2`+`#plRun`, purSupplierSpend eval from/to+`runSupplierSpend()`);
(b) selection reports need ids: projectBillableItems `&id=5344` (Mezzanine
Design & Construct — 164 items, ~$1.1M invoiced; old id 7609 was purged
from dev), invitemhist
`&itemid=1243`, invbomrep eval cat 61+`fetchInventory()`, invBomRestock `&branch=1`
(branch 1 = "Olympus Fabrication Maitland" has the outstanding manufactured lines);
(c) the reports dashboard is `index.php?page=reportsdashboard` — capture the
**`.rd-dashboard`** element via `--selector`, NOT `--full`, because index.php has
in-progress debug scaffolding (`<div class="development container">`, ~L579-590)
dumping memory/included-files/$_SESSION/$_COOKIE at page bottom; card crops use
`.rd-cat-section[data-cat="financials"|"sales"]`.
