agentleFS
mikezamayiasmikezamayias/agent-skills/skills/app-screenshots/SKILL.md

app-screenshots

Skill1 starsChanged 28 days agoBSD-3-ClauseView on GitHub

Runs the App Store and Play Store screenshot pipeline for a Flutter, Swift or Kotlin app. Covers compliance, capture, framing and locales. Use when preparing submission-ready store screenshots or framing captures, deferring to asc-* skills.

6 other projects use a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this skill into the rules it gives an agent

22 rules. 0 are common, 17 are distinctive, and 5 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 17

    Distinctive

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    If neither exists, skip to the framing-only path (skill prompts the human to confirm).

    line 42
  2. Distinctive:

    If neither exists, the skill prompts the human to draft a 6-screen sequence + caption matrix before going further.

    line 66
  3. Distinctive:

    Before drafting captions, write the one-sentence value prop and the one deck-level outcome described in that reference.

    line 68
  4. Distinctive:

    Keep Apple-designated recognitions such as Editor's Choice or App of the Day, and unverifiable awards, out of the screenshots.

    line 69
  5. Distinctive:

    When the app has an in-app language switch, use it for locale fan-out instead of changing the device language, because it is faster.

    line 72
  6. Distinctive:

    If the project does not declare its locales, ask the human.

    line 73
  7. Distinctive:

    Do both steps, and check the live product page on a device after approval.

    line 103
  8. Distinctive:

    Never use a generated device render as a store screenshot.

    line 109
  9. Very specific:

    Before asc screenshots upload, write a slide-by-slide table (slide, headline, real screen yes or no), and do the same for decks designed by …

    line 128
  10. Distinctive:

    Only the build and capture steps differ.

    line 134
  11. Very specific:

    Look for scripts/render-*.sh, a StoreScreenshotTests file, or an environment switch that turns render tests on.

    line 139
  12. Distinctive:

    Run the script and read its output folder.

    line 140
  13. Distinctive:

    Use an AVD that yields 1080×1920 or frame the capture to 9:16 as above.

    line 168
  14. Distinctive:

    Put the hook in the first seconds, because the preview autoplays muted when the product page opens.

    line 195
  15. Distinctive:

    Do not quote an install lift for app previews.

    line 210
  16. Very specific:

    Do not write a custom Python framing pipeline.

    line 219
  17. Very specific:

    If a locale cannot be captured or framed correctly, log it as Stuck in store_assets/SCREENSHOTS_LOG.md and ask the human.

    line 221
  18. Distinctive:

    Never draw a framed device bigger than its source bitmap.

    line 227
  19. Very specific:

    Put the check in the layout helper itself, for example a function that throws when scale > 1, so a later layout change cannot bring the …

    line 230
  20. Distinctive:

    When a composition needs a bigger device, render the raw screenshot at a higher scale and frame that, instead of upscaling a framed bitmap.

    line 231
  21. Distinctive:

    If a Koubou frame has to stay, erode its alpha by 1 px and composite it onto the final background colour, never onto white first.

    line 234
  22. Distinctive:

    Verify every device placement by cropping it at native size and at 300 to 400 percent against its final background, and look for soft text, …

    line 235

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

app-screenshots

Single skill for the screenshot pipeline — App Store + Play Store, release flavor only, production environment. The pipeline reuses the asc App Store Connect CLI and any installed App Store Connect skills; this skill is the orchestrator on top.

When to invoke

User says: "take store screenshots", "generate App Store shots for X", "do the screenshot run", "ship screenshots for tomorrow's submission", "frame the captures I just did".

Activation rules

  1. CWD must be a project root: Flutter (pubspec.yaml), native Apple (project.yml, *.xcodeproj or Package.swift) or native Android (settings.gradle.kts with gradlew).
  2. Mobile-mcp must be connected for capture, or the project must have its own capture path (see "Native Swift and Kotlin projects"). If neither exists, skip to the framing-only path (skill prompts the human to confirm).

Phases

PhaseWhatTooling
0Compliance pre-flight — block capture if red items remainlaunch-readiness --tier 1, App Store Connect ASO and submission-health checks
1Production release build, signedXcode archive, signing, and build upload tooling (for example the asc CLI)
2Capture via mobile-mcp on an iPhone simulator + Pixel 8 Pro AVD, or the native paths belowmobile-mcp tools, xcrun simctl, adb, or the project's render tests
3Frame via Koubou (pinned to 0.20.0)Koubou
4Locale fan-outApp Store Connect metadata and subscription localization
5Pre-submit final gateApp Store Connect submission check
6Upload to App Store Connect / Play Consoleasc CLI screenshot upload, Play Console listing upload

