@taloswork/ose-shared 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/skills/document/SKILL.md +135 -219
- package/skills/document/art-directions/base.css +27 -2
- package/skills/document/art-directions/cinematic-depth.css +3 -1
- package/skills/document/art-directions/collage-paper.css +5 -1
- package/skills/document/art-directions/editorial-cut.css +5 -1
- package/skills/document/art-directions/geometric-pop.css +6 -0
- package/skills/document/art-directions/gradient-mesh.css +5 -1
- package/skills/document/art-directions/illustrated-doodle.css +5 -0
- package/skills/document/art-directions/luxury-ornament.css +4 -1
- package/skills/document/art-directions/maximalist-blocks.css +6 -0
- package/skills/document/art-directions/technical-grid.css +4 -0
- package/skills/document/assets/fonts/fonts.json +2 -2
- package/skills/document/assets/pdf-fonts/NotoSansSC-PDF-Bold.ttf +0 -0
- package/skills/document/assets/pdf-fonts/NotoSansSC-PDF-Regular.ttf +0 -0
- package/skills/document/assets/pdf-fonts/OFL.txt +93 -0
- package/skills/document/assets/pdf-fonts/README.md +35 -0
- package/skills/document/assets/tessdata/LICENSE-Apache-2.0.txt +202 -0
- package/skills/document/assets/tessdata/README.md +21 -0
- package/skills/document/assets/tessdata/chi_sim.traineddata.gz +0 -0
- package/skills/document/assets/tessdata/eng.traineddata.gz +0 -0
- package/skills/document/bin/deck-build.cjs +12563 -83
- package/skills/document/bin/deck-chart.cjs +771 -0
- package/skills/document/bin/deck-plan.cjs +12414 -0
- package/skills/document/bin/deck-qa.cjs +1075 -266
- package/skills/document/bin/deck-scenario.cjs +1363 -0
- package/skills/document/bin/deck-styles.cjs +1604 -0
- package/skills/document/bin/doc-convert.cjs +308 -292
- package/skills/document/bin/doc-fill.cjs +73264 -192
- package/skills/document/bin/doc-gen.cjs +2491 -312
- package/skills/document/bin/doc-run.cjs +162 -24
- package/skills/document/bin/doc-scan.cjs +13 -0
- package/skills/document/bin/doc-text.cjs +13 -0
- package/skills/document/bin/doc-validate.cjs +838 -68
- package/skills/document/bin/doc-xml.cjs +9 -5
- package/skills/document/bin/docx-annotate.cjs +95 -19
- package/skills/document/bin/docx-defaults.cjs +9907 -0
- package/skills/document/bin/fontkit.cjs +1 -0
- package/skills/document/bin/html2pptx.cjs +36622 -31394
- package/skills/document/bin/ocr-worker.cjs +1 -0
- package/skills/document/bin/ocr.cjs +131 -40
- package/skills/document/bin/pdf-form.cjs +682 -177
- package/skills/document/bin/pdf-images.cjs +13 -0
- package/skills/document/bin/pdf-ops.cjs +642 -199
- package/skills/document/bin/pdf-render.cjs +19 -3
- package/skills/document/bin/pdf-tables.cjs +13 -0
- package/skills/document/bin/pptx-clone.cjs +3 -3
- package/skills/document/bin/pptx-notes.cjs +10038 -0
- package/skills/document/bin/pptx-slide.cjs +3 -3
- package/skills/document/bin/pptx-tokenize.cjs +19 -4
- package/skills/document/bin/template-skin.cjs +10910 -0
- package/skills/document/bin/xlsx-query.cjs +192 -61
- package/skills/document/bin-reference.md +61 -33
- package/skills/document/catalog.json +33 -32
- package/skills/document/content-pipeline.md +179 -257
- package/skills/document/deck-design.md +378 -638
- package/skills/document/generated-visuals.md +99 -0
- package/skills/document/layouts/MAINTAINERS.md +33 -0
- package/skills/document/layouts/README.md +49 -36
- package/skills/document/layouts/big-stat.tpl +1 -1
- package/skills/document/layouts/capacity.json +1 -0
- package/skills/document/layouts/cards-3.tpl +1 -1
- package/skills/document/layouts/chart-full.tpl +1 -1
- package/skills/document/layouts/chart-kpi.tpl +1 -1
- package/skills/document/layouts/comparison.tpl +1 -1
- package/skills/document/layouts/data-table.tpl +1 -1
- package/skills/document/layouts/funnel.tpl +1 -1
- package/skills/document/layouts/gantt.tpl +1 -1
- package/skills/document/layouts/hub-flow.tpl +4 -0
- package/skills/document/layouts/icon-row.tpl +1 -1
- package/skills/document/layouts/image-grid.tpl +1 -1
- package/skills/document/layouts/matrix-2x2.tpl +1 -1
- package/skills/document/layouts/mock-qa.tpl +4 -0
- package/skills/document/layouts/profiles.json +2 -2
- package/skills/document/layouts/pyramid.tpl +1 -1
- package/skills/document/layouts/radar.tpl +1 -1
- package/skills/document/layouts/ring-progress.tpl +1 -1
- package/skills/document/layouts/slots.json +1 -1
- package/skills/document/layouts/steps-vertical.tpl +1 -1
- package/skills/document/layouts/steps.tpl +1 -1
- package/skills/document/layouts/three-kpi.tpl +1 -1
- package/skills/document/layouts/timeline.tpl +1 -1
- package/skills/document/layouts/toc-panel.tpl +2 -2
- package/skills/document/layouts/two-kpi.tpl +2 -2
- package/skills/document/layouts/versus.tpl +1 -1
- package/skills/document/motion/README.md +3 -2
- package/skills/document/office.md +3 -3
- package/skills/document/packs/README.md +1 -1
- package/skills/document/packs/board-brief/backdrop.html +2 -0
- package/skills/document/packs/board-brief/pack.css +2 -1
- package/skills/document/packs/mckinsey-photo/backdrop.html +2 -0
- package/skills/document/packs/mckinsey-photo/pack.css +2 -1
- package/skills/document/packs/press-room/backdrop.html +2 -0
- package/skills/document/packs/press-room/pack.css +2 -1
- package/skills/document/packs/prismatic-3d/backdrop.html +2 -0
- package/skills/document/packs/prismatic-3d/pack.css +4 -1
- package/skills/document/pdf.md +60 -43
- package/skills/document/rewrite.md +257 -309
- package/skills/document/scenarios.json +1307 -0
- package/skills/document/scenarios.schema.json +104 -0
- package/skills/document/styles/README.md +15 -25
- package/skills/document/styles/_backdrops/rimlight.html +3 -2
- package/skills/document/styles/_contract-defaults.css +31 -2
- package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
- package/skills/document/styles/_samples/mckinsey.webp +0 -0
- package/skills/document/styles/anthropic/skin.css +6 -3
- package/skills/document/styles/apple/skin.css +4 -3
- package/skills/document/styles/bistro-warm/backdrop.html +2 -0
- package/skills/document/styles/bistro-warm/skin.css +4 -1
- package/skills/document/styles/black-gold/skin.css +6 -5
- package/skills/document/styles/bold-clash/backdrop.html +2 -0
- package/skills/document/styles/bold-clash/skin.css +2 -1
- package/skills/document/styles/branding/skin.css +4 -4
- package/skills/document/styles/campus-teal/backdrop.html +2 -0
- package/skills/document/styles/campus-teal/skin.css +2 -1
- package/skills/document/styles/cinereel/skin.css +7 -3
- package/skills/document/styles/clinic-care/backdrop.html +2 -0
- package/skills/document/styles/clinic-care/skin.css +2 -1
- package/skills/document/styles/cool/skin.css +6 -5
- package/skills/document/styles/dark-glass/backdrop.html +2 -0
- package/skills/document/styles/dark-glass/skin.css +2 -1
- package/skills/document/styles/gov-brief/backdrop.html +2 -0
- package/skills/document/styles/gov-brief/skin.css +2 -1
- package/skills/document/styles/grid-tech/backdrop.html +2 -0
- package/skills/document/styles/grid-tech/skin.css +2 -1
- package/skills/document/styles/hand-drawn/skin.css +3 -3
- package/skills/document/styles/ivory-gold/skin.css +7 -6
- package/skills/document/styles/legal-slate/backdrop.html +2 -0
- package/skills/document/styles/legal-slate/skin.css +2 -1
- package/skills/document/styles/magazine-ink/skin.css +4 -3
- package/skills/document/styles/mckinsey/backdrop.html +7 -5
- package/skills/document/styles/mckinsey/skin.css +2 -1
- package/skills/document/styles/memphis/backdrop.html +2 -0
- package/skills/document/styles/memphis/skin.css +2 -1
- package/skills/document/styles/mono/skin.css +6 -2
- package/skills/document/styles/neon-cyber/backdrop.html +2 -0
- package/skills/document/styles/neon-cyber/skin.css +2 -1
- package/skills/document/styles/olive-gold/skin.css +7 -6
- package/skills/document/styles/organic-earth/backdrop.html +2 -0
- package/skills/document/styles/organic-earth/skin.css +2 -1
- package/skills/document/styles/pastel-saas/backdrop.html +2 -0
- package/skills/document/styles/pastel-saas/skin.css +2 -1
- package/skills/document/styles/portfolio-noir/backdrop.html +2 -0
- package/skills/document/styles/portfolio-noir/skin.css +2 -1
- package/skills/document/styles/retro-press/backdrop.html +2 -0
- package/skills/document/styles/retro-press/skin.css +2 -1
- package/skills/document/styles/sport-arena/backdrop.html +2 -0
- package/skills/document/styles/sport-arena/skin.css +4 -1
- package/skills/document/styles/swiss-grid/skin.css +10 -5
- package/skills/document/styles/wedding-blush/backdrop.html +2 -0
- package/skills/document/styles/wedding-blush/skin.css +4 -1
- package/skills/document/theme-system.md +85 -77
- package/skills/document/themes/README.md +7 -5
- package/skills/document/vision.md +8 -5
- package/skills/document/xlsx.md +15 -25
- package/skills/grill-me/SKILL.md +6 -0
- package/skills/grill-me/agents/openai.yaml +5 -0
- package/skills/grilling/SKILL.md +28 -0
- package/skills/grilling/agents/openai.yaml +3 -0
|
@@ -1,316 +1,198 @@
|
|
|
1
1
|
# Deck design — html2pptx (hybrid) is THE deck engine
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
`
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
**broken-image glyph** (缺图红叉) into the hybrid backdrop. Paste the SVG markup
|
|
151
|
-
inline (lucide/heroicons path data), or a `data:image/svg+xml` URI at worst.
|
|
152
|
-
- **No crude full-height accent bar.** A raw bright `var(--accent)` rectangle down
|
|
153
|
-
the left edge reads as an unfinished template — if a family wants a spine it is
|
|
154
|
-
baked into its `.tpl`; do not bolt a colored bar onto a bespoke slide.
|
|
155
|
-
- Mapped to native pptx: text (per style run, editable/searchable), boxes
|
|
156
|
-
(background/border/radius), `<img>`, `<hr>`. **Inline `<svg>`/`<canvas>` are
|
|
157
|
-
rasterized per-element** — only that box becomes a PNG, everything else on the
|
|
158
|
-
slide stays native editable text. So a slide with an SVG icon/diagram + text
|
|
159
|
-
keeps its text editable; you do NOT need `--rasterize` for SVG anymore. Use
|
|
160
|
-
SVG freely for icons, logos, small diagrams, decorative shapes.
|
|
161
|
-
- **Full-bleed photo covers stay editable**: an `<img>` with `object-fit:cover`
|
|
162
|
-
/`contain` maps to a NATIVE pptx crop/letterbox (aspect preserved — no need to
|
|
163
|
-
pre-crop to 16:9), and a semi-transparent `rgba(...)` fill maps to native fill
|
|
164
|
-
transparency, so a dark scrim over a photo no longer flattens to an opaque
|
|
165
|
-
block. Overlay a title + scrim on a photo and the text stays native/editable.
|
|
166
|
-
- Still not mapped as native: CSS gradients (flatten to a solid backgroundColor
|
|
167
|
-
in the converter) and `<video>`. When a WHOLE slide relies on effects the
|
|
168
|
-
mapper can't express natively, `--rasterize` turns every slide into a
|
|
169
|
-
pixel-perfect **image** (zero text editability — say so when delivering).
|
|
170
|
-
- HTML input renders in the app's Chromium when available, else a **bundled
|
|
171
|
-
headless Chromium** (Playwright) — so it works off-app too (CI/cloud/doc-run),
|
|
172
|
-
not only in-app. `.layout.json` snapshot input converts anywhere with no
|
|
173
|
-
browser. (CJK renders natively where the host has CJK fonts; a font-less Linux
|
|
174
|
-
CI may need a CJK font installed.)
|
|
175
|
-
- **Speaker notes**: add a hidden `<div class="talos-notes" style="display:none">
|
|
176
|
-
…notes…</div>` (or `data-notes="…"` on the `<section>`) per slide → it becomes
|
|
177
|
-
the slide's pptx notesSlide (never rendered on the slide). Pass `--notes-doc
|
|
178
|
-
<out.md>` to also emit a standalone speaker-notes document.
|
|
179
|
-
- Fonts are measured by Chromium but re-laid-out by PowerPoint — keep ~10%
|
|
180
|
-
slack in text boxes; don't butt text against box edges.
|
|
181
|
-
|
|
182
|
-
After generating: the build reports `valid` and `qa` itself; sign off with
|
|
183
|
-
`deck-qa --final` like any deck ("Verify before delivering").
|
|
184
|
-
|
|
185
|
-
## HTML slide authoring — the design-first route
|
|
186
|
-
|
|
187
|
-
This is the **toolbox for the bespoke escape-hatch slides** identified above (the
|
|
188
|
-
one architecture diagram / hero the catalog can't express) — NOT a license to
|
|
189
|
-
hand-author every slide (that's the #1 AI tell; compose the rest from the catalog).
|
|
190
|
-
When a slide DOES earn it, you get the full CSS toolbox (flexbox/grid, layering,
|
|
191
|
-
`position:absolute`, per-element SVG) and the output is still **native, editable**
|
|
192
|
-
pptx — text boxes stay text, only SVG boxes rasterize. Author against the skin/theme
|
|
193
|
-
CSS variables (incl. the ramp `var(--c1..--c4)`) so the same HTML re-skins for free.
|
|
194
|
-
|
|
195
|
-
Every slide is `<section class="slide" style="position:relative;width:1280px;height:720px">`.
|
|
196
|
-
Position with `absolute` inside it. Compose from these recipes (vary them across
|
|
197
|
-
the deck — don't repeat one layout):
|
|
198
|
-
|
|
199
|
-
- **Full-bleed cover** — `background:var(--primary)`; oversized title (64–96px)
|
|
200
|
-
bottom-left; one thin accent bar; presenter/date small at the very bottom.
|
|
201
|
-
- **Two-column split** — 50/50 flex row: text column left (title + 3–4 short
|
|
202
|
-
lines), a visual right (an `<img>` data-URI, an SVG diagram, or a big stat).
|
|
203
|
-
- **Half-bleed image** — image fills the left or right ~55% (`object-fit:cover`),
|
|
204
|
-
content overlaid on the other half with a solid or scrim panel behind the text.
|
|
205
|
-
- **Big-stat hero** — one number at 140–200px in `var(--accent)`, a short label
|
|
206
|
-
under it, one supporting sentence. Nothing competes.
|
|
207
|
-
- **Icon rows / 2×2 grid** — each cell: an SVG icon in a colored circle, a bold
|
|
208
|
-
header, one line of body. Equal cells, consistent gaps.
|
|
209
|
-
- **Quote / statement** — one sentence at 40–56px, generous padding, attribution
|
|
210
|
-
small below. Let the type be the visual.
|
|
211
|
-
- **Section divider** — `background:var(--primary)`; an oversized ghosted chapter
|
|
212
|
-
number; the section title beside it.
|
|
213
|
-
|
|
214
|
-
Honor the **Design principles** below (dominant color, one visual anchor per
|
|
215
|
-
slide, size hierarchy, ≥0.5" margins, NO accent line under a title). Icons: inline
|
|
216
|
-
`<svg>` (stroke `currentColor`/theme vars) — they rasterize per-element, so the
|
|
217
|
-
rest of the slide stays editable.
|
|
218
|
-
|
|
219
|
-
**Charts — pick by where the deck will be OPENED (this is a real tradeoff, not a
|
|
220
|
-
default):**
|
|
221
|
-
- **Inline `<svg>` bar/line you hand-draw** = DEFAULT for a delivered deck. It
|
|
222
|
-
rasterizes into the backdrop, so it renders **everywhere** — Keynote, macOS
|
|
223
|
-
Preview / Quick Look, Google Slides, WPS, PowerPoint. The cost: the chart is a
|
|
224
|
-
picture, not editable data.
|
|
225
|
-
- **Native `data-chart`** `<div class="talos-chart" style="position:absolute;
|
|
3
|
+
Every deck is slide HTML rendered by `html2pptx` in its default **hybrid** mode: Chromium
|
|
4
|
+
lays out the HTML (flexbox/grid, layering, per-element SVG), the decorative layer bakes
|
|
5
|
+
into one pixel-perfect backdrop per slide, and text plus native `data-chart`s stay
|
|
6
|
+
editable pptx objects on top. Pitch, keynote, report or plain — same path.
|
|
7
|
+
|
|
8
|
+
- `doc-gen` makes no decks, and `doc-run` PptxGenJS is **not** a deck path (it remains for
|
|
9
|
+
non-deck jobs: data tables, batch generation, shape-level one-offs).
|
|
10
|
+
- html2pptx needs a browser (the app's Chromium service or the bundled Playwright). With
|
|
11
|
+
neither, **say so and stop** — never downgrade to a lesser deck.
|
|
12
|
+
|
|
13
|
+
Where things live: layout choice and fill contract → `layouts/README.md`; Theme V2 vs
|
|
14
|
+
classic-v1 → `theme-system.md`; flags, outputs and exit codes → `bin-reference.md`;
|
|
15
|
+
content and outline → `content-pipeline.md`.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. **Plan, then fill.** The approved `plan.json` IS the outline (content-pipeline.md
|
|
20
|
+
Phase 3 — written once, `--outline` renders what the user approved) and runs
|
|
21
|
+
```
|
|
22
|
+
node <skill>/bin/deck-plan.cjs plan.json spec.json # → per slide: pick · alternatives · rejected[{layout, why}]
|
|
23
|
+
node <skill>/bin/deck-build.cjs spec.json deck.html
|
|
24
|
+
```
|
|
25
|
+
`deck-plan` maps each slide's content onto every candidate layout's slots, checks
|
|
26
|
+
every string against the layout's capacity **measured under your style**
|
|
27
|
+
(`layouts/capacity.json`), applies P1/P2/P3 and drafts the spec (every slot filled,
|
|
28
|
+
charts as `chartRender:"svg"`). A slide with `pick: null` fits nothing as written —
|
|
29
|
+
change the content its `rejected[].why` names ("holds exactly 3 items, content has
|
|
30
|
+
4", "card2_body is ~58 wide but holds ≤42 — cut ~16"), or pin `layout` + `slots`, and
|
|
31
|
+
re-plan; do NOT render to find out. Edit `spec.json` freely afterwards — `deck-build`
|
|
32
|
+
re-checks capacity on every build, and its warnings (unfilled slot → demo copy) are
|
|
33
|
+
defects. Put the confirmed `scenario` in the plan (it decides motion, below). A
|
|
34
|
+
`\n` in a value is a line break (a typed `<br>` ships as text); a slide's `source`
|
|
35
|
+
("IDC,2026") is its one short source line, in the footer.
|
|
36
|
+
2. **Bespoke slides** (no layout fits, or approved generated-visual pages): author one
|
|
37
|
+
`<section class="slide">` in its own file and give the plan slide `file` — deck-build
|
|
38
|
+
puts it at its position (its `notes` too); every other slide stays catalog. **Never patch the built `deck.html`
|
|
39
|
+
with a script or regex**: capacity checks cannot see those edits. Change content
|
|
40
|
+
or slots and re-plan, or replace
|
|
41
|
+
that ONE slide with a bespoke `file`. Speaker notes are each slide's `notes`.
|
|
42
|
+
3. **Preview, build, sign off** — "Verify before delivering" below.
|
|
43
|
+
|
|
44
|
+
Hand-pasting a `layouts/<id>.tpl` skips the capacity check; a layout with a `{{#rows}}`
|
|
45
|
+
block (gantt · radar · ring-progress · map-distribution · team-row · brand-values ·
|
|
46
|
+
color-palette · steps-vertical · toc-panel) can only be filled through `deck-build`,
|
|
47
|
+
which repeats the block and derives the figure geometry from your numbers.
|
|
48
|
+
|
|
49
|
+
## Delivery modes — the fidelity ⇄ editability dial
|
|
50
|
+
|
|
51
|
+
- **hybrid** (default — no flag): visuals (gradients, glass, glow, mesh, cards, shadows,
|
|
52
|
+
art, gradient-clipped display text) bake into the backdrop; solid text and
|
|
53
|
+
`data-chart`s stay native. Gradients/shadows *look* right but live in the image. If the
|
|
54
|
+
backdrop capture is unavailable it falls back to plain native and reports a
|
|
55
|
+
`layout (fallback)` engine.
|
|
56
|
+
- **`--editable`** (alias `--mode native`): everything native; CSS gradients flatten to
|
|
57
|
+
a solid, blur/glow drop. Fully editable, smallest file. For designs that live in
|
|
58
|
+
layout + type. One exception: a Theme V2 art layer / generated-skin signature in
|
|
59
|
+
`.slide-backdrop` is one full-slide picture under the native content (its opacity,
|
|
60
|
+
blur and masks survive); the content on top stays native.
|
|
61
|
+
- **`--rasterize`**: every slide one image — pixel-perfect, ZERO editability; only when
|
|
62
|
+
even the text must be exact, and say so when delivering.
|
|
63
|
+
|
|
64
|
+
## The slide contract
|
|
65
|
+
|
|
66
|
+
Violations fail loudly; nothing degrades silently.
|
|
67
|
+
|
|
68
|
+
- One `<section class="slide">` per slide on a **1280×720 px** canvas (13.33×7.5 in).
|
|
69
|
+
- **Colour only from the skin's tokens**: `var(--accent|--title|--body|--muted|--hair|
|
|
70
|
+
--slide-bg|--title-color|--body-color|--font-heading|--font-body)` and the ramp
|
|
71
|
+
`var(--c1..--c4)`. Any other name (`--primary`, `--text`, `--card-bg`, `--border`,
|
|
72
|
+
`--accent2`) exists only under the legacy `--theme` path, so on a `--style` deck it
|
|
73
|
+
silently sticks on its fallback. A raw hex triggers html2pptx's `N hardcoded brand
|
|
74
|
+
color(s) bypass theme vars` warning — that deck won't re-skin; fix it (SVG diagram
|
|
75
|
+
semantic colours are exempt). To recolour one element, override a token on its
|
|
76
|
+
`<section>`: `style="--accent:#b8292e"`.
|
|
77
|
+
- **Tailwind utilities** are vendored offline (`grid grid-cols-2 gap-16`, `p-16`,
|
|
78
|
+
`rounded-3xl`…) and map to native pptx — use them for layout/spacing, tokens for
|
|
79
|
+
colour. Type scale: `size="1".."7"` → 12/14/16/24/32/48/72px.
|
|
80
|
+
- **Images**: `src` accepts an absolute path, a path relative to deck.html, or HTTPS;
|
|
81
|
+
html2pptx inlines assets before rendering. Mark required content with
|
|
82
|
+
`<img data-required-image src="…" alt="…">`: unreadable or undecodable images fail
|
|
83
|
+
export and previews. Unmarked images retain best-effort loading. For useful `gen`
|
|
84
|
+
pages, follow generated-visuals.md.
|
|
85
|
+
- **Icons = inline `<svg>` only** (lucide/heroicons path data, or a
|
|
86
|
+
`data:image/svg+xml` URI at worst). An icon `<img>` that fails to load bakes a
|
|
87
|
+
broken-image glyph into the backdrop.
|
|
88
|
+
- **No crude full-height accent bar** down an edge, and **no thin accent line under a
|
|
89
|
+
title** — the two loudest "template" tells. A family that wants a spine bakes it into
|
|
90
|
+
its `.tpl`.
|
|
91
|
+
- Native mapping: text (per style run), boxes (background/border/radius), `<img>`
|
|
92
|
+
(`object-fit:cover|contain` → native crop/letterbox, no pre-cropping), `<hr>`,
|
|
93
|
+
`rgba()` fills (native transparency — a scrim over a photo stays a scrim).
|
|
94
|
+
Inline `<svg>`/`<canvas>` rasterize **per element**; the rest of the slide stays
|
|
95
|
+
editable, so SVG icons/diagrams never need `--rasterize`. Not mapped: CSS gradients
|
|
96
|
+
in `--editable`, `<video>`.
|
|
97
|
+
- **Speaker notes**: `<div class="talos-notes" style="display:none">…</div>` (or
|
|
98
|
+
`data-notes="…"` on the `<section>`) → the slide's notes page; `--notes-doc
|
|
99
|
+
<out.md>` also writes a standalone notes document.
|
|
100
|
+
- PowerPoint re-lays out what Chromium measured: keep ~10% slack in multi-line text
|
|
101
|
+
boxes (single-line boxes are widened automatically — see CJK notes).
|
|
102
|
+
- Runs in the app's Chromium or a bundled headless Chromium, so it works off-app; a
|
|
103
|
+
`.layout.json` snapshot converts with no browser. A font-less Linux host may need a
|
|
104
|
+
CJK font installed.
|
|
105
|
+
|
|
106
|
+
## Bespoke slides — the escape hatch
|
|
107
|
+
|
|
108
|
+
The catalog is a palette, not a cage: a structure no layout expresses (a specific
|
|
109
|
+
architecture diagram, a custom flow/topology, a signature hero moment) earns a
|
|
110
|
+
hand-authored slide. Approved generated-visual pages also use this route; other pages
|
|
111
|
+
stay catalog. A bespoke slide must:
|
|
112
|
+
|
|
113
|
+
- be one `<section class="slide" style="position:relative;width:1280px;height:720px">`,
|
|
114
|
+
positioned with `absolute`, text native, diagram parts inline `<svg>`;
|
|
115
|
+
- paint from the skin: its classes (`.card`, `.eyebrow`, `.deck-title`, `.accent-bar`…)
|
|
116
|
+
and tokens, with the ramp `--c1..--c4` for per-item colour-coding (that is how a
|
|
117
|
+
legend colour-matches its boxes). The zero-colour rule binds only the reusable
|
|
118
|
+
`layouts/*.tpl`; deck.html may use colour, but through tokens;
|
|
119
|
+
- write sizes and gutters on the skin's scale — `calc(48px * var(--type-scale,1))`,
|
|
120
|
+
`calc(96px * var(--space-scale,1))` — or it ignores the skin's density;
|
|
121
|
+
- pass the Design principles below and look of the same deck.
|
|
122
|
+
|
|
123
|
+
Composition recipes (vary them): **full-bleed statement** (the skin's background or
|
|
124
|
+
`.slide-inverse`, oversized title bottom-left, presenter/date small at the bottom) ·
|
|
125
|
+
**two-column split** (text left, visual right) · **half-bleed image** (~55% image with
|
|
126
|
+
`object-fit:cover`, text on a scrim/panel on the other half) · **big stat** (one number
|
|
127
|
+
at 140–200px in `var(--accent)`, a label, one sentence) · **icon rows / 2×2** (SVG icon,
|
|
128
|
+
bold header, one line each; equal cells) · **quote** (one sentence at 40–56px) ·
|
|
129
|
+
**section divider** (oversized ghost chapter number + title). Example: a 4-layer
|
|
130
|
+
architecture — annotated L1–L4 list left, connected stages right colour-matched via
|
|
131
|
+
`--c1..--c4`, dashed `<svg>` connectors. A pattern that recurs across decks graduates
|
|
132
|
+
into a real `layouts/<id>.tpl`.
|
|
133
|
+
|
|
134
|
+
## Charts — pick by where the deck will be OPENED
|
|
135
|
+
|
|
136
|
+
- **Inline `<svg>` drawn FROM DATA** — the default. It bakes into the backdrop, so it
|
|
137
|
+
renders everywhere (Keynote, macOS Preview / Quick Look, Google Slides, WPS,
|
|
138
|
+
PowerPoint); its labels stay native text, but the data is not editable.
|
|
139
|
+
**Never hand-write the chart's SVG** (scales, stacking and axes are where hand-drawn charts go wrong): in a catalog
|
|
140
|
+
chart layout give the spec `"chartRender":"svg"` (or one chart `"render":"svg"`) and
|
|
141
|
+
`deck-build` draws it for that layout's measured chart box; on a bespoke slide run
|
|
142
|
+
`bin/deck-chart.cjs chart.json --width W --height H` and paste the printed `<svg>`
|
|
143
|
+
into a W×H box. Types `bar` · `barH` · `line` · `area` · `pie` · `doughnut` (+
|
|
144
|
+
`stacked`, `unit`, `highlight` (category index → accent), `showValues`,
|
|
145
|
+
`centerLabel`, `zeroBaseline` (line axis from 0)); ≤4 series (a 5th+ slice folds into 其他); painted only with skin
|
|
146
|
+
variables, so it re-skins. `radar`: 3–8 `labels`, 1–3 series of 0..`max` scores (the
|
|
147
|
+
`radar` layout draws it from its rows); `scatter`: `series[].points` `[x,y]`/`{x,y,label}`
|
|
148
|
+
+ `xLabel`/`yLabel`.
|
|
149
|
+
- **Native `data-chart`** — `<div class="talos-chart" style="position:absolute;
|
|
226
150
|
left/top/width/height" data-chart='{"type":"bar|line|pie|doughnut|area","labels":
|
|
227
|
-
[…],"series":[{"name":"…","values":[…]}]
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
slides
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
`
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
7. **Refined type: three-tier contrast.** An **eyebrow** — tracked (`letter-
|
|
273
|
-
spacing:.28em`) small-caps label with a short lead rule (`— MARKET RESEARCH
|
|
274
|
-
REPORT`); a **display** title (cover 82–96px); a **micro-label** at 12–14px. Big
|
|
275
|
-
size jumps + deliberate tracking is the line between "designed" and "typed".
|
|
276
|
-
8. **Ghost-safe export (hybrid rules).** Two hard rules for html2pptx hybrid:
|
|
277
|
-
- **Solid text only.** NEVER `-webkit-background-clip:text` gradient text — the
|
|
278
|
-
backdrop-hide pass zeroes `color`/`-webkit-text-fill-color` but NOT
|
|
279
|
-
`background`, so a gradient-clipped glyph renders TWICE (a ghost behind the
|
|
280
|
-
native text). Use a solid `color:`.
|
|
281
|
-
- **Charts follow the cross-viewer rule above** (SVG by default).
|
|
282
|
-
|
|
283
|
-
The shipped `layouts/*.tpl` are this recipe applied as structure-only slides —
|
|
284
|
-
paste the nearest one and paint it with a skin (`--style`) rather than rebuilding
|
|
285
|
-
the stack by hand; each already carries the 8 layers correctly wired.
|
|
286
|
-
|
|
287
|
-
**Every catalog entry ships a motion preset; the scenario decides whether
|
|
288
|
-
`deck-build` applies it.** (`motion/<id>.json`, named by the entry's `motion` field.)
|
|
289
|
-
Put the confirmed scenario in the spec as `"scenario"`: a **presented** deck (pitch /
|
|
290
|
-
路演 / 发布会 / keynote / 大会 / 讲座 / 销售) gets the preset — `data-anim*` /
|
|
291
|
-
`data-transition*` injected per slide by the layout's role; a **read** deck (内审 /
|
|
292
|
-
评审 / 报告 / 汇报 / 讲义 / 培训 / 述职) gets none; no or an unknown scenario keeps the
|
|
293
|
-
preset. `"motion": true|false` overrides the scenario. The build's JSON says which
|
|
294
|
-
applied and why (`motion: {on, reason}`). Hand-written `data-anim` /
|
|
295
|
-
`data-transition` always wins — `deck-build` only adds an attribute an element does
|
|
296
|
-
not already have, and a deck authored straight into `deck.html` animates only
|
|
297
|
-
where you write `data-anim`.
|
|
298
|
-
|
|
299
|
-
## Motion — entrance animation + slide transitions
|
|
300
|
-
|
|
301
|
-
### Entrance animation (`data-anim`) — opt-in, hero pages only
|
|
302
|
-
|
|
303
|
-
html2pptx emits **native PowerPoint entrance animations** (a real `<p:timing>`
|
|
304
|
-
build sequence — not a video, not a GIF). Mark an element with `data-anim` and it
|
|
305
|
-
becomes one build step; the deck then plays like a keynote instead of appearing
|
|
306
|
-
all at once.
|
|
307
|
-
|
|
308
|
-
**The attribute itself is opt-in.** No `data-anim` on the page → no `<p:timing>`.
|
|
309
|
-
Write your own when the scenario is a **stage** — 发布会 / 路演 / pitch / 主题演讲;
|
|
310
|
-
for 内审 / 报告 / 讲义 decks that people read rather than watch, add none beyond
|
|
311
|
-
what the preset already injects.
|
|
312
|
-
|
|
313
|
-
#### The attribute contract
|
|
151
|
+
[…],"series":[{"name":"…","values":[…]}]}'></div>` becomes an editable `c:chart`,
|
|
152
|
+
**but it only renders in PowerPoint / WPS / LibreOffice and shows BLANK in Keynote,
|
|
153
|
+
macOS Preview, Quick Look and Google Slides.** Only when you KNOW the deck stays in
|
|
154
|
+
PowerPoint and the client must edit the numbers.
|
|
155
|
+
- Never Chart.js/`<canvas>`. One insight per chart, highlight the key datapoint, no junk.
|
|
156
|
+
When unsure, ship the SVG — a chart nobody can see is worse than one nobody can edit.
|
|
157
|
+
|
|
158
|
+
## Premium craft — the 8-layer finish
|
|
159
|
+
|
|
160
|
+
The shipped layouts already wire these layers; this is what to reproduce on a bespoke
|
|
161
|
+
hero slide (cover / section / big-stat / ending: all eight; content slides: 1–2 and 6–8).
|
|
162
|
+
Spend the boldness in ONE place (layer 5).
|
|
163
|
+
|
|
164
|
+
1. **Tonal base** — a low-angle (`160deg`) gradient between two near-neighbours of the
|
|
165
|
+
base colour, not a flat fill.
|
|
166
|
+
2. **Grain** — one full-bleed `feTurbulence` noise `<svg>` at `opacity:.03;
|
|
167
|
+
mix-blend-mode:multiply`; give each slide's filter a unique `id`.
|
|
168
|
+
3. **Light (hero only)** — ONE of `spotlight` · `bloom` · `duotone` · `aurora` ·
|
|
169
|
+
`frosted` · `rimlight`, as plain background-gradient divs (no text, no
|
|
170
|
+
`background-clip`); full strength on dark skins, low alpha on light ones; vary it
|
|
171
|
+
per page.
|
|
172
|
+
4. **Depth** — an edge vignette and a top inset hairline on cards; felt, not seen.
|
|
173
|
+
5. **One signature motif** per style (rings + star-dots, an aurora arc, a ghost chapter
|
|
174
|
+
number); never put content in it.
|
|
175
|
+
6. **Chrome** — running header (title · chapter) + 1px hairline + footer + page number:
|
|
176
|
+
what makes ten slides read as one document.
|
|
177
|
+
7. **Three-tier type** — tracked (`letter-spacing:.28em`) eyebrow with a lead rule, a
|
|
178
|
+
display title, 12–14px micro-labels.
|
|
179
|
+
8. **Ghost-safe export** — solid text only: NEVER `-webkit-background-clip:text`
|
|
180
|
+
(the backdrop pass hides `color` but not `background`, so the glyph renders twice).
|
|
181
|
+
Charts follow the rule above.
|
|
182
|
+
|
|
183
|
+
## Motion — presets, entrance animation, transitions
|
|
184
|
+
|
|
185
|
+
**Every catalog entry ships a motion preset (`motion/<id>.json`); the scenario decides
|
|
186
|
+
whether `deck-build` applies it.** Put the confirmed scenario in the spec as
|
|
187
|
+
`"scenario"`: a **presented** deck (pitch / 路演 / 发布会 / keynote / 大会 / 讲座 / 销售)
|
|
188
|
+
gets the preset — `data-anim*` / `data-transition*` injected per slide by role; a
|
|
189
|
+
**read** deck (内审 / 评审 / 报告 / 汇报 / 讲义 / 培训 / 述职) gets none; no or an unknown
|
|
190
|
+
scenario keeps the preset. `"motion": true|false` overrides; the build reports
|
|
191
|
+
`motion: {on, reason}`. Hand-written attributes always win (deck-build only adds what an
|
|
192
|
+
element lacks), and a deck written straight into `deck.html` animates only where you
|
|
193
|
+
write `data-anim`. Add your own only on a stage deck, never on a read deck.
|
|
194
|
+
|
|
195
|
+
html2pptx emits native PowerPoint builds (`<p:timing>`). Attribute contract:
|
|
314
196
|
|
|
315
197
|
| attribute | value | default |
|
|
316
198
|
|---|---|---|
|
|
@@ -320,85 +202,36 @@ what the preset already injects.
|
|
|
320
202
|
| `data-anim-delay` | ms before this step | `0` first step, `200` after |
|
|
321
203
|
| `data-anim-dur` | ms the effect runs | `500` |
|
|
322
204
|
|
|
323
|
-
`fade-up`
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
a `.card` animates the whole card as a unit. That is almost always what you want:
|
|
330
|
-
animate BLOCKS, not individual words.
|
|
331
|
-
|
|
332
|
-
#### Playback model
|
|
333
|
-
|
|
334
|
-
The first step fires when the presenter advances to the slide's build; every later
|
|
335
|
-
step chains **after-previous**, so its `data-anim-delay` reads as the stagger
|
|
336
|
-
between items. One click plays the whole page — you never click per element.
|
|
337
|
-
|
|
338
|
-
#### Hard constraints (silent failure if ignored)
|
|
339
|
-
|
|
340
|
-
- **Only native shapes animate.** Anything baked into the raster backdrop is one
|
|
341
|
-
flat image and cannot be a step. That includes every `--talos-bake:1` title —
|
|
342
|
-
**`cinereel` and `ivory-gold` bake ALL their title classes**, so on those two
|
|
343
|
-
skins a `data-anim` on `.cover-title`/`.section-title` is silently dropped.
|
|
344
|
-
Animate the eyebrow, body, cards and image instead, or pick another skin.
|
|
345
|
-
**Same rule for a motion preset's `entrance.<role>[].sel`** — `deck-build` writes
|
|
346
|
-
`data-anim*` onto whatever the selector matches by class, so a preset step aimed
|
|
347
|
-
at a title class on a bake-everything skin drops just as silently; a family's
|
|
348
|
-
`motion/<id>.json` has to know its own skin's `--talos-bake` list.
|
|
349
|
-
- **`background-clip:text` is baked too** (layer 8 above) — same silent drop.
|
|
350
|
-
- **PDF flattens everything.** `doc-convert` / LibreOffice / Gotenberg ignore
|
|
351
|
-
`<p:timing>`; the animation exists only in the .pptx opened in PowerPoint,
|
|
352
|
-
Keynote or Impress. Never promise animation on a PDF deliverable.
|
|
353
|
-
- **Charts and images animate**, as whole objects — a `data-chart` cannot animate
|
|
354
|
-
series-by-series.
|
|
355
|
-
|
|
356
|
-
#### Recipes (paste onto the layout you already picked)
|
|
357
|
-
|
|
358
|
-
**Cover** — one statement, one beat:
|
|
205
|
+
`fade-up` = `float` (gentle 5% rise — the house default); `fly-*` travels 30% of the
|
|
206
|
+
slide and is loud (once, on a cover); `appear` is a hard cut for a punchline. Put the
|
|
207
|
+
attribute on a **container** — text inside inherits its nearest `[data-anim]`
|
|
208
|
+
ancestor, so one attribute on a `.card` animates the card as a unit. The first step
|
|
209
|
+
fires when the presenter advances; later steps chain after-previous, so
|
|
210
|
+
`data-anim-delay` is the stagger — one click plays the page.
|
|
359
211
|
|
|
360
212
|
```html
|
|
361
213
|
<h1 class="cover-title" data-anim="fade-up" data-anim-seq="1" data-anim-dur="700">…</h1>
|
|
362
214
|
<div class="cover-sub" data-anim="fade-up" data-anim-seq="2" data-anim-delay="120">…</div>
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
**Section divider** — the number lands, then the title:
|
|
366
|
-
|
|
367
|
-
```html
|
|
368
|
-
<div class="section-ghost" data-anim="fade" data-anim-seq="1">03</div>
|
|
369
|
-
<h2 class="section-title" data-anim="fly-up" data-anim-seq="2" data-anim-delay="150">…</h2>
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
**Card grid / TOC** — stagger the blocks, never the words. One attribute per card,
|
|
373
|
-
`seq` in reading order, a short even delay:
|
|
374
|
-
|
|
375
|
-
```html
|
|
376
|
-
<div class="card" data-anim="fade-up" data-anim-seq="1">…</div>
|
|
377
|
-
<div class="card" data-anim="fade-up" data-anim-seq="2" data-anim-delay="140">…</div>
|
|
378
215
|
<div class="card" data-anim="fade-up" data-anim-seq="3" data-anim-delay="140">…</div>
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
**Big stat** — the label sets up, the number pays off:
|
|
382
|
-
|
|
383
|
-
```html
|
|
384
|
-
<div class="stat-lead" data-anim="fade" data-anim-seq="1">…</div>
|
|
385
216
|
<div class="stat-num" data-anim="appear" data-anim-seq="2" data-anim-delay="260">…</div>
|
|
386
217
|
```
|
|
387
218
|
|
|
388
|
-
|
|
219
|
+
Silent-failure constraints:
|
|
389
220
|
|
|
390
|
-
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
-
|
|
394
|
-
|
|
395
|
-
|
|
221
|
+
- **Only native shapes animate.** Baked text is part of the backdrop image: every
|
|
222
|
+
class a skin marks `--talos-bake:1` drops its `data-anim` silently. Many skins bake
|
|
223
|
+
their titles (`cinereel` and `ivory-gold` bake all title classes; check the skin's
|
|
224
|
+
`skin.css` for `--talos-bake:1`) — animate the eyebrow, body, cards and images
|
|
225
|
+
instead. A preset's `entrance.<role>[].sel` obeys the same rule, so a family's
|
|
226
|
+
`motion/<id>.json` must know its skin's bake list. `background-clip:text` is baked too.
|
|
227
|
+
- **PDF flattens everything** (doc-convert / LibreOffice / Gotenberg ignore timing and
|
|
228
|
+
transitions): never promise animation on a PDF.
|
|
229
|
+
- Charts and images animate as whole objects — never series-by-series.
|
|
396
230
|
|
|
397
|
-
|
|
231
|
+
Discipline: ≤4 steps per slide; hero pages only (cover, section, big-stat, ending, at
|
|
232
|
+
most one content page per chapter); never animate the chrome; 500–700ms.
|
|
398
233
|
|
|
399
|
-
|
|
400
|
-
moves BETWEEN slides. Put it on the `<section class="slide">` — it describes the move
|
|
401
|
-
**into** that slide.
|
|
234
|
+
**Transitions** go on the `<section class="slide">` and describe the move INTO it:
|
|
402
235
|
|
|
403
236
|
| attribute | value | default |
|
|
404
237
|
|---|---|---|
|
|
@@ -406,272 +239,179 @@ moves BETWEEN slides. Put it on the `<section class="slide">` — it describes t
|
|
|
406
239
|
| `data-transition-dir` | `l` · `r` · `u` · `d` (wipe/push/cover) · `in` · `out` (zoom/split) | per-effect default |
|
|
407
240
|
| `data-transition-dur` | ms | the `med` speed bucket |
|
|
408
241
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
persist across two slides instead of cutting. Two caveats before you reach for it:
|
|
416
|
-
it needs **PowerPoint 2016+** (older consumers get the fade fallback we emit), and in
|
|
417
|
-
hybrid mode most of each slide is a single baked backdrop image, so morph has little
|
|
418
|
-
to tween — it reads as a soft cross-dissolve unless the two slides share **native**
|
|
419
|
-
shapes (text/charts) in similar positions. Use it between slides that genuinely
|
|
420
|
-
continue one another (a title that moves, a stat that grows); elsewhere `fade` is more
|
|
421
|
-
honest and costs nothing.
|
|
422
|
-
|
|
423
|
-
**Pick one transition for the deck and stay with it** — a different effect per slide is
|
|
424
|
-
the single loudest "amateur deck" signal. `fade` for almost everything; `push` or
|
|
425
|
-
`cover` when chapters should feel like turning a page; `cut` (or nothing) for dense
|
|
426
|
-
analytical decks where motion is noise; `morph` for the two or three slides that
|
|
427
|
-
actually continue each other.
|
|
428
|
-
|
|
429
|
-
Same two constraints as animation: **PDF export flattens transitions** (they exist only
|
|
430
|
-
in the .pptx opened in PowerPoint/Keynote/Impress), and an unknown name degrades to
|
|
431
|
-
`fade` rather than failing.
|
|
432
|
-
|
|
433
|
-
## Type & space scale — how a skin sets its own rhythm
|
|
434
|
-
|
|
435
|
-
Every `font-size` and page gutter in `layouts/*.tpl` is written as a scalable value:
|
|
436
|
-
|
|
437
|
-
```html
|
|
438
|
-
font-size:calc(23px * var(--type-scale,1)) left:calc(96px * var(--space-scale,1))
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
A skin sets `--space-scale` / `--type-scale` in its `:root` and the whole deck retimes —
|
|
442
|
-
**without touching a single layout**, and keeping each layout's internal hierarchy intact
|
|
443
|
-
(everything scales together). Both default to `1`, so a skin that ignores them renders
|
|
444
|
-
exactly as before. The shipped range runs from `mckinsey` at `0.86` (board-pack density)
|
|
445
|
-
to `apple` at `1.22` (keynote-stage air).
|
|
242
|
+
Pick ONE transition for the deck — a different effect per slide is the loudest amateur
|
|
243
|
+
signal: `fade` for almost everything, `push`/`cover` for page-turn chapters, `cut` (or
|
|
244
|
+
none) for dense analytical decks. `morph` needs PowerPoint 2016+ (older apps get the
|
|
245
|
+
emitted fade fallback) and only tweens **native** shapes in similar positions on both
|
|
246
|
+
slides — in hybrid most of a slide is one baked image, so use it only between slides
|
|
247
|
+
that genuinely continue each other. An unknown name degrades to `fade`.
|
|
446
248
|
|
|
447
|
-
|
|
249
|
+
## Type & space scale
|
|
448
250
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
251
|
+
Every `font-size` and gutter in `layouts/*.tpl` is `calc(Npx * var(--type-scale,1))` /
|
|
252
|
+
`calc(Npx * var(--space-scale,1))`; a skin sets the two scales in `:root` and the whole
|
|
253
|
+
deck retimes with its hierarchy intact (from `mckinsey` 0.86 to `apple` 1.22; both
|
|
254
|
+
default 1). A bespoke slide writes its sizes the same way. **Changed a scale? Re-export
|
|
255
|
+
(`html2pptx deck.html out.pptx`) and read its `qa`** — scaling reflows text and can push
|
|
256
|
+
it off-canvas; never eyeball it. (`deck-qa` takes the .pptx only.)
|
|
454
257
|
|
|
455
258
|
## Fonts — bundled faces reach the render, not the native text layer
|
|
456
259
|
|
|
457
|
-
`assets/fonts/fonts.json` is the single source of
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
**
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
**
|
|
565
|
-
|
|
566
|
-
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
diagram/hero pages.
|
|
575
|
-
|
|
576
|
-
All snippets are hybrid-native: chips, rules, frames, gradients, SVG **bake into the
|
|
577
|
-
backdrop**; labels, page numbers, chart data stay **native/editable**. Route every
|
|
578
|
-
color through the skin tokens (`var(--accent, …)`) so one skin reskins them — the same
|
|
579
|
-
`footer-pageno` fragment becomes tech-cyan or 国风-朱红 by swapping `--accent`.
|
|
580
|
-
|
|
581
|
-
**Pairing a snippet with the theme** — two independent dimensions:
|
|
582
|
-
- **Color = automatic.** Snippets read only the skin tokens listed in the slide
|
|
583
|
-
contract above (`--accent --title --body --muted --hair --slide-bg --title-color
|
|
584
|
-
--body-color --font-heading --font-body --c1..--c4`). Pick the skin and every
|
|
585
|
-
snippet recolors for free; the value after the comma is just the fallback. Any
|
|
586
|
-
OTHER var name (e.g. `--accent2`, `--primary`) is not defined → it silently sticks
|
|
587
|
-
on its fallback, so **only use those names**. Need one snippet in an off-skin
|
|
588
|
-
color? Override on its `<section>`: `style="--accent:#b8292e;--muted:#9a8b76"`.
|
|
589
|
-
- **Form = your choice.** The theme supplies the palette, NOT the shape. A `neon-dot`
|
|
590
|
-
on a 侘寂 light theme reads wrong even recolored — pick the motif/functional family
|
|
591
|
-
that matches the style's aesthetic (seal→chinese, gold-flourish→black-gold,
|
|
592
|
-
neon/corner-frame→tech).
|
|
593
|
-
- **Exception — semantic colors don't follow the theme.** Multi-color ramps that
|
|
594
|
-
encode meaning (`neural-net` layer colors, `cube-3d` Layer 1/2/3, `radar` severity)
|
|
595
|
-
are intentionally hardcoded; the theme reskins their title/bg/accent but the ramp
|
|
596
|
-
stays so the hierarchy reads.
|
|
597
|
-
|
|
598
|
-
## Verify before delivering (MANDATORY automated visual-QA loop)
|
|
599
|
-
|
|
600
|
-
**Assume there are problems — your job is to find them.** Treat QA as a bug hunt,
|
|
601
|
-
not a confirmation step. Use the cheapest faithful surface for each stage: HTML
|
|
602
|
-
screenshots while authoring, the build's own checks on every build, and one
|
|
603
|
-
Office-rendered sign-off at the end. Do not launch LibreOffice after every edit.
|
|
604
|
-
|
|
605
|
-
**Machine checks come with the build.** Every `html2pptx … out.pptx` run prints,
|
|
606
|
-
next to the build result, `valid` (does the file open — `false` exits 1: never
|
|
607
|
-
deliver) and `qa: { ok, findings:[{slide,code,message}] }` — deck-qa's lint:
|
|
608
|
-
**off-canvas**, **tiny-font** (<10pt), **shape-overlap**, **text-only-slide**,
|
|
609
|
-
**low-contrast-text**, **placeholder-text** (替换为…/占位/在这里写/Lorem left in a
|
|
610
|
-
slide) and **font-mismatch** (CJK in a Latin-only font → 豆腐; language defaults to
|
|
611
|
-
the system locale, override with `TALOS_DECK_LANG`). **Fix every finding before
|
|
612
|
-
anything else** — they are objective and free, so they must never reach the
|
|
613
|
-
vision pass or delivery. No separate `doc-validate` / `deck-qa` call is needed
|
|
614
|
-
after a build.
|
|
615
|
-
|
|
616
|
-
**The loop** (≤2 delivery rounds, then report residuals — never silently ship):
|
|
617
|
-
|
|
618
|
-
1. **Author against the HTML preview.** `html2pptx.cjs deck.html --preview-dir
|
|
619
|
-
<dir> --style <id> …` renders every slide the first time; after a fix,
|
|
620
|
-
`--preview-pages 3,7-8` renders only the changed ones. Read these images and
|
|
621
|
-
iterate until the composition is clean.
|
|
622
|
-
2. **Build and fix the build's findings** (`html2pptx … deck.pptx`, see above).
|
|
623
|
-
3. **Sign off once: `deck-qa.cjs deck.pptx --final`.** One call runs strict XSD
|
|
624
|
-
validation (a failure exits 1), the lint, an Office render (LibreOffice via
|
|
625
|
-
`doc-convert`, cached), and the render check: `render-overflow` (text Office
|
|
626
|
-
re-wrapped onto more lines than its box holds, or past its side) and
|
|
627
|
-
`render-collision` (text that grew out of its box onto another). It returns
|
|
628
|
-
`review` — the slides with such a finding or a native chart (Office draws
|
|
629
|
-
charts; the preview never showed them) — and `previews`, a ≈72dpi image of
|
|
630
|
-
each. **Read only `previews`.** Every other slide already passed your eyes in
|
|
631
|
-
the HTML preview, and in the default hybrid mode its visuals are baked from
|
|
632
|
-
that same render; Office only re-lays the native text, which was just
|
|
633
|
-
measured. Re-wrapping at a different word, spacing CJK and Latin apart or a
|
|
634
|
-
substituted Latin face is normal, not a defect.
|
|
260
|
+
`assets/fonts/fonts.json` is the single source of the font set: html2pptx base64-injects
|
|
261
|
+
every face from it (sample/fidelity scripts serve the same files). Add a face there with
|
|
262
|
+
its `.woff2` — never inline a base64 `@font-face` into a `skin.css`. An injected face
|
|
263
|
+
styles only the **browser** render (backdrop, baked text, `--rasterize`, previews); a
|
|
264
|
+
native pptx run carries just a typeface *name*, and PowerPoint / Keynote / LibreOffice
|
|
265
|
+
substitute what they have. A non-system face survives into the delivered deck only if:
|
|
266
|
+
|
|
267
|
+
1. **baked** (`--talos-bake:1` on the class) — exact, but that text is no longer
|
|
268
|
+
editable, searchable, `deck-qa`-checkable or animatable;
|
|
269
|
+
2. **embedded** — `bin/pptx-embed-fonts.cjs` (needs a TTF; small Latin faces only, never
|
|
270
|
+
CJK); or
|
|
271
|
+
3. **a system face** (Helvetica Neue / Georgia / Arial, the CJK families) — why most
|
|
272
|
+
skins lead with them.
|
|
273
|
+
|
|
274
|
+
## Design principles (the bar EVERY deck passes)
|
|
275
|
+
|
|
276
|
+
The catalog layouts bake most of this in; on a bespoke slide it is yours.
|
|
277
|
+
|
|
278
|
+
- **Colour — commit.** One dominant colour (~60–70% of the coloured area), accent as a
|
|
279
|
+
spark; let the skin's palette choose the hue, never a "safe" corporate blue. The
|
|
280
|
+
background comes from the skin — don't paint your own. Alternate value: put dark
|
|
281
|
+
slides (cover, section breaks, a punchy stat — via a dark layout or `.slide-inverse`
|
|
282
|
+
where the skin defines it) between light content slides.
|
|
283
|
+
- **Every slide earns a visual anchor** — a colour band, big number, icon row, 2×2,
|
|
284
|
+
chart or image, plus ≥2 visual elements in all (anchor, motif, chrome). Title +
|
|
285
|
+
bullets on a plain ground is the classic AI tell (`qa` flags `text-only-slide`). Vary the layout slide to slide; ≥0.5" margins; if a slide feels
|
|
286
|
+
full at 60%, stop adding.
|
|
287
|
+
- **Type.** One focal element per slide; ≤3 sizes per slide; ≤2 font families; contrast
|
|
288
|
+
by weight or family. Catalog layouts already set the ladder — don't override their
|
|
289
|
+
sizes. Bespoke: title `size 6–7` (48–72px), section headings `size 5–6`, body 14–24px,
|
|
290
|
+
labels ≥13px; `qa` flags anything under 10pt as `tiny-font`. Never shrink type to fit
|
|
291
|
+
— split or cut instead (≤6 items, each ≤2 lines; past that, cards or a graphic).
|
|
292
|
+
- **Alignment.** Snap to a grid; one alignment per zone; never centre running body
|
|
293
|
+
text. Siblings share radius, border and accent placement (use the skin's classes);
|
|
294
|
+
filled boxes keep ≥0.15" inner padding, siblings ≥0.25" apart.
|
|
295
|
+
- **Contrast.** Text on fills clears ~4.5:1 (large/bold ~3:1): `var(--title)` /
|
|
296
|
+
`var(--body)` on the skin's own surfaces; `qa` flags `low-contrast-text`.
|
|
297
|
+
|
|
298
|
+
## Snippets — self-serve, not planned
|
|
299
|
+
|
|
300
|
+
`assets/snippets/`: **`functional.md`** (`nav-bar` · `breadcrumb` · `footer-pageno` ·
|
|
301
|
+
`cta-row` — a footer on nearly every content page is the cheapest "produced" signal;
|
|
302
|
+
`cta-row` on the ending) · **`motifs.md`** (`seal` · `gold-flourish` · `neon-dot` ·
|
|
303
|
+
`corner-frame` · `thin-geo` · `grid-dots`; ≤2 per slide, never content inside) ·
|
|
304
|
+
**`decorations.md`** (full-slide `neural-net` · `data-pipeline` · `code-editor` ·
|
|
305
|
+
`cube-3d` · `radar` · `glow-cover` · `chinese-seal` for diagram/hero pages). They read
|
|
306
|
+
only the contract tokens, so colour follows the skin automatically; FORM is your choice —
|
|
307
|
+
match the family's aesthetic (seal→chinese, gold-flourish→black-gold,
|
|
308
|
+
neon/corner-frame→tech). Exception: meaning-bearing ramps (`neural-net` layers,
|
|
309
|
+
`cube-3d` levels, `radar` severity) stay hardcoded on purpose.
|
|
310
|
+
|
|
311
|
+
## Custom skins
|
|
312
|
+
|
|
313
|
+
When the user picks 其他/自定义 or 使用我的模板文件 in the style picker, clarify the route —
|
|
314
|
+
**prefer B**:
|
|
315
|
+
|
|
316
|
+
- **B — derive a bespoke look (PREFERRED).** From an **existing deck** (the picker's
|
|
317
|
+
使用我的模板文件): learn its STYLE — what every page shows (logo, bars, footer,
|
|
318
|
+
page number, palette, fonts) — with `template-skin <deck.pptx> <name> --label "<a short name the user would recognise, e.g. 太平洋证券研报>"`, not its
|
|
319
|
+
photos/tables/text. The template's look **is** the style: it overrides an earlier
|
|
320
|
+
深色/浅色 ask — do not ask how to blend them. Confirm the two `samples` + `uncertain`
|
|
321
|
+
list as an image card (relay any `warnings`); a fix is a re-run: `--exclude <kept key>`
|
|
322
|
+
— a brand logo, a disclaimer (read `kept[].hint`), a photo taken as logo —
|
|
323
|
+
`--include <uncertain key>`, `--content-page N`. Never rebuild the look as a
|
|
324
|
+
hand-written skin and never set `TALOS_DOC_STYLES_DIR` yourself (2026-10-09 a deck
|
|
325
|
+
dropped its learned template for a patched mckinsey copy). Then
|
|
326
|
+
author with `style: "<name>"`: titles go in the template's title bar, content in its
|
|
327
|
+
free area (a bespoke slide starts at top ≥210px); `deck-plan --layouts --style <name>`
|
|
328
|
+
lists what fits. Refilling its
|
|
329
|
+
ORIGINAL PAGES is a separate route, if asked (rewrite.md "Reuse an uploaded
|
|
330
|
+
deck"). From a **reference image / brand color**: sample the palette into a new skin.
|
|
331
|
+
- **A — map to the nearest catalog family** (they only described a vibe): pick the
|
|
332
|
+
closest, render its sample, confirm.
|
|
333
|
+
- **C — tweak an existing skin** ("刚才那个族但换绿色"): clone it, swap accent/palette or
|
|
334
|
+
flip light↔dark.
|
|
335
|
+
|
|
336
|
+
Render a cover+content sample of the result and confirm (same image-card step as a
|
|
337
|
+
normal pick) before authoring; save the preference to memory.
|
|
338
|
+
|
|
339
|
+
A new skin is a user style: one `skin.css` defining the full class contract
|
|
340
|
+
(`layouts/README.md`), saved at `$TALOS_DOC_STYLES_DIR/styles/<name>/skin.css` (the
|
|
341
|
+
user's own styles, kept across sessions and shared by every expert) and rendered with
|
|
342
|
+
`--style <name>`. Pick a name no catalog entry uses — catalog ids resolve first. The
|
|
343
|
+
saved ones are `ls "$TALOS_DOC_STYLES_DIR/styles"`; offer them for "我之前那个风格". If
|
|
344
|
+
`$TALOS_DOC_STYLES_DIR` is unset (CI / bare headless run), build it in the working folder
|
|
345
|
+
and pass `--style ./styles/<name>`. Never write inside the skill directory: it is an
|
|
346
|
+
integrity-checked install, reinstalled — and your file lost — once it changes.
|
|
347
|
+
Start from the catalog skin of the same light/dark polarity
|
|
348
|
+
(`styles/<id>/skin.css`) and replace its tokens with the sampled palette — every layout
|
|
349
|
+
then works in it. To reuse an existing deck's palette, `pptx-theme` extracts it as JSON:
|
|
350
|
+
copy its colours into those tokens. `html2pptx --theme` does not do this: on a
|
|
351
|
+
`--style` deck the skin's tokens override the theme's.
|
|
352
|
+
|
|
353
|
+
## Verify before delivering (MANDATORY)
|
|
354
|
+
|
|
355
|
+
**Assume there are problems — your job is to find them.** Use the cheapest faithful
|
|
356
|
+
surface per stage: HTML screenshots while authoring, the build's own checks on every
|
|
357
|
+
build, one Office-rendered sign-off at the end.
|
|
358
|
+
Do not launch LibreOffice after every edit.
|
|
359
|
+
|
|
360
|
+
1. **Author against the HTML preview.** `html2pptx.cjs deck.html --preview-dir <dir>
|
|
361
|
+
--style <id> …` renders every slide the first time; after a fix,
|
|
362
|
+
`--preview-pages 3,7-8` renders only the changed ones. Iterate until clean.
|
|
363
|
+
**Look at each preview once:** after the first render read `sheet.png` (every slide
|
|
364
|
+
as a 640×360 tile, one image), then open a single `slide-NNN.png` only where the
|
|
365
|
+
sheet shows something to check, then only the pages you re-rendered. Never re-read an
|
|
366
|
+
image you already looked at — `deck-qa --final` (step 3) is the final check.
|
|
367
|
+
2. **Build and fix the build's findings.** Every `html2pptx … out.pptx` prints `valid`
|
|
368
|
+
(`false` exits 1 — never deliver) and `qa: {ok, findings}` — deck-qa's lint (codes in
|
|
369
|
+
bin-reference.md). Fix every finding first; they are objective and free.
|
|
370
|
+
No separate `doc-validate` / `deck-qa` call is needed after a build.
|
|
371
|
+
3. **Sign off once: `deck-qa.cjs deck.pptx --final`** — strict XSD validation (failure
|
|
372
|
+
exits 1), the lint, a cached Office render and its `render-overflow` /
|
|
373
|
+
`render-collision` check. It returns `review` (slides with a finding or a native
|
|
374
|
+
chart, which only Office draws) and `previews` (≈72dpi images of those).
|
|
375
|
+
**Read only `previews`.** For hybrid PPTX QA, other slides already passed the HTML
|
|
376
|
+
preview; their visuals come from that render. PDF delivery needs the final check below.
|
|
635
377
|
- **Read every slide instead** (`pdf-render.cjs <deck>.office.pdf all 1`) when
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
tokens each; a 1280×720 slide ≈ 1.2k). Preview and `--final` images are ≈72dpi,
|
|
664
|
-
¼ of the default render; `pdf-render … 2` only when fine print must be legible.
|
|
665
|
-
|
|
666
|
-
**Do not declare done before at least one complete build→sign-off→critic cycle.**
|
|
378
|
+
html2pptx reported a `layout (fallback)` engine, or you changed the PPTX after
|
|
379
|
+
building it (`doc-xml`, `pptx-slide`, a script).
|
|
380
|
+
- `office.unavailable`: PPTX has no Office layout check; disclose this. A running
|
|
381
|
+
LibreOffice that fails exits 1; rerun `--final`. `--require-office` fails both.
|
|
382
|
+
4. **Vision critic — you, not a sub-agent.** Judge the HTML previews (step 1) and the
|
|
383
|
+
`previews` of step 3; PDF delivery also requires the check below. LOOK at every image you critique.
|
|
384
|
+
Never dispatch the visual review to sub-agents: they may not see images at all, and
|
|
385
|
+
one deck lost 10 minutes to critics reading placeholders. Judge what a machine can't: balance and whitespace, hierarchy and
|
|
386
|
+
focal point, a real anchor, palette/motif consistency, image quality, crowding and
|
|
387
|
+
uneven gaps, misaligned sibling columns, decorative lines sized for one-line text when
|
|
388
|
+
the title wrapped, leftovers the lint can't phrase-match (`{{tokens}}`, "undefined",
|
|
389
|
+
"xxx"). Each critic returns `{slide, verdict: pass|fail, defects:[…]}`.
|
|
390
|
+
5. **Regenerate only the failing slides** (re-author that `<section>`, or
|
|
391
|
+
`pptx-slide` / `pptx-clone` for template-driven slides), preview them, rebuild, run
|
|
392
|
+
`--final` again. Stop when a pass finds nothing new **or** after 2 rounds; deliver
|
|
393
|
+
with an explicit note of what remains.
|
|
394
|
+
|
|
395
|
+
Images are the most token-expensive step (≈ w×h∕750 tokens; a 1280×720 slide ≈ 1.2k):
|
|
396
|
+
previews and `--final` images are ≈72dpi; `pdf-render … 2` only when fine print must be
|
|
397
|
+
legible. **Do not declare done before one complete build → sign-off → critic cycle.**
|
|
398
|
+
|
|
399
|
+
**PDF delivery:** convert the exact final PPTX with `doc-convert.cjs deck.pptx out.pdf`,
|
|
400
|
+
or reuse its final QA Office PDF if the PPTX is unchanged. Inspect every delivered PDF
|
|
401
|
+
page once. If Office is unavailable or fails, do not deliver a substitute PDF.
|
|
402
|
+
Use matching fonts in the Office environment; font substitution and different viewers
|
|
403
|
+
can change wrapping. Fix visible differences in the source or font environment and
|
|
404
|
+
re-export. HTML previews guide authoring; they are not the final PDF.
|
|
667
405
|
|
|
668
406
|
## CJK notes
|
|
669
407
|
|
|
670
|
-
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
~10%
|
|
408
|
+
- html2pptx drops the typeface from CJK runs on purpose (any pinned family can render
|
|
409
|
+
blank somewhere), so a CJK title cannot be forced into a serif face natively — bake it
|
|
410
|
+
if the face matters. The runs are tagged zh-CN / zh-TW / ja-JP / ko-KR and a Chinese deck's
|
|
411
|
+
theme names Microsoft YaHei (Traditional: JhengHei) as its East Asian font, so bold Chinese
|
|
412
|
+
gets a real bold. Traditional is read from the text; `<html lang="zh-Hant">` (or zh-TW/HK) decides a deck whose text shows neither script.
|
|
413
|
+
- Text boxes are widened automatically on conversion because PowerPoint lays text out
|
|
414
|
+
wider than Chromium: single-line boxes by ~22% (CJK) / ~16% (Latin), multi-line by
|
|
415
|
+
~10% / ~6%. Don't hand-pad labels; do leave slack in multi-line boxes.
|
|
416
|
+
- Slot capacity is measured (`layouts/capacity.json`) and enforced by deck-plan /
|
|
417
|
+
deck-build — trust their numbers over a character estimate.
|