Like a lot of people shipping iOS apps this year, I tried generating App Store screenshots with image models. GPT Image, nano banana — the results looked genuinely great. Then App Store Connect rejected them: wrong canvas sizes, subtly warped text, device frames that don't match any real device.
After the third rejection I realized the problem wasn't prompt engineering. Frames and canvases are geometry, and geometry is arithmetic — something a coding agent expresses perfectly in CSS, and something an image model can only approximate statistically. Asking a diffusion model to hit 1290×2796 exactly, with a pixel-true bezel and crisp 17px mono type, is asking statistics to do arithmetic.
So I split the work, and open-sourced the result as a skill for Claude Code and Codex: HyperShots.
The split: deterministic where Apple has rules, generative where it sells
Deterministic half (no AI involved at all):
- Your agent designs marketing panels as plain HTML/CSS against a small geometric contract — a device frame with a fixed screen aspect (0.460, matched to real captures), profile-driven canvas variables, sticker primitives
- Headless Chrome renders them at exact store dimensions: 430×932 CSS at 3× = 1290×2796, to the pixel
- A fail-closed validator checks everything Apple actually rejects for: dimensions, alpha channels (yes, an RGBA PNG gets bounced), non-sRGB ICC profiles, panel count (max 10), and the 8 MB size cap. Green means the store cannot reject the set for asset specs
- Localization is one command per language:
data-i18nmarkers, atomic string injection (missing or unused keys are fatal — no silently shipping English), and auto-fit headlines that shrink until they clear the device instead of overflowing when German runs 30% long
Generative half (optional, bring your own fal.ai key):
- Cut-out sticker art: image generation → background removal → transparent PNG, positioned by the agent with plain CSS transforms
- An optional whole-set "makeover" pass — image-to-image over the rendered panel, where a mask plus a re-composite step restores your text and frames from the clean render afterward. The model never ships your typography
- Set consistency via a style anchor: grade the first panel freely, then pass it as a reference image for the rest. Measured drift across an anchored set: ~4% in palette
Then fastlane deliver pushes the set to App Store Connect — the skill ships the runbook, including the first-version metadata crash workaround that cost me an afternoon.
Things I learned the hard way
Chrome's 1fr respects min-content. Same-aspect images in a CSS grid rendered at different heights because nowrap captions silently widened their columns. repeat(N, minmax(0, 1fr)) or your geometry lies to you.
Headless Chrome's minimum window width is 500px. If your "mobile" screenshots look clipped, you may be cropping a 500px layout to 390 — the page was fine.
Image-model edit endpoints can't output store dimensions at all. gpt-image edits snap to multiples of 16; 1290, 1284, and 1320 aren't. Any AI style pass must end with a resample + re-composite, or the output is nonconforming by construction.
Masks are guidance, not guarantees. Inpainting-style "protected" regions come back approximately preserved — re-rendered through the model. If text must be pixel-true, composite it back from the source. Always.
Fonts must be vendored. Google Fonts @import at render time means your "deterministic" renderer silently falls back to system fonts under a timeout, and upstream font updates drift your metrics. @font-face with local woff2 or nothing.
Does it actually work?
Two production apps have shipped sets through it so far — one went from a one-paragraph brief to a store-ready, validated set in a single agent session, then through ~8 founder-driven revision rounds without a single spec failure. The gallery at hypershots.dev shows both sets; every image on that page, including the site's own icons, was generated by the pipeline it describes.
It's MIT, works with whatever agent you already use, and the deterministic half needs no API keys:
npx skills add hypersocialinc/hypershots
Honest limitations, because those belong in the README and in posts: iPad needs a separate authoring pass (0.75 aspect doesn't re-render from iPhone panels), RTL/CJK is roadmap (latin + latin-ext fonts are vendored today), and the style pass has documented caveats on layouts where text and device cover the whole canvas.
If you've been through screenshot-rejection hell, I'd genuinely love to hear what broke for you — and if you ship a set with it, submissions to the gallery are open (featured apps get a backlink).
Top comments (0)