Per-app spec input

The skill expects to find the app's screen sequence + captions at one of these paths (project-managed):

store_assets/
├── README.md                              # documents intent + sequence
└── templates/screenshot_text.json         # captions per locale (en, es, de, …)

If neither exists, the skill prompts the human to draft a 6-screen sequence + caption matrix before going further. Do not invent the sequence — reviewers reject screenshots that don't match the app's actual UX. Draft and review captions with references/copy-and-design.md before capture, so each capture is chosen to prove its headline. Before drafting captions, write the one-sentence value prop and the one deck-level outcome described in that reference. Keep Apple-designated recognitions such as Editor's Choice or App of the Day, and unverifiable awards, out of the screenshots.

Locales: read them from store_assets/templates/screenshot_text.json. When the app has an in-app language switch, use it for locale fan-out instead of changing the device language, because it is faster. If the project does not declare its locales, ask the human.

Output paths

store_assets/screenshots/
├── raw/<locale>/                # native sim/emulator capture
│   ├── 01_<screen-id>.png
│   ├── 02_…
│   └── …
└── framed/<locale>/             # Koubou-framed marketing version
    ├── 01_<screen-id>.png
    ├── 02_…
    └── …

iOS target: the required iPhone slot, which Apple now labels "iPhone with Dynamic Island (medium display)", at 1206×2622 or 1179×2556 portrait. Apple accepts either size and does not tie either one to a device. Capture at the chosen size on a simulator that produces it, never by resizing a capture from another size. The slot labeled "iPhone with Dynamic Island (large display)" (1260×2736, 1290×2796 or 1320×2868) has no requirement line. Apple says that when the interface is consistent across sizes, only the highest required resolution is needed and App Store Connect scales it down. Apps that run on iPad also need 13" iPad screenshots (2064×2752 or 2048×2732). App Store Connect accepts 1 to 10 screenshots per device size and locale, as PNG or JPEG without alpha.

iPhone Duo: outer display 1398×2034 or 2034×1398, inner display 2007×2853 or 2853×2007. Apple's screenshot specifications require Duo screenshots starting April 2027 for apps built with the iOS 27.1 SDK or later, and the October 5, 2026 developer news says any app submitted from April 2027. Submitting Duo screenshots in App Store Connect adds a badge to the product page. Apple's developer pages say it shows the app is "optimized for iPhone Duo", and Apple's October 22, 2026 newsroom post calls it the "Made for iPhone Duo" badge. Apple's pages tie the badge to the screenshot submission and describe the iOS 27.1 SDK build as what makes an app optimized, but they do not say what happens to the badge without that build. One secondary report (9to5Mac, October 5) says the Xcode 27.1 build triggers it, which conflicts with Apple's current pages. Do both steps, and check the live product page on a device after approval. Capture each display on the iPhone Duo simulator at its exact size, never by stretching another iPhone capture. Koubou 0.20.0, the version asc pins, has no Duo frame (asc screenshots list-frame-devices lists none), so Duo framing is an open step: log it as Stuck and ask the human rather than improvising a frame. Duo deck design rules are in references/copy-and-design.md. Optional for the human, not for the store deck: one author composites app captures into an image-model render of a hand holding a Duo for social and press visuals (Tobia Donadon, product page read 2026-10-20, one sentence, unverified, untested here). Apple's store screenshots still use the exact simulator captures from the step above. Never use a generated device render as a store screenshot. Android target: 1080×1920 portrait (9:16, Play Store phone). Play rejects screenshots whose long side is more than twice the short side, so raw 20:9 captures such as 1080×2400 must be framed to 9:16. Play accepts up to 8 phone screenshots as JPEG or 24-bit PNG without alpha, and promotion eligibility needs at least 4 at 1080 px or more.

Production-environment hard requirements

