WebMCP

Let AI agents make your store screenshots

Storedeck registers 22 tools with document.modelContext — the WebMCP API — covering everything the editor can do. An agent can run the whole job, from simulator captures to localized, A/B-ready exports, while you watch the canvas.

How agents connect

  • WebMCP-capable browsers and agent runtimes discover the tools automatically on any Storedeck page; calling one opens the editor if needed.
  • Browser automation without WebMCP (Playwright, CDP, agent-browser eval): call the same tools through await window.storedeck.callTool("get_app_state", {}) and list them with window.storedeck.listTools().
  • Inputs are validated against the published JSON schemas and errors explain what to fix, so agents can self-correct.

The model agents work with

Project (one app, its languages) → variants (A/B test arms with status and hypothesis) → platform decks (store + device + exact size) → screens (images and copy per language, background, device, text, elements, popouts). Every id is returned by get_app_state; most tools also accept screenIndex and default to the current selection, and design tools take a scope of screen, platform or variant.

A complete run

  1. get_app_state → pick or create a project with manage_project.
  2. manage_screens upload with data URLs; get_images mode original to read the app.
  3. set_copy with every screen × language in one call.
  4. set_background, set_device, set_text_style with scope: "platform".
  5. get_images (rendered) + get_screen layout warnings → fix → repeat.
  6. manage_platform add with cloneFromDeckId for Android, iPad, Mac or TV; manage_variant create for A/B tests.
  7. export and save the PNGs.

Add this to your repo's AGENTS.md

Coding agents (Claude Code, Codex, Cursor…) read AGENTS.md. With this section they can refresh your store screenshots on request — capture, design, review with you, export.

## Store screenshots (Storedeck)

Use **Storedeck** (https://storedeck.byanr.com — free, open source, runs in
the browser) to create App Store, Google Play, desktop and TV store
screenshots. Prefer it over hand-editing images or writing canvas scripts.
It exposes WebMCP tools (also callable as `window.storedeck.callTool(name, input)`).

**Workflow — do this without asking the user to click:**

1. Capture fresh screenshots (e.g. `xcrun simctl io booted screenshot shot-01.png`,
   `adb exec-out screencap -p > shot-01.png`). For other languages, capture again
   with the app in that language and name files `shot-01_de.png`, `shot-01_te.png`.
2. Open https://storedeck.byanr.com and call `get_app_state`. Open this app's
   project if it exists (`manage_project` action=open) or create it with the
   platforms you ship on (`platformIds`, see `get_platform_catalog`).
3. Upload captures with `manage_screens` action=upload (`filename` +
   `data:image/png;base64,...`, max 10 per call). Localized files land on the
   matching screen automatically.
4. Look at the originals (`get_images` mode=original), then write one headline
   (2–5 words, benefit-first) and subheadline (4–10 words) per screen with a
   single `set_copy` call — include every project language.
5. Style with `set_background`, `set_device` (preset, 2D `chrome` or 3D) and
   `set_text_style`, using `scope: "platform"` or `"variant"` to keep the set
   consistent. Reuse a finished platform for others with `manage_platform`
   action=add + `cloneFromDeckId`.
6. Review: `get_images` (rendered) and `get_screen` layout warnings (text
   overlapping the device, headlines wrapping too much). Fix and re-check.
7. Show the user the rendered previews and ask for feedback. For A/B tests,
   create a variant with `manage_variant` action=create (it copies the current
   one) and change only what is being tested.
8. `export` with `delivery: "return"` and save each `dataUrl` to
   `store-assets/<platform>/<language>/<NN-name>.png`, then report the paths.

Notes: sizes and counts come from the catalog — never upscale previews for
final assets. Everything stays in the user's browser storage.

Tool reference

Read

get_app_state

Get app stateread-only

START HERE. Returns the open project (languages, variants → platform decks → screens with ids, image languages and headline/subheadline copy), all saved projects, the current selection and view, undo history and next-step hints. Image bytes are not included (use get_images). Call again after structural changes.

Parameters (2)
variantIdstringOnly include this variant
includeCopybooleanInclude headline/subheadline text per screen (default true)

get_screen

Get screen designread-only

Full design of one screen (default: selected): background, device, text style, copy per language, elements, popouts, image info, output size, plus computed layout (device and text rectangles in output px) and warnings such as text overlapping the device or running off-canvas.

Parameters (4)
screenIdstringScreen id. Defaults to the selected screen.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
languagestringLanguage used for layout warnings (default: current)

