| name | appshot |
| description | Create production-ready App Store creative assets from real app captures, supplied images, app metadata, localization inputs, and experiment results. iOS and watchOS only. Use for local screenshot studios, App Store listings, WidgetKit/watch previews, locale matrices, validation, review approvals, packaging, publishing dry-runs, and analytics-informed variant iteration. |
| voice_triggers | ["use appshot","appshot screenshots","app store screenshots"] |
appshot
App Store screenshots from real captures — iOS and watchOS. appshot
scaffolds a local Nuxt 3 review studio, captures your real product UI
from Xcode + Simulator (or accepts supplied PNGs), composes
store-ready variants you review on localhost, then exports,
validates, and packages only the assets you approve into an
upload-ready zip. Everything runs on your machine: no hosted accounts,
no cloud queues, no credential vaults.
Quick Start
npx skills add ai-zixun/appshot
appshot init \
--brief "Screenshots for KeyTimes" \
--out demo-studio --force
cp examples/keytimes/snapshot.config.json demo-studio/snapshot.config.json
mkdir -p demo-studio/public/captures
cp examples/keytimes/captures/*.png demo-studio/public/captures/
appshot start --project demo-studio
For your own app, point appshot init --app-root <path-to-xcode-project>
at a real project — init discovers the scheme, captures from the
Simulator, and drops you into the same review studio.
What this skill does
- Capture. Drives Xcode + Simulator to capture iPhone, iPad,
widget, and watch routes; supplied PNG/JPG mode is also a first-
class input. XCUITest-driven navigation closures cover auth-gated
and mid-animation routes.
- Compose. A Nuxt 3 review studio renders store-shaped variants
via a typed template DSL (screenshot-fill, tilted device, panoramic,
badge callout, feature graphic, before/after, widget, watch, and a
3D device mockup via vendored YUZU-Hub/appscreen).
- Review.
localhost:4173 shows every variant, supports
comments and per-locale approvals, and persists selections to
snapshot.selection.json.
- Export, validate, package. Saving a selection runs
export:selected → validate:assets → package:assets and writes a
ready-to-upload dist/app-store-assets.zip.
- Publish dry-run + analytics. Optional
publish:plan:apple
produces an upload plan; analytics:import ingests prior-experiment
data into variant recommendations.
Agent Workflow
Standalone-mode preamble. If the user already has the standalone server
running (they ran appshot themselves, the wizard at :4173/wizard
is on screen, or they're driving the review studio directly), your job is to
help inside that session — answer questions, edit configs, suggest copy.
Do not re-scaffold or restart their server. The agent recipe below is for
sessions where the user has delegated the whole flow to you.
Interactive triage gate. If the user invokes this skill with no task text,
no brief, no command-like parameters, or an underspecified ask such as "use
appshot", "make screenshots", or "help with App Store assets", ask what they
want to do before running commands. Ask one question at a time, include your
recommended answer, and keep walking the decision tree until you know the
workflow intent and minimum app context. If a question can be answered by
inspecting the repo, existing snapshot.config.json, tmp/appshot,
snapshot.routes.json, or local Xcode project signals, inspect first and ask
only for the remaining product or design choice.
Treat a request as actionable enough to proceed when it clearly names a
workflow such as: run the bundled demo, scaffold screenshots from a brief,
capture from an Xcode project, use supplied PNG captures, review an existing
studio, export/package selected variants, run a publishing dry-run, or import
analytics for variant recommendations. For a bare $appshot invocation, the
first question should orient the user around these workflows; recommend
"inspect this repo/app root and suggest the best appshot path" unless they
already gave a stronger intent.
Build the capture story first (node 2a-S)
Before capturing, build a capture story — the narrative + usage-flow
spine that tells you which screens to capture, in what order, in
what state, and how to navigate to them. Authoring the story first is
what lets capture land the right screens (seeded, signed-in,
mid-action) instead of whatever the structural route scan happened to
find. Full design, schema, and the D1–D4 decisions are in
PLAN-capture-story.md.
The story lives at the snapshot.story.json sidecar next to
snapshot.config.json (override via capture.storyPath). appshot init seeds a partial one from the brief's benefits (one narrative
beat per slide: order + benefit + headline, no screen binding yet), so
your job is to edit a draft, not start blank.
Author it interactively — one beat at a time, recommend an answer, walk
the list — like the triage gate. For each beat confirm:
- Which benefit does this slide sell? (seeded from the brief)
- Which screen shows it? (recommend the best-matching discovered
screen from
snapshot.project.json; the user may pick another or
describe a marketing/widget/watch scene, which is inlined per D1)
- What state must it be in? auth (
none/signed-in), seed
fixture, moment (static/mid-action/animating)
- How do we reach it? navigation steps from the discovered
accessibilityIdentifiers — these become the route's XCUITest
navigation verbatim
Then enrichment + reconcile run as pipeline steps (no hand-wiring):
profiling → plan-story (binds screens, derives captureStrategy,
writes inline scenes through to config) → plan-routes (reconciles the
story into snapshot.routes.json: enrich matched routes, synthesize
missing ones, mark the rest selected: false). Capture then shoots only
the selected deck. For a supplied-image flow there is nothing to
navigate, so beats stay narrative-only and captureStrategy is
supplied.
Skip this gate only when the user explicitly declines a story or is
working inside an already-captured studio. A story is optional: with no
snapshot.story.json, plan-story is a no-op and route planning
behaves exactly as before.
Upfront decisions (collect BEFORE any slow work runs)
The first invoke is slow because capture, copy generation, and the dev
server each take 30s–several minutes. Collect the three decisions below
in the TUI first, then fan the work out — capture on the foreground
thread, copy generation as a background subagent, dev server as a
background Bash process. The user should be answering questions or
reading the studio while the slow paths run, never waiting on a
serial pipeline.
After the triage gate has identified the workflow as a fresh
scaffold + capture + review run (not the demo, not "help inside an
existing studio"), and before running appshot init, ask these
three questions in sequence. Each is an AskUserQuestion with a
recommendation. Do not batch them into a single multi-select — the
answers branch into different background jobs.
Q-capture — Where do the source captures come from?
Recommendation: Claude captures, if an Xcode project is detected
(appshot discover --json returns a project + scheme). If no
Xcode project resolves, default to user-supplied. Options:
- A) Claude captures via Xcode + Simulator (recommended when project detected)
- B) I'll supply PNG/JPG captures (drop them in
<studio-dir>/public/captures/ and tell me when done)
- C) Use the bundled KeyTimes demo captures (skip capture entirely)
If A: run appshot capture --kind ios … on the foreground thread
after scaffold lands. If B: scaffold now, then STOP and wait for the
user to paste paths or say "captures are ready" before continuing to
step 3. If C: switch to the demo path described under §Demo.
Q-copy — Should Claude draft the App Store copy (hero, subtitle,
per-slide headlines, description) while you set up?
Recommendation: Yes. Copy drafting is independent of capture and
benefits from running in parallel.
- A) Yes, draft it in the background and show me when ready (recommended)
- B) I'll write the copy myself / I already have it in the brief
- C) Skip copy — just use placeholders for now
If A: spawn an Agent subagent (subagent_type=general-purpose,
run_in_background=true) with a prompt that reads the brief + any
existing README/landing page + snapshot.config.json and produces
hero, subtitle, per-slide headlines, and a long description as JSON
matching the copy shape in snapshot.config.json. The subagent
writes its output to <studio-dir>/.appshot-draft-copy.json. When the
foreground reaches step 3, merge that file into
snapshot.config.json (or surface it for the user to accept in the
studio). If B/C: skip the spawn.
Q-studio — Start the review studio now in the background, or wait
until captures + copy are ready?
Recommendation: Start now. The studio's first boot (npm install +
nuxt build) is the slowest single step; running it in parallel with
capture hides that latency. The studio wizard at /wizard will show
"waiting for captures" until they land.
- A) Start now in the background (recommended)
- B) Start after captures land (cleaner first paint, slower overall)
- C) Don't start the studio — I just want the artifacts on disk
If A: run appshot start --project <studio-dir> via Bash with
run_in_background: true as soon as the scaffold completes. Capture
the background shell id; print the URL (http://127.0.0.1:4173/) to
the user immediately so they can open the wizard. If B: defer to
step 3. If C: skip appshot start entirely and only run export +
validate + package.
Background-work coordination rules
- Never block on a background job to log a single line. Use
run_in_background: true for appshot start (long-running server)
and for the copy-drafting subagent (independent of capture).
- Do block on capture.
appshot capture writes the PNGs the
studio needs to render anything useful; running it in the foreground
keeps error handling simple and keeps the user informed via streamed
output.
- Reconcile on the way out. Before telling the user the studio is
ready for review, check that (a) captures are on disk, (b) the
background studio process is still alive (
appshot doctor or a
curl to :4173/api/health), and (c) the draft copy file exists if
Q-copy was A. Surface any failure as a single concrete message, not
a generic "something went wrong."
- One progress update per slow phase. While capture runs, tell the
user once: "Capturing N routes from on — this
usually takes ~M seconds." Do not narrate each frame. The studio
shows per-route progress already.
The unified entry point is the appshot CLI at
skills/appshot/bin/appshot (it's also reachable as
.claude/skills/appshot/bin/appshot or
.agents/skills/appshot/bin/appshot when installed into a project via
npx skills add ai-zixun/appshot, and as
~/.codex/skills/appshot/bin/appshot or
~/.claude/skills/appshot/bin/appshot in globally-installed skill
contexts). All subcommands accept --json so you can parse responses
without scraping prose.
-
Scaffold. Translate the brief into snapshot.config.json and copy
the studio template into the user's app root:
appshot init --brief "<brief>" --app-root <app-root> --json
init delegates the brief → config translation to
assets/nuxt-template/lib/brief-to-config.ts — a deterministic,
schema-aware library. Do not hand-write snapshot.config.json from
scratch; let init do it, then edit only the fields the brief leaves
ambiguous. For supplied-image mode (no Xcode project), drop the
--app-root flag and pass --out <dir>.
-
Capture (per Q-capture answer). If Q-capture was A, populate
public/captures/ from the Simulator on the foreground thread. If
Q-capture was B, STOP here until the user confirms their PNGs are in
place. If Q-capture was C, jump to the §Demo recipe and skip this
step entirely.
appshot discover --app-root <app-root> --json
appshot capture --kind ios --app-root <app-root> --project <studio-dir> --json
For supplied-image flows, copy the user's PNGs into
<studio-dir>/public/captures/ instead. Read
references/marketing-scenes.md for native marketing, widget mock, and
watch scene authoring detail.
For routes that require interaction (auth, seeded data, multi-step
navigation, mid-animation moments), set strategy: "existing-ui-test-route"
on the route in snapshot.routes.json and emit a navigation array of
action steps. The capture pipeline then runs the route through
xcodebuild test against the installed AppshotUITests.swift template
and harvests PNGs via xcresulttool. Use
snapshot.project.json's swift.accessibilityIdentifiers (extracted by
profile_project.py) as the menu of tap targets you can author against.
Full schema, action-step shapes, launchEnvironment seeding pattern, and
the agent-authoring prompt skeleton live at
references/xcuitest-strategy.md.
-
Hand off to the user. If Q-studio was A, the studio is already
running in the background and the user has the URL — your job here
is just the reconcile step: confirm the process is alive, merge
.appshot-draft-copy.json (if Q-copy was A and it landed) into
snapshot.config.json, and tell the user the studio is ready. If
Q-studio was B, start it now via Bash with run_in_background: true:
appshot start --project <studio-dir>
Either way, point the user at http://127.0.0.1:4173/, ask them to
pick variants, and confirm selections inside the review studio. The
studio's POST /api/selection already runs export:selected → validate:assets → package:assets, so finalising is the user's
click, not a chore you need to drive.
-
Wrap up. When the user reports the selection is saved, tell them
the final zip is at <studio-dir>/dist/app-store-assets.zip. If they
ask for publishing dry-runs or analytics summaries, run
bun run publish:plan:apple or bun run analytics:import from the
studio dir — those still ship as Bun scripts on the studio (see the
demo block below).
For slides tagged layout: "appscreen-3d", run
scripts/plan_appscreen_variants.py prompt and apply to author the
per-slide appscreenParams after step 1. Schema:
references/appscreen-params.md.
Pre-render + auto-generate review images. After captures land,
appshot start --project <studio-dir> opportunistically warms the L1
framed cache and then runs bun run export:variants against the live
studio server when outputs are missing or stale. It respects
framed.autoRender: false, pipelineSkip, and --no-autogen. Manual
fallback: run bun run prerender:framed and then
bun run export:variants from <studio-dir>. The cache is the
schema-versioned .appshot-cache/framed/vN/ directory with
content-addressed L1 framed captures. iPhone 2D and 3D auto frames use
the vendored appscreen engine in device-only mode; iPad 2D keeps the Vue
/framed-snapshot fallback. Failures fall through to the live render
path where possible. See PLAN-prerender-cache.md,
PLAN-3d-engine-for-2d-frame.md, and docs/workflow.md §7.6.
The pre-CLI Python-by-Python recipe (calling each script in sequence by
hand) is preserved at references/agent-fallback.md for the rare case
the CLI is missing or broken — but appshot is the canonical
entry now, and reaching for the fallback should be a deliberate
choice.
Reference Map
Load only the reference needed for the current task:
- Apple screenshot dimensions and upload rules:
references/apple-specs.md
- Widget, watch, and complication preview guidance:
references/widget-guidelines.md
- Template schema and layout DSL:
references/template-dsl.md
- Copy, ASO order, and quick localization guidance:
references/copy-localization.md
- Native scene scaffolding and route prefixes:
references/marketing-scenes.md
- Validation checklist currently shipped with the skill:
references/validation.md
- Expanded compliance validation rules and warning taxonomy:
references/compliance-validation.md
- Local review studio states, comments, approvals, and selected-only export:
references/review-workflow.md
- Publishing dry-runs, folder layouts, and credential boundaries:
references/publishing.md
- Analytics imports, experiment summaries, and next-variant recommendations:
references/analytics-import.md
- Baseline Nuxt screenshot workflow lessons:
references/parthjadhav-app-store-screenshots.md
- 3D device mockup parameters (vendored YUZU-Hub/appscreen):
references/appscreen-params.md
- XCUITest capture strategy + agent-authored navigation closures + launchEnvironment seeding:
references/xcuitest-strategy.md
- Pre-CLI Python-by-Python recipe (fallback only, kept for audit):
references/agent-fallback.md
When current store compliance matters, verify live Apple documentation before asserting exact requirements.
Design Rules
- Lead with the strongest user outcome, then core workflow, differentiators, trust proof, and ecosystem surfaces.
- Each slide sells one idea. Split copy that tries to sell two benefits.
- Vary the deck rhythm across screenshot fill, framed device, panoramic, feature graphic, badge or callout, before-after, widget, and watch layouts.
- Store screenshots are ads grounded in real UI, not documentation panels.
- Keep headlines large, readable after downscaling, benefit-led, and concrete.
- Avoid dense feature lists, unsupported claims, price or ranking claims, and store badges unless the target store explicitly allows them.
- For RTL locales, set locale direction, mirror ordering where appropriate, and align text naturally.
- Landscape screenshots should use a clear caption and one primary product surface; avoid crowded side-by-side device layouts.
Output Defaults
- Apple defaults are iPhone and iPad screenshot sets plus optional WidgetKit/watch previews. Read
references/apple-specs.md and references/widget-guidelines.md.
- Custom outputs may define exact width, height, format, naming, and package path when a campaign or press kit needs a nonstandard target.
- Supported final formats should remain explicit per output. Prefer PNG for lossless UI, JPEG when store constraints or file size call for it, and WebP only for custom surfaces that accept it.
Bundled Resources
bin/appshot: Unified CLI entry point. Subcommands: init,
discover, capture, start, export, doctor, upgrade,
config. Use this in preference to invoking the Python/Bun scripts
directly — it composes them with one set of conventions across the
standalone, Claude, and Codex flows.
assets/nuxt-template/: Nuxt 3 + Tailwind renderer and local review studio.
Boots into a first-run wizard at /wizard when launched with
APPSHOT_MODE=bootstrap (the CLI does this automatically when no
project resolves).
assets/nuxt-template/lib/brief-to-config.ts: Canonical brief → starter
config library. Both appshot init and the wizard call it; do not
duplicate this logic in agent prompts.
VERSION: current installed skill version, used by GitHub releases under tag v<version>. Users upgrade with npx skills@latest add ai-zixun/appshot.
scripts/scaffold.py: Copies the renderer template and creates starter config from a brief.
scripts/discover_xcode.py: Detects Xcode projects, schemes, bundle IDs, simulator runtimes, widgets, previews, and Watch targets.
scripts/profile_project.py: Writes snapshot.project.json from Xcode metadata and Swift source scanning.
scripts/plan_story.py: Node 2a-S. Enriches the capture story (snapshot.story.json) — binds each beat to a discovered screen, derives its captureStrategy from state + navigation, and writes inline marketing/widget/watch scenes through to snapshot.config.json. See PLAN-capture-story.md.
scripts/plan_routes.py: Writes snapshot.routes.json with route IDs, confidence, strategies, source files, and output paths. When a capture story is present it reconciles the story's beats into the route model (enrich / synthesize / selected: false) and orders the deck by beat order.
scripts/install_harness.py: Adds an idempotent native snapshot harness and scene scaffolds.
scripts/capture_simulator.py: Captures iPhone/iPad app UI, marketing scenes, and widget mocks in Simulator.
scripts/capture_widgets.py: Crops widget mock captures to widget bounds when possible.
scripts/capture_watch.py: Captures watch routes from paired watch simulators.
scripts/validate_assets.py: Validates exported PNG/JPG dimensions, opacity, and nonblank pixels.
scripts/package_exports.py: Creates packaged export archives.
scripts/plan_appscreen_variants.py: Emits the prompt + per-slide briefs the calling agent feeds to a model, then merges the model-authored appscreenParams back into snapshot.config.json.
scripts/sync_appscreen.py: Refreshes the vendored YUZU-Hub/appscreen tree from upstream while preserving the one-file fork delta.
assets/nuxt-template/public/vendor/appscreen/: Vendored MIT-licensed fork of YUZU-Hub/appscreen, driven headlessly by the studio for 3D iPhone mockup variants. The vendored renderer ships additional device profiles upstream, but only device3D: "iphone" is exposed by this skill. See assets/nuxt-template/public/vendor/appscreen/UPSTREAM.md.
Demo (KeyTimes)
When the user asks to "run the appshot demo" or similar, scaffold a
studio against the bundled examples/keytimes/ content. Supplied-image
mode only — the demo never touches an Xcode project.
- Read
examples/keytimes/KeyTimes.md for the brief and per-slide intent.
- Scaffold via the CLI:
appshot init \
--brief "Screenshots for KeyTimes. $(sed -n '3p' examples/keytimes/KeyTimes.md)" \
--out demo-studio --force --json
- Replace the generated starter with the curated demo config and drop in
the demo captures:
cp examples/keytimes/snapshot.config.json demo-studio/snapshot.config.json
mkdir -p demo-studio/public/captures
cp examples/keytimes/captures/*.png demo-studio/public/captures/
- Start the studio (installs deps on first run, then opens at
http://127.0.0.1:4173/):
appshot start --project demo-studio
- After the user picks variants in the studio, the studio's
POST /api/selection runs export/validate/package automatically. The
final zip lands at demo-studio/dist/app-store-assets.zip.
Agent Notes
- Prefer
snapshot.project.json, snapshot.routes.json, and snapshot.selection.json over rediscovering or reselecting work.
- Treat
bun run dev:review as the human approval checkpoint for final assets. bun run export:selected requires a saved review selection; use APPSHOT_ALLOW_DEFAULT_SELECTION=1 only for explicitly requested draft automation.
- Prefer config, template, capture route, and locale edits over one-off image generation.
- Ask before shipping final assets when every source image is placeholder-only.
- Keep credentials local and ignored. Publishing helpers may plan and dry-run uploads, but real uploads require user-owned local environment variables or credential files.
- Do not copy proprietary templates, branding, copy, or assets from commercial screenshot tools.