@easysociable/cli 0.1.17 → 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/README.md +2 -1
- package/dist/easysociable.js +560 -451
- package/dist/easysociable.js.map +1 -1
- package/package.json +18 -14
- package/skills/easysociable-slideshow/SKILL.md +202 -155
- package/skills/easysociable-slideshow/references/CONTENT_PACK.md +13 -15
- package/skills/easysociable-slideshow/references/DECK_STYLES.md +132 -0
- package/skills/easysociable-slideshow/references/PLATFORM_CAPS.md +1 -1
- package/skills/easysociable-slideshow/scripts/check-pages.mjs +136 -0
- package/skills/easysociable-slideshow/workflows/CREATE_RUN.md +12 -43
- package/skills/easysociable-slideshow/workflows/MCP_FIRST.md +1 -3
- package/skills/easysociable-slideshow/workflows/OUT_OF_SCOPE.md +1 -1
- package/skills/easysociable-template/references/CATALOG_METADATA.md +2 -2
- package/skills/easysociable-template/scripts/generate-theme-from-hex.mjs +0 -0
- package/skills/easysociable-tweet-image/SKILL.md +57 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easysociable/cli",
|
|
3
|
-
"version": "0.1.
|
|
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
|
-
"
|
|
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/tsconfig": "0.0.0",
|
|
68
|
-
"@easysociable/template-gateway-client": "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
|
-
|
|
5
|
-
EasySociable
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
so
|
|
21
|
-
|
|
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
|
-
|
|
19
|
+
Ask only for what only the user knows:
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`
|
|
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
|
-
|
|
12
|
-
It does not require Cover → Point → Steps → Recap → CTA.
|
|
11
|
+
Generated page:
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
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).
|