@taloswork/ose-shared 0.1.12 → 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.
Files changed (66) hide show
  1. package/package.json +3 -3
  2. package/skills/document/SKILL.md +33 -45
  3. package/skills/document/bin/deck-build.cjs +10482 -272
  4. package/skills/document/bin/deck-chart.cjs +21 -12
  5. package/skills/document/bin/deck-plan.cjs +11654 -42
  6. package/skills/document/bin/deck-qa.cjs +95 -21
  7. package/skills/document/bin/deck-scenario.cjs +20 -3
  8. package/skills/document/bin/deck-styles.cjs +1604 -0
  9. package/skills/document/bin/doc-convert.cjs +182 -257
  10. package/skills/document/bin/doc-fill.cjs +140 -19
  11. package/skills/document/bin/doc-gen.cjs +1903 -281
  12. package/skills/document/bin/doc-validate.cjs +127 -52
  13. package/skills/document/bin/docx-defaults.cjs +9907 -0
  14. package/skills/document/bin/html2pptx.cjs +35949 -31972
  15. package/skills/document/bin/pdf-form.cjs +8 -0
  16. package/skills/document/bin/pdf-ops.cjs +8 -0
  17. package/skills/document/bin/pptx-notes.cjs +10038 -0
  18. package/skills/document/bin/pptx-tokenize.cjs +19 -4
  19. package/skills/document/bin/template-skin.cjs +10910 -0
  20. package/skills/document/bin-reference.md +15 -10
  21. package/skills/document/catalog.json +33 -32
  22. package/skills/document/content-pipeline.md +79 -44
  23. package/skills/document/deck-design.md +55 -32
  24. package/skills/document/generated-visuals.md +99 -0
  25. package/skills/document/layouts/MAINTAINERS.md +33 -0
  26. package/skills/document/layouts/README.md +20 -20
  27. package/skills/document/layouts/big-stat.tpl +1 -1
  28. package/skills/document/layouts/capacity.json +1 -1
  29. package/skills/document/layouts/cards-3.tpl +1 -1
  30. package/skills/document/layouts/chart-full.tpl +1 -1
  31. package/skills/document/layouts/chart-kpi.tpl +1 -1
  32. package/skills/document/layouts/comparison.tpl +1 -1
  33. package/skills/document/layouts/data-table.tpl +1 -1
  34. package/skills/document/layouts/funnel.tpl +1 -1
  35. package/skills/document/layouts/gantt.tpl +1 -1
  36. package/skills/document/layouts/hub-flow.tpl +4 -0
  37. package/skills/document/layouts/icon-row.tpl +1 -1
  38. package/skills/document/layouts/image-grid.tpl +1 -1
  39. package/skills/document/layouts/matrix-2x2.tpl +1 -1
  40. package/skills/document/layouts/mock-qa.tpl +4 -0
  41. package/skills/document/layouts/profiles.json +2 -2
  42. package/skills/document/layouts/pyramid.tpl +1 -1
  43. package/skills/document/layouts/radar.tpl +1 -1
  44. package/skills/document/layouts/ring-progress.tpl +1 -1
  45. package/skills/document/layouts/slots.json +1 -1
  46. package/skills/document/layouts/steps-vertical.tpl +1 -1
  47. package/skills/document/layouts/steps.tpl +1 -1
  48. package/skills/document/layouts/three-kpi.tpl +1 -1
  49. package/skills/document/layouts/timeline.tpl +1 -1
  50. package/skills/document/layouts/toc-panel.tpl +1 -1
  51. package/skills/document/layouts/two-kpi.tpl +2 -2
  52. package/skills/document/layouts/versus.tpl +1 -1
  53. package/skills/document/packs/README.md +1 -1
  54. package/skills/document/pdf.md +13 -0
  55. package/skills/document/rewrite.md +23 -8
  56. package/skills/document/scenarios.json +19 -2
  57. package/skills/document/scenarios.schema.json +1 -0
  58. package/skills/document/styles/_backdrops/rimlight.html +3 -2
  59. package/skills/document/styles/_contract-defaults.css +6 -1
  60. package/skills/document/styles/_samples/_groups/biz-premium.webp +0 -0
  61. package/skills/document/styles/_samples/mckinsey.webp +0 -0
  62. package/skills/document/styles/mckinsey/backdrop.html +7 -5
  63. package/skills/grill-me/SKILL.md +6 -0
  64. package/skills/grill-me/agents/openai.yaml +5 -0
  65. package/skills/grilling/SKILL.md +28 -0
  66. package/skills/grilling/agents/openai.yaml +3 -0
