Skip to content

Work / Charades / Wiki / Concepts

screenshot-seam

Conceptverified 2026-10-30

screenshot-seam

A capture build is this app with a few files swapped, so store screenshots can be captured from the running app rather than drawn. Under EXPO_PUBLIC_SCREENSHOT_MODE=1, metro.config.js resolves @/a/b to src/a/b.screenshot.ts wherever that file exists. The flag is set by scripts/build-screenshot-* and nowhere else.

App code holds no flag and no capture branch, so a store binary contains nothing of what a capture build runs. It used to: the app read a SCREENSHOT_MODE boolean in five places and the seeded game shipped in every store binary, dead. App Review rejects that pattern under guideline 5.6 (features "hidden during the review process"). src/config/seams.test.ts asserts the flag is in no eas.json, app.config.ts or .env*, that no app file reads it or imports a capture-only file, and that the swap does what it says.

The state lives in src/lib/screenshot-fixture.ts. Two files are swapped:

Swapped file What a capture build changes
config/seams.ts → seams.screenshot.ts ROUND_START: seeding movieResults also derives the score, renders the streak badge, and makes GameScreen skip the 3-2-1 overlay
STARTING_PACKS: three packs picked, every paid pack owned
FIRST_HISTORY: so the history screen is a list, not its empty state
startingPrices: RevenueCat refuses a Test Store key in Release, so prices would otherwise render empty
STORAGE_ID: a separate MMKV id; sharing one let a capture run's fake week survive into a normal build
lib/movie.ts → movie.screenshot.ts the deck: the Fisher-Yates shuffle is the only true randomness

A new source of difference is a new export in seams.ts and its twin in seams.screenshot.ts, never a branch in app code. Import a swapped module as @/…, never by a relative path: the swap matches on that spelling.

goldie reinstalls the app with cleared data before every flow, so none of this can be seeded by hand once; it has to reassert on every cold launch.

The fixture owns every paid pack, so no price or padlock reaches the store artwork. Capturing: .context/ops/runbooks/store-listing.md.