get_platform_catalog

Get store platform catalogread-only

Store screenshot specs: every platform id with its output sizes, orientation, screenshot count limits and requirements. Stores: app-store, google-play, microsoft-store, steam, amazon-appstore, tv-stores, web.

Parameters (1)
store"app-store" | "google-play" | "microsoft-store" | "steam" | "amazon-appstore" | "tv-stores" | "web"Filter by store

get_strings

Get localization stringsread-only

The localization table: every headline, subheadline and text-element string per language, with missing translations listed. Filter by variant/platform. Use before translating, then write with set_copy.

Parameters (4)
variantIdstring
deckIdstring
languagesstring[]Only these languages
onlyMissingbooleanOnly rows with missing translations

get_images

Get images for visionread-only

Images for visual QA. mode "rendered" (default) returns the styled composition exactly as exported, downscaled to maxDimension (default 900 px, JPEG). mode "original" returns uploaded source screenshots (use to read the app UI before writing copy). Waits for fonts, images and 3D models. Target with screenId/screenIds/screenIndex or scope.

Parameters (10)
screenIdstringScreen id. Defaults to the selected screen.
screenIdsstring[]Several screen ids at once.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
scope"screen" | "platform" | "variant"screen (default): one screen. platform: every screen in the platform deck. variant: every screen of every platform in the selected variant.
languagestringLanguage to render (default: current)
mode"rendered" | "original"
maxDimensionintegerLongest side in px (200-1600, default 900). Never upscales.
format"jpeg" | "png"Default jpeg (smaller for agent context)
maxImagesintegerCap for multi-screen requests (default 6)

Navigate

select

Select variant, platform, screen or language

Moves the editor focus so the user sees what you work on: variantId (A/B variant), deckId (platform), screenId or screenIndex, and language (preview language). Switching variant keeps the same platform and screen position when possible.

Parameters (5)
variantIdstring
deckIdstring
screenIdstring
screenIndexinteger
languagestringProject language code, e.g. "de"

set_view

Change editor view

Controls the editor UI: view (design = single screen canvas, board = all screens × languages grid, strings = localization table, compare = A/B variants side by side), inspectorTab, selected element/popout, which variants to compare, and the store safe-area overlay.

Parameters (6)
view"design" | "board" | "strings" | "compare"
inspectorTab"background" | "device" | "text" | "elements" | "popouts"
selectedElementIdstringElement id or "" to clear
selectedPopoutIdstringPopout id or "" to clear
compareVariantIdsstring[]Variants shown in compare view (2-4)
showSafeAreaboolean

Structure

manage_project

Manage projects

Projects are the top-level container (one per app). Actions: create {name, appName?, platformIds?, languages?} — new project with an "Original" variant; open {projectId}; rename {name, appName?}; duplicate {projectId?, name?}; delete {projectId, confirm:true} (permanent); export_file {projectId?} downloads a .storedeck.json backup for the user; import_file {bundle} imports a backup (object or JSON string).

Parameters (8)
action*"create" | "open" | "rename" | "duplicate" | "delete" | "export_file" | "import_file"
namestringProject name (1-100 chars)
appNamestringApp name used in guides/exports
projectIdstring
platformIds"app-store-iphone" | "app-store-ipad" | "app-store-mac" | "app-store-apple-tv" | "app-store-vision-pro" | "app-store-watch" | "google-play-phone" | "google-play-tablet-7" | "google-play-tablet-10" | "google-play-chromebook" | "google-play-tv" | "google-play-wear" | "google-play-xr" | "google-play-automotive" | "google-play-artwork" | "ms-store-desktop" | "ms-store-xbox" | "steam-screenshots" | "steam-capsules" | "amazon-fire-tv" | "amazon-fire-tablet" | "smart-tv" | "web-social"[]create: initial platforms (default app-store-iphone)
languagesstring[]create: initial languages (default ["en"])
confirmbooleandelete: must be true
bundleanyimport_file: project bundle object or JSON string

manage_variant

Manage A/B variants

Variants are alternative screenshot sets for A/B tests (App Store Product Page Optimization, Google Play store listing experiments). Actions: create {name?, cloneFromVariantId?, blank?, platformIds?} — clones the selected variant by default so you only change what the test is about; update {variantId, name?, status?, hypothesis?} (status draft|control|testing|winner|archived — one control/winner at a time); delete {variantId}; move {variantId, toIndex}.

