pr-snapshots
Invoke whenever a pull request changes what the viewer shows (a look, a layer, a bake that alters the picture, a palette, a post pass). Every such PR carries JSON snapshots the reviewer pastes into th
SKILL.md.claude/skills/pr-snapshots/SKILL.md
GitHubPR snapshots
The maintainer reviews visual changes by looking at them in the PR's Vercel preview, at the places the author picked. So a PR that changes what the viewer shows is not ready for review until its description has a Snapshots section. Screenshots are optional: a SwiftShader render is slow and lies about light and shadow, so add them only when they are cheap and say that they are SwiftShader. The JSON is the deliverable.
What counts as visual
Anything a reviewer would judge by eye: a scene material or shader term, a layer or its dressing, a bake whose output changes the picture (land cover, trees, facades, rails, …), the palette, a post pass or picture style, the sky and the sun, the HUD's look. A pure refactor, a test, a doc or a pipeline change that writes the same files needs none.
The section
Put it in the PR description (not a comment, so it stays at the top as
the PR evolves), under ## Snapshots:
- One line on how to use them: open the preview at the site's route
(
/dresden, …), sidebar Erweitert → Snapshot, paste one JSON, Anwenden. Link the preview deployment when it exists. - Two to five views, each named after the place in a few words (Königsbrücker Straße, schräg von oben), with one sentence on what to look for there.
- Per view a
<details>block holding the snapshot JSON in a ```json fence, so the description stays short. - Before and after in one place where the change has a control:
give the pair as two snapshots that differ only in that look key
(e.g.
"look": {"fogPct": 0}vs100,"style": "pastel"vs"comic"), so the reviewer flips between them in the same preview. Only Nebel, the picture style and the data layers are controls; the rest of the look is fixed — named constants in the code (ADR 0018, plan 073) — so a change to it has no look key: say that before is the same snapshot on the production site or the base PR's preview. - On a stacked PR, say which preview shows the base.
Keep look to the keys the comparison needs: a snapshot's look keys are
all optional, and every key left out keeps the reviewer's current value
(set fogPct and style when the view depends on them). Never write a
retired key (RETIRED_SNAPSHOT_KEYS in lib/city/look-controls.ts):
it is ignored, and suggests a slider that is not there.
Set date to an instant whose light shows the change (afternoon sun for
relief and shadow, night for lamps).
Getting the JSON
A snapshot is { v: 1, camera, date, look? } (lib/city/snapshot.ts,
checked by parseSnapshot; camera needs pos in the Y-up scene frame
and epsg, so capture it rather than writing it by hand):
- In a running viewer: sidebar Erweitert → Snapshot → Kopieren, or
__poc.handle.getCameraState()(the page needs a build withNEXT_PUBLIC_POC_DEBUG=1or the dev server). Link kopieren gives the same view as a link (?snap=…): put it next to the JSON, with the preview's origin, and the reviewer opens it in one click. - A committed QA view (
qa/views/, its index has the links) may already show the place: reuse it. - Headless, at a place given in EPSG: place the camera with
__poc.handle.flyToViewpointorapplyCameraState, wait for__poc.firstFrame, then readgetCameraState(). The camera needs the spawn tile only, so?scene=liteis enough to capture a pose (never to judge pixels). - Check a hand-trimmed JSON with
parseSnapshotbefore posting it.
Pick views from oblique angles, at the height a reviewer would stand or fly, where the change is on screen and not hidden behind a tree crown or inside a building (AGENTS.md, Verify renders from oblique angles).
Screenshots, when cheap
bun run shots (e2e/snapshot-shot.spec.ts, headed, a real GPU) turns
the same snapshots into plates when a GPU is at hand. In the cloud
container there is none: a SwiftShader render of the full profile takes
minutes per view and leaves out night lamps and late trees, so post such
images in the conversation if at all, marked as SwiftShader, and never
hold the PR for them.