@appscreenshotstudio/mcp 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.js +31 -6
- package/package.json +1 -1
- package/skills/appscreenshotstudio/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -95,6 +95,9 @@ Attach local image files as `{ file_path, kind }`. Max 5 per call. The `kind` de
|
|
|
95
95
|
| `screenshot` (default) | Your real app UI, straight from a simulator or device | Inside the generated device frames, in attachment order |
|
|
96
96
|
| `mascot` | Your app's character or logo creature | Decoratively around the phones (peeking from behind the hook card, beside the closing card). Use a transparent PNG |
|
|
97
97
|
| `reference` | A look to **match**: a competitor's App Store listing, a design the user pointed you at, any image that already shows a phone with a headline above it | Nowhere. It is read for palette, type weight, headline length and composition, and never placed in a frame |
|
|
98
|
+
| `background` | The user's own photo: an arena, a product shot, a brand photo, a still from their video | **Behind** the cards. One photo becomes one panorama across the first three cards (or the cards your message names, e.g. "across all of them"); several become one per card, in attachment order. Free: the photo is cut to fit, nothing is generated |
|
|
99
|
+
|
|
100
|
+
The images in one call must stay under about 4MB encoded. The tool does not resize, and a photo straight off a camera is often bigger, so shrink it first (a 3840px long edge at JPEG quality 85 is plenty). An oversized call is refused before anything is sent, with no credits spent.
|
|
98
101
|
|
|
99
102
|
**Do not send a competitor's store screenshots as `screenshot`.** They are finished marketing cards, so putting one inside a device frame nests a phone inside a phone and ships someone else's artwork into your listing. If the user says "make it look like this app" and hands you that app's listing, it is `reference`. Their own raw captures are `screenshot`. One call can carry both, and the reference ones are simply skipped when the frames get filled.
|
|
100
103
|
|
|
@@ -265,7 +268,7 @@ Full policy: [appscreenshotstudio.com/privacy](https://appscreenshotstudio.com/p
|
|
|
265
268
|
|
|
266
269
|
**Retention.** Projects persist in your account until you delete them. Rendered PNG download URLs expire after 7 days.
|
|
267
270
|
|
|
268
|
-
**Contact.** [
|
|
271
|
+
**Contact.** [contact@bookillustrationai.com](mailto:contact@bookillustrationai.com)
|
|
269
272
|
|
|
270
273
|
## Links
|
|
271
274
|
|
package/dist/index.js
CHANGED
|
@@ -168,6 +168,21 @@ function buildDesignMessage(input, hasScreenshotImages = false) {
|
|
|
168
168
|
parts.push(`Please include projectMeta with brand colors, mood, appCategory, and a rich globalVisualTheme description.`);
|
|
169
169
|
return parts.join('\n');
|
|
170
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Characters of image data one chat call may carry. The server sits behind a
|
|
173
|
+
* 4.5MB request-body limit that rejects the call before it runs, so an agent
|
|
174
|
+
* sees a bare failure. This package does not resize (no image library), and a
|
|
175
|
+
* background photo straight off a camera is several MB, so say so up front.
|
|
176
|
+
*/
|
|
177
|
+
const CHAT_IMAGE_BUDGET_CHARS = 4_000_000;
|
|
178
|
+
/** A message telling the agent how to fit, or null when the images fit. */
|
|
179
|
+
function imagesOverBudget(payload) {
|
|
180
|
+
const total = payload.reduce((n, img) => n + img.dataUrl.length, 0);
|
|
181
|
+
if (total <= CHAT_IMAGE_BUDGET_CHARS)
|
|
182
|
+
return null;
|
|
183
|
+
return `The attached images are ${(total / 1e6).toFixed(1)}MB encoded, over the ${(CHAT_IMAGE_BUDGET_CHARS / 1e6).toFixed(1)}MB one call can carry, so nothing was sent and no credits were spent. `
|
|
184
|
+
+ 'Shrink them first, e.g. to a 3840px long edge as JPEG quality 85 (macOS: sips -Z 3840 -s format jpeg in.png --out out.jpg; ImageMagick: magick in.png -resize "3840x3840>" -quality 85 out.jpg), or send background photos in a call of their own.';
|
|
185
|
+
}
|
|
171
186
|
function readImagesForChat(images) {
|
|
172
187
|
const payload = [];
|
|
173
188
|
const errors = [];
|
|
@@ -193,10 +208,10 @@ function readImagesForChat(images) {
|
|
|
193
208
|
/** Shared images param for generate-screenshots and edit-screenshots. */
|
|
194
209
|
const chatImagesSchema = z.array(z.object({
|
|
195
210
|
file_path: z.string().describe('Absolute path to an image file on the local filesystem (PNG, JPG, or WEBP)'),
|
|
196
|
-
kind: z.enum(['screenshot', 'mascot', 'reference']).default('screenshot')
|
|
197
|
-
.describe("'screenshot' = real app UI, automatically placed inside the generated device frames (in attachment order). 'mascot' = the app's character/mascot, placed decoratively around the phones (peeking from behind the hook card's phone, beside or in a corner on the closing card); use a transparent PNG. 'reference' = a look to match rather than content: a competitor's App Store listing, a design you want the style of, any image that already shows a phone with a headline above it. A reference is read for taste and is NEVER placed inside a frame, which is the point: wrapping a finished marketing card in a device frame puts a phone inside a phone."),
|
|
211
|
+
kind: z.enum(['screenshot', 'mascot', 'reference', 'background']).default('screenshot')
|
|
212
|
+
.describe("'screenshot' = real app UI, automatically placed inside the generated device frames (in attachment order). 'mascot' = the app's character/mascot, placed decoratively around the phones (peeking from behind the hook card's phone, beside or in a corner on the closing card); use a transparent PNG. 'reference' = a look to match rather than content: a competitor's App Store listing, a design you want the style of, any image that already shows a phone with a headline above it. A reference is read for taste and is NEVER placed inside a frame, which is the point: wrapping a finished marketing card in a device frame puts a phone inside a phone. 'background' = the user's own photo, placed BEHIND the cards: one background photo becomes one panorama across a group of cards (the first three, or the cards the message names, e.g. \"across all of them\"), several become one per card in attachment order. Free, nothing is generated; cards the photo lands on get a dark band and light text so the words stay readable."),
|
|
198
213
|
})).max(5).optional()
|
|
199
|
-
.describe('Images to attach to this generation. App screenshots land inside the device frames automatically; a mascot gets placed around the phones; a reference only informs the design. All survive later edits and regenerations.');
|
|
214
|
+
.describe('Images to attach to this generation. App screenshots land inside the device frames automatically; a mascot gets placed around the phones; a reference only informs the design; a background photo goes behind the cards. All survive later edits and regenerations. Together they must stay under about 4MB encoded: this tool does not resize, so shrink camera photos first.');
|
|
200
215
|
// ─── MCP Server ─────────────────────────────────────────────────────────────────
|
|
201
216
|
// Read from package.json rather than a literal. This is the version a client
|
|
202
217
|
// sees in the MCP handshake, and a hand-synced literal silently sat at 0.6.1
|
|
@@ -216,7 +231,7 @@ server.registerTool('generate-screenshots', {
|
|
|
216
231
|
destructiveHint: false,
|
|
217
232
|
openWorldHint: false,
|
|
218
233
|
},
|
|
219
|
-
description: `Create a complete set of App Store screenshot designs for an app. Attach real app screenshots via the images param and they are placed inside the device frames automatically; attach a mascot/character image (kind: "mascot", transparent PNG) and it gets placed around the phones. Returns a project URL where the developer can preview, refine, and export final PNGs.
|
|
234
|
+
description: `Create a complete set of App Store screenshot designs for an app. Attach real app screenshots via the images param and they are placed inside the device frames automatically; attach a mascot/character image (kind: "mascot", transparent PNG) and it gets placed around the phones; attach the user's own photo (kind: "background") and it goes behind the cards, one photo as a panorama or several as one per card. Returns a project URL where the developer can preview, refine, and export final PNGs.
|
|
220
235
|
|
|
221
236
|
IMPORTANT: Before calling this tool, research the user's codebase to populate the codebase_context parameter. Search for: package.json/README (app name & description), theme/color config files (brand colors), route definitions (key screens), marketing copy (value proposition), and App Store metadata. The more context you provide, the better the screenshots will be. Call prepare-screenshot-brief first if you need a research checklist.
|
|
222
237
|
|
|
@@ -297,6 +312,13 @@ Costs 5 credits per generation.`,
|
|
|
297
312
|
if ('error' in resolved) {
|
|
298
313
|
return { content: [{ type: 'text', text: resolved.error }] };
|
|
299
314
|
}
|
|
315
|
+
// Read the images before anything is created, so an oversized attachment
|
|
316
|
+
// fails here instead of leaving an empty project behind.
|
|
317
|
+
const { payload: chatImages, errors: imageErrors } = readImagesForChat(input.images);
|
|
318
|
+
const tooBig = imagesOverBudget(chatImages);
|
|
319
|
+
if (tooBig) {
|
|
320
|
+
return { content: [{ type: 'text', text: tooBig }] };
|
|
321
|
+
}
|
|
300
322
|
// Step 1: Create project (with codebase context if provided)
|
|
301
323
|
const projectName = `${input.app_name} Screenshots`;
|
|
302
324
|
const createBody = {
|
|
@@ -316,7 +338,6 @@ Costs 5 credits per generation.`,
|
|
|
316
338
|
const projectId = project.id;
|
|
317
339
|
// Step 2: Chat to generate all cards (with attached images when provided:
|
|
318
340
|
// screenshots auto-fill the device frames, mascots decorate around them)
|
|
319
|
-
const { payload: chatImages, errors: imageErrors } = readImagesForChat(input.images);
|
|
320
341
|
const hasScreens = chatImages.some((img) => img.kind === 'screenshot');
|
|
321
342
|
const message = buildDesignMessage(input, hasScreens);
|
|
322
343
|
const chatRes = await apiCall('POST', `/api/v1/projects/${projectId}/chat`, {
|
|
@@ -375,7 +396,7 @@ server.registerTool('edit-screenshots', {
|
|
|
375
396
|
destructiveHint: true,
|
|
376
397
|
openWorldHint: false,
|
|
377
398
|
},
|
|
378
|
-
description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 5 credits per edit. You can also attach images: app screenshots fill the device frames of regenerated cards, a mascot (kind: "mascot") gets placed around the phones.
|
|
399
|
+
description: `Make changes to an existing screenshot project. Use natural language to describe what you want to change. Costs 5 credits per edit. You can also attach images: app screenshots fill the device frames of regenerated cards, a mascot (kind: "mascot") gets placed around the phones, and a background photo (kind: "background") goes behind the cards, one photo as a panorama or several as one per card.
|
|
379
400
|
|
|
380
401
|
What you can change:
|
|
381
402
|
- Text: headlines, subtitles, badge text, font size, font family (Inter, Poppins, Montserrat, DM Sans, Space Grotesk, etc.)
|
|
@@ -455,6 +476,10 @@ Example edit messages:
|
|
|
455
476
|
}
|
|
456
477
|
}
|
|
457
478
|
const { payload: chatImages, errors: imageErrors } = readImagesForChat(images);
|
|
479
|
+
const tooBig = imagesOverBudget(chatImages);
|
|
480
|
+
if (tooBig) {
|
|
481
|
+
return { content: [{ type: 'text', text: tooBig }] };
|
|
482
|
+
}
|
|
458
483
|
const res = await apiCall('POST', `/api/v1/projects/${project_id}/chat`, {
|
|
459
484
|
message: enrichedMessage,
|
|
460
485
|
selected_card_indices: card_indices || [],
|
package/package.json
CHANGED
|
@@ -68,10 +68,11 @@ Call the `generate-screenshots` MCP tool with:
|
|
|
68
68
|
- `count`: number of cards (3-10)
|
|
69
69
|
- `story_flow`: `"auto"` (default), `"hero-intro"`, `"problem-solution"`, `"benefit-first"`, etc.
|
|
70
70
|
- `codebase_context`: the full context object from Step 1
|
|
71
|
-
- `images`: local file paths, each tagged with a `kind`.
|
|
71
|
+
- `images`: local file paths, each tagged with a `kind`. Four kinds, four destinations:
|
|
72
72
|
- `kind: "screenshot"` (default): real app UI, placed inside the device frames automatically, in order. If screenshots exist in the repo (fastlane/screenshots, store assets, README images), attach them here so the set comes back with real UI in the phones instead of empty frames.
|
|
73
73
|
- `kind: "mascot"`: the app's character, placed peeking from behind the hook card's phone and on the closing card. Transparent PNG.
|
|
74
74
|
- `kind: "reference"`: a look to **match**, never placed in a frame. Use this for a competitor's App Store listing, a design the user pointed you at, or any image that already shows a phone with a headline above it. It is read for palette, type weight, headline length and composition.
|
|
75
|
+
- `kind: "background"`: the user's own photo, placed BEHIND the cards. One photo becomes a panorama across the first three cards (or the cards your message names); several become one per card, in order. Use it when the user wants their own arena, product or brand photo as the backdrop. Keep all images in a call under about 4MB encoded: shrink camera photos first (3840px long edge, JPEG).
|
|
75
76
|
|
|
76
77
|
**Do not tag a competitor's store screenshots as `screenshot`.** They are finished marketing cards, so placing one inside a device frame nests a phone inside a phone and ships someone else's artwork. If the user says "make it look like X" and hands you X's listing, that is `kind: "reference"`. Their own raw captures are `kind: "screenshot"`, and a message can carry both.
|
|
77
78
|
|