@hypersocial/decks-cli 0.2.1 → 0.2.2

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 CHANGED
@@ -108,7 +108,7 @@ credits per second, refunded if fal fails to produce the clip.
108
108
  ## Narration
109
109
 
110
110
  `narrate` turns a deck's `script.md` into voiced clips in your own voice, word-timed
111
- captions, 60 fps mouth frames and a deck manifest. Rendering runs on the Hyperdecks
111
+ captions and a deck manifest (the player's live head lip-syncs from the audio). Rendering runs on the Hyperdecks
112
112
  backend with the platform's ElevenLabs key; the CLI only sends the script and polls.
113
113
  Each line is cached by a hash of its spoken text and voice, so after an edit only the
114
114
  slides whose words changed re-render.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypersocial/decks-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Command-line client for Hypersocial Decks live analytics and share management.",
5
5
  "type": "module",
6
6
  "main": "./src/commands.mjs",
@@ -53,13 +53,18 @@ Hyperdecks server; use the CLI where you have a shell and the tool otherwise.
53
53
 
54
54
  | Step | CLI | MCP tool |
55
55
  |---|---|---|
56
- | Scaffold | `hyperdecks deck new <slug> "<title>" --narrated` | `new_deck` |
56
+ | Scaffold | `hyperdecks deck new <slug> "<title>" --narrated [--layouts hero,product,number,closer]` | `new_deck` (`layouts`) |
57
57
  | Images | `hyperdecks gen-image "<prompt>" --slug <slug>` | `generate_image` |
58
58
  | Video clips | `hyperdecks gen-video "<prompt>" --slug <slug>` | `generate_video` |
59
+ | Product screenshot | `hyperdecks screenshot <url> --slug <slug>` | `capture_url` |
60
+ | Chart from numbers | `hyperdecks chart <spec.json> --slug <slug>` | `render_chart` |
61
+ | Icon set | `hyperdecks icons <subject...> --style "<style>" --slug <slug>` | `generate_icon_set` |
62
+ | Outside review (required before release) | `hyperdecks review <slug> --script decks/<slug>/script.md` | `review_deck` |
59
63
  | Your voice (once) | `hyperdecks voice clone <file...> --name <name>` | `clone_voice` |
60
64
  | Narrate | `hyperdecks narrate decks/<slug>` | `narrate_deck` |
61
65
  | Check | `hyperdecks check decks/<slug>` | `check_deck` |
62
66
  | Ship | `hyperdecks release decks/<slug> --to "<name>" --email <e>` | `release_deck` |
67
+ | Share-link poster | `hyperdecks poster <slug>` | `generate_deck_poster` |
63
68
  | Import only | `hyperdecks import <file> --slug <slug>` | `import_deck_from_url` |
64
69
  | One more link | `hyperdecks share new <slug> "<name>"` | `create_share` |
65
70
  | Who watched | `hyperdecks deck stats <slug>` | `deck_stats` |
@@ -79,15 +84,27 @@ number on a slide that has no row.
79
84
  ### 2. Scaffold
80
85
 
81
86
  ```bash
82
- hyperdecks deck new <slug> "<title>" --narrated # writes decks/<slug>/, registers a draft you own
87
+ hyperdecks deck new <slug> "<title>" --narrated --layouts hero,features,product,number,closer
88
+ # one slide per layout, from the layout library
89
+ hyperdecks deck new <slug> "<title>" --narrated [--presenter-style stage|bubble|glass|corner]
90
+ # the plain eight-slide outline
83
91
  ```
84
92
 
93
+ Both write `decks/<slug>/` and register a draft you own. Prefer `--layouts`:
94
+ pick the layouts from the story (see **Design** below), in order; repeat one
95
+ for more of the same (`number,number` gives slides `number` and `number-2`).
96
+
85
97
  Files, all in `decks/<slug>/`:
86
98
 
87
- - `index.html`: eight `<section class="slide" id="…">` slides (hello, problem,
88
- why-now, idea, how, proof, ask, bye) and the hosted player script. Keep, cut or
89
- add slides; keep the contract below.
90
- - `script.md`: the narration, one `## <slide-id>` block per slide.
99
+ - `index.html`: the `<section class="slide" id="…">` slides and the hosted
100
+ player script. With `--layouts` each slide is a layout's section (ids like
101
+ `features`, inner ids like `features-f1`) and its CSS sits once in `<head>`;
102
+ without, eight outline slides (hello, problem, why-now, idea, how, proof, ask,
103
+ bye). Keep, cut or add slides; keep the contract below.
104
+ - `script.md`: the narration, one `## <slide-id>` block per slide. With
105
+ `--layouts` each block starts as the layout's starter line with its `[go]` /
106
+ `[look]` cues already pointing at the slide's elements: rewrite the words,
107
+ keep the cues at the words they belong to.
91
108
  - `evidence.md`: the sources table. Private: release never uploads it.
