Shoot the README screenshots, and make them regenerable

The screenshot section had been a placeholder since the shell was rebuilt as
three panes, because there was no cheap way to re-shoot and a stale image is
worse than no image. So this ships the capture, not just the captures:
scripts/screenshots.mjs takes all ten pages at 1440x900 and 393x852, in light
and dark, and screenshots-encode.py halves and re-encodes them to WebP — 16MB
of PNG becomes 1.9MB in the tree.

Two things would silently ruin a run, and the script exists to encode both.
Seeding localStorage['pig.themeMode'] is not enough: the appearance preference
is authoritative server-side and adopted after hydration, so every dark capture
snapped back to light a beat after first paint. The /api/me/profile response is
rewritten instead. And pig.sidebarOpen / pig.piggyDockOpen are per-device, so
whatever the last human left behind would otherwise leak in. The run also fails
on a wrong theme, a horizontal scrollbar or a console error — three things a
screenshot cannot show you.

Piggy is not pictured mid-conversation. It is off by default and no inference
credential exists, so such an image would be a staged transcript rather than a
capture. The README says that rather than implying the feature is missing.

Correcting what the README asserted while shooting against the running code:
read authorisation IS enforced — createReadGuardRoutes is mounted ahead of the
feature routes, and routes/learn.ts and routes/activities.ts are mounted too,
so only the HubSpot pair is still unreachable. The remaining read gap is that a
grant cannot be narrowed, there being no row-level team filter in the query
layer. Counts refreshed against the tree: 275 tests, ~47k lines, 14 migrations.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-13 21:15:45 -07:00
parent 9db53cb36f
commit 10d79fc35d
44 changed files with 563 additions and 33 deletions
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""Downscale and re-encode the raw Playwright captures as WebP.
Called by scripts/screenshots.mjs; not useful on its own.
python3 scripts/screenshots-encode.py <raw-png-dir> <out-dir>
The captures are taken at 2x (desktop) and 3x (mobile) so text is sampled
cleanly, then halved here. Halving rather than keeping the full capture is
deliberate: a README renders images at roughly 850px wide, so a 2880px-wide PNG
buys nothing but repository weight. WebP at q86 takes the forty-image set from
about 16MB to under 2MB.
"""
from __future__ import annotations
import pathlib
import sys
from PIL import Image
QUALITY = 86
def main() -> int:
if len(sys.argv) != 3:
print(__doc__, file=sys.stderr)
return 2
src = pathlib.Path(sys.argv[1])
dst = pathlib.Path(sys.argv[2])
dst.mkdir(parents=True, exist_ok=True)
captures = sorted(src.glob("*.png"))
if not captures:
print(f"no PNG captures in {src}", file=sys.stderr)
return 1
before = after = 0
for png in captures:
image = Image.open(png).convert("RGB")
image = image.resize((image.width // 2, image.height // 2), Image.LANCZOS)
out = dst / f"{png.stem}.webp"
image.save(out, "WEBP", quality=QUALITY, method=6)
before += png.stat().st_size
after += out.stat().st_size
print(f"encoded {len(captures)} images: {before / 1e6:.1f}MB PNG -> {after / 1e6:.1f}MB WebP")
return 0
if __name__ == "__main__":
raise SystemExit(main())