Parameters (9)
action*"create" | "update" | "delete" | "move"
variantIdstring
namestring
cloneFromVariantIdstring
blankbooleancreate: start with empty platforms instead of cloning
platformIds"app-store-iphone" | "app-store-ipad" | "app-store-mac" | "app-store-apple-tv" | "app-store-vision-pro" | "app-store-watch" | "google-play-phone" | "google-play-tablet-7" | "google-play-tablet-10" | "google-play-chromebook" | "google-play-tv" | "google-play-wear" | "google-play-xr" | "google-play-automotive" | "google-play-artwork" | "ms-store-desktop" | "ms-store-xbox" | "steam-screenshots" | "steam-capsules" | "amazon-fire-tv" | "amazon-fire-tablet" | "smart-tv" | "web-social"[]create+blank: platforms to add
status"draft" | "control" | "testing" | "winner" | "archived"
hypothesisstringWhat this variant tests, e.g. "Benefit-first headlines lift installs"
toIndexinteger

manage_platform

Manage store platforms

Each variant holds one deck per store platform (iPhone, iPad, Android phone, Mac, Apple TV, Android TV, Windows, Steam, Fire TV, …; ids via get_platform_catalog). Actions: add {platformId, sizeId?, variantId?, cloneFromDeckId?, allVariants?} — cloneFromDeckId copies screens, images and copy and rescales the design to the new size (the fastest way to go from iPhone to Android/iPad); remove {deckId}; set_size {deckId?, sizeId? | width+height, orientation?} — design values rescale automatically.

Parameters (10)
action*"add" | "remove" | "set_size"
platformId"app-store-iphone" | "app-store-ipad" | "app-store-mac" | "app-store-apple-tv" | "app-store-vision-pro" | "app-store-watch" | "google-play-phone" | "google-play-tablet-7" | "google-play-tablet-10" | "google-play-chromebook" | "google-play-tv" | "google-play-wear" | "google-play-xr" | "google-play-automotive" | "google-play-artwork" | "ms-store-desktop" | "ms-store-xbox" | "steam-screenshots" | "steam-capsules" | "amazon-fire-tv" | "amazon-fire-tablet" | "smart-tv" | "web-social"
sizeIdstringSize id from the catalog, or "custom" with width/height
variantIdstring
deckIdstring
cloneFromDeckIdstring
allVariantsbooleanadd: add to every variant
widthintegerset_size: custom width
heightintegerset_size: custom height
orientation"portrait" | "landscape"

manage_screens

Manage screens

Screens are the individual store images of a platform deck. Actions: upload {screenshots:[{filename, dataUrl, language?}], deckId?, screenId?} — PNG/JPEG data URLs, max 10 per call; language suffixes in filenames (home_de.png, home-pt-br.png) are detected, and files whose base name matches an existing screen become its localized image; new screens copy the selected screen's style. add_blank {deckId?, name?}; delete {screenId}; duplicate {screenId}; move {screenId, toIndex} (store order); rename {screenId, name}; remove_image {screenId, language}.

Parameters (8)
action*"upload" | "add_blank" | "delete" | "duplicate" | "move" | "rename" | "remove_image"
screenshots{ filename, dataUrl, language }[]upload: images
deckIdstring
screenIdstring
screenIndexinteger
namestring
toIndexinteger
languagestring

Copy & localization

manage_languages

Manage languages

Project languages (lower-case BCP-47 like "de", "pt-br", "zh-tw", "te"). Actions: add {languages:[...]}, remove {language} (copy is kept and returns if re-added), set_default {language} (fallback for missing copy/images), switch {language} (preview language — same as select).

Parameters (3)
action*"add" | "remove" | "set_default" | "switch"
languagestring
languagesstring[]

set_copy

Write headlines & translations

Writes store copy (the words, not styling) in bulk. Each entry targets a screen (screenId, or screenIndex + optional deckId), a field (headline, subheadline, or "element:<elementId>" for text badges), a language and text. Languages are added to the project automatically. Copywriting: headline 2–5 words, benefit-first; subheadline 4–10 words that expand it; every screen tells a different part of the story and screen 1 carries the core value proposition. Use \n for manual line breaks. Prefer one call with all entries.

Parameters (1)
entries*{ screenId, screenIndex, deckId, field, language, text }[]

copy_strings

Copy strings between platforms

