@easysociable/cli 0.1.16 → 0.1.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easysociable/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Agent-first CLI for EasySociable: Content Engine, Template, Slideshow, and MCP",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -51,27 +51,31 @@
51
51
  "LICENSE",
52
52
  "README.md"
53
53
  ],
54
+ "scripts": {
55
+ "typecheck": "tsc --noEmit",
56
+ "test": "vitest run",
57
+ "build": "tsup",
58
+ "prepack": "node scripts/prepack.mjs && pnpm build",
59
+ "pack:check": "npm pack --dry-run"
60
+ },
54
61
  "publishConfig": {
55
62
  "access": "public",
56
63
  "registry": "https://registry.npmjs.org/"
57
64
  },
58
65
  "dependencies": {
59
- "commander": "^11.1.0"
66
+ "@resvg/resvg-wasm": "^2.6.2",
67
+ "commander": "^11.1.0",
68
+ "satori": "^0.36.0"
60
69
  },
61
70
  "devDependencies": {
71
+ "@easysociable/mcp-server": "workspace:*",
72
+ "@easysociable/template-gateway-client": "workspace:*",
73
+ "@easysociable/tsconfig": "workspace:*",
74
+ "@easysociable/tweet-card": "workspace:*",
75
+ "@easysociable/vitest-config": "workspace:*",
62
76
  "@types/node": "^22.14.0",
63
77
  "tsup": "^8.0.2",
64
78
  "typescript": "^5.8.3",
65
- "vitest": "^1.3.1",
66
- "@easysociable/mcp-server": "0.0.0",
67
- "@easysociable/template-gateway-client": "0.0.0",
68
- "@easysociable/tsconfig": "0.0.0",
69
- "@easysociable/vitest-config": "0.0.0"
70
- },
71
- "scripts": {
72
- "typecheck": "tsc --noEmit",
73
- "test": "vitest run",
74
- "build": "tsup",
75
- "pack:check": "npm pack --dry-run"
79
+ "vitest": "^1.3.1"
76
80
  }
77
- }
81
+ }
@@ -1,178 +1,225 @@
1
1
  ---
2
2
  name: easysociable-slideshow
3
3
  description: >
4
- Create, list, update and review durable multi-page Slideshow Runs for
5
- EasySociable from a local Content Pack. Name the argument (arc) first, then
6
- pick a Layout Family per page (one layout, adapted to every platform) by
7
- role, slotSummary and density — never default Cover→Point→Steps→Recap→CTA.
8
- A Formula with a Look already fixes each page's Layout Family. Page 1 must
9
- be a cover or hook class family; those must not appear on later pages. Use the
10
- unified `easysociable` CLI or MCP, open Studio to preview and edit, then
11
- ask the user to click Download for a PNG ZIP. CLI/MCP must not call
12
- render/export or create_render_job for final pixels. Runs remain in the
13
- owner dashboard until archive or hard delete.
4
+ Turn a topic into an editable, ready-to-post carousel (Slideshow Run) in
5
+ EasySociable Studio. Research facts, pick a proven hook and structure
6
+ (Formula), adapt pages from one Deck Style's catalog layouts, render-check
7
+ every page locally, then create the Run and hand the user a Studio link.
8
+ Ask the user only for what only they know (their Brand, once; their own
9
+ images/screenshots). Final pixels come only from Studio Download.
14
10
  ---
15
11
 
16
12
  # EasySociable Slideshow Skill
17
13
 
18
- A Slideshow Run is a composition of explicit Layout Families, one per page.
19
- A Layout Family is one layout whose templates differ only by platform canvas,
20
- so one Run yields the carousel for every platform (Studio switches variants).
21
- It is not a reusable Carousel/Deck Template and it is not a public post.
22
- Page order is the argument of **this pack**, not a catalog recipe.
14
+ The user gives a topic. You return a Studio link to a carousel that is good
15
+ enough to post, where every word is still editable. The output is editable,
16
+ so **a wrong guess is cheap and a question is expensive**: decide platform,
17
+ page count, arc, style and copy yourself; the user fixes details in Studio.
23
18
 
24
- ## Rules
19
+ Ask only for what only the user knows:
25
20
 