92
109
 
93
110
  The deck contract (`check` enforces each line):
@@ -100,13 +117,145 @@ The deck contract (`check` enforces each line):
100
117
  - A title (first `<h1>`/`<h2>`) over 28 characters carries
101
118
  `data-title-mobile="<shorter>"`. The scaffold puts one on every title.
102
119
  - Each slide keeps its `<div class="narration-slot"></div>` (where the
103
- presenter's face and caption bubble sit); the first slide has `data-intro`.
120
+ presenter's face and captions sit; the player glides the presenter there,
121
+ so put slots on different sides across slides, as the scaffold's
122
+ `.slot-left` does); the first slide has `data-intro`.
104
123
  - The player script stays
105
124
  `<script type="module" src="https://decks.hypersocial.ai/player/v1/player.js" data-manifest="…">`.
106
125
  `narrate` fills `data-manifest`; do not edit it by hand.
107
126
  - Local images and files sit inside the deck folder and are referenced
108
127
  relatively (`img/chart.png`). Hosted images (`gen-image` URLs) are fine too.
109
128
 
129
+ #### Which presenter style
130
+
131
+ Set the deck's on the player tag (`data-presenter-style="stage"`) or in
132
+ script.md's front matter (`presenterStyle: stage`); override one slide with
133
+ `data-presenter-style` on its `<section>` or `presenter-style: corner` under
134
+ its `##` heading.
135
+
136
+ | Style | Pick it when |
137
+ |---|---|
138
+ | `stage` (default with the live head) | the presenter carries the deck: a founder pitch, a walkthrough. Large unframed head, lower-third captions; leave ~500 px beside the text for it |
139
+ | `bubble` (default otherwise) | a light aside; the face in a circle with a speech bubble |
140
+ | `glass` | dark or busy slides: head and captions on one frosted panel |
141
+ | `corner` | the slide is the point (a product shot, a chart, a demo): small head bottom-right, subtitles along the bottom |
142
+
143
+ Below 650 px stage and glass become corner on their own. Run
144
+ `hyperdecks check <deck> --layout` to be warned about any slide whose presenter
145
+ would cover its title.
146
+
147
+ ### Design: make it look good
148
+
149
+ A narrated deck is only as convincing as it looks. Design before you write the
150
+ narration, and check the result at both widths (step 6).
151
+
152
+ **One idea per slide.** The title states the idea as a sentence a listener
153
+ could repeat ("Narration renders in two minutes", not "Speed"). Everything
154
+ else on the slide supports that sentence; if it needs a second idea, it is a
155
+ second slide. Five to nine slides carry a three-minute deck.
156
+
157
+ **Type scale.** The layout shell defines it in `:root`; use the tokens, not
158
+ new sizes:
159
+
160
+ | Token | Stage (1600×900) | Phone | For |
161
+ |---|---|---|---|
162
+ | `--t-display` | 128px | 54px | one hero line or a closing word, at most once per slide |
163
+ | `--t-title` | 84px | 38px | the slide's title |
164
+ | `--t-sub` | 56px | 28px | a title beside a visual, a number's label |
165
+ | `--t-lead` | 30px | 17px | one supporting sentence |
166
+ | `--t-body` | 24px | 15px | list items, card text |
167
+ | `--t-label` | 17px | 12px | kickers, sources, captions (mono, uppercase) |
168
+
169
+ Nothing on a slide below 17px at stage size (a screenshot's frame chrome aside). A title over 28 characters needs
170
+ `data-title-mobile`; write the short version as a real sentence.
171
+
172
+ **Colour and contrast.** Three colours do the work: `--ink`, `--paper` and one
173
+ `--accent` (a second, `--accent-2`, only for a chart's other series, an
174
+ illustration or a placeholder face). Text is ink on paper or accent, or paper on ink: never accent
175
+ on paper, never grey on a colour. Alternate slide grounds (`on-accent`,
176
+ plain, `on-ink`) so the slide changes read, and keep every number, source and
177
+ label at full contrast. Change the palette and fonts once, in `:root`; every
178
+ layout reads them.
179
+
180
+ **Pick the layout from what the slide says.** Each layout's file in
181
+ `templates/layouts/` opens with its slot side, presenter and the cues that
182
+ suit it.
183
+
184
+ | Layout | Use it for | Presenter, moves |
185
+ |---|---|---|
186
+ | `hero` | the opening, a section opener; the presenter is the visual, no `.art` unless it shows the real subject | stage, bottom-right; `[wave]`, `[look: h1]` |
187
+ | `number` | one number with its source: proof, traction, a delta | stage; `[look: #<id>-figure]` as it is said |
188
+ | `product` | a screenshot in a browser frame (`.frame.phone` for a phone shot) with the point beside it | stage; `[look: #<id>-frame]`, `[reveal: #<id>-callout]` |
189
+ | `quote` | a customer or user in their own words, quoted exactly | stage, bottom-left; `[look: #<id>-quote]` |
190
+ | `compare` | before/after, them/us, three parallel lines each | stage; `[look: #<id>-before]`, `[go: #<id>-after]` |
191
+ | `timeline` | four milestones: history, a roadmap, a process | stage; `[go: #<id>-m1]` … `m4`, `[go: slot]` |
192
+ | `features` | three things it does, an icon each | stage; `[go: #<id>-f1]` … `f3`, `[go: slot]` |
193
+ | `chart` | real numbers drawn with `chart`, the takeaway beside | stage; `[look: #<id>-chart]`, `[reveal: #<id>-takeaway]` |
194
+ | `team` | up to four people, faces only with permission | stage; `[go: #<id>-p1]` … `p4`, `[go: slot]` |
195
+ | `closer` | the end: one line and one action (a command, a link) | stage, bottom-left; `[go: #<id>-cta]`, `[go: slot]`, `[wave]` |
196
+
197
+ Presenter style follows the deck (step 2, *Which presenter style*): `stage`
198
+ when the presenter carries the story, which is what the layouts are drawn for
199
+ (they keep the slot's corner clear); `corner` on a slide where a big
200
+ visual is the point and moves are not needed; `glass` on a dark or busy
201
+ picture. Two layouts (`quote`, `closer`) sit left; put a `slot-left` on others
202
+ where there is room so slide changes move the presenter.
203
+
204
+ **Visuals: real first, generated second.**
205
+
206
+ - Product: `hyperdecks screenshot <url>` (`capture_url`) into `product`'s
207
+ `.shot`; crop to what the narration talks about. Never mock a UI that
208
+ exists.
209
+ - Numbers: `hyperdecks chart <spec.json>` (`render_chart`) in the deck's
210
+ palette into `chart`'s `.chart`, the source in `data-note` and evidence.md.
211
+ Never a generated picture of a chart.
212
+ - **No decorative imagery.** Generic illustration (stages, speech bubbles,
213
+ floating shapes, abstract "tech" art, clip-art metaphors) makes a deck look
214
+ cheap. A visual earns its place only if it shows something real from the
215
+ story: the product, the data, a concrete situation or object. When in doubt,
216
+ leave it out: one big statement in type beats a picture of nothing. The
217
+ presenter is the hero of the opening slide; don't put art behind it.
218
+ - Icons: only when they label something the viewer must tell apart at a
219
+ glance. Three short statements set large usually beat three icon cards.
220
+ - Images: `gen-image` (`generate_image`) only for a concrete subject the
221
+ deck is about (a product in use, a place, a real object), never a metaphor.
222
+ One style per deck, described the same way every time (subject, medium,
223
+ palette hexes, "no text"). `--model nano-banana-2.1` when the image must
224
+ carry legible type.
225
+ - Video: `gen-video` for a short loop behind a hero or a product moment, with
226
+ `[play: video]` at its word; never needed for a deck to work.
227
+ - People: real photos only with permission; initials otherwise.
228
+
229
+ **Motion.** The presenter's moves are the deck's motion; keep everything else
230
+ still.
231
+
232
+ - `[go]` when the narration walks through items (cards, milestones, people,
233
+ the action on the closer): one `go` per item at the word that starts it,
234
+ then `[go: slot]` before the slide ends. Never more than one `go` per
235
+ sentence; never a `go` on a slide in `corner` style.
236
+ - `[look]` for a glance: the title as it is read, a number as it is said, a
237
+ screenshot as the narration turns to it.
238
+ - `[reveal]` for the one detail that should not be read before it is said (a
239
+ takeaway, a callout); not for every line.
240
+ - `[wave]` once at the start and once at the end.
241
+ - No CSS animation on slides beyond `.reveal`; the player animates the slide
242
+ change.
243
+
244
+ **Review before release (required).** After `check` passes and the deck is
245
+ imported, run `hyperdecks review <slug> --script decks/<slug>/script.md`
246
+ (`review_deck`, then poll `check_review_job`). Act on every finding:
247
+
248
+ - `fix`: change the slide or the script, re-import (or `release --qa`), and
249
+ review again until no `fix` is left. Do not release with a `fix` open.
250
+ - `consider`: apply it when it serves the slide's one idea; otherwise note in
251
+ your reply to the user why you left it.
252
+ - A finding you disagree with (a deliberate choice, a misread screenshot):
253
+ say so to the user with the reason instead of silently ignoring it.
254
+
255
+ If review cannot run (no credits, the service is down), say so to the user and
256
+ do the step 6 screenshot pass yourself as the reviewer: the same desktop and
257
+ phone screenshots, the same `fix` bar.
258
+
110
259
  ### 3. Write slides and script
111
260
 
112
261
  - One idea per slide; the title states it.
@@ -118,6 +267,29 @@ The deck contract (`check` enforces each line):
118
267
  - Holds: 1.1 s by default; `hold: 2` under the heading on interactive slides.
119
268
  - Cues: `[reveal: #id]` reveals `.reveal#id` at the word before it; also
120
269
  `[wave]`, `[mood: excited]`, `[pause: 0.5]`, `[custom: name]`.
270
+ - Moves, to point at part of a slide: `[go: <selector>]` flies the presenter
271
+ beside that element (the side with room) until the next `go`, the slide's
272
+ end, or `[go: slot]`; `[look: <selector>]` turns the head toward it without
273
+ moving. One selector each, matched inside that slide; check fails one that
274
+ matches nothing. Use `go` when the narration walks through a list or chart,
275
+ `look` for a glance at a title or number. Not in `corner` style. The best
276
+ showcase is a slide of stacked cards, one point each, with a `go` to each
277
+ card at the word that starts it: `Write [go: #step-1] the slides, write
278
+ [go: #step-2] what you'd say`. Give each card an id.
279
+
280
+ | Cue | Effect |
281
+ |---|---|
282
+ | `[wave]` | the presenter greets (the live head's joy emote) |
283
+ | `[mood: excited]` / `[emote: name]` | the head's mood or emote |
284
+ | `[reveal: #id]` | adds `is-revealed` to `#id` |
285
+ | `[pause: 0.5]` | a beat of silence (≤ 5 s) |
286
+ | `[play: video]` / `[pause: video]` | play or pause the slide's video |
287
+ | `[go: .list]` / `[go: slot]` | fly beside `.list` / back to the slot |
288
+ | `[look: h2]` | look at the title |
289
+ | `[custom: name]` | only the slide's controller sees it |
290
+ - `voice: dash` narrates with D.A.S.H.'s own robot voice, a synthetic
291
+ character voice (not a clone of anyone) any account may use, for decks that
292
+ D.A.S.H. presents. It works once the deployment sets `CHARACTER_VOICE_DASH`.
121
293
  - No `voice:` in the front matter means the user's first ready voice. If
122
294
  `hyperdecks voice list` shows none, ask the user to record one and run
123
295
  `voice clone` (it asks them for consent; never clone anyone else's voice).
@@ -136,9 +308,14 @@ reword the sentence (spell numbers and names the way they are said, or add a
136
308
  ### 5. Check
137
309
 
138
310
  ```bash
139
- hyperdecks check decks/<slug> [--forbid "Other Co,codename"]
311
+ hyperdecks check decks/<slug> [--forbid "Other Co,codename"] [--layout]
140
312
  ```
141
313
 
314
+ `--layout` lays each slide out in Chromium (needs `hyperdecks preview setup`).
315
+ At the stage size it warns, without failing, when a slide's presenter would
316
+ overlap its title. On a 390×844 phone (the share player's 374×736 slide card)
317
+ it fails any slide whose content overflows: the player never scrolls a slide.
318
+
142
319
  `--forbid` lists phrases that must not reach this audience (another customer,
143
320
  an internal codename). Messages and what to do:
144
321
 
@@ -152,25 +329,42 @@ an internal codename). Messages and what to do:
152
329
  | `narration runs …s, over the …s cap` | shorten the script |
153
330
  | `clip <id>: audio …` / `clip <id>: timeline …` | narrate again; the asset is missing or wrong |
154
331
  | `clip <id>: caption N runs` | narrate that slide again (`--slide <id>`) |
155
- | `clip <id>: caption words do not match` | narrate that slide again |
332
+ | `clip <id>: captions do not cover the clip text` | narrate that slide again |
156
333
  | `clip <id>: caption N is … characters` | split or join sentences in that block |
157
334
  | `local reference does not resolve` / `leaves the deck folder` | move the file into the deck folder or fix the path |
158
335
  | `player script must be` / `no player script` | restore the player/v1 script tag |
159
336
  | `the player script has no data-manifest` | run `narrate` |
337
+ | `no loading state` | copy the template's `<style data-hd-loading>` block (and the preload lines above it) into `<head>`; set `--hd-ground` / `--hd-ground-ink` to the first slide's colours |
160
338
  | `forbidden phrase` | remove it from the page, script or narration |
161
339
  | `slide <id>: needs a data-note` | add the source |
162
340
  | `slide <id>: title … needs a data-title-mobile` | add a shorter title |
341
+ | `… presenter style "…" is not one of` | use stage, bubble, glass or corner |
342
+ | `script.md line N: [go: …] matches nothing in slide <id>` | fix the selector, or add the element to that slide |
343
+ | `slide <id>: its content runs …px past the slide on a 390×844 phone` | trim that slide on phones: smaller type, fewer items, or hide decoration in its `@media (max-width: 650px)` rules (an `#id` rule outranks them; restate it there) |
344
+ | ⚠ `slide <id>: the … presenter would overlap the title` | move that slide's `.narration-slot`, pad the text away from it, or use `corner` |
163
345
 
164
346
  ### 6. Look at it, at both widths
165
347
 
166
348
  Serve the folder (`npx serve decks/<slug>` or `python3 -m http.server -d decks/<slug>`)
167
349
  and screenshot it with Playwright at 1440×900 and 390×844, every slide
168
- (`#scene=<id>`). Look at both: nothing clipped, the bubble clear of the text, the
169
- mobile titles in use. Fix and repeat until both read well.
350
+ (`#scene=<id>`). Look at both: nothing clipped, the presenter and its captions
351
+ clear of the text, the mobile titles in use. Fix and repeat until both read well.
352
+
353
+ Then the required review (see **Design**, *Review before release*): once the
354
+ deck is imported, `hyperdecks review <slug> --script decks/<slug>/script.md`
355
+ (`review_deck`, then `check_review_job`) has GPT-6 Luna look at every slide of
356
+ the deck's QA link on desktop and phone and list each problem as `fix` or
357
+ `consider` with a concrete suggestion. Release only when no `fix` is left.
358
+
359
+ Pick image models by job: `gen-image` defaults to GPT Image 2.5; `--model
360
+ nano-banana-2.1` is stronger on typography and photoreal scenes. `gen-video`
361
+ defaults to MiniMax H3 Max (`--model kling-v3` is the fallback). Use `chart` for
362
+ real numbers instead of a generated picture of a chart, and `icons` with the
363
+ deck's palette for a set that matches.
170
364
 
171
365
  ### 7. Release
172
366
 
173
- Commit the deck folder first: release refuses uncommitted changes so every
367
+ Only after `check` passes and the last review has no `fix` finding. Commit the deck folder first: release refuses uncommitted changes so every
174
368
  release matches a commit.
175
369
 
176
370
  ```bash
@@ -187,6 +381,11 @@ references must be tracked by git (an ignored `*.mp4` is refused). Then it impor
187
381
  (each `--email` pairs with the `--to` before it). Confirm recipients with the
188
382
  user before sending real links; send the links yourself only if asked.
189
383
 
384
+ Release also makes the deck's share-link poster (its first slide with a Play
385
+ badge, shown when a link is pasted into Slack, iMessage or email, and on the
386
+ dashboard card) within a minute. When the first slide changed look, check it
387
+ with `hyperdecks poster <slug>` (`generate_deck_poster`), which prints its URL.
388
+
190
389
  ### 8. Report who watched
191
390
 
192
391
  ```bash