@@ -16,7 +16,8 @@ content and outline → `content-pipeline.md`.
16
16
 
17
17
  ## Workflow
18
18
 
19
- 1. **Plan, then fill.** Write the approved outline as a plan and run
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
20
21
  ```
21
22
  node <skill>/bin/deck-plan.cjs plan.json spec.json # → per slide: pick · alternatives · rejected[{layout, why}]
22
23
  node <skill>/bin/deck-build.cjs spec.json deck.html
@@ -29,9 +30,15 @@ content and outline → `content-pipeline.md`.
29
30
  4", "card2_body is ~58 wide but holds ≤42 — cut ~16"), or pin `layout` + `slots`, and
30
31
  re-plan; do NOT render to find out. Edit `spec.json` freely afterwards — `deck-build`
31
32
  re-checks capacity on every build, and its warnings (unfilled slot → demo copy) are
32
- defects. Put the confirmed `scenario` in the plan (it decides motion, below).
33
- 2. **Bespoke slides, only where no layout fits** (below): hand-author that `<section>`
34
- and insert it into `deck.html` at its position.
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`.
35
42
  3. **Preview, build, sign off** — "Verify before delivering" below.
36
43
 
37
44
  Hand-pasting a `layouts/<id>.tpl` skips the capacity check; a layout with a `{{#rows}}`
@@ -70,10 +77,11 @@ Violations fail loudly; nothing degrades silently.
70
77
  - **Tailwind utilities** are vendored offline (`grid grid-cols-2 gap-16`, `p-16`,
71
78
  `rounded-3xl`…) and map to native pptx — use them for layout/spacing, tokens for
72
79
  colour. Type scale: `size="1".."7"` → 12/14/16/24/32/48/72px.
73
- - **Images**: write `src="./hero.png"` (relative to deck.html) or an https URL —
74
- html2pptx inlines each as a `data:` URI before render (the render sandbox has no
75
- network); an image it cannot fetch or read is dropped. Generate figures with the
76
- media-generation tool into local files.
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.
77
85
  - **Icons = inline `<svg>` only** (lucide/heroicons path data, or a
78
86
  `data:image/svg+xml` URI at worst). An icon `<img>` that fails to load bakes a
79
87
  broken-image glyph into the backdrop.
@@ -99,8 +107,8 @@ Violations fail loudly; nothing degrades silently.
99
107
 
100
108
  The catalog is a palette, not a cage: a structure no layout expresses (a specific
101
109
  architecture diagram, a custom flow/topology, a signature hero moment) earns a
102
- hand-authored slide. Only then — a deck that hand-authors every slide is the #1
103
- "AI-generated" tell. A bespoke slide must:
110
+ hand-authored slide. Approved generated-visual pages also use this route; other pages
111
+ stay catalog. A bespoke slide must:
104
112
 
105
113
  - be one `<section class="slide" style="position:relative;width:1280px;height:720px">`,
106
114
  positioned with `absolute`, text native, diagram parts inline `<svg>`;
@@ -243,8 +251,9 @@ that genuinely continue each other. An unknown name degrades to `fade`.
243
251
  Every `font-size` and gutter in `layouts/*.tpl` is `calc(Npx * var(--type-scale,1))` /