26
- 1. Read a local `content-pack.v1` from the Content Engine.
27
- 2. Use the unified `easysociable` CLI or the unified MCP server. All hosted
28
- calls go through Gateway; never call Directus, R2, Stripe or private services.
29
- 3. Choose a Brand (or Profile/Theme) and an explicit Layout Family for every
30
- page, sent as `layoutFamilyId` in the pack (Gateway resolves it to the
31
- family's template on the Run's native canvas; `pageTemplateId` is still
32
- accepted). The server never silently chooses or replaces a layout.
33
- Order of precedence: (a) a Formula **Look** (see Formula handoff),
34
- (b) families already chosen on the Content Engine pack (**Template
35
- Selection** after **Page Contracts**), (c) a shortlist from
36
- `easysociable slideshows recommend --file contracts.json --seed <slug>`
37
- (MCP `recommend_slideshow_templates`) — pick one `familyId` per page with a reason.
38
- The recommender filters platform + native canvas + slotSummary + cover rule,
39
- demotes Layout Families used in the owner's recent Runs, and keeps one
40
- unused family per page. `role` / `supportedRoles` are weak retrieval tags,
41
- not sequence position. Never browse with bare `templates list` (first 20
42
- ids only); use `--platform <p> --all` if you must see the full catalog.
43
- Do not copy a previous pack's Template Selection as the default.
44
- 4. **Cover / hook placement (hard):** a template is cover/hook class when
45
- `supportedRoles` includes `cover` or `hook`. `pages[0]` must use one.
46
- Cover/hook class templates must not appear on any later page. Later pages
47
- use metric / quote / compare / value / steps / cta / etc. Do not put a
48
- Point or metric-only template on page 1 to “open with a number” — pick a
49
- cover or hook template whose slots fit the opening copy.
50
- 5. A Run has up to 8 pages on Free and 20 on paid, one native platform
51
- (`tiktok`, `instagram`, `linkedin` or `threads`; it sets the page cap and
52
- the canvas edited first) and one Brand across pages. Studio renders the
53
- same Run for every platform its Layout Families support.
54
- 6. Topology is fixed after creation: no add, copy, delete, reorder or template
55
- switch. Page-instance slot/layout/type/style/decoration edits remain allowed
56
- in Studio.
57
- 7. Final pixels leave the product only from **Studio Download** (browser PNG
58
- ZIP). Do not call `slideshows render`, `slideshows export`, `renders create`
59
- or MCP `render_slideshow_run` / `create_render_job`. Those return
60
- `HEADLESS_RENDER_DISABLED`.
61
- 8. Before creating a new Run, list/find prior Runs by `contentSlug`. **Update**
62
- the same Run only when page count, Layout Families, and intended sequence
63
- still match. A different arc or family set is a **new Run** — never PATCH
64
- new copy into a locked Cover-Point-Steps-Recap-CTA skeleton.
65
- 8b. **Knowledge hard gate (every create, not only the first Run):** before
66
- `create_run` / `slideshows create`, read Identity (Role / What I build /
67
- Point of view — no `(fill)`, non-empty) and `boundaries.md` (Not covering
68
- and Never claim non-empty), or run
69
- `easysociable engine validate --run <run-dir> --require-knowledge`.
70
- If `needs/` exists, `needs/_index.md` ≥ 3 `N-` rows; if `needs/` is absent, skip that count. Fail → hand back to
71
- **easysociable-content** / refuse create; list missing files. Do not add
72
- Gateway or MCP params. User must say **强制继续** / **force continue**
73
- to call Gateway. **Exempt:** Formula handoff Runs (prompt names
74
- `Formula: F-…`) — the Formula supplies the arc and the user supplies the
75
- topic, so a first-time user with no Content Engine is not blocked.
76
- 8c. **Identity chain (ADR-0036, hard):** before create, the CLI must be
77
- logged in with the **user's Dashboard Workspace API key** (same account
78
- that will open Studio). Refuse fixture `workspace_local` / local
79
- `test-key` unless the user explicitly asked for a local fixture
80
- (`--allow-local-fixture`). Order: `easysociable auth login` (opens the
81
- browser; the user approves once and the key is stored — use
82
- `--api-key <key>` only when headless) → create Run → open
83
- `studioUrl` while logged in as that user. If Studio shows “belongs to
84
- another account”, recreate with the current key — do not invent
85
- cross-workspace access.
86
- 9. Preview is free. Free Download is 3 successful ZIPs per month and one
87
- platform. Paid Download is unmetered.
88
- 10. **Forbidden default:** do not assemble Cover → Point → Steps → Recap → CTA
89
- because those are P0 family names. Name the arc first
90
- (`references/ARC.md`). Page count follows the argument, not the catalog.
91
- Rule 4 still applies: page 1 is cover/hook class, not “whatever family
92
- is named Cover”.
21
+ - their Brand (IP name, handle, avatar) — once, ever;
22
+ - their own material (screenshots, photos) when a page needs it.
93
23
 
