| name | app-store-screenshots |
| description | Capture App Store / TestFlight screenshots from the iOS Simulator at native resolution, downscale to every required display size, and upload to App Store Connect via helm-asc. Use when asked to take/produce/refresh App Store screenshots, marketing screenshots, or screenshots for custom product pages. |
App Store Screenshots
Capture native-resolution screenshots on the simulator, downscale to the other required sizes, upload via helm-asc.
Sizes (only TWO files per screen are actually needed)
| Display | Pixels | Device |
|---|
| 6.9" | 1320×2868 | iPhone 16/17 Pro Max (capture native here) |
| 6.7" | 1290×2796 | downscale from 6.9" |
| 6.5" | 1242×2688 | downscale from 6.9" |
Aspect ratios differ <0.4%, so downscaling 6.9"→6.7"/6.5" is visually lossless. If the app's deployment target is iOS 26+, no real 6.5"-class device can run it — those sizes MUST be derived from a 6.9" capture, never captured natively.
Capture pipeline
- Boot the largest Pro Max sim and build/install:
flowdeck simulator boot <udid>; flowdeck run -S <udid> -d ios/DerivedData-shots. Find the UDID with flowdeck simulator list (pick an iPhone 17/16 Pro Max).
- Clean status bar:
flowdeck simulator status-bar override -S <udid> --time "9:41" --data-network 5g --wifi-mode active --wifi-bars 3 --cellular-mode active --cellular-bars 4 --battery-state charged --battery-level 100. Re-assert it before each capture (navigation can reset it).
- Capture at NATIVE resolution — use
flowdeck simulator frames --images -S <udid> -t 1s --fps 2 -o <dir>, then take frame-000-*.png (1320×2868). ⚠️ Do NOT use flowdeck ui simulator screen --screenshot for the deliverable — it returns POINT resolution (440×956 @1x), which ASC rejects. frames --images is the native-res path.
- Navigate with
flowdeck ui simulator screen --json (read the a11y tree) + flowdeck ui simulator tap "<label>" or tap --point x,y (point coords from the tree). Re-assert status bar, capture each screen.
- Downscale to the other sizes:
sips -z 2796 1290 6.7/NN.png and sips -z 2688 1242 6.5/NN.png (note sips -z is height-then-width).
Upload via helm-asc
helm-asc is sandboxed — it can't read arbitrary paths. Stage the tree in its inbox:
INBOX=$(helm-asc paths --agent | python3 -c "import json,sys;print(json.load(sys.stdin)['uploadsInbox'])")
# Build <path>/<locale>/<deviceType>/NN_name.png e.g. en-US/APP_IPHONE_67/01_home.png
helm-asc version <version-id> screenshots upload --path "$INBOX/<dir>" --dry-run # validate first
helm-asc version <version-id> screenshots upload --path "$INBOX/<dir>"
- Device types:
APP_IPHONE_67 (6.7"), APP_IPHONE_65 (6.5"). helm-asc does not support APP_IPHONE_69 — the 6.9" native set must be added through the ASC web UI if wanted (the 6.5" tier satisfies Apple's required iPhone size, so 67+65 is a valid submittable set).
- The
NN_ filename prefix sets display order in ASC.
- Custom Product Pages can't be created or populated by helm-asc — those are ASC-web-UI only; reuse the same
.shots/ folders there.
Gotchas
- You cannot CLI-screenshot a physical device. Network-connected devices route through CoreDevice;
idevicescreenshot/libimobiledevice only speak legacy usbmuxd and won't see them, and the RocketSim/flowdeck CLIs are simulator-only. For real-device shots (e.g. a signed-in premium account), have the user take them on-device and AirDrop them (they land in ~/Downloads, native 1320×2868).
- Gated screens: in signed-out "Explore"/guest mode the player shows a premium error and Stats/streaks does nothing. The paywall is reachable signed-out via Settings → Subscribe. A clean "playing" player and real Stats need a signed-in account — either sign one into the sim or use AirDropped device shots.
- Real-device shots carry a real status bar (time/battery), not 9:41 — acceptable for App Store, but note the inconsistency vs the sim's 9:41 shots; RocketSim's GUI can overlay a clean status bar on device captures if needed.