7.4 KiB
| name | description |
|---|---|
| store-screenshots | Produce store screenshots and the Play feature graphic for a mobile game in every required size and many languages - capture raw frames from the running game (web build via playwright, iOS Simulator via simctl, Android emulator or device via adb, or a folder of frames from any engine), write per-language marketing copy (incl. RTL Arabic and CJK fonts), render captioned scenes with device frames, JPEG copies for Play, and upload to both stores. Use when the user needs App Store / Google Play screenshots, preview images, a feature graphic, localized screenshot captions, or screenshot sizes. |
Store screenshots
CLI: storebound (or bunx storebound in a project that has it, or bun <toolchain>/cli/index.ts). Needs ffmpeg, and playwright in the project
(bun add -d playwright; it uses Playwright's Chromium or an installed Google Chrome) for rendering and web capture.
iOS Simulator capture needs macOS + Xcode (xcrun); Android capture needs adb (platform-tools).
Sizes (what each store wants)
| size key | pixels | where |
|---|---|---|
| ios69 | 1320 x 2868 | App Store 6.9" (APP_IPHONE_67), required |
| ios65 | 1284 x 2778 | App Store 6.5" (APP_IPHONE_65) |
| ipad13 | 2064 x 2752 | App Store 13" iPad (APP_IPAD_PRO_3GEN_129), required when the app runs on iPad; only with apple.ipad: true |
| play | 1080 x 1920 | Play phone (2-8, ratio at most 2:1) |
| tab7 | 1080 x 1920 | Play 7" tablet (tablet frames) |
| tab10 | 1440 x 2560 | Play 10" tablet |
| feature | 1024 x 500 | Play feature graphic (required) |
Sources (re-check before a release; Apple renames display classes often):
- Apple "Screenshot specifications": https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications (13" iPad: 2064 x 2752 or 2048 x 2732, landscape too, "Required if app runs on iPad"; 1-10 per size; JPEG / PNG, no alpha or transparency).
- ASC API
ScreenshotDisplayType: https://developer.apple.com/documentation/appstoreconnectapi/screenshotdisplaytype (there is no "13 inch" value: the 13" iPad set isAPP_IPAD_PRO_3GEN_129). - Play graphics: https://support.google.com/googleplay/android-developer/answer/9866151 (screenshots 320-3840 px, at most 2:1, JPEG or 24-bit PNG, 8 MB; feature graphic 1024 x 500).
iPad. Set apple.ipad: true only if the app runs on iPad (iPhone-only apps skip the iPad set). Then the default
sizes include ipad13 (3:4 layout), apple screenshots uploads it, validate requires it, and tablet frames default
to the 13" iPad screen (1032 x 1352 CSS px @2x below a 24 px bar), so an iPad Pro 13-inch / iPad Air 13-inch
simulator screenshot fits after the bar is cropped. Play tablet sizes (tab7 / tab10) reuse the same tablet frames.
Steps
- Game switches. Give the game URL params for screenshots: language, fixed seed, no ads / analytics / purchase UI, skip tutorial, jump to a level, freeze at a moment. Frames must show real gameplay (store rule).
- Capture. Configure
shots.capturewith asource(or pass--source), thenstorebound shots capture --lang en --dryto see the plan, and without--dryto capture. Frames land in<shots.frames>/<lang>/<phone|tablet>/<shot>.png, local, not committed.web(default):baseUrl,querywith{lang}, shots:path/waitFor/eval/delayMs/device. Phone 440 x 902 @3x and tablet 800 x 1240 @2x by default; the template draws the status bar above.ios-sim(Unity, Godot, Flutter, native, Capacitor: any Simulator build):ios.device(simulator name or UDID, e.g. a 6.9" iPhone),ios.bundleId, optionalios.app(.app to install),ios.args. Per shot:args(launch arguments, read them with UserDefaults / your engine) and / orurl(deep link). Language goes in as-AppleLanguages/-AppleLocale; status bar is forced to 9:41, full battery. After a cold boot the app is launched once and givenios.warmupMs(default 8000) before the first shot; without it the first frame of a fresh simulator is often blank. A simulator storebound boots is shut down afterwards (--keep-bootedkeeps it). For iPad shots setios.devices.tablet(e.g. "iPad Pro 13-inch (M5)") anddevice: 'tablet' | 'both'per shot.android-emu:android.package, optionalserial,activity,apk. Per shot:url(VIEW intent) and / or typedextras. Demo-mode status bar; per-app language on Android 13+ (older: pass{lang}in an extra). Nothing is wiped or rebooted.folder: frames made any other way;shots capture(andshots check) only verify that every frame the scenes use exists with the right aspect ratio and resolution.{lang},{locale},{shot}are replaced in args, extras and URLs. Simulator / emulator screenshots losecropToprows (the status bar) so they fit the template: by default the frame's bar share per device class (162 px on a 6.9" iPhone, 48 px on a 13" iPad withapple.ipad); setcropTop: 120or{ phone, tablet }for other devices, andshots.phone/shots.tabletto that device's screen in points. Capture warns when a frame's aspect does not match. Give the game time to load:delayMs(simulator / emulator; 2500 default is short for a cold start) orwaitFor(web).
- Copy.
store/shots/copy.json: per language, per scene:eyebrow,title[white line, gold line],sub,badgesbig, small. Short and true (only claim what is in the game); about 15 Latin characters per title line. Natural marketing tone per language, not literal translation; use the game's own terms. - Fonts.
storebound shots fontsdownloads title/body fonts and a Noto subset for every non-Latin script found in the copy (CJK, Arabic, Hebrew, Devanagari, Thai, Cyrillic/Greek). Re-run after copy edits. - Scenes.
shots.scenes: palette (fire, violet, blast, green, night, sky, gold, candy or custom), frames (one front phone + optional back phones with x / dy / scale / rotate), badge slots (y, side, icon, hot, stars). - Render.
storebound shots render --lang enfirst, reviewstore/renders/en/sheet.png(contact sheet), then all languages in the background:storebound shots render > .storebound/render.log 2>&1 &. - JPEG for Play.
storebound shots jpeg(q92, about 4x smaller than PNG; App Store stays PNG). - Check.
storebound shots check(read-only, exit 1 on errors): pixel sizes (Apple: a listed size, portrait or landscape; Play screenshots 320-3840 px at most 2:1; feature graphic exactly 1024 x 500), alpha, Play JPEG / 24-bit PNG and 8 MB, counts per set (Apple 1-10, Play 2-8), text overflow flags (warnings).--variantsalso checks A/B variant folders.storebound validateruns the same checks on the renders folder and lists errors as blockers next to the store state (--no-localskips them). - Upload.
storebound play imagesandstorebound apple screenshots(both idempotent, background + log).
Gotchas
- Output is 24-bit RGB PNG: Play rejects alpha / palette PNGs, Apple rejects alpha.
- Arabic:
rtl: trueon the language; numbers stay LTR inside RTL text automatically. - Japanese breaks by phrase, Korean at spaces; long words shrink the line rather than wrap.
- Check every language's sheet for overflow before uploading; German / Russian titles run long.
- Play: 8 per type max; Apple: 10 per set max.
- Do not include prices, "free" badges for paid items, or other platforms' UI.