wand-kit 0.1.0 → 0.3.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/PROMPT.md +91 -7
- package/SKILL.md +68 -14
- package/START-HERE.md +7 -1
- package/examples/gallery/job.mjs +3 -1
- package/examples/storyboard/job.mjs +72 -0
- package/examples/storyboard/script.txt +6 -0
- package/examples/talk/agents-demo.html +69 -0
- package/examples/talk/agents-demo.poster-next.png +0 -0
- package/examples/talk/agents-demo.poster.png +0 -0
- package/examples/talk/job.mjs +85 -0
- package/lib/board.js +152 -0
- package/lib/brand.js +23 -0
- package/lib/components.js +151 -5
- package/lib/engine.js +33 -7
- package/lib/html_export.js +35 -4
- package/lib/runtime_check.js +108 -0
- package/lib/talk.js +620 -0
- package/package.json +2 -2
- package/templates/storyboard.mjs +33 -0
- package/wand.js +65 -18
package/PROMPT.md
CHANGED
|
@@ -37,8 +37,11 @@ strokes) and `art` (which file plays which role). A component asks for a role
|
|
|
37
37
|
`tokens.json` and `BRAND.md` differ, `BRAND.md` is right and `tokens.json` has
|
|
38
38
|
drifted.
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
`current` is the default while the two overlap; a job is on `next` when the
|
|
41
|
+
user asks for the new brand. The default is one constant, `DEFAULT_BRAND` in
|
|
42
|
+
`kit/lib/brand.js`, and `doctor` prints the rule from it. The FK Roman
|
|
43
|
+
Standard licence for documents is still to be confirmed
|
|
44
|
+
(`brand-next/fonts/LICENSE-FONTS.md`).
|
|
42
45
|
|
|
43
46
|
## 1. Surfaces — locked
|
|
44
47
|
|
|
@@ -140,6 +143,9 @@ The components (`node wand.js components`; `kit/lib/components.js`):
|
|
|
140
143
|
| `stats`, `delta(from, to)` | figures, before-and-after |
|
|
141
144
|
| `steps(items)` | next steps with arrows |
|
|
142
145
|
| `callout`, `list`, `chapter`, `img`, `icon`, `tile` | the rest |
|
|
146
|
+
| `enter(kind, i)`, `step(n, html)`, `countup(text)`, `stat({ count })` | motion in a talk (§12) |
|
|
147
|
+
| `video({ src, poster })`, `demo({ src, poster })` | a clip or a live page on a slide (§12) |
|
|
148
|
+
| `storyboard({ title, shots })`, `sketch({ people, apps, agents })` | a board from a script, and a quick frame for it (§13) |
|
|
143
149
|
|
|
144
150
|
**Composition is free.** A job writes the markup it needs from these, adds its
|
|
145
151
|
own CSS on top (custom properties only) and may write raw markup where no
|
|
@@ -181,7 +187,9 @@ new ─▶ argue ─▶ content ─▶ compose ─▶ build ─▶ review ─▶
|
|
|
181
187
|
6. **review** — look at `out/sheet.png`, then at any page the gates named.
|
|
182
188
|
Read the pages as the reader will: does each carry its claim?
|
|
183
189
|
7. **ship** — `node wand.js ship <job> [--pptx]`: the build, the one-file HTML,
|
|
184
|
-
the PowerPoint.
|
|
190
|
+
the PowerPoint. A deck's HTML is a talk (§12), a storyboard's plays (§13),
|
|
191
|
+
and either runtime is driven before it ships. `--brand next` (or `current`)
|
|
192
|
+
builds the same job on the other brand into `out-<brand>/`. The review note says what was changed from the source and
|
|
185
193
|
why, which gates ran, and what a human still has to decide.
|
|
186
194
|
|
|
187
195
|
## 7. Gates — every build, every job
|
|
@@ -199,7 +207,13 @@ new ─▶ argue ─▶ content ─▶ compose ─▶ build ─▶ review ─▶
|
|
|
199
207
|
| pdf text | the PDF's text misses a line, or carries an em dash | |
|
|
200
208
|
| contrast (warn) | text under WCAG AA against its background, chrome excepted | |
|
|
201
209
|
| measure (warn) | a paragraph over the surface's characters-per-line | |
|
|
210
|
+
| images | an image did not load | an image that loaded and is the wrong one |
|
|
211
|
+
| media | a demo, a clip or its poster is missing | a demo that loads and misbehaves |
|
|
202
212
|
| console | a page error | |
|
|
213
|
+
| runtime (ship, decks) | a slide or step the keyboard cannot reach, the overview or notes not opening, the presenter view out of step, a demo that never loads | how the motion feels |
|
|
214
|
+
| timing (warn, boards) | the board is more than 10% off its `target` | the real voiceover's pace |
|
|
215
|
+
| frames (warn, boards) | a frame is still to draw | a frame that is drawn and wrong |
|
|
216
|
+
| player (ship, boards) | the player does not run, scrub, or caption | |
|
|
203
217
|
|
|
204
218
|
The gates read the DOM Chromium laid out for the PDF; nothing is inferred from
|
|
205
219
|
the spec. What no gate sees: the argument, the pacing, and whether the right
|
|
@@ -245,8 +259,78 @@ component was chosen. That is the review.
|
|
|
245
259
|
1. **DOCX export.** Declined for now: Word cannot hold these pages. If needed,
|
|
246
260
|
a semantic export (headings, prose, tables) as an editable-text version,
|
|
247
261
|
labelled as such.
|
|
248
|
-
2. **The sandbox's browser.**
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
262
|
+
2. **The sandbox's browser.** Confirmed 2026-10-19: claude.ai's sandbox carries
|
|
263
|
+
Playwright's Chromium in `/opt/pw-browsers`, which `findChrome()` reads, and
|
|
264
|
+
a page renders there exactly as it does on the Mac.
|
|
265
|
+
3. **The talk runtime** from the BofA deck: carried into every slide deck's HTML
|
|
266
|
+
in 0.3.0 (§12). The chapter panel is still a component for a job to draw.
|
|
267
|
+
4. **A scratch voice.** The Wand OS film timed its board against a voice from
|
|
268
|
+
macOS `say`; the chat sandbox has none, so timing here is words at `wpm`.
|
|
269
|
+
A recorded voiceover passed as `audio` leads the player.
|
|
252
270
|
4. **Email and banner surfaces**: declared in §1's spirit, not yet in the table.
|
|
271
|
+
|
|
272
|
+
## 12. Talks: motion and the presenter
|
|
273
|
+
|
|
274
|
+
Every slide deck's one-file HTML is a talk, with the runtime ported from the
|
|
275
|
+
BofA deck (`kit/lib/talk.js`): a crossfade between slides, entrances, steps,
|
|
276
|
+
media, the presenter view in a second window kept in step, the talk clock and
|
|
277
|
+
its pace, notes, the overview. The PDF, the PNGs and the PowerPoint never see
|
|
278
|
+
any of it: they show every slide at its end state, every step in, every
|
|
279
|
+
figure final, every poster.
|
|
280
|
+
|
|
281
|
+
- **Entrances, not effects.** By default (`talk: { motion: "auto" }`) a slide
|
|
282
|
+
that marks nothing has its blocks rise in, staggered. Mark a slide yourself
|
|
283
|
+
when one thing should lead: `enter("pop", 0)` on it and the rest follow.
|
|
284
|
+
`talk: { motion: "none" }` stills a deck; `motion: "none"` on a page stills
|
|
285
|
+
one slide. One orchestrated moment a slide; nothing loops, nothing bounces.
|
|
286
|
+
- **Kinds.** `rise` (the default), `fade`, `pop` for a mark or a figure,
|
|
287
|
+
`grow` for a bar going up, `widen` for a bar going across, `draw` for a
|
|
288
|
+
line that tells a trend (an SVG path with `pathLength="1"`), `count` for a
|
|
289
|
+
figure the room should watch arrive (`stat({ count: true })`, `countup()`).
|
|
290
|
+
- **Steps** when the order of the argument is the point: `step(1, html)`, then
|
|
291
|
+
2, then 3. Never more than four on a slide. Going back undoes the last step.
|
|
292
|
+
- **Notes on every slide of a talk**, and `seconds` on each when the talk has a
|
|
293
|
+
slot: the presenter view shows the slide's window and whether you are on
|
|
294
|
+
pace. `talk: { minutes }` gives the clock a total when slides carry none.
|
|
295
|
+
- **A demo** is one self-contained HTML file (no network, no relative assets),
|
|
296
|
+
mounted in a frame when its slide comes up and the next one preloaded. It
|
|
297
|
+
may expose `window.wandDemo = { play, pause, reset }` for the D and R keys,
|
|
298
|
+
and dress itself from `window.wandEmbed.brand` (bg, card, stroke, ink, text,
|
|
299
|
+
label, accent), which the deck fills from its brand. Its poster is required:
|
|
300
|
+
`node wand.js poster demo.html --play 3 --brand <the deck's>`.
|
|
301
|
+
- **A clip** plays muted and looping while its slide is on; MP4 (H.264) plays
|
|
302
|
+
in every browser. The HTML carries it, so it carries its size: over 60 MB
|
|
303
|
+
warns.
|
|
304
|
+
- **The presenter's keys:** arrows, Space and PgUp/PgDn move (a clicker works),
|
|
305
|
+
P opens the presenter view, N the notes, G the overview, T the clock, B
|
|
306
|
+
blanks the screen, F goes full screen, D and R play and restart media, a
|
|
307
|
+
number then Enter jumps, ? lists them.
|
|
308
|
+
|
|
309
|
+
## 13. Storyboards
|
|
310
|
+
|
|
311
|
+
A storyboard turns a script into a film's plan (`storyboard()`, generalised
|
|
312
|
+
from the Wand OS film in `runs/2026-10-06-wand-os-video`): a cover, the run
|
|
313
|
+
of show, then a page a shot with its number, name and timecode, the
|
|
314
|
+
voiceover word for word, one to four frames on their cue words, and the
|
|
315
|
+
direction (the line, camera, motion, on screen, sound, into next).
|
|
316
|
+
|
|
317
|
+
- **The script is the content file**, one voiceover line a shot. Split a long
|
|
318
|
+
paragraph where the edit will cut. Coverage then proves every word of the
|
|
319
|
+
script is on the board.
|
|
320
|
+
- **Timing is scratch timing:** each line lasts its words at `wpm` (150 for a
|
|
321
|
+
conversational read, 160 to 170 for a promo), with `lead` before and `tail`
|
|
322
|
+
after; a shot without voiceover `hold`s; `seconds` on a shot overrides the
|
|
323
|
+
estimate once a real read exists. `target` warns when the board is more
|
|
324
|
+
than 10% off. `timing.csv` and `captions.srt` ship with the board.
|
|
325
|
+
- **A frame is drawn four ways:** `sketch` (people as dots, software as
|
|
326
|
+
labelled boxes, agents as sparks: the script's own vocabulary, in the
|
|
327
|
+
brand's colours), the job's own SVG on brand roles, an image (a product
|
|
328
|
+
screen, a demo poster), or left to draw, which the frames gate counts. The
|
|
329
|
+
first frame is on screen from the cut; the others land on their cues.
|
|
330
|
+
- **The HTML plays the board:** the pages to read, and a player (P, or the
|
|
331
|
+
button) that cross-fades the frames on their cues with the voiceover as the
|
|
332
|
+
caption, a track of every shot to scrub, and a title-safe overlay. An
|
|
333
|
+
`audio` file, a scratch or final read, leads the clock when given.
|
|
334
|
+
- **Both brands:** the board is one job; `--brand next` builds it on the
|
|
335
|
+
website's brand beside the first. Frames drawn as sketches or on brand roles
|
|
336
|
+
follow; an image frame is per brand when it shows the brand.
|
package/SKILL.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: wand-
|
|
3
|
-
description:
|
|
2
|
+
name: wand-design
|
|
3
|
+
description: Rebrand or create Wand material on the current or new brand - decks and talks, documents, case studies, storyboards from a script, social cards. Use when a file is attached or branded work is wanted.
|
|
4
4
|
compatibility: Requires Node.js 18+, code execution enabled in claude.ai (Settings > Features), and a Chromium the kit can find (Playwright's cache or the system). No network needed once installed. Python 3 embeds fonts in the .pptx; without it the deck ships with the faces named, not embedded.
|
|
5
5
|
license: Proprietary - Wand AI
|
|
6
6
|
metadata:
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.3.0"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
# Wand
|
|
11
|
+
# Wand design
|
|
12
12
|
|
|
13
13
|
## First: find the kit and stand in it
|
|
14
14
|
|
|
15
15
|
1. **Installed from npm** (the usual way): it is at `node_modules/wand-kit/`.
|
|
16
|
-
If it is not there yet: `npm install wand-kit@
|
|
16
|
+
If it is not there yet: `npm install wand-kit@latest --no-audit --no-fund`.
|
|
17
17
|
2. **Attached to the chat as a zip**: unzip it and enter the folder it makes.
|
|
18
18
|
3. **You are already inside it**: `wand.js` is next to this file.
|
|
19
19
|
|
|
@@ -35,16 +35,28 @@ PDF, the PNGs, the PowerPoint and the one-file HTML are all read from it.
|
|
|
35
35
|
`PROMPT.md` is the design system: read it once for design decisions, not per
|
|
36
36
|
page. `node wand.js components` lists the vocabulary.
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
## Which brand
|
|
39
|
+
|
|
40
|
+
Two brands, one kit: `current` (Geist) and `next` (the website's). `doctor`
|
|
41
|
+
ends with the brand rule: which one is the default, and the words that ask
|
|
42
|
+
for the other. Follow it as printed. When the user names no brand, build on
|
|
43
|
+
the default without asking; when their words ask for the other, pass
|
|
44
|
+
`--brand` to `new`. One brand per piece, never a mix, and the review note
|
|
45
|
+
says which. The rule lives in the kit, not here, so it can change without
|
|
46
|
+
anyone reinstalling the skill.
|
|
47
|
+
|
|
48
|
+
**The same piece on the other brand:** `node wand.js ship <job> --brand next`
|
|
49
|
+
(or `current`) builds the job again on that brand, into `out-<brand>/`
|
|
50
|
+
beside the first. Nothing in the job changes.
|
|
41
51
|
|
|
42
52
|
## Read only what the job needs
|
|
43
53
|
|
|
44
54
|
| Job | Read |
|
|
45
55
|
|---|---|
|
|
46
56
|
| A document, a two-pager, a case study | `PROMPT.md` §5 and `templates/page.mjs`; `examples/overview/job.mjs` for a finished one |
|
|
47
|
-
| A deck
|
|
57
|
+
| A deck | §5 and `templates/slide.mjs` |
|
|
58
|
+
| An animated deck, a talk, a live demo | §12 and `templates/slide.mjs`; `examples/talk/job.mjs` for a finished one |
|
|
59
|
+
| A storyboard from a script | §13 and `templates/storyboard.mjs`; `examples/storyboard/job.mjs` |
|
|
48
60
|
| Social cards, a banner | `templates/card.mjs` |
|
|
49
61
|
| Edit a job this kit built | the job's `job.mjs` only, then `build` |
|
|
50
62
|
|
|
@@ -57,8 +69,8 @@ user says *new brand*, *new guidelines* or *website look*.
|
|
|
57
69
|
text runs in order, or use the decks kit's `tools/extract.py` if present.
|
|
58
70
|
2. **Write the page list in the chat before any markup**: one line per page
|
|
59
71
|
with the claim it carries and which source lines it takes. Then compose.
|
|
60
|
-
3. `node wand.js new work/<name> --surface letter|slide
|
|
61
|
-
write `pages(c)` with `c.L(n)` for every string, declare every departure
|
|
72
|
+
3. `node wand.js new work/<name> --surface letter|slide` (plus `--brand` only
|
|
73
|
+
when the brand rule says so), write `pages(c)` with `c.L(n)` for every string, declare every departure
|
|
62
74
|
in `edits` (no em dashes: swap them for commas or semicolons there) and
|
|
63
75
|
every line left out in `cut`.
|
|
64
76
|
4. `node wand.js build work/<name>/job.mjs` until every hard gate is ok. Look
|
|
@@ -79,22 +91,64 @@ Author from the client piece: remove the client's figures, names, quotes and
|
|
|
79
91
|
vendors; put the client's name and its people in `denylist` so the gate proves
|
|
80
92
|
they are gone. Say in the note what was cut and what was generalised.
|
|
81
93
|
|
|
94
|
+
### An animated deck or a talk
|
|
95
|
+
|
|
96
|
+
Every deck's HTML already animates: blocks rise in, slides crossfade, and the
|
|
97
|
+
presenter has notes, a clock, an overview and a presenter view (P). What a
|
|
98
|
+
talk adds:
|
|
99
|
+
|
|
100
|
+
1. Notes on every slide, and `seconds` on each when the talk has a slot.
|
|
101
|
+
2. Motion where it carries the argument (PROMPT.md §12): `step(n, html)` for
|
|
102
|
+
a reveal in order, `stat({ count: true })` for a figure to watch arrive,
|
|
103
|
+
`enter("draw")` on a trend line, `enter("grow", i)` on bars. Restraint: one
|
|
104
|
+
moment a slide.
|
|
105
|
+
3. A live demo: one self-contained HTML file, then its poster on the deck's
|
|
106
|
+
brand: `node wand.js poster demo.html --play 3 --brand <brand>`, and
|
|
107
|
+
`c.demo({ src, poster })` on the slide. A clip: `c.video({ src, poster })`.
|
|
108
|
+
4. `ship` drives the HTML like a presenter before it ships (the runtime row).
|
|
109
|
+
Deliver the HTML as the deck to present, with the PDF and .pptx beside it.
|
|
110
|
+
|
|
111
|
+
### A storyboard from a script
|
|
112
|
+
|
|
113
|
+
1. The script into `content.txt`, one voiceover line a shot (split where the
|
|
114
|
+
edit will cut). `node wand.js new work/<name> --surface storyboard`.
|
|
115
|
+
2. **Write the shot list in the chat first**: act, name, the line, and what
|
|
116
|
+
each frame shows. Then the job: `c.storyboard({ title, wpm, target, shots })`.
|
|
117
|
+
3. Frames: `sketch` for a quick one in the brand's colours, the job's own SVG,
|
|
118
|
+
an image, or left to draw (the frames gate counts them).
|
|
119
|
+
4. `ship`: the board as PDF and .pptx, `timing.csv`, `captions.srt`, and the
|
|
120
|
+
HTML with its player. Say in the note that timing is scratch timing at the
|
|
121
|
+
`wpm` given until a real read exists, and which frames are still to draw.
|
|
122
|
+
|
|
82
123
|
### Social cards
|
|
83
124
|
|
|
84
125
|
`--surface square` or `og`; one `c.page()` per card; `out/pages/pNN.png` are
|
|
85
126
|
the deliverables.
|
|
86
127
|
|
|
128
|
+
### Older Wand work
|
|
129
|
+
|
|
130
|
+
A deck or document made before this kit has no `job.mjs`. Treat it as a
|
|
131
|
+
source and rebuild it (the first job above), on the brand the rule gives.
|
|
132
|
+
One exception: a small edit (a date, a word, a figure) to a deck the old
|
|
133
|
+
decks kit built, where they want the file otherwise untouched. For that edit
|
|
134
|
+
only, `npm install wand-decks-kit@0.11.0 --no-audit --no-fund` and follow
|
|
135
|
+
that kit's SKILL.md on editing (`node wand.js show`, then `edit --set`).
|
|
136
|
+
An older copy of this skill may describe that kit, a routing table between
|
|
137
|
+
two kits, or `edit --set`; none of it applies to anything else.
|
|
138
|
+
|
|
87
139
|
## The review note, always
|
|
88
140
|
|
|
89
|
-
|
|
90
|
-
table as printed; what a human still has to decide (a figure to confirm, a
|
|
141
|
+
Which brand it is on; what was changed from the source and why (every edit,
|
|
142
|
+
every cut); the gate table as printed; what a human still has to decide (a figure to confirm, a
|
|
91
143
|
quote to clear, a claim legal should see). A file delivered without the gate
|
|
92
144
|
table has been checked by nobody.
|
|
93
145
|
|
|
94
146
|
## Available scripts
|
|
95
147
|
|
|
96
|
-
- **`wand.js`** — doctor, new, build, check, ship, watch, gallery, components, brands
|
|
148
|
+
- **`wand.js`** — doctor, new, build, check, ship, watch, poster, gallery, components, brands
|
|
97
149
|
- **`lib/engine.js`** — the render and the gates
|
|
98
150
|
- **`lib/components.js`** — the vocabulary and its CSS
|
|
99
151
|
- **`lib/pptx.js`**, **`tools/embed_fonts.py`** — the PowerPoint export
|
|
100
152
|
- **`lib/html_export.js`** — the one-file HTML with its runtime
|
|
153
|
+
- **`lib/talk.js`**, **`lib/board.js`** — the talk and the storyboard runtimes
|
|
154
|
+
- **`lib/runtime_check.js`** — the HTML driven like a presenter, at ship
|
package/START-HERE.md
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
```bash
|
|
4
4
|
node wand.js doctor # what works here; chromium must name a binary
|
|
5
|
-
node wand.js new work/acme --surface letter
|
|
5
|
+
node wand.js new work/acme --surface letter # the default brand; doctor prints the rule
|
|
6
6
|
# write work/acme/job.mjs (pages(c)) and, for a rebuild, work/acme/content.txt
|
|
7
7
|
node wand.js build work/acme/job.mjs # gates, PDF, a PNG per page, out/sheet.png
|
|
8
8
|
node wand.js ship work/acme/job.mjs --pptx # + one-file HTML, PowerPoint
|
|
9
|
+
node wand.js ship work/acme/job.mjs --brand next # the same job on the other brand, in out-next/
|
|
9
10
|
```
|
|
10
11
|
|
|
12
|
+
A deck's HTML is a talk: entrances, steps, a presenter view (P). A demo needs
|
|
13
|
+
a poster: `node wand.js poster demo.html --play 3`. A storyboard starts from
|
|
14
|
+
`node wand.js new work/film --surface storyboard`; its HTML plays the board.
|
|
15
|
+
`examples/talk/` and `examples/storyboard/` are finished ones.
|
|
16
|
+
|
|
11
17
|
`node wand.js components` lists the vocabulary; `examples/overview/job.mjs` is
|
|
12
18
|
a finished document and `examples/gallery/job.mjs` every component on one
|
|
13
19
|
sheet (`node wand.js gallery --brand next` draws it on the website's brand).
|
package/examples/gallery/job.mjs
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* It is the regression for the component library: a change to components.js
|
|
5
5
|
* or to a brand's tokens is reviewed here once, on one sheet, before any job.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
import { DEFAULT_BRAND } from "../../lib/brand.js";
|
|
8
|
+
|
|
9
|
+
const brand = process.env.WAND_GALLERY_BRAND || DEFAULT_BRAND;
|
|
8
10
|
|
|
9
11
|
export default {
|
|
10
12
|
name: `Gallery ${brand}`,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The storyboard example — a 30-second film from a six-line script, the
|
|
3
|
+
* regression for the storyboard component and lib/board.js.
|
|
4
|
+
*
|
|
5
|
+
* The script is the content file, one voiceover line a shot, so coverage
|
|
6
|
+
* proves every word of it is on the board. Frames show each way a frame can
|
|
7
|
+
* be drawn: a sketch in the brand's colours (people, software, agents), the
|
|
8
|
+
* job's own SVG, an image (the talk example's demo poster), and one left to
|
|
9
|
+
* draw, which the frames gate counts.
|
|
10
|
+
*
|
|
11
|
+
* node wand.js ship examples/storyboard/job.mjs the current brand
|
|
12
|
+
* node wand.js ship examples/storyboard/job.mjs --brand next the website's, in out-next/
|
|
13
|
+
*
|
|
14
|
+
* Outputs: the board as PDF and PNGs, timing.csv, captions.srt, and one HTML
|
|
15
|
+
* file with the board to read and a player that runs it against the clock.
|
|
16
|
+
*/
|
|
17
|
+
export default {
|
|
18
|
+
name: "The dual workforce, a 30-second film",
|
|
19
|
+
file: "Wand_Dual_Workforce_Storyboard",
|
|
20
|
+
brand: "current",
|
|
21
|
+
surface: "slide",
|
|
22
|
+
tag: "Wand · Storyboard",
|
|
23
|
+
footer: "Wand AI · Draft for review",
|
|
24
|
+
content: "script.txt",
|
|
25
|
+
css: `
|
|
26
|
+
.frame-art .own .ring{fill:none;stroke:var(--stroke);stroke-width:6}
|
|
27
|
+
.frame-art .own .core{fill:var(--accent)}
|
|
28
|
+
.frame-art .own text{fill:var(--ink);font-family:var(--face-display);font-size:96px}
|
|
29
|
+
`,
|
|
30
|
+
pages: (c) => c.storyboard({
|
|
31
|
+
title: "The dual workforce",
|
|
32
|
+
lede: "A 30-second film for the website and LinkedIn. Six shots, three acts.",
|
|
33
|
+
wpm: 160,
|
|
34
|
+
target: 30,
|
|
35
|
+
shots: [
|
|
36
|
+
{ act: "Today", name: "Two things", vo: c.L(1),
|
|
37
|
+
line: "Every company is people plus software; we show both, plainly.",
|
|
38
|
+
camera: "Locked off, wide.", motion: "People dots settle in; three app boxes slide up.", sound: "Low pad comes in.", next: "Cut on 'software'.",
|
|
39
|
+
frames: [
|
|
40
|
+
{ sketch: { people: 6, label: "People" }, caption: "The team, as the script draws it: dots." },
|
|
41
|
+
{ cue: "software", sketch: { people: 6, apps: ["CRM", "ERP", "Email"], label: "People and software" }, caption: "The systems arrive beside them." },
|
|
42
|
+
] },
|
|
43
|
+
{ act: "Today", name: "Software waits", vo: c.L(2),
|
|
44
|
+
line: "Software only moves when a person moves it.",
|
|
45
|
+
camera: "Slow push in on the boxes.", motion: "An arrow from the people to each box, one at a time.", onscreen: "30 years", sound: "A single click per arrow.", next: "Hold, then dip.",
|
|
46
|
+
frames: [{ cue: "waited", sketch: { people: 3, apps: ["CRM", "ERP"], label: "Every task starts with a person" } }] },
|
|
47
|
+
{ act: "The arrival", name: "A new kind of worker", vo: c.L(3),
|
|
48
|
+
line: "The turn of the film: something new enters the frame.",
|
|
49
|
+
camera: "Pull out to reveal the right third.", motion: "A spark draws itself in, then pulses once.", sound: "Rising tone, then silence.", next: "Match cut on the spark.",
|
|
50
|
+
frames: [{ cue: "worker", art: `<svg class="own" viewBox="0 0 1920 1080"><circle class="ring" cx="960" cy="500" r="230"/><circle class="ring" cx="960" cy="500" r="330"/><path class="core" d="M960 380Q990 470 1080 500Q990 530 960 620Q930 530 840 500Q930 470 960 380Z"/><text x="960" y="930" text-anchor="middle">A new worker</text></svg>`, caption: "The job's own SVG, on brand roles." }] },
|
|
51
|
+
{ act: "The arrival", name: "Agents at work", vo: c.L(4),
|
|
52
|
+
line: "Agents do the work inside the systems people already use.",
|
|
53
|
+
camera: "Over the shoulder of the boxes.", motion: "Sparks move into the boxes; the boxes light up.", onscreen: "Read · Decide · Act", sound: "Three soft ticks.", next: "Cut.",
|
|
54
|
+
frames: [
|
|
55
|
+
{ sketch: { apps: ["CRM", "ERP", "Email"], agents: 3, label: "Agents inside the systems" } },
|
|
56
|
+
{ cue: "act", img: c.brand === "next" ? "../talk/agents-demo.poster-next.png" : "../talk/agents-demo.poster.png", caption: "The live product, as it looks on screen." },
|
|
57
|
+
] },
|
|
58
|
+
{ act: "Wand", name: "A place in the organisation", vo: c.L(5),
|
|
59
|
+
line: "Wand is what makes an agent a colleague: identity, manager, budget, record.",
|
|
60
|
+
camera: "Locked off.", motion: "Four labels type in under the spark, one per beat of the voiceover.", onscreen: "Identity · Manager · Budget · Record", sound: "One tick per label.", next: "Dissolve.",
|
|
61
|
+
frames: [
|
|
62
|
+
{ cue: "identity", sketch: { agents: 1, apps: ["Identity", "Manager"], label: "An agent, provisioned" } },
|
|
63
|
+
{ cue: "budget", sketch: { agents: 1, apps: ["Budget", "Record"], label: "Governed like a person" } },
|
|
64
|
+
{ cue: "record", caption: "End card for the governance beat: to draw." },
|
|
65
|
+
] },
|
|
66
|
+
{ act: "Wand", name: "One workforce", vo: c.L(6),
|
|
67
|
+
line: "The close: people and agents in one picture, then the wordmark.",
|
|
68
|
+
camera: "Slow pull out to the full frame.", motion: "Dots and sparks gather into one grid; the wordmark fades up.", sound: "Pad resolves.", next: "End.",
|
|
69
|
+
frames: [{ cue: "workforce", sketch: { people: 6, agents: 4, label: "One workforce", arrows: false } }] },
|
|
70
|
+
],
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
Every company runs on two things: people and software.
|
|
2
|
+
For thirty years, software waited for people to tell it what to do.
|
|
3
|
+
Now a new kind of worker has arrived.
|
|
4
|
+
AI agents that read, decide and act, inside the systems you already run.
|
|
5
|
+
Wand gives each one a place in your organisation: an identity, a manager, a budget, a record.
|
|
6
|
+
One workforce. People and agents, working as one.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Agents at work</title>
|
|
6
|
+
<!--
|
|
7
|
+
A live demo for a talk deck: requests arrive, agents take them, a person
|
|
8
|
+
approves the ones that need a person. Self-contained, as a demo must be to
|
|
9
|
+
travel inside the deck. It dresses itself in the brand the deck hands it
|
|
10
|
+
(window.wandEmbed.brand) and answers the deck's D and R keys through
|
|
11
|
+
window.wandDemo = { play, pause, reset }.
|
|
12
|
+
-->
|
|
13
|
+
<style>
|
|
14
|
+
:root { --bg:#1A1033; --card:#291D5A; --stroke:#5B4BB0; --ink:#FFFFFF; --text:#F5F5F5; --label:#746B98; --accent:#9481FF; }
|
|
15
|
+
* { box-sizing: border-box; }
|
|
16
|
+
html, body { margin: 0; height: 100%; }
|
|
17
|
+
body { background: var(--bg); color: var(--text); font: 15px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif; overflow: hidden; }
|
|
18
|
+
main { height: 100%; display: grid; grid-template-columns: 1fr 1.25fr 1fr; gap: 18px; padding: 26px; }
|
|
19
|
+
section { display: flex; flex-direction: column; gap: 10px; min-width: 0; padding: 16px; border: 1px solid var(--stroke); border-radius: 14px; background: color-mix(in srgb, var(--card) 55%, transparent); }
|
|
20
|
+
h2 { margin: 0 0 4px; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: var(--label); display: flex; justify-content: space-between; }
|
|
21
|
+
h2 b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: 0; }
|
|
22
|
+
.lane { display: flex; flex-direction: column; gap: 8px; overflow: hidden; flex: 1; }
|
|
23
|
+
.task { padding: 10px 12px; border-radius: 10px; background: var(--card); border: 1px solid var(--stroke); color: var(--ink); font-size: 14px; display: flex; justify-content: space-between; gap: 10px; animation: in 380ms cubic-bezier(.16,1,.3,1) both; }
|
|
24
|
+
.task i { font-style: normal; color: var(--label); font-size: 12px; white-space: nowrap; }
|
|
25
|
+
.task.agent { border-color: var(--accent); }
|
|
26
|
+
.task.agent i { color: var(--accent); }
|
|
27
|
+
.task.human i { color: var(--ink); }
|
|
28
|
+
.bar { height: 3px; border-radius: 2px; background: var(--stroke); overflow: hidden; margin-top: 6px; }
|
|
29
|
+
.bar > span { display: block; height: 100%; width: 0; background: var(--accent); }
|
|
30
|
+
@keyframes in { from { opacity: 0; transform: translateY(8px); } }
|
|
31
|
+
</style>
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<main>
|
|
35
|
+
<section><h2>Incoming <b id="n-in">0</b></h2><div class="lane" id="in"></div></section>
|
|
36
|
+
<section><h2>Agents working <b id="n-work">0</b></h2><div class="lane" id="work"></div></section>
|
|
37
|
+
<section><h2>Done <b id="n-done">0</b></h2><div class="lane" id="done"></div></section>
|
|
38
|
+
</main>
|
|
39
|
+
<script>
|
|
40
|
+
(() => {
|
|
41
|
+
const E = window.wandEmbed || {}, B = E.brand || {};
|
|
42
|
+
for (const k of ["bg", "card", "stroke", "ink", "text", "label", "accent"]) if (B[k]) document.documentElement.style.setProperty("--" + k, B[k]);
|
|
43
|
+
const KINDS = ["Invoice match", "Refund request", "Address change", "Claim review", "Contract renewal", "Access request", "Vendor onboarding", "Policy question"];
|
|
44
|
+
const lanes = { in: document.getElementById("in"), work: document.getElementById("work"), done: document.getElementById("done") };
|
|
45
|
+
let seq = 0, timer = null, tick = 0, done = 0;
|
|
46
|
+
const count = () => { for (const k of ["in", "work", "done"]) document.getElementById("n-" + k).textContent = k === "done" ? done : lanes[k].children.length; };
|
|
47
|
+
const card = (txt, cls, tag) => { const d = document.createElement("div"); d.className = "task " + cls; d.innerHTML = "<span>" + txt + "</span><i>" + tag + "</i>"; return d; };
|
|
48
|
+
function step() {
|
|
49
|
+
tick++;
|
|
50
|
+
if (lanes.in.children.length < 6) lanes.in.append(card(KINDS[seq++ % KINDS.length] + " #" + (1040 + seq), "", "queued"));
|
|
51
|
+
if (tick % 2 === 0 && lanes.in.firstElementChild && lanes.work.children.length < 4) {
|
|
52
|
+
const t = lanes.in.firstElementChild, name = t.firstElementChild.textContent, human = seq % 5 === 0;
|
|
53
|
+
t.remove(); const w = card(name, human ? "human" : "agent", human ? "needs a person" : "agent"); const bar = document.createElement("div"); bar.className = "bar"; bar.innerHTML = "<span></span>"; w.firstElementChild.append(bar); lanes.work.append(w);
|
|
54
|
+
}
|
|
55
|
+
[...lanes.work.children].forEach((w) => { const s = w.querySelector(".bar > span"); const v = (parseFloat(s.style.width) || 0) + (w.classList.contains("human") ? 9 : 22); s.style.width = Math.min(100, v) + "%"; if (v >= 100) { w.remove(); done++; lanes.done.prepend(card(w.firstElementChild.firstChild.textContent, w.classList.contains("human") ? "human" : "agent", w.classList.contains("human") ? "approved" : "resolved")); if (lanes.done.children.length > 7) lanes.done.lastElementChild.remove(); } });
|
|
56
|
+
count();
|
|
57
|
+
}
|
|
58
|
+
const api = {
|
|
59
|
+
play() { if (!timer) timer = setInterval(step, E.motion === false ? 900 : 450); },
|
|
60
|
+
pause() { clearInterval(timer); timer = null; },
|
|
61
|
+
reset() { api.pause(); for (const l of Object.values(lanes)) l.replaceChildren(); seq = 0; tick = 0; done = 0; for (let i = 0; i < 8; i++) step(); },
|
|
62
|
+
};
|
|
63
|
+
window.wandDemo = api;
|
|
64
|
+
api.reset();
|
|
65
|
+
if (E.motion !== false) api.play();
|
|
66
|
+
})();
|
|
67
|
+
</script>
|
|
68
|
+
</body>
|
|
69
|
+
</html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The talk example — an animated deck, the regression for lib/talk.js.
|
|
3
|
+
*
|
|
4
|
+
* Every motion the runtime knows, once: entrances staggered in for a slide
|
|
5
|
+
* that marks nothing (`talk.motion: "auto"`), figures that count up, a chart
|
|
6
|
+
* whose line draws and whose bars grow, steps the presenter brings in one at
|
|
7
|
+
* a time, and a live demo in a frame with its poster for the static exports.
|
|
8
|
+
* `seconds` on each slide gives the presenter's clock a pace to keep.
|
|
9
|
+
*
|
|
10
|
+
* node wand.js ship examples/talk/job.mjs --pptx the current brand
|
|
11
|
+
* node wand.js ship examples/talk/job.mjs --pptx --brand next the website's, in out-next/
|
|
12
|
+
* node wand.js poster examples/talk/agents-demo.html --play 3 [--brand next]
|
|
13
|
+
*
|
|
14
|
+
* The demo's poster is per brand, because the demo dresses itself in the
|
|
15
|
+
* deck's colours: agents-demo.poster.png and agents-demo.poster-next.png.
|
|
16
|
+
*/
|
|
17
|
+
import { DEFAULT_BRAND } from "../../lib/brand.js";
|
|
18
|
+
|
|
19
|
+
const brandOf = (c) => c.brand || DEFAULT_BRAND;
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
name: "Agents at work",
|
|
23
|
+
file: "Wand_Agents_at_Work_Talk",
|
|
24
|
+
brand: "current",
|
|
25
|
+
surface: "slide",
|
|
26
|
+
tag: "Wand",
|
|
27
|
+
footer: "Wand AI · Example talk",
|
|
28
|
+
talk: { motion: "auto", minutes: 8 },
|
|
29
|
+
css: `
|
|
30
|
+
.chart{width:100%;height:auto;display:block}
|
|
31
|
+
.chart .axis{stroke:var(--rule);stroke-width:2}
|
|
32
|
+
.chart .line{fill:none;stroke:var(--accent);stroke-width:6;stroke-linecap:round;stroke-linejoin:round}
|
|
33
|
+
.chart .bar{fill:var(--emph)}
|
|
34
|
+
.chart text{fill:var(--soft);font-family:var(--face-body);font-size:22px}
|
|
35
|
+
.demo-wrap{margin-top:calc(var(--m-gap) * .6);width:66%}
|
|
36
|
+
`,
|
|
37
|
+
pages: (c) => [
|
|
38
|
+
c.cover({
|
|
39
|
+
label: "Example talk",
|
|
40
|
+
title: `Agents at <em>work</em>`,
|
|
41
|
+
lede: "What changes when software stops waiting to be told.",
|
|
42
|
+
meta: "An animated deck from the Wand studio",
|
|
43
|
+
notes: "Open on the question. Nothing on this slide needs explaining; let the title land.",
|
|
44
|
+
}),
|
|
45
|
+
|
|
46
|
+
c.page({ eyebrow: "The shift", seconds: 60, notes: "Left is every company today. Right is what we deploy. Pause on the word 'colleagues'.", body: `
|
|
47
|
+
${c.h1(`Two <em>models</em>`)}
|
|
48
|
+
${c.cols(2, [
|
|
49
|
+
c.card({ tag: "Today", title: "Software waits", level: "h3", body: [`People read, decide and act. Software holds the records and waits to be told.`] }),
|
|
50
|
+
c.card({ tag: "With agents", title: "Software works", level: "h3", emph: true, body: [`Agents read, decide and act inside the same systems, and people manage them like colleagues.`] }),
|
|
51
|
+
])}
|
|
52
|
+
` }),
|
|
53
|
+
|
|
54
|
+
c.page({ eyebrow: "What it adds up to", seconds: 50, notes: "The three figures count up as the slide arrives. Read the first one out; the room reads the rest.", body: `
|
|
55
|
+
${c.h1("In the first year")}
|
|
56
|
+
${c.stats([{ v: "62%", k: "of routine requests closed by agents", hero: true, count: true }, { v: "4,800", k: "hours a month back to the team", count: true }, { v: "3.5x", k: "faster from request to resolution", count: true }])}
|
|
57
|
+
` }),
|
|
58
|
+
|
|
59
|
+
c.page({ eyebrow: "How it rolls out", seconds: 90, notes: "Three steps; press once for each. Do not jump ahead: each step is the reason for the next.", body: `
|
|
60
|
+
${c.h1("One step at a time")}
|
|
61
|
+
${c.cols(3, [
|
|
62
|
+
c.step(1, c.card({ tag: "Step 1", title: "Give agents an identity", body: ["Every agent is provisioned like a person: an owner, access, a record."] })),
|
|
63
|
+
c.step(2, c.card({ tag: "Step 2", title: "Start where the volume is", body: ["Pick the work that is high in volume and low in judgement."] })),
|
|
64
|
+
c.step(3, c.card({ tag: "Step 3", title: "Widen what they may decide", body: ["Raise the limits as the record earns it."], emph: true })),
|
|
65
|
+
])}
|
|
66
|
+
` }),
|
|
67
|
+
|
|
68
|
+
c.page({ eyebrow: "The curve", seconds: 60, notes: "The line draws itself: resolution time falling as agents take the volume. The bars are the agents' share.", body: `
|
|
69
|
+
${c.h1("Time to resolve, month by month")}
|
|
70
|
+
<svg class="chart" viewBox="0 0 1600 520" role="img" aria-label="Resolution time falls while the agents' share of requests rises">
|
|
71
|
+
<line class="axis" x1="60" y1="460" x2="1560" y2="460"/>
|
|
72
|
+
${[18, 26, 35, 44, 52, 58, 62].map((v, i) => `<rect class="bar"${c.enter("grow", i)} x="${120 + i * 205}" y="${460 - v * 5}" width="110" height="${v * 5}"/>`).join("")}
|
|
73
|
+
<path class="line" pathLength="1"${c.enter("draw", 2)} d="M175 120 L380 170 L585 230 L790 300 L995 350 L1200 385 L1405 400"/>
|
|
74
|
+
${["M1", "M2", "M3", "M4", "M5", "M6", "M7"].map((m, i) => `<text x="${175 + i * 205}" y="500" text-anchor="middle">${m}</text>`).join("")}
|
|
75
|
+
</svg>
|
|
76
|
+
` }),
|
|
77
|
+
|
|
78
|
+
c.page({ eyebrow: "Live", seconds: 120, notes: "The demo is live: press D to pause or play it, R to restart. Esc gives the keys back to the deck.", body: `
|
|
79
|
+
${c.h1(`Watch them <em>work</em>`, "md")}
|
|
80
|
+
<div class="demo-wrap">${c.demo({ src: "agents-demo.html", poster: brandOf(c) === "next" ? "agents-demo.poster-next.png" : "agents-demo.poster.png", label: "Agents at work, live" })}</div>
|
|
81
|
+
` }),
|
|
82
|
+
|
|
83
|
+
c.closing({ pair: "Wand", title: "Agents at work", url: "www.wand.ai", eyebrow: "Thank you" }),
|
|
84
|
+
],
|
|
85
|
+
};
|