94
24
  ## Workflow
95
25
 
96
- 1. Write one arc line (`references/ARC.md`). Do not skip this for a five-family fill-in.
97
- 2. Validate Page Contracts / pack when present:
98
- `python3 scripts/validate-pack.py runs/<slug>/pack.md` (in the Content Engine).
99
- Refuse create if contracts are empty or contain `templateId`.
100
- 3. Resolve or create the user's Brand through the unified CLI/MCP.
101
- 4. Use the Formula Look's families, else pack **Template Selection**. Otherwise run
102
- `easysociable slideshows recommend --file contracts.json --seed <slug> --json`
103
- and choose a `familyId` from each page's `candidates`; never place a cover/hook class
104
- family after page 1. Report `gaps` (pages with < 2 role-matching
105
- templates) to the user as authoring backlog. Record Layout Family evidence
106
- as `hypothesis` unless published comparable results support `tested` /
107
- `supported` — a template having been used before is not evidence.
108
- 5. List existing Runs when the Pack has a stable content slug:
109
-
110
- ```bash
111
- easysociable slideshows list --content-slug my-post --json
26
+ ### 0. Login (once per session)
27
+
28
+ `easysociable auth status --json`.
29
+
30
+ - `authenticated: false` → stop; ask the user to run `easysociable auth login`
31
+ (one browser approval covers CLI and Studio). Draft nothing while logged out.
32
+ - `authenticated: true` → say once: "This Run will be created as
33
+ `<account.email>` — open Studio with the same account."
34
+
35
+ ### 1. Brand (ask once, ever)
36
+
37
+ `easysociable brands list --json`.
38
+
39
+ - A Brand exists → use it (the most recently updated if several), silently.
40
+ - None → ask in **one** message, everything skippable:
41
+ "What name and @handle should appear on your carousels? (Optional: an
42
+ avatar/logo image path.) Reply 'skip' to post without a signature."
43
+ Create it with `easysociable brands create --file brand.json` using the
44
+ palette of the chosen Deck Style (`references/DECK_STYLES.md`).
45
+ Skipped → no Brand: header shows the topic, the CTA has no handle, and the
46
+ Deck Style palette goes in `theme.json` as
47
+ `{ "color": { "canvas", "text", "textMuted", "accent", "primary" } }`
48
+ (without a Brand or theme Studio falls back to its dark default).
49
+
50
+ ### 2. Facts
51
+
52
+ Research the topic from primary sources (official announcement, docs,
53
+ reputable press). Keep a source URL for every fact. Drop claims you can only
54
+ find in secondary blogs. Never invent numbers, dates, quotes or features.
55
+
56
+ When the user started from a Content Engine run, facts come from its knowledge
57
+ pages instead (see `easysociable-content`).
58
+
59
+ ### 3. Hook and structure
60
+
61
+ Both catalogs are hosted cards distilled from real viral posts, with evidence
62
+ pooled across niches (a hook or structure works by its mechanism, not its
63
+ niche). Use a card when it fits; otherwise write your own. Never force one.
64
+
65
+ - Decide the content's **shape** from your facts: N tips → `tip-list`, a
66
+ procedure → `steps`, a transformation → `before-after`, errors →
67
+ `mistake-list`, a single piece of news or a claim → no list recipe.
68
+ - `easysociable hooks recommend --json` → one mold per hook type (list-tease,
69
+ contrast, number, identity, …), ranked by evidence.
70
+ - `easysociable formulas recommend --recipe <recipe> --platform <p> --fact-count <n> --json`
71
+ when the shape is a recipe.
72
+ - Use a card only if `stop` is false **and** it fits this content (a news
73
+ explainer is not an "N things" list). Prefer `published`; a `hypothesis`
74
+ card is thin evidence: use it only when it clearly fits.
75
+ - Hook: fill the mold's `format` with the topic (never copy its example).
76
+ Formula: its `swipe` is the page order and each `beat.fill` guides the copy.
77
+ - No fitting card → write the hook and arc yourself (`references/ARC.md`):
78
+ draft 3 hooks of different types, keep the most specific one the carousel
79
+ fully pays off.
80
+ - Platform: what the user said, else the one their Brand/history uses, else
81
+ Instagram 4:5. Page count follows the argument (usually 6–9), within
82
+ `references/PLATFORM_CAPS.md`.
83
+ - One idea per page, ≤ 45 words per page. Page 1 is the hook. Last page asks
84
+ for one action (comment, save or follow).
85
+
86
+ ### 4. Style and pages
87
+
88
+ Pick one Deck Style (`references/DECK_STYLES.md`): the Brand's style if it has
89
+ one, else by content. Styles that need images only when you have the images.
90
+
91
+ For each page, take the family that fits its purpose and adapt its source:
92
+
93
+ ```bash
94
+ easysociable templates source --family <familyId> --platform <platform> --json
95
+ ```
96
+
97
+ Follow "Adapting a family" in `DECK_STYLES.md`. Put the result in the pack as a
98
+ generated page:
99
+
100
+ ```json
101
+ { "role": "hook", "slots": { "text_0": "…", "text_1": "…" },
102
+ "layout": { "studioJson": "<div id=\"Graphic\" data-type=\"post\" …>…</div>",
103
+ "canvas": { "width": 1080, "height": 1350 } } }
104
+ ```
105
+
106
+ `slots` maps each `data-variable` to its plain text. Generated pages carry no
107
+ `layoutFamilyId` / `pageTemplateId`. A Formula with a Look uses the Look's
108
+ families as the sources instead of a Deck Style.
109
+
110
+ ### 5. Images
111
+
112
+ - Real products, apps, people, data → real screenshots or photos only. Never
113
+ an AI-generated picture of a real product UI.
114
+ - Concept / mood / background → generate one if this environment has an
115
+ image-generation tool; otherwise leave the page text-only.
116
+ - Images never contain text: all words stay in editable text layers.
117
+ - **Every page whose content needs a real image you don't have gets a
118
+ placeholder slot** (as many pages as need one), never a text-only layout. Size it into the composition (usually the
119
+ lower half of the page) and label it with exactly what belongs there, e.g.
120
+ "Add: Grok Bot app screenshot". The user selects it in Studio and clicks
121
+ the upload button to replace it. Markup and SVG in `DECK_STYLES.md`
122
+ ("Image placeholder").
123
+ - An image you do have: upload it
124
+ (`easysociable images upload --file body.json` with
125
+ `{ "file": "data:image/png;base64,…", "filename": "x.png" }`) and use the
126
+ returned `asset.url` as `src`.
127
+ - List every placeholder in the final message ("page 2: app screenshot").
128
+
129
+ ### 6. Check (hard gate)
130
+
131
+ ```bash
132
+ easysociable brands get --id <brandId> --json > brand.json
133
+ node <skill>/scripts/check-pages.mjs pack.json --out ./check --brand brand.json
134
+ # no Brand: --theme theme.json instead of --brand brand.json
135
+ ```
136
+
137
+ - Exit 1 → fix every ERROR (overflow, off-canvas, text overlap, contrast) and
138
+ re-run. Do not create the Run with errors.
139
+ - Warnings (small text, too many words, empty band) → fix unless deliberate.
140
+ - Open `check/grid.png` and review it as a designer: one clear focal point per
141
+ page, nothing cramped, no two adjacent pages alike, reads in 2 seconds.
142
+ At most two fix rounds.
143
+ - Exit 2 (no Chrome) → continue, and tell the user the visual check was skipped.
144
+
145
+ ### 7. Create and hand off
146
+
147
+ ```bash
148
+ easysociable slideshows create --file pack.json --brand-id <brandId> --json
149
+ # no Brand: --theme theme.json instead of --brand-id
150
+ ```
151
+
152
+ Reply once with: the `studioUrl`, the arc in one line, the sources, and each
153
+ image placeholder to replace (page + what to upload). Tell them to edit in
154
+ Studio and click **Download** for the PNG ZIP.
155
+
156
+ ### 8. Revise (same Run, never a copy)
157
+
158
+ Feedback on an existing Run ("page 3 looks off", "shorter hook") edits that Run.
159
+
160
+ 1. `easysociable slideshows get --id <runId> --json > revisions/<runId>-r<revision>.json`
161
+ — the saved Run is the source of truth (it holds the user's Studio edits);
162
+ never rebuild from your local pack.json. The file is also the backup.
163
+ 2. Change only the pages the user named. Start from each page's saved `layout`
164
+ and `slots`, adapt as in step 4, and run step 6 on the changed pages.
165
+ 3. Write `patch.json` and apply it:
166
+ ```json
167
+ { "baseRevision": <run.revision>,
168
+ "pages": [{ "pageIndex": 2, "layout": { "studioJson": "…", "canvas": { "width": 1080, "height": 1350 } }, "slots": { … } }] }
112
169
  ```
113
-
114
- 6. **Hard gate, then** create (new arc/templates) or update (same topology,
115
- slot copy only). Check files or:
116
-
117
170
  ```bash
