wand-decks-kit 0.8.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 +461 -0
- package/README.md +137 -0
- package/START-HERE.md +98 -0
- package/assets/README.md +40 -0
- package/assets/_icon-contact-sheet.png +0 -0
- package/assets/bg-cover-dark.png +0 -0
- package/assets/bg-overlay-dark.png +0 -0
- package/assets/bg-statement-dark.png +0 -0
- package/assets/glyphs/README.md +29 -0
- package/assets/glyphs/activity.svg +15 -0
- package/assets/glyphs/atom.svg +17 -0
- package/assets/glyphs/badge-check.svg +16 -0
- package/assets/glyphs/bell.svg +16 -0
- package/assets/glyphs/blocks.svg +16 -0
- package/assets/glyphs/book-open.svg +16 -0
- package/assets/glyphs/bot.svg +20 -0
- package/assets/glyphs/boxes.svg +26 -0
- package/assets/glyphs/brain.svg +23 -0
- package/assets/glyphs/briefcase.svg +16 -0
- package/assets/glyphs/building-2.svg +21 -0
- package/assets/glyphs/calendar.svg +18 -0
- package/assets/glyphs/chart-column.svg +18 -0
- package/assets/glyphs/chart-line.svg +16 -0
- package/assets/glyphs/chart-pie.svg +16 -0
- package/assets/glyphs/circle-check.svg +16 -0
- package/assets/glyphs/clipboard-check.svg +17 -0
- package/assets/glyphs/clock.svg +16 -0
- package/assets/glyphs/cloud.svg +15 -0
- package/assets/glyphs/coins.svg +18 -0
- package/assets/glyphs/compass.svg +16 -0
- package/assets/glyphs/cpu.svg +24 -0
- package/assets/glyphs/database.svg +17 -0
- package/assets/glyphs/eye.svg +16 -0
- package/assets/glyphs/file-check.svg +17 -0
- package/assets/glyphs/filter.svg +15 -0
- package/assets/glyphs/fingerprint.svg +23 -0
- package/assets/glyphs/flag.svg +16 -0
- package/assets/glyphs/gauge.svg +16 -0
- package/assets/glyphs/gavel.svg +19 -0
- package/assets/glyphs/git-branch.svg +18 -0
- package/assets/glyphs/globe.svg +17 -0
- package/assets/glyphs/graduation-cap.svg +17 -0
- package/assets/glyphs/handshake.svg +19 -0
- package/assets/glyphs/hexagon.svg +15 -0
- package/assets/glyphs/index.json +175 -0
- package/assets/glyphs/infinity.svg +15 -0
- package/assets/glyphs/key.svg +17 -0
- package/assets/glyphs/landmark.svg +20 -0
- package/assets/glyphs/layers.svg +17 -0
- package/assets/glyphs/lightbulb.svg +17 -0
- package/assets/glyphs/link.svg +16 -0
- package/assets/glyphs/list-checks.svg +19 -0
- package/assets/glyphs/lock.svg +16 -0
- package/assets/glyphs/map.svg +17 -0
- package/assets/glyphs/megaphone.svg +16 -0
- package/assets/glyphs/message-square.svg +15 -0
- package/assets/glyphs/milestone.svg +17 -0
- package/assets/glyphs/network.svg +19 -0
- package/assets/glyphs/orbit.svg +19 -0
- package/assets/glyphs/package.svg +18 -0
- package/assets/glyphs/plug.svg +18 -0
- package/assets/glyphs/puzzle.svg +15 -0
- package/assets/glyphs/radar.svg +22 -0
- package/assets/glyphs/receipt.svg +17 -0
- package/assets/glyphs/refresh-cw.svg +18 -0
- package/assets/glyphs/rocket.svg +18 -0
- package/assets/glyphs/route.svg +17 -0
- package/assets/glyphs/scale.svg +19 -0
- package/assets/glyphs/search.svg +16 -0
- package/assets/glyphs/server.svg +18 -0
- package/assets/glyphs/settings.svg +16 -0
- package/assets/glyphs/share-2.svg +19 -0
- package/assets/glyphs/shield-check.svg +16 -0
- package/assets/glyphs/shuffle.svg +19 -0
- package/assets/glyphs/sparkles.svg +19 -0
- package/assets/glyphs/square-stack.svg +17 -0
- package/assets/glyphs/target.svg +17 -0
- package/assets/glyphs/trending-up.svg +16 -0
- package/assets/glyphs/triangle-alert.svg +17 -0
- package/assets/glyphs/trophy.svg +20 -0
- package/assets/glyphs/users.svg +18 -0
- package/assets/glyphs/wallet.svg +16 -0
- package/assets/glyphs/wand-sparkles.svg +22 -0
- package/assets/glyphs/workflow.svg +17 -0
- package/assets/glyphs/zap.svg +15 -0
- package/assets/icons/icon-11.png +0 -0
- package/assets/icons/icon-12.png +0 -0
- package/assets/icons/icon-13.png +0 -0
- package/assets/icons/icon-14.png +0 -0
- package/assets/icons/icon-15.png +0 -0
- package/assets/icons/icon-16.png +0 -0
- package/assets/icons/icon-17.png +0 -0
- package/assets/icons/icon-18.png +0 -0
- package/assets/icons/icon-20.png +0 -0
- package/assets/icons/icon-23.png +0 -0
- package/assets/icons/icon-24.png +0 -0
- package/assets/icons/icon-25.png +0 -0
- package/assets/icons/icon-27.png +0 -0
- package/assets/icons/icon-28.png +0 -0
- package/assets/icons/icon-30.png +0 -0
- package/assets/icons/icon-31.png +0 -0
- package/assets/icons/icon-32.png +0 -0
- package/assets/icons/icon-33.png +0 -0
- package/assets/icons/icon-34.png +0 -0
- package/assets/icons/icon-35.png +0 -0
- package/assets/icons/icon-36.png +0 -0
- package/assets/icons/icon-37.png +0 -0
- package/assets/icons/icon-39.png +0 -0
- package/assets/icons/icon-40.png +0 -0
- package/assets/icons/icon-41.png +0 -0
- package/assets/icons/icon-43.png +0 -0
- package/assets/icons/icon-44.png +0 -0
- package/assets/icons/icon-45.png +0 -0
- package/assets/icons/icon-46.png +0 -0
- package/assets/icons/icon-48.png +0 -0
- package/assets/icons/icon-49.png +0 -0
- package/assets/icons/icon-50.png +0 -0
- package/assets/icons/icon-51.png +0 -0
- package/assets/icons/icon-52.png +0 -0
- package/assets/icons/icon-53.png +0 -0
- package/assets/icons/icon-9.png +0 -0
- package/assets/mark-dark.png +0 -0
- package/assets/mark-white.png +0 -0
- package/assets/orb-cover.png +0 -0
- package/assets/wordmark-dark.png +0 -0
- package/assets/wordmark-white.png +0 -0
- package/build.js +192 -0
- package/build_example.js +91 -0
- package/build_infinite.js +283 -0
- package/docs/LAYOUTS.md +86 -0
- package/docs/PIPELINE.md +116 -0
- package/docs/SPEC.md +89 -0
- package/embed_fonts.py +193 -0
- package/examples/template.json +164 -0
- package/fonts/Geist-Bold.ttf +0 -0
- package/fonts/Geist-BoldItalic.ttf +0 -0
- package/fonts/Geist-ExtraBold.ttf +0 -0
- package/fonts/Geist-ExtraBoldItalic.ttf +0 -0
- package/fonts/Geist-Italic.ttf +0 -0
- package/fonts/Geist-Light.ttf +0 -0
- package/fonts/Geist-LightItalic.ttf +0 -0
- package/fonts/Geist-Medium.ttf +0 -0
- package/fonts/Geist-MediumItalic.ttf +0 -0
- package/fonts/Geist-Regular.ttf +0 -0
- package/fonts/Geist-SemiBold.ttf +0 -0
- package/fonts/Geist-SemiBoldItalic.ttf +0 -0
- package/lib/README.md +23 -0
- package/lib/brand.js +51 -0
- package/lib/glyphs.js +87 -0
- package/lib/layouts_client.js +212 -0
- package/lib/layouts_consult.js +301 -0
- package/lib/layouts_dense.js +361 -0
- package/lib/measure.js +109 -0
- package/lib/pdf.js +517 -0
- package/lib/plan.js +305 -0
- package/lib/render_pdf.js +203 -0
- package/lib/schema.js +399 -0
- package/lib/shared.js +15 -0
- package/lib/trace.js +88 -0
- package/lib/ttf.py +167 -0
- package/lib/wandxml.py +37 -0
- package/package.json +17 -0
- package/preview/preview.css +112 -0
- package/preview/preview.html +24 -0
- package/preview/preview.js +169 -0
- package/qa_coverage.py +120 -0
- package/requirements.txt +9 -0
- package/tools/extract.py +199 -0
- package/wand.js +397 -0
- package/wand_kit.js +1016 -0
package/PROMPT.md
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# Wand Deck System — Project Instructions (v6)
|
|
2
|
+
|
|
3
|
+
You turn an uploaded source into a fully **Wand-branded `.pptx`**, then return the deck plus a
|
|
4
|
+
review note. This document is the single source of truth for the Wand visual system. It replaces
|
|
5
|
+
both `wand-deck-improver-instructions.md` and the previous `wand-deck-system-instructions.md` —
|
|
6
|
+
**delete those two files** so their conflicting font and layout specs can't be picked up.
|
|
7
|
+
|
|
8
|
+
Before touching any `.pptx`, read `/mnt/skills/public/pptx/SKILL.md` and follow it. This document
|
|
9
|
+
is the workflow and the design system; the skill is the source of truth for commands.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 0. Ground truth: the reference decks
|
|
14
|
+
|
|
15
|
+
Two decks in Project knowledge define the target output. **They are the specification.** When this
|
|
16
|
+
document and a reference deck disagree, the reference deck wins — say so and flag it.
|
|
17
|
+
|
|
18
|
+
| File | Role |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `Infinite_Labor__by_Rotem__July_2026.pptx` | **Gold standard.** Canonical geometry, tokens, type scale, layout vocabulary. Copy from this one. |
|
|
21
|
+
| `BEZEQ___WAND_Partnership_V2__OLD__.pptx` | **Secondary.** Extra layout types (dividers, timelines, quotes, BYO cards). Marked `OLD` — it has drift (stray Calibri in quote cards and footers). Harvest its *layouts*, never its *typography*. |
|
|
22
|
+
|
|
23
|
+
Both are Google Slides exports: no design lives in the slide masters or layouts. Every element is
|
|
24
|
+
an absolutely positioned shape on the slide itself. Treat the masters/layouts as empty scaffolding
|
|
25
|
+
and build at the slide level.
|
|
26
|
+
|
|
27
|
+
### Project knowledge stores the `.pptx` as text, not as a binary
|
|
28
|
+
Verified 2026-09-01: the two reference `.pptx` files in Project knowledge are ~15–17 KB of
|
|
29
|
+
plain-text slide dumps. The PDFs persist at full size; the PowerPoint binaries do not. So from
|
|
30
|
+
Project knowledge alone you **cannot** read slide XML, measure geometry, or reach `ppt/media/`.
|
|
31
|
+
|
|
32
|
+
Consequences:
|
|
33
|
+
- **Geometry and tokens come from §1–§5 of this document**, which is the durable record of what
|
|
34
|
+
was measured out of the binaries. Do not claim to have re-derived them from the decks unless
|
|
35
|
+
the binaries were uploaded this session.
|
|
36
|
+
- **Art comes from the asset pack** (`wand-assets/`) in Project knowledge, not from `ppt/media/`.
|
|
37
|
+
- **Visual reference comes from the PDFs.** `pdftoppm -jpeg -r 110 Infinite_Labor…pdf ref` and
|
|
38
|
+
view those, instead of `thumbnail.py` — which needs a real `.pptx`.
|
|
39
|
+
- If you need the XML for a layout this document doesn't cover, **ask for the `.pptx` to be
|
|
40
|
+
uploaded to the chat.** Uploads land in `/mnt/user-data/uploads/` at full size.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 1. Canvas and grid — locked
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
Canvas 10.000" × 5.625" (EMU 9144000 × 5143500)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**This is not the PowerPoint 13.333" widescreen canvas.** Every number below is on the 10" grid.
|
|
51
|
+
If you ever build on a 13.333" canvas, multiply these by 1.3333 — but don't: match the references.
|
|
52
|
+
|
|
53
|
+
| Rail | Value |
|
|
54
|
+
|---|---|
|
|
55
|
+
| Left margin | `0.37"` (content), `0.35"` (tag) |
|
|
56
|
+
| Right edge of content | `9.63"` → standard content width `9.25"` |
|
|
57
|
+
| Narrow content width | `8.90"` (titles, subtitles, kickers) |
|
|
58
|
+
| Tag baseline | `y 0.24"`, height `0.17"` |
|
|
59
|
+
| Logo mark | `x 9.52" y 0.24"`, `0.23" × 0.19"` |
|
|
60
|
+
| Title top | `y 0.62"` |
|
|
61
|
+
| Subtitle top | `y 1.10"–1.56"` (sits directly under the title block) |
|
|
62
|
+
| Content band top | `y 1.60"` (no subtitle) / `y 1.94"–2.28"` (with subtitle) |
|
|
63
|
+
| Content band bottom | `y 5.05"` hard limit |
|
|
64
|
+
| Kicker (italic footnote) | `y 4.70"–4.84"`, height `0.30"` |
|
|
65
|
+
| Footer band | `y 5.21"`, height `0.42"` |
|
|
66
|
+
| Gap between cards | `0.22"` – `0.32"` |
|
|
67
|
+
|
|
68
|
+
**Column presets** (use these, don't invent new ones):
|
|
69
|
+
|
|
70
|
+
| Columns | Card width | x positions |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| 2 | `4.25"` | 0.37, 5.38 |
|
|
73
|
+
| 3 (wide) | `2.90"` | 0.38, 3.55, 6.72 |
|
|
74
|
+
| 3 (standard) | `2.84"` | 0.37, 3.58, 6.78 |
|
|
75
|
+
| 3 (tall) | `2.72"` | 0.37, 3.64, 6.90 |
|
|
76
|
+
| 4 | `2.09"` | 0.37, 2.73/2.78, 5.15, 7.54 |
|
|
77
|
+
| 5 | `1.78"` | 0.41, 2.29, 4.18, 6.06, 7.94 |
|
|
78
|
+
| 6 | `1.50"` | 0.41 + 1.55 × n |
|
|
79
|
+
| Full-width row | `9.25"` | 0.37 |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. Color tokens — locked
|
|
84
|
+
|
|
85
|
+
Canonical values live in [brand/BRAND.md](../../brand/BRAND.md), shared with every
|
|
86
|
+
other power prompt. This section owns the *slide-level usage* — which token goes
|
|
87
|
+
where. If a hex here ever differs from BRAND.md, BRAND.md is right.
|
|
88
|
+
|
|
89
|
+
Sampled from the gold-standard deck. **These supersede the old `270264 / 1C0247 / EEE6FB /
|
|
90
|
+
BC92FF / C060E6 / 6E5B9E` table entirely.** That palette does not appear in either reference deck.
|
|
91
|
+
|
|
92
|
+
### Shared
|
|
93
|
+
| Token | Hex | Use |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `accent` | `8B7CF6` | THE one brand purple. Tags, icon tiles, accent italic words, rules, stat numbers, pills. |
|
|
96
|
+
| `accentDeep` | `6C5CE7` | Accent text on light surfaces where `8B7CF6` is too light. |
|
|
97
|
+
| `accentSoft` | `A99CF8` | Accent on dark card interiors, outline pills, closing URL. |
|
|
98
|
+
| `accentPale` | `C4B5F4` | Card eyebrows on dark, quote marks. |
|
|
99
|
+
|
|
100
|
+
### Dark theme
|
|
101
|
+
| Token | Hex | Use |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `bgDark` | `0F0C26` | Slide background fill (under the gradient art) |
|
|
104
|
+
| `bgArt` | *(PNG)* | Full-bleed gradient image at `0,0 → 10.00 × 5.625` |
|
|
105
|
+
| `inkDark` | `F3F1FA` / `FFFFFF` | Titles, card titles |
|
|
106
|
+
| `bodyDark` | `B7B0DC` | Subtitles, card body |
|
|
107
|
+
| `bodyDarkAlt` | `CCC0F2` | Bullet lists inside cards |
|
|
108
|
+
| `card` | `9481FF @ 12% alpha` | **The signature glass card.** 0.75pt stroke `2E2757` or `34237E`. |
|
|
109
|
+
| `cardSolid` | `2C2460` | Opaque card (Bezeq-style), 1pt stroke `4A3F8C` |
|
|
110
|
+
| `cardMuted` | `241D4F` | "Bring your own" / de-emphasised card, **dashed** 1pt `4A3F8C` |
|
|
111
|
+
| `cardEmph` | `GRAD 201541 → 422E7C` | Emphasis card (one per slide, max) |
|
|
112
|
+
| `cardEmphFlat` | `352B70` | Emphasis card, flat variant |
|
|
113
|
+
| `band` | `0F0C26` | Full-width formula / callout band |
|
|
114
|
+
| `pillOutline` | fill `1B1738`, 1pt `A99CF8` | Outline pill |
|
|
115
|
+
| `footerDark` | `F3F3F3` | Footer text |
|
|
116
|
+
|
|
117
|
+
### Light theme
|
|
118
|
+
| Token | Hex | Use |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| `bgLight` | `F8F6FB` | Slide background (solid `<p:bg>`, no art) |
|
|
121
|
+
| `inkLight` | `1D1A33` | Titles, card titles, values |
|
|
122
|
+
| `bodyLight` | `5C5779` | Subtitles, card body |
|
|
123
|
+
| `mutedLight` | `555077` | Dense captions |
|
|
124
|
+
| `cardLight` | `FFFFFF` | Card fill, hairline stroke `FFFFFF` (0.75pt) |
|
|
125
|
+
| `surface` | `EBE8F8` | Icon tiles, rail labels |
|
|
126
|
+
| `track` | `E9E6F5` | Bar-chart track |
|
|
127
|
+
| `divider` | `E4E0F2` | Hairlines inside cards |
|
|
128
|
+
| `footerLight` | `999999` | Footer text |
|
|
129
|
+
|
|
130
|
+
**Rules.** One accent, no second hue — `D946EF` appears twice in the references and is drift, don't
|
|
131
|
+
propagate it. Exactly **one** emphasis card per slide. Icon tiles are `accent` on dark and
|
|
132
|
+
`surface` on light — never accent-on-light for a tile.
|
|
133
|
+
|
|
134
|
+
### Geometry tokens
|
|
135
|
+
- Card corner radius: **`0.10"`** (`roundRect`, `adj ≈ 4785` on a 2.09" card — recompute per shape: `adj = 100000 × 0.10 / min(w,h)`)
|
|
136
|
+
- Icon tile corner radius: `adj = 30000` (squircle)
|
|
137
|
+
- Pill: `adj = 50000` (stadium)
|
|
138
|
+
- Icon tile sizes: `0.46"` (4-up), `0.44"` (2-col), `0.40"` (6-up), `0.36"` (rows)
|
|
139
|
+
- Glyph inside tile: `0.17"–0.21"`, optically centred
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 3. Typography — Geist, embedded
|
|
144
|
+
|
|
145
|
+
Faces and the weight-by-family-name rule are brand-level — see
|
|
146
|
+
[brand/BRAND.md](../../brand/BRAND.md). The type *scale* below is deck-specific.
|
|
147
|
+
|
|
148
|
+
**Resolved: the font is Geist and only Geist.** Ignore every reference to Century Schoolbook or
|
|
149
|
+
Calibri in the old instruction files — those were never in the real decks. Any Calibri in the
|
|
150
|
+
Bezeq deck is drift to be corrected, not copied.
|
|
151
|
+
|
|
152
|
+
Five families ship in the reference decks and all must be embedded:
|
|
153
|
+
`Geist`, `Geist Medium`, `Geist SemiBold`, `Geist ExtraBold`, `Geist Light`.
|
|
154
|
+
|
|
155
|
+
Weight is carried by the **family name**, not by `b="1"`. `Geist SemiBold` with `b="0"` is the
|
|
156
|
+
correct way to get semibold. Use `b="1"` only on `Geist` itself (slide titles, tags).
|
|
157
|
+
|
|
158
|
+
### Type scale (10" canvas)
|
|
159
|
+
|
|
160
|
+
| Role | Size | Family |
|
|
161
|
+
|---|---|---|
|
|
162
|
+
| Cover title | 46pt | Geist ExtraBold |
|
|
163
|
+
| Statement / divider title | 44pt | Geist SemiBold |
|
|
164
|
+
| Quote mark | 30pt | Geist (accentPale) |
|
|
165
|
+
| **Slide title** | **24pt** (23pt if 2 long lines) | Geist, `b="1"` |
|
|
166
|
+
| Big stat number | 21pt | Geist SemiBold |
|
|
167
|
+
| Card title (3-up tall) | 16pt | Geist SemiBold |
|
|
168
|
+
| Card title (5-up) | 14pt | Geist SemiBold |
|
|
169
|
+
| Inline stat number | 15pt | Geist SemiBold |
|
|
170
|
+
| Formula band | 13.5pt | Geist SemiBold |
|
|
171
|
+
| Subtitle / lede | 12.5pt | Geist |
|
|
172
|
+
| Eyebrow (cover, divider, closing) | 12pt | Geist Medium |
|
|
173
|
+
| Card title (small / rows) | 10.5pt | Geist SemiBold |
|
|
174
|
+
| Kicker (italic) | 10pt | Geist / Geist Medium, `i="1"` |
|
|
175
|
+
| List item | 9.5pt | Geist |
|
|
176
|
+
| Card body (roomy) | 9pt | Geist |
|
|
177
|
+
| Card body (dense), bullets, **tag** | 8pt | Geist (`b="1"` on tag) |
|
|
178
|
+
| Badge pill | 7pt | Geist Medium |
|
|
179
|
+
| Footer | 6pt | Geist |
|
|
180
|
+
|
|
181
|
+
### The accent-italic device
|
|
182
|
+
Titles carry one emphasised phrase in `accent` + italic, and the sentence period stays in ink:
|
|
183
|
+
|
|
184
|
+
> **Two kinds of colleagues.** *One set of drives*.
|
|
185
|
+
> **Multiple products.** *One unified workforce*.
|
|
186
|
+
|
|
187
|
+
One per title, never two. Split into separate `<a:r>` runs inside one `<a:p>`.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 4. Slide chrome — on every slide
|
|
192
|
+
|
|
193
|
+
1. **Tag** — `x0.35 y0.24 w6.75 h0.17`, 8pt Geist `b="1"`, `accent`. Short caps label ("THE SHIFT", "TRACK A · INTERNAL USE"). Same colour on both themes.
|
|
194
|
+
2. **Logo mark** — `w✦` PNG at `x9.52 y0.24 w0.23 h0.19`. White on dark, dark on light. Tag + mark are grouped.
|
|
195
|
+
3. **Footer** — group at `y5.21 h0.42`. Left: `x0.37 w4.58`, `WAND · <DECK NAME>`. Right: `x5.23 w4.76`, right-aligned, `STRICTLY CONFIDENTIAL · NN / TT`. 6pt Geist, `footerDark` / `footerLight`.
|
|
196
|
+
4. **Background** — dark: `<p:bg>` solid `0F0C26` **plus** the full-bleed gradient PNG as the first shape. Light: `<p:bg>` solid `F8F6FB`, no art.
|
|
197
|
+
|
|
198
|
+
**Exception — full-bleed slides** (cover, section divider, closing): no footer, no page number.
|
|
199
|
+
Cover and closing also drop the tag; dividers keep it.
|
|
200
|
+
|
|
201
|
+
The page number is literal text, not a field. Fix `TT` once from the final slide count and write
|
|
202
|
+
`NN` per slide. Never ship `01 / 13` on slide 7 — that bug is present in the reference deck and
|
|
203
|
+
must not be reproduced.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 5. Layout catalog
|
|
208
|
+
|
|
209
|
+
Twenty layouts. Each has a **dark (D)** and **light (L)** variant unless noted. Geometry below is
|
|
210
|
+
the dark/light-agnostic skeleton; swap tokens per §2. Names are the ones to use in mapping plans.
|
|
211
|
+
|
|
212
|
+
### Structural
|
|
213
|
+
|
|
214
|
+
**L1 · `cover`** — dark only, full bleed.
|
|
215
|
+
Eyebrow 12pt accent `y1.24` · title 46pt ExtraBold `y1.58 w5.55` (2 lines) · body 12.5pt `y3.25 w5.52` · accent rule `x0.38 y3.95 w0.60 h0.04` fill `accent` · kicker 10pt `y4.03` (second half `b="1"`) · orb art `x5.72 y0.38 w4.61 h4.61`. Tag optional. No footer.
|
|
216
|
+
|
|
217
|
+
**L2 · `divider`** — dark only, full bleed.
|
|
218
|
+
Eyebrow 12pt accent `y2.02` · title 44pt SemiBold `y2.34 w8.60` · body 12pt `y3.17 w5.81`. Tag kept, no footer. Use for every section break and for the agenda.
|
|
219
|
+
|
|
220
|
+
**L3 · `closing`** — dark only, full bleed, centred.
|
|
221
|
+
Logo tile `0.58"` accent `x4.71 y0.98` + glyph `0.27"` · eyebrow 12pt `y1.85 w8.90` centred · title 24pt `y2.19 w8.90 h1.00` centred, line 2 accent italic · body 12.5pt `y3.23 w7.00` centred · URL 10pt accentSoft `y4.30`. Wordmark variant: full `wand` wordmark image centred in place of the tile.
|
|
222
|
+
|
|
223
|
+
### Content
|
|
224
|
+
|
|
225
|
+
**L4 · `threeUp`** — 3 tall cards `2.72 × 2.70` at `y2.02`.
|
|
226
|
+
Card: eyebrow 8pt Medium `+0.22,+0.22` · title 16pt SemiBold `+0.22,+0.46` · pill `2.00 × 0.34` `+0.36,+0.96` · body 9pt `+0.22,+1.50 h1.05`. One card may be the emphasis card (white pill, white body).
|
|
227
|
+
|
|
228
|
+
**L5 · `threeUpArrows`** — L4 plus `0.27"` chevron PNGs at `x3.23` and `x6.50`, `y3.22`. For progressions (today → target → horizon).
|
|
229
|
+
|
|
230
|
+
**L6 · `fourUpIcon`** — 4 cards `2.09 × 2.34` at `y2.28`.
|
|
231
|
+
Card: icon tile `0.46"` `+0.22,+0.24` · title 12.5pt Medium `+0.22,+0.86` · body 9pt `+0.21,+1.20 h1.02`. Kicker below at `y4.82`.
|
|
232
|
+
|
|
233
|
+
**L7 · `sixUpIcon`** — 6 cards `2.84 × 1.62`, rows at `y1.63` and `y3.46`.
|
|
234
|
+
Card: icon tile `0.40"` `+0.20,+0.16` · title 10.5pt SemiBold `+0.20,+0.64 w2.44` · body 8pt `+0.20,+1.01 h0.55`.
|
|
235
|
+
|
|
236
|
+
**L8 · `fiveUpStack`** — 5 cards `1.78 × 3.00` at `y1.76` (Bezeq stack).
|
|
237
|
+
Card: eyebrow 7pt SemiBold `+0.14,+0.15` · title 12pt SemiBold `+0.14,+0.39 h0.60` · body 8pt `+0.14,+1.05 h1.80`. Cards 4–5 use `cardMuted` + **dashed** stroke + muted eyebrow for "BRING YOUR OWN". This dashed treatment is the canonical way to mark not-ours.
|
|
238
|
+
|
|
239
|
+
**L9 · `rows`** — 5 full-width rows `9.25 × 0.58` from `y1.94`, step `0.645`.
|
|
240
|
+
Row: icon tile `0.36"` `+0.20,+0.11` · label 10.5pt Medium `x1.08 w1.95` · description 8pt `x3.03 w4.76` · badge pill `1.30 × 0.30` at `x8.15` (accent-filled for ours, `pillOutline` for theirs). Best layout for a stack/ownership table.
|
|
241
|
+
|
|
242
|
+
**L10 · `parity`** — 2 cards `4.25 × 2.92` at `y1.68`, x `0.37` / `5.38`.
|
|
243
|
+
One `cardLight`, one `cardEmph` — the contrast is the point. Card: icon tile `0.44"` `+0.30,+0.26` · label 12pt SemiBold `+0.89,+0.26 w3.20` · then check rows: glyph `0.15"` `+0.35`, text 9.5pt `+0.61 w3.50`, first at `+0.90`, step `0.38`. Centre badge: `0.50"` ellipse `accent` at `x4.75 y2.89` with a 17pt white `=` / `→` / `vs`. Kicker at `y4.84`.
|
|
244
|
+
|
|
245
|
+
**L11 · `twoColBullets`** — 2 or 3 cards `4.30 × 3.00` (2-col) or `2.90 × 3.00` (3-col) at `y1.76`.
|
|
246
|
+
Card: eyebrow 8pt accent · title 12pt SemiBold · then label/description pairs (10pt SemiBold + 8pt body) or a bullet list at 8pt, `0.26"` line step. For "X brings / Y brings" and track breakdowns.
|
|
247
|
+
|
|
248
|
+
**L12 · `numberedList`** — 6 rows `4.30 × 0.56`, 2 columns × 3 rows, `x0.55` / `x5.15`, from `y2.18`, step `0.70`.
|
|
249
|
+
Row: number `0.32 × 0.20` 14pt ExtraBold accent `+0.13,+0.17` · title 10pt SemiBold `+0.56,+0.07 w3.60` · description 8.2pt Medium `+0.56,+0.27`. Kicker below. Use for "what it takes to get started" style asks.
|
|
250
|
+
|
|
251
|
+
**L13 · `timeline`** — 6 cards `1.50 × 2.70` at `y1.50`, `x0.41` step `1.55`.
|
|
252
|
+
Card: period 8pt SemiBold `+0.12,+0.14` · title 9pt SemiBold `+0.12,+0.38 h0.56` · body 8pt Medium `+0.12,+0.98 h1.57`. Final card = emphasis. Optional full-width band `9.25 × 0.55` at `y4.40` carrying the trajectory line, label in `b="1"`.
|
|
253
|
+
|
|
254
|
+
**L14 · `phaseCards`** — 4 cards `2.20 × 2.90` at `y1.60`, x `0.41 / 2.71 / 5.01 / 7.31`.
|
|
255
|
+
Card: number 20pt SemiBold · period 9pt accent · title 11pt SemiBold · 4 bullets 8pt. Card 1 = emphasis. For go-to-market / engagement sequences.
|
|
256
|
+
|
|
257
|
+
### Data
|
|
258
|
+
|
|
259
|
+
**L15 · `statQuad`** — 4 cards `2.09 × 1.42` at `y2.90`, x `0.37 / 2.78 / 5.15 / 7.54`.
|
|
260
|
+
Card: number 21pt SemiBold accent `+0.18,+0.16 h0.42` · caption 8–9pt `+0.18,+0.66 h0.62`.
|
|
261
|
+
|
|
262
|
+
**L16 · `statGrid`** — 6 cards `3.00 × 1.35`, 3 × 2, from `y1.60`, gaps `0.25`.
|
|
263
|
+
Card: number 20pt SemiBold · label 12pt SemiBold · caption 8pt accentDeep. Card 1 = emphasis. Italic footnote below at `y4.70 w9.25` (this is where measurement caveats go).
|
|
264
|
+
|
|
265
|
+
**L17 · `featureStats`** — emphasis card `2.09 × 2.10` at `x0.37 y2.63` (icon tile + 12pt body with one accent italic word) + 3 hairline cards `2.09 × 2.10` at x `2.75 / 5.13 / 7.51`, each 26pt number + 12pt two-line caption.
|
|
266
|
+
|
|
267
|
+
**L18 · `barRank`** — left block: 4 bars from `y2.10`, step `0.64`. Each bar = track `5.40 × 0.48` fill `track`, then the value bar same y, width proportional, fill stepping `7C6AE8 → 8B7CF6 → 9C8EF6 → 6F5DE8`. Label 9.5pt SemiBold white inside the bar at `+0.18`; value 10.5pt SemiBold — white when inside the fill, `inkLight` when past it. Italic footnote at `y4.76`. Right block: 3 cards `3.25 × 0.86` at `x6.38` from `y2.10`, step `1.00`, each icon tile `0.40"` + 15pt number + caption.
|
|
268
|
+
**Use this instead of a native chart for ranked magnitudes** — it's how the reference decks do TAM and margin bridges. Native `addChart()` only when the source has real multi-series data.
|
|
269
|
+
|
|
270
|
+
**L19 · `bridge`** — one `cardLight` `5.40 × 3.30` at `x0.37 y2.10` containing an 8pt accent eyebrow and 5 label/bar/value rows (label 9.5pt at `+0.20`, track `2.80 × 0.20` at `+2.30`, value 9.5pt SemiBold right-aligned at `+5.00`) + 4 stat cards `1.60 × 1.55` 2 × 2 at `x6.38`. For margin bridges and waterfalls.
|
|
271
|
+
|
|
272
|
+
**L20 · `band`** — full-width band `9.25 × 0.86` at `y1.78`, fill `band` (dark) with icon tile `0.42"` `+0.31,+0.22` and 13.5pt SemiBold text at `x1.30 w7.75`, mixing `bodyDark` / white / accent-italic runs. Pairs with `statQuad` below and an italic quote kicker. For equations and single-sentence assertions.
|
|
273
|
+
|
|
274
|
+
**L21 · `quotes`** — 3 cards `3.02 × 1.95` at `y2.72`, x `0.41 / 3.53 / 6.65`.
|
|
275
|
+
Card: quote mark 30pt accentPale `+0.17,+0.21` · quote 10pt italic `+0.20,+0.52 h1.42` · name 10pt SemiBold `+0.20,+1.31` · role 8pt accentDeep `+0.20,+1.56`. **Attributed quotes only.** Never invent or reword a quote — see §8.
|
|
276
|
+
|
|
277
|
+
### Choosing
|
|
278
|
+
Vary layouts. Three consecutive `sixUpIcon` slides is a failure even if each one is correct.
|
|
279
|
+
Across a 15-slide deck, aim for at least 8 distinct layouts and alternate dark/light.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 6. Pipeline
|
|
284
|
+
|
|
285
|
+
### Phase 0 — Normalize
|
|
286
|
+
- `.pptx` → `markitdown deck.pptx`; `python scripts/thumbnail.py deck.pptx src-thumbs`; **view the grid.**
|
|
287
|
+
- `.pdf` → `markitdown`, or the pdf-reading skill; rasterize if slide-shaped.
|
|
288
|
+
- `.docx` / `.md` / `.txt` → `markitdown`; H1 → divider, H2 → content slide.
|
|
289
|
+
- Images → view; each is a slide's content or an asset.
|
|
290
|
+
- Multiple files → richest is the spine, rest are assets.
|
|
291
|
+
|
|
292
|
+
Also thumbnail and view **both reference decks** on the first build of a session.
|
|
293
|
+
|
|
294
|
+
### Phase 1 — Extract verbatim
|
|
295
|
+
Dump every string from the source to a working file (`all_text.json` + a readable
|
|
296
|
+
`visible_dump.txt`). This dump is the contract for Phase 4: every string in it lands on a slide,
|
|
297
|
+
unchanged, or appears in the Review Note as explicitly dropped.
|
|
298
|
+
|
|
299
|
+
Skip hidden slides. Count and report: `N slides in source, M visible, M slides out`.
|
|
300
|
+
|
|
301
|
+
### Phase 2 — Classify
|
|
302
|
+
One tag per source slide:
|
|
303
|
+
`cover | divider | agenda | content | data-stats | data-bars | data-chart | comparison | timeline | numbered | quote | closing | other`
|
|
304
|
+
|
|
305
|
+
### Phase 3 — Map
|
|
306
|
+
Stop at the first match.
|
|
307
|
+
|
|
308
|
+
1. **Structural?** cover → `L1`. divider/agenda → `L2`. closing → `L3`. Regardless of how the source looks.
|
|
309
|
+
2. **Attributed quotes?** → `L21`.
|
|
310
|
+
3. **Timeline / phased?** periods, months, weeks, "MO 1–3" → `L13` (6 phases) or `L14` (≤4 phases with bullets).
|
|
311
|
+
4. **Data?**
|
|
312
|
+
- ranked magnitudes, TAM ladders, margin bridges → `L18` / `L19`
|
|
313
|
+
- real multi-series data → native `addChart()` on a light slide
|
|
314
|
+
- 4 standalone stats → `L15`; 6 → `L16`; 1 hero + 3 → `L17`
|
|
315
|
+
5. **Comparative?** two-sided, before/after, "vs", parity → `L10` (2 sides, list-shaped) or `L11` (2 sides, prose-shaped).
|
|
316
|
+
6. **Stack / ownership / layer table?** → `L9`; 5 items with some not-ours → `L8`.
|
|
317
|
+
7. **Single assertion or equation?** → `L20`.
|
|
318
|
+
8. **Numbered asks / decisions?** → `L12`.
|
|
319
|
+
9. **Else content by item count:** 3 → `L4`/`L5`, 4 → `L6`, 6 → `L7`, 5 → `L8`, 2 → `L11`.
|
|
320
|
+
10. **Fallback:** `L7` and **flag**.
|
|
321
|
+
|
|
322
|
+
Emit the mapping plan before building, one line per slide:
|
|
323
|
+
`S07 (timeline, 6 phases + trajectory band) → L13-D`
|
|
324
|
+
|
|
325
|
+
### Phase 4 — Build
|
|
326
|
+
**Hard stop:** if `wand-template.pptx` is not present in Project knowledge, say so and stop.
|
|
327
|
+
Do not build from scratch and do not substitute a reference deck for the template without saying
|
|
328
|
+
that's what you're doing and getting a yes.
|
|
329
|
+
|
|
330
|
+
Then, in order:
|
|
331
|
+
1. Unpack the template.
|
|
332
|
+
2. **All structural work first** — `add_slide.py` once per planned slide, in final order. Never hand-copy slide XML.
|
|
333
|
+
3. Set `<p:sldIdLst>` to final order, drop unused template slides, then `clean.py`.
|
|
334
|
+
4. Inject content into each `ppt/slides/slideN.xml`.
|
|
335
|
+
5. Repack from **inside** the unpacked dir (`rm` the target first).
|
|
336
|
+
|
|
337
|
+
Injection rules:
|
|
338
|
+
- Parse with `defusedxml.minidom`. Never `xml.etree.ElementTree`.
|
|
339
|
+
- Edit `run.text`; never blank a whole text frame.
|
|
340
|
+
- One `<a:p>` per list item. Copy the sibling `<a:pPr>`. Never a literal `•`.
|
|
341
|
+
- `xml:space="preserve"` on any `<a:t>` with leading/trailing space.
|
|
342
|
+
- Weight via family name (`Geist SemiBold`), not `b="1"` — except on `Geist` titles and tags.
|
|
343
|
+
- **Template slots ≠ source items.** 3 cards planned into a 4-card layout means deleting the 4th card's *entire* group — shape, tile, glyph, and every text box — then re-centring the remaining three on the column preset for that count.
|
|
344
|
+
- Recompute `roundRect` `adj` whenever you resize a card: `adj = 100000 × 0.10 / min(w,h)`.
|
|
345
|
+
- Give titles and stat numbers ~10% width slack (§9).
|
|
346
|
+
|
|
347
|
+
### Phase 5 — Review Note
|
|
348
|
+
Markdown, specific, slide-numbered:
|
|
349
|
+
- Any slide split or merged, with source → output numbers.
|
|
350
|
+
- Any mapping flagged fallback or low-confidence.
|
|
351
|
+
- Anything tight after fitting.
|
|
352
|
+
- Off-brand source elements you could not rebrand — screenshots, baked-in-colour images, non-standard charts. Name the slide and the reason.
|
|
353
|
+
- **Anything dropped from the Phase 1 dump**, explicitly.
|
|
354
|
+
- Any place a reference deck and this document disagreed, and which you followed.
|
|
355
|
+
|
|
356
|
+
### Phase 6 — QA + export
|
|
357
|
+
All four, every time.
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# 1. Content
|
|
361
|
+
markitdown output.pptx
|
|
362
|
+
markitdown output.pptx | grep -iE "\bx{3,}\b|lorem|ipsum|\bTODO|\[insert|this.*(page|slide).*layout"
|
|
363
|
+
|
|
364
|
+
# 2. Coverage — every Phase 1 string present
|
|
365
|
+
python qa_coverage.py visible_dump.txt output.pptx
|
|
366
|
+
|
|
367
|
+
# 3. File (required, --original always)
|
|
368
|
+
python scripts/office/validate.py output.pptx --original wand-template.pptx
|
|
369
|
+
|
|
370
|
+
# 4. Visual
|
|
371
|
+
python scripts/office/soffice.py --headless --convert-to pdf output.pptx
|
|
372
|
+
rm -f slide-*.jpg && pdftoppm -jpeg -r 150 output.pdf slide
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
View **every** slide image. Then fix, re-render only what changed, and stop.
|
|
376
|
+
|
|
377
|
+
Deliver the `.pptx` **first**, then the Review Note.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 7. Font embedding — required
|
|
382
|
+
|
|
383
|
+
A Geist deck without embedded fonts renders as Arial on the client's machine. Embedding is not
|
|
384
|
+
optional polish; it is what makes the brand survive the handoff.
|
|
385
|
+
|
|
386
|
+
Per family, in `ppt/fonts/`, as `.fntdata`:
|
|
387
|
+
`Geist`, `Geist Medium`, `Geist SemiBold`, `Geist ExtraBold`, `Geist Light` —
|
|
388
|
+
regular / bold / italic / boldItalic each.
|
|
389
|
+
|
|
390
|
+
Package wiring:
|
|
391
|
+
- `[Content_Types].xml`: `<Default Extension="fntdata" ContentType="application/x-fontdata"/>`
|
|
392
|
+
- `ppt/_rels/presentation.xml.rels`: one relationship per file
|
|
393
|
+
- `ppt/presentation.xml`: `embedTrueTypeFonts="1"` and a `<p:embeddedFontLst>` placed **immediately after `<p:notesSz>`**. Order inside `<p:presentation>` is schema-fixed — a misplaced element makes the deck unopenable.
|
|
394
|
+
- Set **`saveSubsetFonts="0"`** and embed full faces. Subsetting is what garbles digits in exported PDFs (see §9).
|
|
395
|
+
|
|
396
|
+
`/home/claude/fonts/embed_fonts.py` does this; extend it from 2 faces to all 5 families.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## 8. Content rules
|
|
401
|
+
|
|
402
|
+
- **Faithful means verbatim.** Rebuild slide-for-slide. Do not consolidate two source slides into one, do not paraphrase to tighten, do not restructure because a different arrangement seems better. Reflowing text to fit a card is fine; rewording it is not.
|
|
403
|
+
- **Never invent facts.** No numbers, dates, names, logos, or claims that aren't in the source.
|
|
404
|
+
- **Never invent or reword a quote.** Quotes are attributed to real, named people. Reproduce exactly or drop and flag.
|
|
405
|
+
- **Preserve order** unless a Phase 3 rule moves something.
|
|
406
|
+
- **Complete the scope.** Once the plan is agreed, build all of it in one pass. Do not stop mid-deck to re-ask for permission already given.
|
|
407
|
+
- Reskin what you can; flag what you can't. Never silently drop content.
|
|
408
|
+
- Confidentiality markings in the source carry through to the footer.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 9. Environment gotchas — read before trusting QA
|
|
413
|
+
|
|
414
|
+
**LibreOffice ignores embedded fonts.** Verified: rendering the reference deck produces
|
|
415
|
+
DejaVu Sans / Carlito / Liberation Sans, never Geist. Consequences:
|
|
416
|
+
|
|
417
|
+
1. **Weight is lost.** `Geist ExtraBold` renders regular-weight in QA. Do not judge hierarchy, boldness, or the accent-italic device from a QA image — verify those in the XML.
|
|
418
|
+
2. **Widths are wrong, in one direction.** DejaVu Sans is wider than Geist, so QA **over-reports** overflow. Leave ~10% slack on titles and stat numbers; when QA shows a title just touching its box, it almost certainly fits in Geist. Confirm by measured width, not by eye. Genuine overflow — text clipped or spilling far past a card — is still real, so don't dismiss everything.
|
|
419
|
+
3. **What QA *is* reliable for:** shape geometry, overlap, alignment, gaps, contrast, leftover placeholders, orphaned decoration, mispositioned art. Judge those normally.
|
|
420
|
+
|
|
421
|
+
**Garbled digits in exported PDFs.** The reference PDFs show `$ǿǹT+` where the deck says `$60T+`.
|
|
422
|
+
Cause: Google Slides subsets the embedded Geist and writes a `ToUnicode` map offset by +457, so
|
|
423
|
+
digits decode to Latin Extended-B in the PDF text layer. **The `.pptx` is correct — do not "fix"
|
|
424
|
+
these strings.** Our LibreOffice export is clean. To confirm any deck you ship:
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
pdftotext output.pdf - | grep -P '[\x{01C9}-\x{0250}]'
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Empty output is a pass. Hits mean subsetted fonts got in — set `saveSubsetFonts="0"` and re-embed.
|
|
431
|
+
|
|
432
|
+
**Other:** the reference decks use `roundRect` with per-shape `adj`, so copying a card and resizing
|
|
433
|
+
it changes its corner radius — recompute. Icon glyphs are separate PNGs layered over tile shapes;
|
|
434
|
+
moving a tile without its glyph leaves the glyph behind.
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## 10. Known drift in the reference decks — don't propagate
|
|
439
|
+
|
|
440
|
+
| Where | Issue | Do instead |
|
|
441
|
+
|---|---|---|
|
|
442
|
+
| Bezeq `L21` quote cards | Calibri body, Cambria quote mark | Geist italic 10pt; Geist 30pt for the mark |
|
|
443
|
+
| Bezeq footers | Mixed Calibri run, `9A92B8` | Geist 6pt, one colour |
|
|
444
|
+
| Both, footers | Page number frozen at `01 / 13` on every slide | Write real `NN / TT` |
|
|
445
|
+
| Infinite `L1` cover | Accent rule implemented as a filled rect containing a stray `` ` `` in Calibri | Plain filled rect, no text frame |
|
|
446
|
+
| Infinite `L20`, misc | `D946EF` magenta | `accent` `8B7CF6` |
|
|
447
|
+
| Infinite slides 8 and 10 | Duplicate slides, identical content | One slide |
|
|
448
|
+
|
|
449
|
+
Report any new drift you find rather than mirroring it.
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## 11. Open items
|
|
454
|
+
|
|
455
|
+
1. **Build `wand-template.pptx` v6 on the 10" grid.** The current v5 geometry (tag `y0.40`, title `y0.955`, subtitle `y1.574`) is a 13.333" canvas and does not match the reference decks. v6 should be a straight port of §5 at 10 × 5.625, with all 21 layouts in dark and light where applicable.
|
|
456
|
+
2. ~~Harvest assets from the reference decks.~~ **Done 2026-09-01** — extracted to the
|
|
457
|
+
`wand-assets/` pack in Project knowledge: 3 dark gradients, cover orb, both mark polarities,
|
|
458
|
+
the wordmark, and 36 icon glyphs, all RGBA. See its `README.md` for placement. Light slides
|
|
459
|
+
have no art.
|
|
460
|
+
3. **Extend `embed_fonts.py`** to all 5 Geist families × 4 faces, full (unsubsetted).
|
|
461
|
+
4. **Write `qa_coverage.py`** — diffs the Phase 1 verbatim dump against `markitdown` of the output and lists every missing string. This is the check that makes "faithful = verbatim" enforceable instead of aspirational.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# wand-kit v0.4.0
|
|
2
|
+
|
|
3
|
+
The code half of the **Decks** power prompt. `../PROMPT.md` is the other half
|
|
4
|
+
and wins on every design question. **This replaces `wand-template.pptx`** —
|
|
5
|
+
there is no binary template to keep alive any more.
|
|
6
|
+
|
|
7
|
+
## Use it
|
|
8
|
+
|
|
9
|
+
The kit runs in two shapes, and the commands are the same in both:
|
|
10
|
+
|
|
11
|
+
- **From the repo** — `power-prompts/decks/kit/`, with fonts and gradients
|
|
12
|
+
resolved from the shared `brand/` at the repo root. This is where you change
|
|
13
|
+
it. See `../README.md`.
|
|
14
|
+
- **Packaged** — `node tools/package.mjs decks` writes a zip with `PROMPT.md` at
|
|
15
|
+
the root, the kit around it and `brand/` copied in. Upload that zip plus a
|
|
16
|
+
source deck to a fresh chat and say:
|
|
17
|
+
|
|
18
|
+
> Unzip this and read PROMPT.md, then run the pipeline on the attached deck.
|
|
19
|
+
|
|
20
|
+
`lib/brand.js` is what makes both work; `WAND_BRAND_DIR` overrides it.
|
|
21
|
+
|
|
22
|
+
## Why a kit and not a template
|
|
23
|
+
|
|
24
|
+
`wand-template.pptx` could only live in Project knowledge, and Project knowledge
|
|
25
|
+
stores `.pptx` as a ~15 KB text dump — so the binary was unreachable from the
|
|
26
|
+
place it was stored, and the container resets between sessions. That loop is why
|
|
27
|
+
the template never got built. Code doesn't have that problem.
|
|
28
|
+
|
|
29
|
+
## Contents
|
|
30
|
+
|
|
31
|
+
| Path | What |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `wand.js` | **The front door.** `doctor` / `rebuild` / `layouts` / `validate` / `preview` / `ship` |
|
|
34
|
+
| `START-HERE.md` | What to do when all you have is this folder and a `.pptx` |
|
|
35
|
+
| `wand_kit.js` | Tokens, chrome, primitives, 26 layouts |
|
|
36
|
+
| `node_modules/` | `fontkit` and `pptxgenjs`, vendored. Pure JS, no native builds, so the zip is portable |
|
|
37
|
+
| `lib/measure.js` | Real Geist text metrics via fontkit — fit is measured, not guessed |
|
|
38
|
+
| `lib/trace.js` | Records shape calls so the preview reuses the real layout code |
|
|
39
|
+
| `lib/schema.js` | Every layout's fields and item caps, as data. Drives `validate`, `plan` and `layouts` |
|
|
40
|
+
| `lib/plan.js` | Phase 2-3 worksheet: source shape, layout shortlist, verbatim text, field stubs |
|
|
41
|
+
| `pylib/` | `wandxml.py` and `ttf.py` - the stdlib fallbacks that make `pip install` optional |
|
|
42
|
+
| `lib/layouts_dense.js` | Roadmaps, architecture stacks, matrices, proof walls |
|
|
43
|
+
| `lib/layouts_consult.js` | Problem grids, split panels, comparison tables, numbered lists |
|
|
44
|
+
| `build.js` | Spec → `.pptx`, or `--preview`, or `--check` |
|
|
45
|
+
| `preview/` | Browser preview at the 10" grid, with overflow flags and §1 rails |
|
|
46
|
+
| `tools/extract.py` | Phase 0/1 — normalises any canvas onto the 10" grid, dumps verbatim |
|
|
47
|
+
| `embed_fonts.py` | Wraps Geist as uncompressed EOT and wires it into the package |
|
|
48
|
+
| `qa_coverage.py` | Diffs the Phase 1 dump against the built deck; exit 1 on any miss |
|
|
49
|
+
| `lib/brand.js` | Resolves the shared `brand/` — 12 Geist faces, gradients, orb, marks, 36 icons |
|
|
50
|
+
| `docs/` | `SPEC.md` (spec format) · `LAYOUTS.md` (catalog) · `PIPELINE.md` (the six phases as commands) |
|
|
51
|
+
| `examples/` | `template.json` — one slide per layout, self-describing |
|
|
52
|
+
| `../PROMPT.md` | The power prompt. Source of truth on design questions |
|
|
53
|
+
|
|
54
|
+
## Quick start
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
node wand.js doctor # what works here. No install step of any kind:
|
|
58
|
+
# node_modules ships in the zip, and the Python
|
|
59
|
+
# side runs on the standard library
|
|
60
|
+
node wand.js rebuild source.pptx # normalise, dump verbatim, write work/PLAN.md
|
|
61
|
+
# ... you write work/deck.json from the worksheet ...
|
|
62
|
+
node wand.js ship work/deck.json # validate, fit, build, embed, coverage, inspect
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The individual stages are still there (`extract`, `plan`, `validate`, `check`,
|
|
66
|
+
`preview`, `build`, `inspect`) so a failure can be re-run on its own, and
|
|
67
|
+
`build.js` still works exactly as before. Full loop: `docs/PIPELINE.md`.
|
|
68
|
+
|
|
69
|
+
## The three things that make complex rebuilds tractable
|
|
70
|
+
|
|
71
|
+
**Measurement instead of eyeballing.** `lib/measure.js` opens the actual Geist
|
|
72
|
+
TTFs and measures wrapped text. `build.js --check` reports every box that
|
|
73
|
+
overflows *in the real font*. This matters because LibreOffice — the only
|
|
74
|
+
renderer available in the container — ignores embedded fonts and substitutes
|
|
75
|
+
DejaVu, so visual QA over-reports overflow and loses all weight information.
|
|
76
|
+
Two of the three "overflows" fixed by eye in the first Infinite Labor build
|
|
77
|
+
turned out to fit fine.
|
|
78
|
+
|
|
79
|
+
**One spec, two renderers.** `lib/trace.js` runs a spec through the real layout
|
|
80
|
+
functions against a fake presentation object that records every shape. The
|
|
81
|
+
browser preview draws that recording. It therefore cannot drift from the .pptx,
|
|
82
|
+
and you can iterate on layout in a page refresh instead of a build-embed-convert-
|
|
83
|
+
rasterise cycle.
|
|
84
|
+
|
|
85
|
+
**Content separated from geometry.** A spec has no coordinates, colours, or font
|
|
86
|
+
sizes. So a rebuild diffs cleanly in two directions: spec against the source's
|
|
87
|
+
verbatim text, layout against the design system.
|
|
88
|
+
|
|
89
|
+
**Six gates, not one.** `ship` runs all of them because they are blind
|
|
90
|
+
to different things. `validate` checks fields and item counts against the layout
|
|
91
|
+
catalog. `--check` measures fit in real Geist, bounds against the content band,
|
|
92
|
+
and that every asset a slide references exists. `qa_coverage.py` asks whether
|
|
93
|
+
every source string survived. `inspect` reads the built file. And the preview is
|
|
94
|
+
the only one that can tell you a slide is correct and still ugly.
|
|
95
|
+
|
|
96
|
+
A row hidden under a closing band passes coverage — the text is in the XML — and
|
|
97
|
+
fails bounds. A paraphrased sentence passes everything except coverage. A
|
|
98
|
+
mistyped glyph name used to pass all of them and then throw a stack trace from
|
|
99
|
+
inside pptxgenjs; now it fails the asset check with the slide number.
|
|
100
|
+
|
|
101
|
+
## Conventions
|
|
102
|
+
|
|
103
|
+
- Every layout resolves colour through `theme(dark)`. Never hardcode a hex in a
|
|
104
|
+
build script or a spec.
|
|
105
|
+
- Titles take a string or a 3-part array for the accent-italic device:
|
|
106
|
+
`["Two kinds of colleagues. ", "One set of drives", "."]`. One per title.
|
|
107
|
+
- Card corner radius is recomputed per shape by `radius(w, h)`. Use it.
|
|
108
|
+
- Layouts whose title can wrap should place content with `contentTop()` rather
|
|
109
|
+
than a fixed y. `archStack`, `matrixGrid`, `phaseCards` and `numberedCards` do.
|
|
110
|
+
|
|
111
|
+
## Known gaps
|
|
112
|
+
|
|
113
|
+
1. **Icon polarity.** The 36 glyphs are white or accent-tinted. A white glyph on
|
|
114
|
+
a `surface` tile (light theme) is low-contrast. Check
|
|
115
|
+
`assets/_icon-contact-sheet.png` before picking; the kit doesn't track which
|
|
116
|
+
is which. The asset check catches a *missing* glyph, not a wrong one.
|
|
117
|
+
2. **Icons are chosen by number, not meaning.** The example specs pick plausible
|
|
118
|
+
glyphs, not semantically right ones.
|
|
119
|
+
3. **Older layouts use fixed content-band coordinates.** Migrate one to
|
|
120
|
+
`contentTop()` when it next misbehaves.
|
|
121
|
+
4. **`compareTable` tops out at 3 reason cards and 4 table rows.** Wider
|
|
122
|
+
comparisons need a new layout.
|
|
123
|
+
5. **No `addChart()` wrapper.** Native charts only for real multi-series data;
|
|
124
|
+
ranked magnitudes go through `barRank` / `bridge`.
|
|
125
|
+
6. **The preview approximates text layout.** It's a browser, not PowerPoint —
|
|
126
|
+
trust `--check` over the preview's own overflow flags for the final call.
|
|
127
|
+
7. **The layout shortlist is tuned on one deck.** `plan` ranks candidates by
|
|
128
|
+
shape and gets the right layout into the top three reliably on the deck it
|
|
129
|
+
was measured against. Treat a confident single answer with suspicion, and
|
|
130
|
+
read the verbatim text before choosing.
|
|
131
|
+
|
|
132
|
+
## Versioning
|
|
133
|
+
|
|
134
|
+
Bump `VERSION` in `wand_kit.js`, `version` in `../manifest.json` and the header
|
|
135
|
+
of `../STATUS.md` together, and say what moved in `../CHANGELOG.md`. If a session
|
|
136
|
+
hands you back a new zip, replace your local copy — a stale kit builds on stale
|
|
137
|
+
geometry and nothing will warn you.
|