Copies headline/subheadline copy from one platform deck to another by screen position (e.g. reuse iPhone copy for Android). Optional languages filter.

Parameters (3)
fromDeckId*string
toDeckId*string
languagesstring[]

Design

set_background

Set background

Background of the targeted screens: type gradient|solid|image; gradient {kind linear|radial, angle (CSS degrees, 0 = up), stops [{color, position 0-100}]}; gradientPreset (Indigo Rush, Midnight Abyss, Obsidian Plum, Carbon Slate, Steel Blue, Neon Horizon, Electric Surge, Synthwave Dusk, Northern Lights, Deep Forest, Emerald Canopy, Ocean Pulse, Desert Dusk, Ember Glow, Mocha Silk, Golden Hour, Pacific Sunset, Volcanic Dawn, Deep Ocean, Reef Lagoon, Gold Noir, Velvet Noir, Morning Mist, Sage Whisper, Royal Navy, Paper White); solid; imageDataUrl (sets type image); imageFit cover|contain|stretch; imageBlur; overlayColor/overlayOpacity (tint for contrast); noise/noiseIntensity.

Parameters (16)
screenIdstringScreen id. Defaults to the selected screen.
screenIdsstring[]Several screen ids at once.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
scope"screen" | "platform" | "variant"screen (default): one screen. platform: every screen in the platform deck. variant: every screen of every platform in the selected variant.
type"gradient" | "solid" | "image"
gradient{ kind, angle, stops }
gradientPreset"Indigo Rush" | "Midnight Abyss" | "Obsidian Plum" | "Carbon Slate" | "Steel Blue" | "Neon Horizon" | "Electric Surge" | "Synthwave Dusk" | "Northern Lights" | "Deep Forest" | "Emerald Canopy" | "Ocean Pulse" | "Desert Dusk" | "Ember Glow" | "Mocha Silk" | "Golden Hour" | "Pacific Sunset" | "Volcanic Dawn" | "Deep Ocean" | "Reef Lagoon" | "Gold Noir" | "Velvet Noir" | "Morning Mist" | "Sage Whisper" | "Royal Navy" | "Paper White"
solidstringHex color #rrggbb
imageDataUrlstringdata:image/... background image
imageFit"cover" | "contain" | "stretch"
imageBlurnumberpx
overlayColorstringHex color #rrggbb
overlayOpacitynumber0-100
noiseboolean
noiseIntensitynumber0-100

set_device

Set device frame & placement

How the screenshot is presented. preset (centered: Centered; bleed-bottom: Bleed bottom; bleed-top: Bleed top; float-center: Float center; tilt-left: Tilt left; tilt-right: Tilt right; perspective: Perspective; float-bottom: Float bottom; side-right: Text left, device right; side-left: Device left, text right) — explicit fields override it. scale (% of canvas width), x/y (50 = centered; <0 or >100 bleeds off-canvas), rotation, perspective, cornerRadius; chrome {style: none|phone|tablet|laptop|monitor|browser|window|tv|watch, color} draws a 2D device frame (phone for mobile, laptop/window/browser for desktop, tv for TV); use3D with model3D iphone|samsung, modelColor and rotation3D {x,y,z}; shadow {...}; border {...} (outline stroke).

Parameters (19)
screenIdstringScreen id. Defaults to the selected screen.
screenIdsstring[]Several screen ids at once.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
scope"screen" | "platform" | "variant"screen (default): one screen. platform: every screen in the platform deck. variant: every screen of every platform in the selected variant.
preset"centered" | "bleed-bottom" | "bleed-top" | "float-center" | "tilt-left" | "tilt-right" | "perspective" | "float-bottom" | "side-right" | "side-left"
scalenumber% of canvas width
xnumber
ynumber
rotationnumberDegrees
perspectivenumberShear -50..50
cornerRadiusnumber
chrome{ style, color }
use3Dboolean
model3D"iphone" | "samsung"
modelColorstringiphone: natural|blue|white|black|desert|deep-purple|gold|red; samsung: gray|black|silverblue|whitesilver|pinkgold|jadegreen|jetblack
rotation3D{ x, y, z }
shadow{ enabled, color, blur, opacity, x, y }
border{ enabled, color, width, opacity }

set_text_style

Style headline & subheadline