118
- easysociable engine validate --run <run-dir> --require-pack --require-knowledge
171
+ easysociable slideshows update --id <runId> --file patch.json --json
119
172
  ```
173
+ `slots` replaces the page's slots, so send the full set for that page.
174
+ Unlisted pages stay untouched.
175
+ 4. `RUN_REVISION_CONFLICT` → the user saved in Studio meanwhile: `get` again,
176
+ re-apply your change on top, retry once.
177
+ 5. "Go back to the previous version" → take those pages' `layout` / `slots`
178
+ from the newest `revisions/<runId>-r*.json` before the change and send them
179
+ as a normal patch with the current `baseRevision`. The original generated
180
+ pages are in the Run's `packSnapshot`.
181
+
182
+ Same `studioUrl`; tell the user to reload Studio. A new Run only for a
183
+ different topic, or when the user asks for an alternative version to compare.
184
+
185
+ ## Formula handoff (prompt names `Formula: F-…`)
186
+
187
+ `easysociable formulas get --id <id> --json`. Its `beats` are the pages (same
188
+ order and roles); `title_template` with `{X}` = the topic is the arc. Write copy
189
+ from each `beat.fill` and your facts; never copy the formula's example posts.
190
+ With `Look: L-…` (else the formula's first `looks` entry) the page source is
191
+ `look.slides["<n>"]` or `look.layouts[beat.role]`: adapt that family exactly as
192
+ in step 4. Then continue at step 5.
120
193
 
121
- Fail → refuse; return to **easysociable-content**. **强制继续** / **force continue**
122
- is the only override (conversational — not a CLI flag). Formula handoff
123
- Runs skip this knowledge check (rule 8b) but not the identity gate. Then:
124
-
125
- ```bash
126
- easysociable slideshows create --file ./pack.json --json
127
- ```
194
+ ## Rules
128
195
 
129
- 7. Open the returned `studioUrl` and inspect every page.
130
- 8. Save Studio edits and wait for the saved revision.
131
- 9. After explicit user confirmation, tell them to click **Download** in Studio.
132
- Do not render or export from CLI/MCP.
133
-
134
- ## Formula handoff (prompt names a `Formula: F-…` id)
135
-
136
- 1. `easysociable formulas get --id <id> --json` (falls back to the hosted
137
- catalog). Not found → tell the user; do not guess a structure.
138
- 2. The formula's `beats` are the page order: one page per beat, same roles,
139
- same count. Its `title_template` with `{X}` = the user's topic is the arc
140
- line, so rule 10 is satisfied by the formula, not by P0 family names.
141
- 3. Write each page's copy from `beat.fill` and the user's topic. Ask at most
142
- one question when tip/point pages need facts the topic doesn't supply.
143
- Never copy sentences from the formula's viral example posts.
144
- 4. **Look = copy the layout.** If the prompt names `Look: L-…` (else use the
145
- formula's first entry in `looks`), set each page's `layoutFamilyId` to
146
- `look.slides["<1-based slide number>"]` if present, else
147
- `look.layouts[beat.role]`. Do not run `slideshows recommend` for those
148
- pages and ignore the "demote recently used families" preference — the
149
- user asked for this layout. Only roles missing from the Look fall back to
150
- the recommender. Copy layout only: colours and fonts come from the user's
151
- Brand. If a Look family has image slots, ask the user for images (or say
152
- which slots are empty) instead of delivering blank image slots.
153
- 5. Turn beats into Page Contracts, then continue at Workflow step 3
154
- (Brand → families → identity gate → create → Studio). The knowledge gate
155
- (rule 8b) does not apply to Formula handoff Runs.
196
+ 1. All hosted calls go through the `easysociable` CLI or the unified MCP
197
+ server (Gateway). Never call Directus, R2, Stripe or private services.
198
+ 2. Final pixels leave only via Studio **Download**. Do not call
199
+ `slideshows render`, `slideshows export`, `renders create`, or MCP
200
+ `render_slideshow_run` / `create_render_job` (`HEADLESS_RENDER_DISABLED`).
201
+ 3. Revisions edit the same Run page by page (step 8): layout, text and images
202
+ can all change. Page count and order are fixed for now (no add, delete,
203
+ reorder) — if the user needs that, say so; create a new Run only when they agree.
204
+ 4. Free: up to 8 pages and 3 Downloads per month; paid: 20 pages, unmetered.
205
+ 5. Identity: create with the user's own login, not `workspace_local` /
206
+ `test-key` (unless they asked for `--allow-local-fixture`). Studio says
207
+ "belongs to another account" → recreate with the current login.
208
+ 6. Content Engine runs keep their knowledge gate:
209
+ `easysociable engine validate --run <run-dir> --require-knowledge`.
210
+ Topic-only requests (no Content Engine) use researched, sourced facts.
156
211
 
157
212
  ## Failure handling
158
213
 
159
- - If the knowledge hard gate fails, do not create the Run. Hand back to
160
- easysociable-content and list missing files unless the user said
161
- **强制继续** / **force continue**.
162
- - If page 1 is not cover/hook class, or a later page uses a cover/hook
163
- class template, stop and rebuild the Pack. Do not create the Run.
164
- - If a page template, slot or image is invalid, return the structured Gateway
165
- error to the Agent; do not substitute another template.
166
- - `LAYOUT_FAMILY_NOT_FOUND`: the family has no template for the Run's
167
- platform. Tell the user and pick another platform or family; do not guess.
168
- - If Download is exhausted (`USAGE_LIMIT_REACHED`) or past due, tell the user
169
- to upgrade or update billing.
170
- - If a Run was deleted, or Gateway returns `RUN_TOPOLOGY_LOCKED` because the
171
- pack changed sequence/templates, create a new Run from the Pack.
214
+ - `CONTENT_PACK_INVALID` → fix the pack field it names; do not drop pages silently.
215
+ - `BRAND_NOT_FOUND` → the Brand belongs to another account; list Brands again.
216
+ - `USAGE_LIMIT_REACHED` / past due → tell the user to upgrade or update billing.
217
+ - `RUN_REVISION_CONFLICT` → `slideshows get`, re-apply on the latest revision, retry once.
218
+ - `RUN_TOPOLOGY_LOCKED` → you sent a full `pack` or a `pageTemplateId`; send
219
+ page `layout` / `slots` instead (step 8).
172
220
 
173
221
  ## Handoff boundary
174
222
 
175
- The Content Engine owns semantic copy, Pack creation, and the arc.
176
- The Template Skill owns single-page authoring and publish.
177
- This Skill composes explicit page instances and opens Studio for review/Download.
178
- It does not own a product-level story recipe.
223
+ The Content Engine owns knowledge pages and Formula research. The Template
224
+ skill owns authoring new catalog layouts. This skill turns a topic into a Run
225
+ and opens Studio.
@@ -1,18 +1,20 @@
1
1
  # ContentPack v1
2
2
 
3
- Page `role` is a **weak retrieval tag** (layout-ish), not sequence position.
4
- `layoutFamilyId` is the explicit Layout Family chosen by the Agent (from a
5
- Formula Look or the recommender's `familyId`); Gateway resolves it to that
6
- family's template on the pack platform's canvas, and Studio derives the other
7
- platforms from the same family. `pageTemplateId` (one exact template) is still
8
- accepted and wins when both are sent. `slots` are public values only. Do not add a `deck_template_id`,
9
- `bindingMap`, AST, ContentDocument, or product `arc` / `pageSequence`.
3
+ A page is either **generated** (`layout: { studioJson, canvas }` adapted from a
4
+ Deck Style family — the default, see `DECK_STYLES.md`) or a **catalog page**
5
+ (`layoutFamilyId` / `pageTemplateId`, used as-is; only for Formula Looks the
6
+ user asked to copy exactly). `role` is a weak tag from the closed enum, not a
7
+ sequence position. `slots` are public values only. Do not add a
8
+ `deck_template_id`, `bindingMap`, AST, ContentDocument, or product `arc` /
9
+ `pageSequence`.
10
10
 
11
- The Gateway validates each `role` against the closed enum and that slots exist.
12
- It does not require Cover → Point → Steps → Recap → CTA.
11
+ Generated page:
13
12
 
14
- This skill **does** require page 1 to be cover/hook class (`supportedRoles`
15
- includes `cover` or `hook`) and forbids that class on later pages.
13
+ ```json
14
+ { "role": "hook", "slots": { "text_0": "Meta's new AI doesn't chat." },
15
+ "layout": { "studioJson": "<div id=\"Graphic\" data-type=\"post\" …>…</div>",
16
+ "canvas": { "width": 1080, "height": 1350 } } }
17
+ ```
16
18
 
17
19
  ## Example: cost → mechanism (TikTok)
18
20
 
@@ -47,10 +49,6 @@ Opening beat is cost; page 1 is still a hook-class template.
47
49
  }
48
50
  ```