244
252
  `calc(Npx * var(--space-scale,1))`; a skin sets the two scales in `:root` and the whole
245
253
  deck retimes with its hierarchy intact (from `mckinsey` 0.86 to `apple` 1.22; both
246
- default 1). A bespoke slide writes its sizes the same way. **Changed a scale? Re-run
247
- `deck-qa`** — scaling reflows text and can push it off-canvas; never eyeball it.
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.)
248
257
 
249
258
  ## Fonts — bundled faces reach the render, not the native text layer
250
259
 
@@ -279,7 +288,7 @@ The catalog layouts bake most of this in; on a bespoke slide it is yours.
279
288
  by weight or family. Catalog layouts already set the ladder — don't override their
280
289
  sizes. Bespoke: title `size 6–7` (48–72px), section headings `size 5–6`, body 14–24px,
281
290
  labels ≥13px; `qa` flags anything under 10pt as `tiny-font`. Never shrink type to fit
282
- — split or cut instead (≤6 bullets of ≤6 words; past that, cards or a graphic).
291
+ — split or cut instead (≤6 items, each ≤2 lines; past that, cards or a graphic).
283
292
  - **Alignment.** Snap to a grid; one alignment per zone; never centre running body
284
293
  text. Siblings share radius, border and accent placement (use the skin's classes);
285
294
  filled boxes keep ≥0.15" inner padding, siblings ≥0.25" apart.
@@ -304,11 +313,21 @@ neon/corner-frame→tech). Exception: meaning-bearing ramps (`neural-net` layers
304
313
  When the user picks 其他/自定义 or 使用我的模板文件 in the style picker, clarify the route —
305
314
  **prefer B**:
306
315
 
307
- - **B — derive a bespoke look (PREFERRED).** From an **existing deck**: keep its EXACT
308
- layouts/master/brand as a fillable template (`pptx-tokenize` → `doc-fill`, rewrite.md
309
- "Reuse an uploaded deck"), OR take just its palette into a new skin. From a
310
- **reference image / brand color**: sample the palette into a new skin. *(A deck given
311
- here is for its STYLE — distinct from a deck given as content, which is text-only.)*
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.
312
331
  - **A — map to the nearest catalog family** (they only described a vibe): pick the
313
332
  closest, render its sample, confirm.
314
333
  - **C — tweak an existing skin** ("刚才那个族但换绿色"): clone it, swap accent/palette or
@@ -341,8 +360,9 @@ Do not launch LibreOffice after every edit.
341
360
  1. **Author against the HTML preview.** `html2pptx.cjs deck.html --preview-dir <dir>
342
361
  --style <id> …` renders every slide the first time; after a fix,
343
362
  `--preview-pages 3,7-8` renders only the changed ones. Iterate until clean.
344
- **Look at each preview once:** every slide after the first render (a contact sheet
345
- of several slides is fine), then only the pages you re-rendered. Never re-read an
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
346
366
  image you already looked at — `deck-qa --final` (step 3) is the final check.
347
367
  2. **Build and fix the build's findings.** Every `html2pptx … out.pptx` prints `valid`
348
368
  (`false` exits 1 — never deliver) and `qa: {ok, findings}` — deck-qa's lint (codes in
@@ -352,21 +372,17 @@ Do not launch LibreOffice after every edit.
352
372
  exits 1), the lint, a cached Office render and its `render-overflow` /
353
373
  `render-collision` check. It returns `review` (slides with a finding or a native
354
374
  chart, which only Office draws) and `previews` (≈72dpi images of those).
355
- **Read only `previews`.** Every other slide already passed your eyes in the HTML
356
- preview, and its hybrid visuals were baked from that same render. Office re-wrapping
357
- at a different word, spacing CJK and Latin apart or substituting a Latin face is
358
- normal, not a defect.
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.
359
377
  - **Read every slide instead** (`pdf-render.cjs <deck>.office.pdf all 1`) when