Apple/Google reject screenshots that show debug overlays or staging data. Verify all of:

  • No debug banner (Flutter: MaterialApp.debugShowCheckedModeBanner = false or release mode forces it off. Native: no debug-only overlay, banner or #if DEBUG UI in the captured build)
  • No performance overlay, no debug paint, no leak tracker
  • Status bar locked to a clean state via xcrun simctl status_bar booted override --time "9:41" --batteryLevel 100 --cellularBars 4 --wifiBars 3 --cellularMode active --dataNetwork wifi
  • Test account looks realistic (no "test test test", no lorem ipsum)
  • No PII (real names, real emails, real bank balances)
  • Light mode by default; add a dark mode pass when the listing calls for it
  • More than half of the screenshots for each supported device show the app in use (Guideline 2.3.3). With 3 screenshots per device, 2 must show the app in use on that device, and with 4, 3 must. Title art, a login page, and a splash screen do not count. Count a slide as showing the app in use only if it contains a real or realistic screen of the running app. A mascot, photo, orbiting-avatar graphic, floating money chips, a lone notification or a placeholder grey-row mock does not count. Apple's 2.3.3 text as fetched allows overlays and text, so the test is the presence of a real screen and not the absence of decoration. Before asc screenshots upload, write a slide-by-slide table (slide, headline, real screen yes or no), and do the same for decks designed by a third party. Example from one agency-deck post (October 2026, image reading, inference, no review outcome known): of four agency decks of six slides, one had no real screen by that reading and the others had 4 or 5.

Native Swift and Kotlin projects

Everything above applies. Only the build and capture steps differ. Pick the capture path the project already has before inventing one.

  1. Project render tests. Some native projects draw store screenshots from their own views inside a test target, which needs no running app and no device. Look for scripts/render-*.sh, a StoreScreenshotTests file, or an environment switch that turns render tests on. Run the script and read its output folder. These renders are the app's real screens, so they count as "app in use" under Guideline 2.3.3.
  2. Apple simulator capture, when no render path exists:

    xcodegen generate                      # only when project.yml exists
    xcrun simctl list devices available    # pick the simulator that produces the required size
    xcodebuild build -project <P>.xcodeproj -scheme <App> -configuration Release \
      -destination 'platform=iOS Simulator,name=<simulator>' -derivedDataPath build/shots-dd
    xcrun simctl boot "<simulator>"
    xcrun simctl install booted build/shots-dd/Build/Products/Release-iphonesimulator/<App>.app
    xcrun simctl status_bar booted override --time "9:41" --batteryLevel 100 --cellularBars 4 --wifiBars 3 --cellularMode active --dataNetwork wifi
    xcrun simctl launch booted <bundle id>
    xcrun simctl io booted screenshot --type=png store_assets/screenshots/raw/en-US/01_home.png

    Drive the app to each screen with launch arguments, deep links (xcrun simctl openurl booted <url>) or a UI test. Watch captures use a paired watchOS simulator the same way. A StoreKit configuration file only applies to Xcode runs, so for paywall shots use a UI test or run from Xcode.

  3. Android emulator capture:

    ./gradlew :app:installRelease          # or the release-like build type the project defines
    adb exec-out screencap -p > store_assets/screenshots/raw/en-US/01_home.png

    Lock the status bar with demo mode: adb shell settings put global sysui_demo_allowed 1, then adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm 0941. Use an AVD that yields 1080×1920 or frame the capture to 9:16 as above.

  4. Mac app. A Mac app distributed outside the App Store has no App Store screenshot slot. Capture it for the landing page and cask page with a render test, or with screencap-style window capture (screencapture -l <window id> file.png), and hand the files to app-landing-page. Mac App Store sizes apply only if the app ships there.
  5. Devices: xcrun devicectl list devices lists connected devices, but simctl and the emulator give the exact sizes the stores require.

Strip alpha and check sizes after any path: sips -g pixelWidth -g pixelHeight -g hasAlpha <file>. The release build for Phase 1 is xcodebuild archive (Apple) or ./gradlew :app:bundleRelease (Android), and the uploaded store build comes from asc-xcode-build.

App previews (optional)

Make two cuts from one recording.

  • Store cut: a screen capture of the app itself. Guideline 2.3.4 says "previews may only use video screen captures of the app itself" and allows narration and video or textual overlays. Apple does not name device frames in 2.3.4 or on its app previews page, so keeping frames out of the store cut is our own rule. A developer forum thread quotes a 2.3.4 rejection that cites device frames.
  • Social cut: framed device on a backdrop, for social posts and the landing page. Framing here is our own rule, and this cut is never uploaded to a store.
  • Apple spec: 15 to 30 seconds, up to 30 fps, .mov, .m4v or .mp4 for H.264 or .mov for ProRes 422 HQ, 500 MB maximum, up to three previews per device size and language. Accepted resolution is 886×1920 portrait or 1920×886 landscape for iPhone Duo and the Dynamic Island and Face ID classes, 1080×1920 for Home Button (large) and 750×1334 for Home Button (medium). Apple says to use the accepted resolution, not the device resolution.
  • Apple's app previews page says "Don't include specific prices, as pricing and currencies vary across regions." It also says that if you display features only available through in-app purchase, or your app uses a subscription model or requires login, "you must disclose this", in the footage or the end frame. Previews play muted by default, so carry the meaning in on-screen text.
  • Put the hook in the first seconds, because the preview autoplays muted when the product page opens. Apple's product page guidance says "make sure the first few seconds of your video are visually compelling" (read 2026-11-03). Apple's app previews page says previews autoplay on the product page and within search results. App Store Connect help says previews always appear before screenshots, and a preview whose aspect ratio differs from the screenshots appears in the "A Closer Look" section instead, so match the screenshot aspect ratio when the preview should lead the page. "The first 5 seconds" in one X post is the author's figure and not Apple's. The only 5-second value on Apple's pages is the default poster frame time.
  • Choose the poster frame before the first review. Apple says it shows when someone has turned off video autoplay in their App Store settings and during app install, and App Store Connect defaults it to the frame at 5 seconds. Apple's app previews page says changing the poster frame of an already approved preview needs a new submission of that preview. One reply on X suggests making the first frame look like a screenshot of the app, so the video is not read as a video until it moves (single report, untested).
  • Record with xcrun simctl io booted recordVideo --codec=h264 (Android: adb shell screenrecord), because recordVideo defaults to HEVC and accepts --codec=h264. Then scale the file to the accepted resolution at 30 fps or less. Apple's specification table lists audio as stereo, 256 kbps AAC at 44.1 or 48 kHz for H.264 files, and PCM or 256 kbps AAC for ProRes, with all tracks enabled (read 2026-11-03). Neither Apple page says whether a preview with no audio track uploads, so test the upload. One reply on X says stripping the audio from an iMovie export took a specific procedure (single report, no detail given).
  • Do not quote an install lift for app previews. One author posted "up to 25% (depending on the niche)" on 2026-05-30 and "up to 30%" on 2026-10-19, both without a source. Apple's Product Page Optimization page lists app previews as testable, with up to three treatments, so test the preview against the screenshots-only page in App Store Connect and read the confidence figure. Apple's own Simply Piano story may show a preview treatment losing to the original page, though the direction of the result is ambiguous in the story (read 2026-10-22), so a preview is a hypothesis and not a guaranteed lift.
  • Google Play: one YouTube video, ads disabled, no maximum length, and only the first 30 seconds autoplay. The video must be public or unlisted, embeddable and not age-restricted.

Tooling notes

  • Do not write a custom Python framing pipeline. Frame with Koubou 0.20.0, the version the asc CLI pins.
  • Reference other skills by name rather than inlining their work.
  • If a locale cannot be captured or framed correctly, log it as Stuck in store_assets/SCREENSHOTS_LOG.md and ask the human.

Device frames in compositions

Learned on 2026-11-02, where an Apple Watch on a deck slide looked soft, with a lumpy band edge and a light ring, twice in a row.

  • Never draw a framed device bigger than its source bitmap. Koubou frames a Watch at the screenshot's own size (416×496 for Series 11), so a slide that trims it and scales it to 560 px upscales it about 1.9 times, which softens the text and turns the band's alpha edge jagged.
  • Compute the scale of every device placement as placed width over source width, and fail the render when it is above 1. Put the check in the layout helper itself, for example a function that throws when scale > 1, so a later layout change cannot bring the upscale back.
  • When a composition needs a bigger device, render the raw screenshot at a higher scale and frame that, instead of upscaling a framed bitmap.
  • For a Watch, and for any device shown large on a coloured or dark backdrop, place the raw shot 1:1 inside Apple's own product bezel from Apple Design Resources instead of the Koubou frame. Koubou pads its frames with white and blends the outermost pixel of the case and band with that white, which shows as a light fringe on dark backgrounds.
  • If a Koubou frame has to stay, erode its alpha by 1 px and composite it onto the final background colour, never onto white first.
  • Verify every device placement by cropping it at native size and at 300 to 400 percent against its final background, and look for soft text, a jagged band edge and a light ring. A downscaled contact sheet hides all three, so never judge device edges from one.

Done state

  • store_assets/screenshots/{raw,framed}/<locale>/ populated for every required locale
  • Dimensions verified (sips -g pixelWidth -g pixelHeight <file>)
  • store_assets/SCREENSHOTS_LOG.md written with what shipped + what was skipped
  • One line appended to store_assets/screenshots-runs-log.md:

    YYYY-MM-DD HH:MM — <project> — <locale>×N shots

Related skills

  • launch-readiness — Phase 0 dep
  • app-graphics — adjacent skill for icons, banners and App Store creative assets (product page header and search results). Don't generate them here. Without a search result creative asset, the App Store shows in-app events, app previews and screenshots in search results.
  • app-landing-page — adjacent skill, uses screenshots from this one

Sources

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.