FrameHero
From App Store screenshot tool to AI-powered API — building a product that agents can use
At a Glance
- Role
- Design & Engineering
- Timeline
- 3 months
- Tech Stack
- SwiftSwiftUICore ImageNWListenerMCP Protocol
- Live
- framehero.app
The Problem
Publishing an iOS app to the App Store requires screenshots for every supported device size, in every locale you want to support. A single app targeting 5 device sizes across 10 languages needs 500 individual screenshots. Most indie developers either skip localization entirely or spend days in Figma doing it manually.
The existing tools (AppScreens, Screenshots Pro) work but they're web-based, expensive, and none of them can automate the hardest part: capturing locale-specific screenshots from the iOS Simulator.
What We Built
FrameHero is a macOS app that automates App Store screenshot creation. The core differentiator: it controls the iOS Simulator directly, switching locales and capturing screenshots programmatically. No other tool does this.
The App
The desktop app handles the full workflow:
- Automated locale capture — connects to iOS Simulator via
simctl, switches languages, relaunches the app, and captures screenshots across all 40 App Store locales automatically - Visual editor — layer-based compositor (Core Image, GPU-accelerated) for adding device frames, text overlays, backgrounds, and custom layouts
- Template system — 12 pre-built templates covering minimal and bold styles, with full customization
- Video previews — App Store preview video generation with captions, transitions, and device frame overlays using AVFoundation
- AI metadata — Claude-powered generation of optimized titles, subtitles, keywords, and descriptions
- Translation — context-aware App Store copy translation across all supported locales
- Direct upload — App Store Connect API integration for pushing screenshots directly
The Architecture
Everything runs locally. No cloud dependency for core features.
| Component | Technology | Why |
|---|---|---|
| UI | SwiftUI | Modern, declarative, fast iteration |
| Persistence | SwiftData | First-party, simple, sufficient |
| Image compositing | Core Image | GPU-accelerated, non-destructive pipeline |
| Video rendering | AVFoundation + custom AVVideoCompositing | Alpha-channel support for overlays |
| Text rendering | TextKit 2 | Render to image, then composite |
| Simulator control | simctl CLI | The differentiator |
| AI | Claude API via proxy | Metadata generation + translation |
| Payments | Polar (Lemon Squeezy) | License key validation |
| Updates | Sparkle | Direct download distribution |
The compositor follows a strict Model → Compositor → View pattern. Source images are never modified. The view shows a rendered CGImage from the compositor. Interaction (drag, resize, select) happens in a transparent SwiftUI overlay layer. This keeps rendering deterministic and makes the preview-to-export path trivial.
Then We Built the API
The app works great for humans. But we kept thinking about the target audience: indie developers who build with AI coding tools. If someone is using Claude Code or Cursor to build their app, why should they switch to a GUI to make screenshots?
So we built an HTTP API and MCP server directly into FrameHero.
Local HTTP API
When FrameHero is running, it serves a REST API on localhost:9820:
GET /health
GET /v1/templates
GET /v1/templates/{id}
GET /v1/devices
POST /v1/screenshots/generate
POST /v1/screenshots/batch
POST /v1/metadata/generate
POST /v1/metadata/translate
POST /v1/export
An agent can send raw simulator screenshots plus a template ID and text overlays, and get back finished App Store screenshots. The batch export endpoint generates every device size × locale combination in one call, organized in the exact directory structure App Store Connect expects.
MCP Server
The real unlock: FrameHero as an MCP tool. Launch with --mcp and it becomes a tool server that Claude Code or Cursor can call natively:
framehero_list_templates— browse available designsframehero_generate_screenshot— create a single screenshotframehero_generate_metadata— AI-optimized App Store copyframehero_translate_metadata— localize to any of 40 localesframehero_batch_export— full export run
The workflow becomes: developer says "make App Store screenshots for this app," the coding agent calls FrameHero's MCP tools, and the entire listing is generated without a human touching the GUI.
Technical Details
The Compositor Pipeline
Every screenshot generation request follows the same path, whether it comes from the GUI, the HTTP API, or an MCP tool call:
- Parse input into Layer models (background, device frame, screenshot, text overlays)
- Compositor renders layers bottom-to-top using Core Image (CISourceOverCompositing)
- Text rendered via TextKit 2 to NSImage, then converted to CIImage for compositing
- Device frame loaded from asset bundle, screenshot placed in screen rect
- Output at full resolution (e.g., 1320×2868 for iPhone 6.9")
Preview renders at 1x for speed. Export renders at full device resolution. Same pipeline, different scale factor.
The API Server
Built with Foundation's Network framework (NWListener + NWConnection). No third-party HTTP dependencies. The server runs as a Swift actor, keeping it thread-safe and non-blocking. Routes are simple pattern matches dispatched to handler functions that share logic with the app's core services.
MCP Implementation
The MCP server implements the JSON-RPC stdio transport. It handles the initialize/initialized handshake, responds to tools/list with the six tool definitions, and dispatches tools/call to the same handlers used by the HTTP routes. One codebase, two interfaces.
Results
- 12 files, 2,289 lines of API code added to the existing app
- Zero new dependencies — built entirely on Foundation frameworks
- Same compositor serves GUI, HTTP, and MCP — no code duplication
- Full App Store coverage — all 40 locales, all required device sizes
- Sub-second screenshot generation on Apple Silicon
What We Learned
Design for the API first. If we'd built the API from the start, the compositor architecture would have been cleaner. The Layer model was already well-structured (because SwiftData needs it), which made the API translation straightforward. But some GUI-specific assumptions had to be worked around.
MCP is underrated. The stdio transport is trivially simple to implement. The hardest part was deciding which parameters to expose. If your app has clear input/output boundaries, adding MCP support is a few hundred lines of code for a significant distribution advantage.
Local-first matters. Running the API server inside the app means zero deployment, zero auth complexity, zero latency. The developer installs FrameHero, and their agent can use it immediately. No API keys, no cloud accounts, no pricing tiers.
This project was built by Parallel Studio. We design and build AI-native products — from concept through production. Tell us about your project.