Typography and layout of the headline/subheadline (content is set with set_copy). headline/subheadline {enabled, font, size (output px), weight, color, opacity, italic, underline, strikethrough, uppercase, letterSpacing}; position top|bottom; align left|center|right (mirrored automatically for RTL languages); offsetY (% from edge); x (block center %) and maxWidth (% of width) for side-by-side layouts; lineHeight (%); gap (% of headline size). With language set, headline/subheadline size, offsetY and lineHeight are stored as an override for that language only (for long German or short CJK copy); resetLanguageOverride removes it.

Parameters (16)
screenIdstringScreen id. Defaults to the selected screen.
screenIdsstring[]Several screen ids at once.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
scope"screen" | "platform" | "variant"screen (default): one screen. platform: every screen in the platform deck. variant: every screen of every platform in the selected variant.
languagestringStore size/offset/lineHeight as a per-language override
resetLanguageOverrideboolean
headline{ enabled, font, size, weight, color, opacity, italic, underline, strikethrough, uppercase, letterSpacing }
subheadline{ enabled, font, size, weight, color, opacity, italic, underline, strikethrough, uppercase, letterSpacing }
position"top" | "bottom"
align"left" | "center" | "right"
offsetYnumber% from top/bottom edge
xnumberText block center in % of width
maxWidthnumber% of canvas width
lineHeightnumber%
gapnumber% of headline size

manage_elements

Manage overlay elements

Floating overlays on a screen (badges, awards, emoji, icons, logos — not the headline). Actions: add {kind: text|emoji|icon|image, text+language (text), emoji, icon (Lucide name), imageDataUrl (image), properties?}; update {elementId, properties?, text?, language?}; delete {elementId}; reorder {elementId, toIndex} (later = on top). Layers: behind-device, above-device, above-text.

Parameters (13)
action*"add" | "update" | "delete" | "reorder"
screenIdstringScreen id. Defaults to the selected screen.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
elementIdstring
kind"text" | "emoji" | "icon" | "image"
textstring
languagestring
emojistring
iconstring
imageDataUrlstring
properties{ name, x, y, width, rotation, opacity, layer, font, fontSize, fontWeight, color, italic, frame, frameColor, frameScale, emoji, icon, strokeWidth, shadow }Element properties; only those matching the element kind apply.
toIndexinteger

manage_popouts

Manage magnified popouts

Popouts crop a region of the screen's source screenshot and show it enlarged (callouts for key UI). Actions: add {properties?}, update {popoutId, properties}, delete {popoutId}. Crop values are % of the source image; placement is % of the canvas.

Parameters (6)
action*"add" | "update" | "delete"
screenIdstringScreen id. Defaults to the selected screen.
screenIndexinteger0-based screen position within deckId (or the selected platform); alternative to screenId.
deckIdstringPlatform deck id used with screenIndex or scope. Defaults to the selected platform.
popoutIdstring
properties{ cropX, cropY, cropWidth, cropHeight, x, y, width, rotation, opacity, cornerRadius, shadow, border }

transfer_style

Copy design to other screens

Copies design from a source screen to targets — across screens, platforms or variants. Copy (words) and screenshots stay with each target; pixel values rescale when sizes differ. parts selects background/device/text/elements (all by default). Targets: targetScreenIds, or targetScope platform (source deck) | variant (every deck in source variant) | project (everything).

Parameters (6)
sourceScreenIdstring
sourceScreenIndexinteger
deckIdstringDeck for sourceScreenIndex
targetScreenIdsstring[]
targetScope"platform" | "variant" | "project"
parts{ background, device, text, elements }

Output

export

Export store imagesread-only

Renders full-resolution store images. delivery "return" (default) returns data URLs to save as files (max 24 per call — narrow with screenIds/deckIds/languages). delivery "download" builds a ZIP in the browser for the user (variant/platform-WxH/lang/NN-name.png). Defaults: selected platform deck, current language, PNG. JPEG is flattened (stores reject alpha).

Parameters (8)
variantIdsstring[]
deckIdsstring[]
screenIdsstring[]
languagesstring[]
allLanguagesbooleanEvery project language
allPlatformsbooleanEvery deck of the selected variant(s)
format"png" | "jpeg"
delivery"return" | "download"

history

Undo / redo

Undo or redo document changes (yours and the user's). steps defaults to 1.

Parameters (2)
action*"undo" | "redo"
stepsinteger

Want the machine-readable version? The same schemas are served at /llms.txt, and the automation guide walks through a full example.

Try it with your agent

Open the editor in a WebMCP-capable browser and ask your agent to “make App Store screenshots for my app”.