49
51
 
50
- Pick families by **slotSummary + density** (or take them from a Formula Look),
51
- not by matching the beat name to a family named Cover / Point / Steps / Recap /
52
- CTA. Page 1 must still be cover/hook class.
53
-
54
52
  The renderer accepts any supported page count within the platform cap. A newly
55
53
  published Layout Family can be selected in a new Run without creating a
56
54
  carousel asset.
@@ -0,0 +1,132 @@
1
+ # Deck Styles
2
+
3
+ A Deck Style is a set of catalog Layout Families that share one visual language
4
+ (type scale, margins, chrome, palette). Every page of a Run is **adapted from one
5
+ family of a single Deck Style** — never drawn from scratch, never mixed across styles.
6
+
7
+ Read a family's Studio source for the Run's platform:
8
+
9
+ ```bash
10
+ easysociable templates source --family <familyId> --platform <platform> --json
11
+ ```
12
+
13
+ Pick the style from the Brand's default style. No Brand style yet → pick by content:
14
+
15
+ | Style | Use for | Needs images | Brand palette (canvas / text / textMuted / accent) |
16
+ |---|---|---|---|
17
+ | `cream-editorial` | explainers, opinions, news breakdowns, prompts — text-first | no | `#F4EEE7` / `#121A2B` / `#4A4F5C` / `#D4450F` |
18
+ | `quiet-ledger` | frameworks, tips, how-tos, lessons — calm, structured | no | `#FFFFFF` / `#15191E` / `#384352` / `#445164` |
19
+ | `dark-news` | breaking AI/tech news with a strong photo or product shot | yes (hero photo) | `#06080C` / `#FFFFFF` / `#C7CBD3` / `#4C9BFF` |
20
+ | `phone-showcase` | app tips, tool demos, "how I use X" — real screenshots | yes (screenshots) | `#F9F9F9` / `#0A0A0A` / `#555555` / `#0066DD` |
21
+
22
+ No images available and none can be generated → only `cream-editorial` or `quiet-ledger`.
23
+
24
+ ## cream-editorial
25
+
26
+ Big 112px headline with an accent-coloured second half, mono page number, pill tag, rule, SWIPE footer.
27
+
28
+ | Family | Page purpose |
29
+ |---|---|
30
+ | `fam_0488u93z` Cream Editorial Headline Poster | hook / cover: headline + one-line aside |
31
+ | `fam_w3p02voe` Cream Five-Line Headline Poster | hook / cover: headline only, up to 5 lines |
32
+ | `fam_vt5zt1xg` Accent Rail Paragraph Chart | context / evidence: one paragraph on an accent rail + 3 numbers |
33
+ | `fam_vw68bzh1` Cream Mono Prompt Card | value / steps: a mono "card" (prompt, quote, example input) |
34
+ | `fam_x6gdbad3` Accent Rail Paragraph Logo Row | proof: paragraph + logo row (needs logos) |
35
+ | `fam_9hlr90o1` Cream Big Button Follow Close | cta / follow: big question + accent button |
36
+
37
+ Point / list / metric pages are not in the catalog for this style: adapt the
38
+ headline poster (title on top, 2–3 rows or one huge number below), keeping its chrome.
39
+
40
+ ## quiet-ledger
41
+
42
+ White, small caps labels, soft green gradient blob, one idea per card.
43
+
44
+ | Family | Page purpose |
45
+ |---|---|
46
+ | `fam_49c6pout` Title + Subtitle Cover | cover |
47
+ | `fam_qery74q3` Bold Claim Hook with Swipe Arrow | hook |
48
+ | `fam_e8d1qpn2` Problem Setup Card | setup / problem |
49
+ | `fam_k9wge9gc` Single Takeaway Card | value / key idea |
50
+ | `fam_ue542bvy` Numbered Point Card | point (one per page, big number) |
51
+ | `fam_78vpdf64` Five-Step How-To List | steps |
52
+ | `fam_3tw3wbxx` Big Metric Proof Card | proof / metric |
53
+ | `fam_eh8wkyql` Closing Recap Summary | recap |
54
+
55
+ CTA: adapt `fam_rahs52cl` Bookmark Save Close into this palette.
56
+
57
+ ## dark-news
58
+
59
+ Near-black, full-bleed photo with headline over a fade.
60
+
61
+ | Family | Page purpose |
62
+ |---|---|
63
+ | `fam_321v25e7` Dark News Hero Poster | cover / hook over a hero photo |
64
+ | `fam_rms4v81m` Dark News Story Stack | point / evidence: image + short story |
65
+ | `fam_9lkrmau1` Monument Metric | metric / proof: one huge number |
66
+
67
+ CTA: adapt `fam_9hlr90o1` (button close) into the dark palette.
68
+
69
+ ## phone-showcase
70
+
71
+ Light grey, a phone mockup holding a real screenshot, short caption.
72
+
73
+ | Family | Page purpose |
74
+ |---|---|
75
+ | `fam_itnu5iiq` Title Over Fading Phone Poster | cover |
76
+ | `fam_wb2l75gl` Phone Left Title Right Poster | cover / screenshot |
77
+ | `fam_nk61xu51` One-Phone Prompt Tip | point: one phone + tip text |
78
+ | `fam_t2x277j8` Two-Phone Tip | point: before / after |
79
+ | `fam_99xxcxs0` Centered App Spotlight Stack | point: app icon + name + one line |
80
+ | `fam_ct0pajcy` Caption Over Big Phone | steps: one step per page |
81
+ | `fam_4ct2w5n5` Phone Left Step Note | steps |
82
+ | `fam_v4yktlzk` Phone Bottom Edge Caption | steps |
83
+ | `fam_sgif0njo` Twin Phones Follow Close | follow |
84
+ | `fam_6lxgv3nd` Follow Me Avatar Close | cta with the Brand avatar |
85
+ | `fam_rahs52cl` Bookmark Save Close | cta: save for later |
86
+
87
+ ## Adapting a family (the rules that make it look designed)
88
+
89
+ 1. Copy the family source. Keep its chrome (header, pill, page number, rule,
90
+ footer), margins (`left` of the first column), type scale and fonts.
91
+ 2. Change text, then fix each text box: explicit `<br />` line breaks, and
92
+ `height` = lines × lineHeight + ~12% of fontSize for descenders.
93
+ 3. Remove what you do not need; add only elements copied from a sibling family
94
+ of the same style (e.g. the rule rows or stat row).
95
+ 4. Brand chrome: the header label is the Brand name (or the topic when there is
96
+ no Brand); the CTA names the Brand handle. Never leave a template's original
97
+ name or handle (e.g. "Will.AI.m") on a page.
98
+ 5. Accent colour only on large text (≥ 36px, or ≥ 28px bold) and blocks. Small
99
+ labels use the text or muted colour.
100
+ 6. Semantic `data-type` values (`title`, `subtitle`, `kicker`, `metric`,
101
+ `caption`) get Brand colours forced by Studio. Text on an accent or image
102
+ block uses `label`, `body` or `statement` with an explicit colour.
103
+ 7. One family per page, no family twice in a Run unless the page purpose
104
+ repeats (e.g. several numbered points), and no two adjacent pages with the
105
+ same composition.
106
+
107
+ ## Image placeholder
108
+
109
+ A replaceable image slot for a real screenshot or photo the user will add.
110
+ Studio shows an upload button when it is selected.
111
+
112
+ ```jsx
113
+ <img data-type="image" data-variable="image_0" data-image-mode="slot_default"
114
+ alt="Add: <what goes here>" src="data:image/svg+xml;base64,<SVG>"
115
+ style={{ position: 'absolute', left: 88, top: 760, width: 904, height: 388, objectFit: 'cover', borderRadius: 24 }} />
116
+ ```
117
+
118
+ `<SVG>` is base64 of a grey box with an image icon and the label, sized to the slot:
119
+
120
+ ```xml
121
+ <svg xmlns='http://www.w3.org/2000/svg' width='904' height='388' viewBox='0 0 904 388'>
122
+ <rect width='904' height='388' fill='#DDD6CC'/>
123
+ <g transform='translate(416,124)' fill='none' stroke='#8C8781' stroke-width='5' stroke-linejoin='round'>
124
+ <rect width='72' height='56' rx='8'/><path d='M6 50 L26 28 L40 42 L50 34 L66 50'/><circle cx='52' cy='16' r='6'/>
125
+ </g>
126
+ <text x='50%' y='230' text-anchor='middle' font-family='Inter, Arial, sans-serif' font-size='32' font-weight='600' fill='#6F6A64'>Add: Grok Bot app screenshot</text>
127
+ </svg>
128
+ ```
129
+
130
+ Put the same data URL in the page's `slots` under `image_N`. Number slots
131
+ `image_0`, `image_1`, … per page. Use the style's own colours for the box
132
+ (canvas-adjacent grey on light styles, `#1A1F27` on dark ones).
@@ -1,4 +1,4 @@
1
- # Platform page caps (ADR-0026)
1
+ # Platform page caps
2
2
 
3
3
  The Run validates only the actual `content-pack.v1.pages.length`. There is no
4
4
  `designMax`, full-page deck skeleton, or deck catalog to clone.