storeframe-mcp 0.1.0 → 0.2.0
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 +72 -19
- package/dist/local.js +936 -177
- package/harness-dist/assets/{index-BppCs90_.js → index-iutW2Tnu.js} +171 -171
- package/harness-dist/index.html +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,11 +25,14 @@ share links) — nothing that could reach a store on your behalf.
|
|
|
25
25
|
| Tool | What it does | Key inputs |
|
|
26
26
|
|------|--------------|------------|
|
|
27
27
|
| `render_strip` | Render screenshots into mocked-up per-panel PNGs | `screenshots`, `panelPresetId?`, `style?` / `look?` / `useSavedLook?`, `project?`, `version?`, `locale?`, `preview?`, `output?` |
|
|
28
|
-
| `emit_bundle` | `render_strip` (or pre-rendered `panels`) + a `fastlane deliver` zip (+ optional share link) | `screenshots` or `panels`, `bundleId`, `locale?`, `projectName?`, `share?`, `output?` (+ the same styling params) |
|
|
28
|
+
| `emit_bundle` | `render_strip` (or pre-rendered `panels`) + a `fastlane deliver` zip (+ optional share link) | `screenshots` or `panels`, `bundleId`, `locale?`, `locales?` (multi-locale bundle), `projectName?`, `share?`, `output?` (+ the same styling params) |
|
|
29
|
+
| `save_project` | Save the strip as an editable Studio project (structure + look only — does NOT render, so it never hits the render timeout); returns `projectId` + an `openUrl` | `screenshots`, `project?` (update in place; omit to create), `projectName?`, `panelPresetId?`, `style?` / `look?` / `useSavedLook?`, `version?`, `locale?`, `sourceDir?` |
|
|
29
30
|
| `read_look` | Return a project's saved Storeframe look (styling only), with its version + pin state | `project?` (default: your most recently edited project) |
|
|
31
|
+
| `read_project` | Return a project's FULL current state as an opaque `ProjectFile` — frame order, per-locale caption words, locale list, styling. Answers *"what did the designer change?"* (remember `updatedAt`, re-read later) | `project?` (default: your most recently edited project) |
|
|
32
|
+
| `render_project` | Re-render a SAVED project with your OWN raw screenshots, matched to its shots **by filename** — the project supplies frame order, captions + styling, so the result reproduces the designer's strip | `project?`, `screenshots` (a FLAT list, each with its original filename as `name`), `locale?`, `preview?`, `output?` |
|
|
30
33
|
| `save_look` | Persist a composed look on a project (styling only — bumps its content version) | `look`, `project?`, `sourceName?` |
|
|
31
34
|
| `describe_look` | The styling field catalog + defaults, for authoring from scratch | *(none)* |
|
|
32
|
-
| `request_screenshot_upload` | Mint signed upload slots for real screenshots | `count` (1–10) |
|
|
35
|
+
| `request_screenshot_upload` | Mint signed upload slots for real screenshots | `count` (1–10), `names?`, `locale?` (a per-locale batch tag) |
|
|
33
36
|
|
|
34
37
|
- **`panelPresetId`** — App Store size: `r69` (default, 6.9″ iPhone 1290×2796), `r65`, `r55`,
|
|
35
38
|
`ipad13`, `ipad129`. This enum is a hand-kept copy of `mockup-engine/appstore.ts`'s
|
|
@@ -38,8 +41,10 @@ share links) — nothing that could reach a store on your behalf.
|
|
|
38
41
|
here.
|
|
39
42
|
- **`style`** — the structured styling input (call `describe_look` for the full catalog):
|
|
40
43
|
`{ shotLook?, background?, captions? }`. `captions` is one entry PER PANEL in slot order;
|
|
41
|
-
each entry
|
|
42
|
-
|
|
44
|
+
each entry is EITHER a single caption object OR an **array of caption layers** stacked on that
|
|
45
|
+
panel (headline + subline + …). Each layer's `text` (and a single caption's `subtitle`) is
|
|
46
|
+
per-RENDER input (never stored — a look carries styling only). Captions auto-layout above the
|
|
47
|
+
device so they never collide with the phone. Wins over `look`/`useSavedLook`.
|
|
43
48
|
- **`look`** — a Storeframe look JSON exactly as `read_look` returns it; feed it back in to
|
|
44
49
|
restyle. Omit for default styling.
|
|
45
50
|
- **`version`** — render a specific saved look version (implies the saved look). Without it,
|
|
@@ -47,34 +52,78 @@ share links) — nothing that could reach a store on your behalf.
|
|
|
47
52
|
- **`emit_bundle` output** — a zip (`README.md`, `fastlane/Deliverfile`,
|
|
48
53
|
`fastlane/screenshots/<locale>/NN_storeframe.png`) as `zipBase64` or `zipUrl`/`zipRef` (see
|
|
49
54
|
Output below), plus `shareLink` when `share: true`.
|
|
50
|
-
- **`locale`** — an App Store locale code, e.g. `de-DE` (default `en-US`). Labels the render
|
|
51
|
-
|
|
55
|
+
- **`locale`** — an App Store locale code, e.g. `de-DE` (default `en-US`). Labels the render,
|
|
56
|
+
picks which `{ "locales": … }` screenshot variants render (see
|
|
57
|
+
[Per-locale screenshots](#per-locale-screenshots--multi-locale-bundles)), and, for
|
|
58
|
+
`emit_bundle`, picks the `fastlane/screenshots/<locale>/` folder. **It does not
|
|
52
59
|
select caption text** — this server never stores or looks up Studio-typed copy (repo owns
|
|
53
60
|
the words). Pass the right words for that locale yourself in `style.captions[].text` /
|
|
54
61
|
`subtitle`.
|
|
55
62
|
|
|
63
|
+
### Per-locale screenshots & multi-locale bundles
|
|
64
|
+
|
|
65
|
+
Any `screenshots` entry (and any `emit_bundle` `panels` entry) can carry **per-locale
|
|
66
|
+
variants** instead of one image:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{ "locales": { "en-US": { "ref": "…en…" }, "de-DE": { "ref": "…de…" } } }
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `render_strip({ locale: "de-DE", … })` renders the `de-DE` variant of each such entry. A
|
|
73
|
+
locale with **no variant of its own falls back** to the `en-US` variant (else the first
|
|
74
|
+
declared) — so you can ship German captions over English screenshots today and upgrade the
|
|
75
|
+
pixels later. Plain (non-`locales`) entries serve every locale. The response echoes the
|
|
76
|
+
declared locales as `screenshotLocales`.
|
|
77
|
+
- `emit_bundle({ locales: ["en-US", "de-DE"], … })` emits **ONE zip** with a
|
|
78
|
+
`fastlane/screenshots/<locale>/` folder per listed locale — `fastlane deliver` uploads every
|
|
79
|
+
locale in a single run. A single-entry list behaves exactly like `locale`; omitting `locales`
|
|
80
|
+
is the unchanged single-locale bundle.
|
|
81
|
+
- `request_screenshot_upload({ count, names, locale })` tags a batch of upload slots with the
|
|
82
|
+
locale it's for (echoed back — bookkeeping only; refs are locale-agnostic).
|
|
83
|
+
|
|
84
|
+
**Recommended multi-locale flow — render per locale, then compose once.** Caption text is
|
|
85
|
+
per-render input, so this is also the only way to get per-locale *captions* into one bundle,
|
|
86
|
+
and it keeps each call fast (see "Cheap preview, then compose" below):
|
|
87
|
+
|
|
88
|
+
1. Per locale `L`: `render_strip({ locale: L, output: "urls", style: { captions: [<L's words>] },
|
|
89
|
+
screenshots: […] })` → per-panel refs for `L`.
|
|
90
|
+
2. One `emit_bundle({ locales: […], bundleId, panels: [ { "locales": { "en-US": { "ref": "p1-en" },
|
|
91
|
+
"de-DE": { "ref": "p1-de" } } }, … ] })` — zips every locale **without re-rendering**.
|
|
92
|
+
|
|
93
|
+
The one-call form (`emit_bundle` with `screenshots` + `locales`) works too, but renders once
|
|
94
|
+
per locale with the *same* captions for every locale, and multiplies the slow full-res render
|
|
95
|
+
by the locale count.
|
|
96
|
+
|
|
56
97
|
### The `captions.<locale>.json` convention
|
|
57
98
|
|
|
58
99
|
The canonical source of shipping caption copy is a file **in your own repo**, one per locale,
|
|
59
100
|
keyed by **panel ordinal** (0-based, in strip order — not panel id, so the file stays stable
|
|
60
101
|
across re-renders):
|
|
61
102
|
|
|
103
|
+
A panel's entry is EITHER a single caption (`{ headline, subtitle? }`) OR an **array of layers**
|
|
104
|
+
(each `{ text, … }`, stacked in order) — use the array when you want more than a headline + one
|
|
105
|
+
subtitle, e.g. an eyebrow over a headline over a caption:
|
|
106
|
+
|
|
62
107
|
```json
|
|
63
108
|
// captions.de-DE.json
|
|
64
109
|
{
|
|
65
110
|
"0": { "headline": "Alles im Blick", "subtitle": "Deine Tage, übersichtlich." },
|
|
66
|
-
"1": { "
|
|
111
|
+
"1": [ { "text": "NEU" }, { "text": "Schneller planen" } ]
|
|
67
112
|
}
|
|
68
113
|
```
|
|
69
114
|
|
|
70
115
|
To render a locale: read that file, map it onto `style.captions[]` in the same order (index
|
|
71
116
|
`i` → panel `i`, `null` for a panel with no caption), and pass `locale` alongside so the
|
|
72
|
-
render/bundle is labeled and routed consistently
|
|
117
|
+
render/bundle is labeled and routed consistently. A single caption maps to one object; a layer
|
|
118
|
+
array maps straight through as an array:
|
|
73
119
|
|
|
74
120
|
```json
|
|
75
121
|
{
|
|
76
122
|
"locale": "de-DE",
|
|
77
|
-
"style": { "captions": [
|
|
123
|
+
"style": { "captions": [
|
|
124
|
+
{ "text": "Alles im Blick", "subtitle": "Deine Tage, übersichtlich." },
|
|
125
|
+
[ { "text": "NEU", "sizePt": 28 }, { "text": "Schneller planen" } ]
|
|
126
|
+
] }
|
|
78
127
|
}
|
|
79
128
|
```
|
|
80
129
|
|
|
@@ -97,10 +146,12 @@ context budget (or get silently truncated by a file-read tool) long before rende
|
|
|
97
146
|
3. Pass `{ "ref": "<ref>" }` — not inline base64 — as that screenshot's entry in
|
|
98
147
|
`render_strip`/`emit_bundle`'s `screenshots` array.
|
|
99
148
|
|
|
100
|
-
`screenshots` entries accept
|
|
149
|
+
`screenshots` entries accept these shapes: an inline base64 string (small payloads only —
|
|
101
150
|
inline is capped and returns a clear "payload too large" error above ~8MB decoded, pointing
|
|
102
|
-
you back at this flow), `{ ref }` from step 1,
|
|
103
|
-
itself: image/png, no redirects, ~20MB cap)
|
|
151
|
+
you back at this flow), `{ ref }` from step 1, `{ url }` (an https URL this server fetches
|
|
152
|
+
itself: image/png, no redirects, ~20MB cap), `{ path }` (local stdio server only — see below),
|
|
153
|
+
or `{ "locales": { "<locale>": <any of those> } }` for per-locale variants (see
|
|
154
|
+
[Per-locale screenshots](#per-locale-screenshots--multi-locale-bundles) above).
|
|
104
155
|
|
|
105
156
|
**Output** works the same way in reverse: `render_strip`/`emit_bundle` take an `output` field
|
|
106
157
|
— `"inline"` (base64), `"urls"` (uploaded under your own prefix, short-lived signed download
|
|
@@ -248,24 +299,26 @@ instead of `{ ref }`/`{ url }`:
|
|
|
248
299
|
(`{ "path": ... }` only works over this LOCAL server — the hosted server rejects it, since
|
|
249
300
|
reading an arbitrary server-side path there would be a local-file-inclusion hole.)
|
|
250
301
|
|
|
251
|
-
**What's different locally, and why:**
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
302
|
+
**What's different locally, and why:** every tool that needs an ACCOUNT to read or persist to —
|
|
303
|
+
`read_look` / `save_look` / `save_project` / `read_project` / `render_project` / share links —
|
|
304
|
+
has nothing to talk to in local mode by default, so they cleanly no-op with a "sign in" message.
|
|
305
|
+
`render_strip` / `emit_bundle` are otherwise **fully functional** — you lose nothing on rendering
|
|
306
|
+
itself, only on persistence, which is exactly the free/paid line:
|
|
255
307
|
|
|
256
308
|
| | Local (free, `npx storeframe-mcp`) | Hosted (Fly, `sfs_…` token) |
|
|
257
309
|
|---|---|---|
|
|
258
310
|
| Render compute | **your machine** ($0, no timeout) | our Fly machine |
|
|
259
311
|
| Auth | none (the process runs as you) | account + API token |
|
|
260
|
-
| Saved looks / editable projects / share links | opt-in via a token (below) — share links still need a direct hosted connection | ✅ |
|
|
312
|
+
| Saved looks / editable projects / project read+re-render / share links | opt-in via a token (below) — share links still need a direct hosted connection | ✅ |
|
|
261
313
|
| Screenshot input | local `{ path }` off disk | `request_screenshot_upload` → `{ ref }` |
|
|
262
314
|
|
|
263
315
|
### Optional: bridge a local render into your hosted account
|
|
264
316
|
|
|
265
317
|
Pass a personal Storeframe API token (Studio → account menu → **API tokens** — the same
|
|
266
318
|
`sfs_…` token the hosted server takes as a bearer) and `save_project` / `read_look` /
|
|
267
|
-
`save_look` start working too — **rendering still happens
|
|
268
|
-
saved-project JSON (structure + look, never screenshot
|
|
319
|
+
`save_look` / `read_project` / `render_project` start working too — **rendering still happens
|
|
320
|
+
locally and for free; only the small saved-project JSON (structure + look, never screenshot
|
|
321
|
+
bytes) goes to your account:**
|
|
269
322
|
|
|
270
323
|
```bash
|
|
271
324
|
STOREFRAME_TOKEN=sfs_… claude mcp add storeframe -- npx -y storeframe-mcp
|