igneum/tools/site/capture.sh
igneum-labs 8e942cd0d5 site-ui-5: the phone menu is seen, the home fold hides the scene until the feed answers, /miner and /wallet show dark screenshots only, /live has no "you" (7 October 2026, 15:5x UK)
the project lead's three on the live site, plus the /live key's last item:
- Mobile nav (URGENT): the sheet was position:fixed inside the bar, and the bar's backdrop-filter is a containing block for
  fixed descendants, so top and bottom resolved against the 60 px bar and the sheet opened with zero height while
  aria-expanded said true. It is now absolute under the sticky bar, a viewport-tall box (100dvh minus the bar), display block
  over the package's grid rule. tools/site/sheet-test.mjs opens every page at 390 px, clicks the burger and asserts the first
  link is on screen and on top (elementFromPoint at its centre returns the link); --self-test forces a zero-height sheet first
  and must catch it; a gate line runs it where a browser exists (the box, CI) and says so where none does. On build-2: the
  zero-height sheet is caught, 23 pages pass.
- Home at 375: the renderer's "Waiting for observer data" was drawn on the fold's canvas under the lead. The fold now carries
  .pending until the feed is live or stale and keeps the canvas at opacity 0 meanwhile; the status pill is its own row under
  the buttons on phones. ?feed=off holds the pending state for a render; the overlap sweep (whose server answers /api with
  503) renders the pending state by construction and ran at 375, 390 and 1440 in both themes: 0 overlaps.
- /miner and /wallet: the light-theme screenshot variants are gone (dark only), captions unwrapped, "light and dark" dropped
  from the gallery line; one gallery of frames with one caption each.
- /live: "Your block" leaves the key, the "Your blocks" filter and tile and the Mark-my-key prompt leave the page (the site
  has no "you"); the stats row is three tiles; the key reads Included, Excluded, Selected chain, Proven, Locked checkpoint.
- Captures: ?motion=off (head partial) marks data-motion=off so every .reveal is drawn in a headless render; capture.sh passes it.
  tools/site/serve.mjs survives a refused api origin (502, never a crash).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-07 14:51:17 +00:00

36 lines
2.7 KiB
Bash
Executable file

#!/usr/bin/env bash
# Captures of every served route at 390 and 1440, dark and light (site-ui-5, 7 October 2026). Runs on igneum-build-2 (the
# Mac captures nothing: CLAUDE.md "Nothing heavy on the Mac"), one headless chromium at a time, against tools/site/serve.mjs
# on a port of its own with /api passed through to the live observer, so the chain scene paints from the real feed.
#
# tools/site/capture.sh <out dir> [<site dir>] [<chromium binary>]
# ROUTES="/ /live" tools/site/capture.sh <out dir> a subset
# WIDTHS="390 1440" THEMES="dark light" the defaults
#
# The binary defaults to Playwright's headless shell in ~/.cache/ms-playwright (the box has it); no npm package is needed.
# One PNG per route, width and theme: <route>__<width>-<theme>.png (the home is "home").
set -euo pipefail
OUT="${1:?out dir}"; HERE="$(cd "$(dirname "$0")" && pwd)"; SITE="${2:-$HERE/../../site}"; CHROME="${3:-}"
if [ -z "$CHROME" ]; then CHROME="$(ls -d "$HOME"/.cache/ms-playwright/chromium_headless_shell-*/chrome-linux/headless_shell 2>/dev/null | sort | tail -1 || true)"; fi
[ -x "$CHROME" ] || { echo "no chromium headless shell (pass its path as the third argument)" >&2; exit 2; }
PORT="${IGNEUM_SITE_PORT:-$((4500 + RANDOM % 400))}"
mkdir -p "$OUT"
node "$HERE/serve.mjs" "$PORT" "$SITE" > "$OUT/serve.log" 2>&1 &
SRV=$!
trap 'kill "$SRV" 2>/dev/null || true' EXIT
for i in $(seq 1 40); do curl -fsS "http://127.0.0.1:$PORT/" > /dev/null 2>&1 && break; sleep 0.25; done
curl -fsS "http://127.0.0.1:$PORT/" > /dev/null || { echo "the site did not answer on $PORT" >&2; cat "$OUT/serve.log" >&2; exit 3; }
ROUTES="${ROUTES:-/ /download /miner /app /wallet /live /explorer /journey /bench /evidence /litepaper /ledger /claims /randomx /provenance /miners /dev-fee /faucet /metamask /404}"
WIDTHS="${WIDTHS:-390 1440}"; THEMES="${THEMES:-dark light}"
shot() { # <route> <width> <theme>
local route="$1" width="$2" theme="$3" name height
name="${route#/}"; name="${name:-home}"; name="${name//\//-}"
if [ "$width" -le 480 ]; then height="${IGNEUM_SHOT_H_PHONE:-2400}"; else height="${IGNEUM_SHOT_H_DESKTOP:-1600}"; fi
local file="${name}__${width}-${theme}.png"
"$CHROME" --headless --no-sandbox --disable-gpu --hide-scrollbars --force-device-scale-factor=2 \
--window-size="$width,$height" --virtual-time-budget=12000 --run-all-compositor-stages-before-draw \
--screenshot="$OUT/$file" "http://127.0.0.1:$PORT$route?theme=$theme&motion=off" > "$OUT/$file.log" 2>&1 || { echo "FAILED $file"; cat "$OUT/$file.log"; return 1; }
echo "$file $(stat -c %s "$OUT/$file" 2>/dev/null || stat -f %z "$OUT/$file") B"
}
for r in $ROUTES; do for w in $WIDTHS; do for t in $THEMES; do shot "$r" "$w" "$t"; done; done; done
echo "done: $OUT"