360
378
  html2pptx reported a `layout (fallback)` engine, or you changed the PPTX after
361
379
  building it (`doc-xml`, `pptx-slide`, a script).
362
- - `office.unavailable` (no LibreOffice here): no Office layout to check — the HTML
363
- preview stands; say so when delivering. A LibreOffice that ran and FAILED exits 1
364
- (never a Chromium stand-in): rerun `--final`. `--require-office` fails both.
365
- 4. **Vision critic.** Judge the HTML previews (step 1) and the `previews` of step 3 —
366
- never a second full pass. LOOK at every image you critique. Either you critique a
367
- slide or a sub-agent does, not both: with sub-agents, hand slides to fresh-eyes
368
- critics in parallel with each slide's findings (so they are not re-reported) and read
369
- their verdicts. Judge what a machine can't: balance and whitespace, hierarchy and
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
370
386
  focal point, a real anchor, palette/motif consistency, image quality, crowding and
371
387
  uneven gaps, misaligned sibling columns, decorative lines sized for one-line text when
372
388
  the title wrapped, leftovers the lint can't phrase-match (`{{tokens}}`, "undefined",
@@ -380,6 +396,13 @@ Images are the most token-expensive step (≈ w×h∕750 tokens; a 1280×720 sli
380
396
  previews and `--final` images are ≈72dpi; `pdf-render … 2` only when fine print must be
381
397
  legible. **Do not declare done before one complete build → sign-off → critic cycle.**
382
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.
405
+
383
406
  ## CJK notes
384
407
 
385
408
  - html2pptx drops the typeface from CJK runs on purpose (any pinned family can render
@@ -0,0 +1,99 @@
1
+ # Generated visuals inside a deck
2
+
3
+ Assess whether generated scenes, product concepts or illustrations will help the
4
+ deck explain its message. The user need not explicitly request image generation.
5
+ Choose about 2–3 useful visual pages, not a quota; use fewer or none for a short or
6
+ data-heavy deck, and respect a request to avoid generated images.
7
+
8
+ The agent calls the actual available `gen` tools; `deck-plan` and `deck-build` only
9
+ assemble existing assets, so rebuilding a deck never regenerates images. The gen
10
+ connector is enabled by default. Call its discovered MCP tool directly using the
11
+ exposed schema for model parameters and references; do not invent tool names or
12
+ duplicate provider-specific rules. Respect a manually disabled connector. If no
13
+ generation tool is available, report that limitation rather than enabling a connector
14
+ or promising an image.
15
+
16
+ ## Plan before generating
17
+
18
+ Include selected visual pages in the confirmed slide count. In `plan.json`, give each
19
+ its conclusion, visual purpose, mode, notes and a `file` path. The outline
20
+ can reference a file that does not exist yet; `deck-build` needs it after generation.
21
+ Use the existing outline/style confirmation before generation, with no separate image authorization.
22
+ Supporting visuals that preserve an approved outline's message and slide count need no
23
+ new approval, even when chosen later during production.
24
+
25
+ Default to **generated image + HTML text**: scene, product concept or illustration in
26
+ the image; title, conclusion, accurate figures and sources in the HTML. Native text
27
+ remains editable unless the selected skin bakes that class (`--talos-bake:1`).
28
+ **Whole-page image** is an option for a poster or visual story; its internal text and
29
+ objects cannot be edited separately. Keep evidence-based charts in the chart tools;
30
+ describe a generated concept as a concept, not a photo of a real event or a source.
31
+
32
+ Example slide entry among the ordinary slides in `plan.json`:
33
+
34
+ ```json
35
+ {
36
+ "role": "content",
37
+ "title": "One workspace brings the team together",
38
+ "image": true,
39
+ "file": "visuals/workspace.html",
40
+ "narrative": "Generated visual: a shared workspace concept, image plus HTML text; make the proposed experience concrete.",
41
+ "notes": "Concept illustration. Explain how shared context reduces handoffs."
42
+ }
43
+ ```
44
+
45
+ Keep plan and spec in the same directory: `file` is resolved relative to the spec.
46
+ Planning keeps the slide's position and notes; write its visible text in the HTML,
47
+ since file slides do not fill catalog slots. Do not put `<img>` into ordinary `slots`
48
+ (they escape HTML), and `image: true` alone does not supply an asset.
49
+
50
+ ## Generate for the actual image box
51
+
52
+ Once approved, prepare each prompt for the intended box: message, subject/action,
53
+ selected palette and photographic/illustration style, subject placement, crop
54
+ tolerance and text space. Set size and aspect ratio in the tool fields for the actual
55
+ image box. Keep titles and exact numbers outside the image by default. For related scenes, carry the same product/person references and visual
56
+ direction through the supported `gen` reference mechanism.
57
+
58
+ Keep a small working record of slide number, prompt file, references and returned
59
+ image path. Use the **exact absolute path returned by `gen`** in the HTML; do not
60
+ rename or move the image. The assembled deck may be in a different directory from
61
+ the per-slide file. Escape HTML attribute characters in the path (`&`, `"`, `<`).
62
+ Inspect each generated result before assembling. Reuse it for text/layout revisions;
63
+ regenerate only when the image needs to change.
64
+
65
+ If gen is unavailable, or a login or network failure prevents generation, report the
66
+ actual error and affected pages. Do not claim a placeholder was generated. If a
67
+ non-generated layout is a suitable fallback, disclose the change and revise the plan
68
+ and slide together; never silently substitute an image already committed in the outline.
69
+ Keep required-image checks on every generated image that remains in the deck.
70
+
71
+ ## Assemble through the existing file route
72
+
73
+ Write exactly one `section.slide` per file. Example split page (replace the example
74
+ image path with the real tool result and match the selected skin's type/spacing):
75
+
76
+ ```html
77
+ <section class="slide" style="position:relative;width:1280px;height:720px">
78
+ <h2 class="deck-title" style="position:absolute;left:64px;top:80px;width:1152px;margin:0;color:var(--title);font-size:calc(48px * var(--type-scale,1))">One workspace brings the team together</h2>
79
+ <p style="position:absolute;left:64px;top:250px;width:420px;color:var(--body);font-size:calc(28px * var(--type-scale,1))">Shared context makes the next step visible.</p>
80
+ <img data-required-image src="/absolute/path/returned-by-gen.png" alt="Concept illustration of a shared team workspace" style="position:absolute;left:552px;top:210px;width:656px;height:420px;object-fit:cover">
81
+ </section>
82
+ ```
83
+
84
+ `data-required-image` is a presence marker: even `="false"` means required. Use it on
85
+ every generated content image. Local read, fetch or browser decode failure blocks
86
+ previews and PPTX export. Repair the path or asset; never silently replace
87
+ a required image with a placeholder, drop the page, or remove the marker to deliver.
88
+
89
+ An uploaded template keeps its title bar, logo and footer: use `h2.deck-title` and
90
+ keep content at top ≥210px in its content zone. A whole-page image must also fit that
91
+ zone; only use full bleed when the selected style permits it. Preserve the deck's
92
+ export mode: a few generated images do not require global `--rasterize`.
93
+
94
+ Build with the usual `deck-build` → `html2pptx` commands and the same style flags.
95
+ Follow deck-design.md's preview and final QA once per image: verify page order and
96
+ notes, image presence, subject crop, image text, contrast, template chrome and style
97
+ consistency across the generated pages. Fix and recheck only changed pages.
98
+ Deliver a PDF by converting the final PPTX through `doc-convert`, including its embedded
99
+ images; do not separately print the slide HTML.
@@ -0,0 +1,33 @@
1
+ # Maintaining the layout library
2
+
3
+ Not read while making a deck — this is for whoever edits a `.tpl`, a skin's geometry or
4
+ the catalog.
5
+
6
+ - **Slot index.** Regenerate `layouts/slots.json` with `node scripts/deck/gen-slots.mjs`
7
+ after touching a `.tpl`.
8
+ - **Capacity is measured, not written down.** `layouts/capacity.json` holds, per layout ×
9
+ catalog style, how wide each slot's text may get (CJK = 1, Latin ≈ 0.5), how many rows
10
+ each `{{#rows}}` block holds, and each chart's box — measured in headless Chromium by
11
+ `node scripts/deck/gen-capacity.mjs` (≈5 min). Re-run it after touching a `.tpl`, a
12
+ skin's geometry (sizes, spacing, `--type-scale`) or the catalog;
13
+ `tests/unit/deck-capacity.test.ts` fails until you do (colour-only edits are ignored).
14
+ - **Optional lines** (2026-10-09): `subhead` (one line at `top:246px`, under a one-line
15
+ title) and `takeaway` (one line at `bottom:56px`, above the footer rule) are offered only
16
+ by layouts whose content clears them in every catalog style — measured: content top
17
+ ≥ 282px for `subhead`, content bottom ≤ 620px at the designed 3-row fill for
18
+ `takeaway`. Both render nothing when empty (`.deck-subhead:empty`,
19
+ `.deck-takeaway:empty` in `styles/_contract-defaults.css`).
20
+
21
+ **不要给可变内容写死容器高度**(`.tpl` 与 bespoke 页都适用)。皮肤给 `.card` 设了
22
+ `overflow:hidden` 时,`.card{height:…px}` 会把超出的文字**静默裁掉**(`blocks-2x2` 就这样
23
+ 带病出厂过)。让高度由内容决定:网格用 `grid-auto-rows:min-content`(必须显式写
24
+ `min-content`——`1fr`/`auto` 的自动下限对 `overflow` 非 visible 的网格项一律归零),余量
25
+ 交给外层 `justify-content:space-between`。这样超量内容会顶出页面,被 `deck-qa` 的
26
+ `off-canvas`/`overlap` 抓到。PPTX walker 不保留祖先的裁切,原来在 HTML 中被裁掉的字可能
27
+ 完整画到容器外;版式生产线的 `scripts/deck/deck-qa-sweep.mjs` 用 `clipped` 阻断裁切。
28
+
29
+ `spill` measures in-flow text outside its nearest painted container. It remains
30
+ advisory until the capacity probe uses the same measure; `decor-overlap` remains
31
+ blocking. Explicitly positioned or transformed elements are excluded because a
32
+ badge may intentionally cross its parent edge. Keep both clipped and visible
33
+ overflow fixtures when changing the measurement.
@@ -61,33 +61,31 @@ Plain list layouts take rows too: `team-row.members{name,role}` ·
61
61
  `brand-values.values{name,body}` · `color-palette.swatches{name,hex}` ·
62
62
  `steps-vertical.steps{name,body}` · `toc-panel.entries{name,desc}`.
63
63
 
64
+ **Optional lines** — a slide's `subtitle` (口径 / why it matters) and `takeaway` (启示) fill
65
+ `subhead` (under a one-line title) and `takeaway` (above the footer), offered by
66
+ cards-3 · three-kpi · two-kpi · steps · steps-vertical · timeline · icon-row ·
67
+ ring-progress · versus · data-table · image-grid · gantt (both) and funnel · pyramid ·
68
+ matrix-2x2 (subtitle) · comparison (takeaway). Left out, they render nothing; written for
69
+ a layout without the line, `deck-plan` warns `dropped` and ranks a layout that has it.
70
+
64
71
  Anything the spec gets wrong — unknown layout/slot/field, a repeat block with no rows, a
65
72
  figure row missing its numbers — **fails the build** (exit 1, nothing written) rather than
66
- shipping the template's demo content. Regenerate the index with `node scripts/deck/gen-slots.mjs`
67
- after touching a `.tpl`.
68
-
69
- **Capacity is measured, not written down.** `layouts/capacity.json` holds, per layout ×
70
- catalog style, how wide each slot's text may get (CJK = 1, Latin ≈ 0.5), how many rows
71
- each `{{#rows}}` block holds, and each chart's box — measured in headless Chromium by
72
- `node scripts/deck/gen-capacity.mjs` (≈5 min). `deck-plan` picks layouts with it and
73
- `deck-build` rejects overflow / un-filled numbered slots with it. Re-run the generator
74
- after touching a `.tpl`, a skin's geometry (sizes, spacing, `--type-scale`) or the
75
- catalog; `tests/unit/deck-capacity.test.ts` fails until you do (colour-only edits are
76
- ignored). The density column below feeds `deck-plan` too: a rows layout is not offered
77
- for fewer items than its `(n–m)` names.
78
-
79
- **不要给可变内容写死容器高度**(`.tpl` 与 bespoke 页都适用)。皮肤给 `.card` 设了
80
- `overflow:hidden` 时,`.card{height:…px}` 会把超出的文字**静默裁掉**(`blocks-2x2` 就这样
81
- 带病出厂过)。让高度由内容决定:网格用 `grid-auto-rows:min-content`(必须显式写
82
- `min-content`——`1fr`/`auto` 的自动下限对 `overflow` 非 visible 的网格项一律归零),余量
83
- 交给外层 `justify-content:space-between`。这样超量内容会顶出页面,被 `deck-qa` 的
84
- `off-canvas`/`overlap` 抓到。被祖先 `overflow:hidden` 裁掉的字不进 pptx 几何,运行时
85
- `deck-qa` 看不到,只有版式生产线的 `scripts/deck/deck-qa-sweep.mjs`(`clipped` 硬失败)拦得住。
73
+ shipping the template's demo content. **Capacity is measured** (`layouts/capacity.json`,
74
+ per layout × style: slot widths, row ceilings, chart boxes): `deck-plan` picks with it,
75
+ `deck-build` rejects overflow with it. The density column below feeds `deck-plan` too: a
76
+ rows layout is not offered for fewer items than its `(n–m)` names. A bespoke slide never
77
+ fixes a card's height around variable text (`overflow:hidden` clips it silently) — use
78
+ `grid-auto-rows:min-content`. Maintaining layouts: `layouts/MAINTAINERS.md`.
79
+
80
+ QA: `clipped` and `decor-overlap` block; `spill` is advisory. The PPTX walker does
81
+ not reproduce ancestor clipping, so inspect the exported deck too.
86
82
 
87
83
  ## Catalog
88
84
 
89
85
  Each slide carries `data-layout="<id>"` (drives the diversity lint + traceability).
90
86
 
87
+ **Theme V2 only:** `pitch-problem` · `pitch-solution` · `market-rings` · `product-device` · `traction-milestones` · `business-model` · `pricing-tiers` · `funding-ask` · `customer-proof` · `team-founders` (profiles.json `themeV2Layouts`). A style in the `classic-v1` collection (cool, mckinsey, apple …) renders V1 and cannot use them — `deck-plan --layouts --style <id>` lists exactly what a style can use and the content each layout takes.
88
+
91
89
  | layout-id | role | structure (P1) | density (P2) | has-image (P1) | pick when |
92
90
  |---|---|---|---|---|---|
93
91
  | `cover` | cover | hero · left-title | — | text-only (bg) | 封面 / 开场 |
@@ -120,6 +118,8 @@ Each slide carries `data-layout="<id>"` (drives the diversity lint + traceabilit
120
118
  | `image-left` | content | image-left + text-right | medium (3) | **photo/diagram slot** | 图文案例(图在左) |
121
119
  | `image-grid` | content | 3-up image gallery + captions | medium (3) | **photo slots** | 三图并列 / 图库 |
122
120
  | `concept-hub` | content | center concept + satellites | medium (4) | text-only | 核心框架(中心+维度) |
121
+ | `hub-flow` | content | 3 inputs → core → result | medium (3) | text-only | 多源汇聚→核心→产出(产品原理/数据流) |
122
+ | `mock-qa` | content · product | interface sketch: question → cited answer + 2 sources | light (2) | text-only | 产品问答/证据链示意(无截图时) |
123
123
  | `image-full` | content | full-bleed image + overlay caption | light | **full-bleed photo** | 全出血大图 + 压字说明 |
124
124
  | `cover-image` | cover | full-bleed image + overlay title | — | **full-bleed photo** | 图片封面(压字) |
125
125
  | `timeline` | content | horizontal dated timeline | medium (4–5) | text-only | 时间轴 / 发展历程 |
@@ -1,4 +1,4 @@
1
1
  <!-- layouts/big-stat — structure-only (paint via styles/<skin>/skin.css). data-layout drives P1/P2/P3 + dedup. -->
2
2
  <section class="slide" data-layout="big-stat" style="position:relative;width:1280px;height:720px;overflow:hidden"><div class="slide-backdrop"></div><div class="eyebrow-row" style="position:absolute;left:calc(96px * var(--space-scale,1));top:132px;display:flex;align-items:center;gap:14px"><span class="accent-bar" style="width:30px;height:1px;display:inline-block"></span><span class="eyebrow" style="font-size:calc(13px * var(--type-scale,1));letter-spacing:.28em">{{eyebrow|KEY METRIC}}</span></div><h2 class="deck-title" style="position:absolute;left:calc(92px * var(--space-scale,1));top:158px;font-size:calc(48px * var(--type-scale,1));letter-spacing:-.4px">{{title|}}</h2>
3
- <div class="stat-num" style="position:absolute;left:90px;top:250px;font-weight:800;line-height:1;font-size:calc(216px * var(--type-scale,1));letter-spacing:-2px">{{stat|585}}<span class="stat-unit" style="font-size:calc(64px * var(--type-scale,1))">{{unit| 单位}}</span></div><div class="stat-lead" style="position:absolute;left:100px;top:520px;font-size:calc(30px * var(--type-scale,1));font-weight:600">{{lead|一句结论,数字说明了什么}}</div><p class="stat-note" style="position:absolute;left:100px;top:580px;width:900px;font-size:calc(17px * var(--type-scale,1));line-height:1.6">{{note|一句支撑说明,给上下文与来源。}}</p>
3
+ <div class="stat-num" style="position:absolute;left:calc(90px * var(--space-scale,1));top:250px;font-weight:800;line-height:1;font-size:calc(216px * var(--type-scale,1));letter-spacing:-2px">{{stat|585}}<span class="stat-unit" style="font-size:calc(64px * var(--type-scale,1))">{{unit| 单位}}</span></div><div class="stat-lead" style="position:absolute;left:calc(100px * var(--space-scale,1));top:520px;font-size:calc(30px * var(--type-scale,1));font-weight:600">{{lead|一句结论,数字说明了什么}}</div><p class="stat-note" style="position:absolute;left:calc(100px * var(--space-scale,1));top:580px;width:900px;font-size:calc(17px * var(--type-scale,1));line-height:1.6">{{note|一句支撑说明,给上下文与来源。}}</p>
4
4
  <div class="rule rule-foot" style="position:absolute;left:calc(96px * var(--space-scale,1));right:calc(96px * var(--space-scale,1));bottom:40px;height:1px"></div><div class="deck-footer" style="position:absolute;left:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1));letter-spacing:.1em">{{footer|报告标题 / 章节}}</div><div class="deck-pageno" style="position:absolute;right:calc(96px * var(--space-scale,1));bottom:17px;font-size:calc(12px * var(--type-scale,1))">{{pageno|01}}</div></section>