@liustack/pptwise 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +127 -0
- package/README.zh-CN.md +136 -0
- package/cordis.patch.yml +5 -0
- package/dist/chunk-3ZUKISTY.js +114 -0
- package/dist/chunk-3ZUKISTY.js.map +1 -0
- package/dist/chunk-M35M4QUC.js +1167 -0
- package/dist/chunk-M35M4QUC.js.map +1 -0
- package/dist/chunk-VUOLBHD7.js +19 -0
- package/dist/chunk-VUOLBHD7.js.map +1 -0
- package/dist/chunk-WL5KWYKS.js +49762 -0
- package/dist/chunk-WL5KWYKS.js.map +1 -0
- package/dist/cli.js +4753 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4224 -0
- package/dist/index.js +99 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +7 -0
- package/dist/node.js +11 -0
- package/dist/node.js.map +1 -0
- package/dist/pixel-audit-H5K6JK3X.js +218 -0
- package/dist/pixel-audit-H5K6JK3X.js.map +1 -0
- package/dist/registry-C0GJH7ZT.d.ts +46 -0
- package/dsh/client.js +1398 -0
- package/dsh/index.js +141 -0
- package/dsh/preview-tool.js +1931 -0
- package/dsh/spawnHidden.js +109 -0
- package/package.json +113 -0
- package/skills/pptwise/SKILL.md +100 -0
- package/skills/pptwise/SKILL.zh-CN.md +102 -0
- package/skills/pptwise/references/branding.md +18 -0
- package/skills/pptwise/references/branding.zh-CN.md +21 -0
- package/skills/pptwise/references/components.md +35 -0
- package/skills/pptwise/references/components.zh-CN.md +40 -0
- package/skills/pptwise/references/density.md +17 -0
- package/skills/pptwise/references/density.zh-CN.md +22 -0
- package/skills/pptwise/references/images.md +42 -0
- package/skills/pptwise/references/images.zh-CN.md +47 -0
- package/skills/pptwise/references/layouts.md +37 -0
- package/skills/pptwise/references/layouts.zh-CN.md +42 -0
- package/skills/pptwise/references/spec.md +107 -0
- package/skills/pptwise/references/spec.zh-CN.md +112 -0
- package/skills/pptwise/references/validate.md +82 -0
- package/skills/pptwise/references/validate.zh-CN.md +87 -0
- package/skills/pptwise/scripts/run.ps1 +192 -0
- package/skills/pptwise/scripts/run.sh +229 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Images
|
|
2
|
+
|
|
3
|
+
Read this when declaring image assets, searching stock, or generating art.
|
|
4
|
+
|
|
5
|
+
### Image slides
|
|
6
|
+
|
|
7
|
+
Declare images once in `assets.images` and reference them by `asset_id` — double-check every `asset_id` spelling, a wrong key renders a silent placeholder instead of failing. An explicit `layout` id always wins over pptwise's auto-selection, which otherwise picks from the theme's layout set for that page type (the full registry set by default, unless the theme curates it narrower) — for a slide built around an image, set `layout` to one of the image takeovers: `image-split` (half-page image + side text, `image_side: left|right`), `image-top` (full-bleed top image + text columns below), `image-bottom` (text above, image below), `image-annotate` (center image + radiating callouts taken from the first 4 bullets). **Every image layout needs an `image` component somewhere in `components`** — pptwise uses the first one it finds as the image source regardless of array position, and every other component becomes the layout's text body.
|
|
8
|
+
|
|
9
|
+
Before generating art for any `image` component whose `asset_id` still has no real file behind it, run `pptwise asset-brief <target>` — it renders the deck for real and reports each slot's actual frame (not the layout's nominal slot size), crop mode with a safe-zone note, suggested generation pixels, the theme's palette, and a paste-ready prompt. Matching the reported aspect ratio and palette is what makes a generated image look intentional once it's placed instead of stretched, cropped wrong, or off-tone.
|
|
10
|
+
|
|
11
|
+
### Stock photos
|
|
12
|
+
|
|
13
|
+
Run `pptwise asset-brief <target>` first so the frame, crop, and palette are known.
|
|
14
|
+
|
|
15
|
+
Query rules: short concrete nouns, English 2–4 words (`office desk`, `wind farm`). Chinese is a variant, not the only query. No mood or quality words (`beautiful`, `4k`, `cinematic`). No negative keywords (`not office`, `no people`).
|
|
16
|
+
|
|
17
|
+
Search order is Pexels, then Pixabay if a key is set, then Openverse (cc0/pdm, commercial filter).
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pptwise config set pexels.apiKey
|
|
21
|
+
pptwise images search "office desk" --orientation landscape
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Do not auto-pick the first result. A person or a vision model picks from the ~8 thumbs. Then download:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pptwise images fetch pexels:123 --deck <dir> --as hero
|
|
28
|
+
pptwise images list --deck <dir>
|
|
29
|
+
pptwise images generate --deck <dir> --as <asset_id>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Local generators stay off until enabled:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pptwise config set images.generators.grok.enabled true
|
|
36
|
+
pptwise config set images.generators.codex.enabled true
|
|
37
|
+
pptwise config set images.generators.antigravity.enabled true
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The file lands in `.pptwise/<deck>/assets/<asset_id>.jpg` with a sidecar next to it. Reference that `asset_id` from the page. Do not delete `.pptwise/` wholesale to "rerun". That drops pinned photos.
|
|
41
|
+
|
|
42
|
+
No key: leave the slot `missing` (grey frame). Do not invent a photo. Do not scrape. Do not use Unsplash. This is a local client fetching with the user's own key. Commercial use in a presentation is allowed. Do not resell the photo standalone. Print attribution in the terminal, not on the slide by default.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: 'skills/pptwise/references/images.md 的中文阅读镜像'
|
|
3
|
+
mirror_of: skills/pptwise/references/images.md
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 配图
|
|
7
|
+
|
|
8
|
+
何时读:声明资产、搜图库、或生图时。
|
|
9
|
+
|
|
10
|
+
### 图片页
|
|
11
|
+
|
|
12
|
+
在 `assets.images` 里统一声明图片,用 `asset_id` 引用——务必逐个核对 `asset_id` 拼写,写错 key 只会渲染出一个静默的占位符,不会报错。显式的 `layout` id 永远优先于 pptwise 的自动选型,否则自动选型会从该页型对应的 theme layout 集合里挑(默认是全部已注册版式,除非 theme 主动收窄)——对于以图片为核心的 slide,把 `layout` 设成某个 image takeover:`image-split`(半页图片 + 侧边文字,`image_side: left|right`)、`image-top`(顶部通版图片 + 下方文字分栏)、`image-bottom`(上方文字,下方图片)、`image-annotate`(居中图片 + 从前 4 条 bullets 取出的放射状标注)。**每个 image layout 都需要 `components` 里至少有一个 `image` component**——不论它在数组里的位置,pptwise 都会用找到的第一个作为图片来源,其余的 component 全部成为该 layout 的文字正文。
|
|
13
|
+
|
|
14
|
+
给任何 `asset_id` 还没有真实文件的 `image` component 生成美术之前,先跑一遍 `pptwise asset-brief <target>`——它会真的渲染一遍 deck,报告每个图片位实际的渲染框(不是版式的名义槽位尺寸)、带安全区说明的裁切模式、建议的生成像素、主题色板,以及一段可直接粘贴的提示词。宽高比和色调对上了,生成的图片摆上去才会显得是设计好的,而不是被拉伸、裁错或跑色。
|
|
15
|
+
|
|
16
|
+
### 图库配图
|
|
17
|
+
|
|
18
|
+
先跑 `pptwise asset-brief <target>`,拿到真实框、裁切和色板。
|
|
19
|
+
|
|
20
|
+
查询词:短而具体的名词,英文 2 到 4 个词(`office desk`、`wind farm`)。中文只作变体,不要当唯一查询。不要加情绪或画质词(`beautiful`、`4k`、`cinematic`)。不要写负向词(`not office`、`no people`)。
|
|
21
|
+
|
|
22
|
+
搜索顺序是 Pexels,有 key 再 Pixabay,然后 Openverse(cc0/pdm,commercial 过滤)。
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pptwise config set pexels.apiKey
|
|
26
|
+
pptwise images search "office desk" --orientation landscape
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
不要自动收第一条。人(或视觉模型)从大约 8 张缩略图里挑。然后下载:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pptwise images fetch pexels:123 --deck <dir> --as hero
|
|
33
|
+
pptwise images list --deck <dir>
|
|
34
|
+
pptwise images generate --deck <dir> --as <asset_id>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
本地生图默认关闭,要显式打开:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pptwise config set images.generators.grok.enabled true
|
|
41
|
+
pptwise config set images.generators.codex.enabled true
|
|
42
|
+
pptwise config set images.generators.antigravity.enabled true
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
文件落在 `.pptwise/<deck>/assets/<asset_id>.jpg`,旁边是 sidecar。页面用这个 `asset_id` 引用。不要为了「重跑」整目录删掉 `.pptwise/`,已钉的图会一起没。
|
|
46
|
+
|
|
47
|
+
没有 key:槽位保持 `missing`(灰框)。不要编一张图。不要刮网页。不要用 Unsplash。这是本机客户端,用用户自己的 key 去拉。幻灯里商用可以。不要把原图单独转卖。署名打在终端,默认不印在画面上。
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Layouts and pins
|
|
2
|
+
|
|
3
|
+
Read this when pinning a `layout`, including climax, quote, and evidence sparse pages.
|
|
4
|
+
|
|
5
|
+
### Pin-only layouts
|
|
6
|
+
|
|
7
|
+
These layouts never appear through auto-selection. Set `layout` explicitly every time you want one. `validate` hard-errors if a pin-only content layout carries more components than its declared capacity (an ordinary layout pinned over capacity only warns).
|
|
8
|
+
|
|
9
|
+
`quote-stage` is a thesis page on a content slide: one short, powerful heading is the entire visual, with at most one short attribution component (a source, a name, a one-line follow-up). Zero components is legitimate — a pure quote needs no attribution. This one still draws the theme's brand footer and motif.
|
|
10
|
+
|
|
11
|
+
`statement` is a whole-page verse or epigram on a content slide. At most one component, rendered as a small source line (quote / paragraph / citation), never as a card. Optional kicker from the preceding chapter. Brand footer and logo stay off. The theme motif still paints. The face is theme-specific (a boarded theme is not the generic italic 500 lines).
|
|
12
|
+
|
|
13
|
+
`pull-quote` is a quotation page on a content slide: heading, source line, optional muted paragraph. Source comes from a quote component's `attribution` when present, otherwise `subheading`. Brand footer and logo stay off. The theme motif still paints.
|
|
14
|
+
|
|
15
|
+
`verse-chapter` is a centered verse as a chapter open (`type: "chapter"`). Tracking chapter-index kicker, 2-line heading, optional italic subheading. No watermark numeral, no body, no footnote — the usual chapter boundary still applies. Logo stays off. The theme motif still paints.
|
|
16
|
+
|
|
17
|
+
`stat-hero` is a whole-page number on a content slide. The hero value comes from the first `kpi_cards` item when present, otherwise the heading. One caption line, optional source. At most one component. Brand footer and logo stay off. The theme motif still paints.
|
|
18
|
+
|
|
19
|
+
`one-evidence` is an assertion-plus-evidence page on a content slide. Heading is a full-sentence claim. At most one component, rendered as the evidence (a chart, table, or image). Brand footer and logo stay off. The theme motif still paints.
|
|
20
|
+
|
|
21
|
+
`mono-bleed` is a full-bleed brand-color field on a content slide, type as the picture. Capacity 0: write the words in the heading, no body component. Brand footer and logo stay off. The theme motif still paints.
|
|
22
|
+
|
|
23
|
+
### Sparse-page contract
|
|
24
|
+
|
|
25
|
+
A deck is for speaking. Extra words that will not fit on the slide go in `slide.notes`. If the file must stand alone as a document, recommend a PDF rather than packing the canvas.
|
|
26
|
+
|
|
27
|
+
This is not a new `pacing` value. The enum stays `dense` / `balanced` / `spacious`. The contract is pin-only layouts, `notes`, and deck `branding`.
|
|
28
|
+
|
|
29
|
+
Climax, quote, and evidence pages pin a sparse pin-only layout when the theme offers it. Name it: `statement`, `pull-quote`, `verse-chapter`, `stat-hero`, `one-evidence`, `mono-bleed`. Do not leave those pages to auto-selection. A page that truly is one sentence still gets this pin even when pacing is `dense`. crayon, classroom, enterprise, pulse, runway, and ember do not offer these layouts. If `validate` warns that the pin is not a sparse page this theme offers, drop the pin and write a regular content page.
|
|
30
|
+
|
|
31
|
+
When the interview or request chose `spacious`: tighten the on-slide budget. Heading is the visual. At most one body component on a pinned sparse page (a source line, a single number, a single chart or table). Zero bullets on those pages. Split instead of stacking.
|
|
32
|
+
|
|
33
|
+
When `balanced` or `dense`: write to the pacing budget. Still pin a sparse layout when a page is one sentence, one number, one quote, or one piece of evidence.
|
|
34
|
+
|
|
35
|
+
The spoken script goes in `slide.notes`. `render` exports it as native PowerPoint speaker notes (View → Notes, Presenter View). Never draw the script onto the canvas.
|
|
36
|
+
|
|
37
|
+
Branding omit/full lives in `references/branding.md`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: 'skills/pptwise/references/layouts.md 的中文阅读镜像'
|
|
3
|
+
mirror_of: skills/pptwise/references/layouts.md
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 版式与写死
|
|
7
|
+
|
|
8
|
+
何时读:钉 `layout`,包括高潮页、金句页、证据页稀排版式时。
|
|
9
|
+
|
|
10
|
+
### Pin-only 版式
|
|
11
|
+
|
|
12
|
+
这些版式从不出现在自动选型里。每次要用都得显式设置 `layout`。pin-only 的 content 版式超出声明容量时 `validate` 会硬报错(普通版式钉住超容量只给警告)。
|
|
13
|
+
|
|
14
|
+
`quote-stage` 是 content 页上的论断页:一句短而有力的标题是整页主视觉,最多再配一个短附注 component(出处、署名、一句补充)。0 个 component 合法。这一页仍会画主题的品牌页脚和 motif。
|
|
15
|
+
|
|
16
|
+
`statement` 是 content 页上的整页诗行或金句。最多一个 component,渲成出处小字(quote / paragraph / citation),不走卡片。可选 kicker 来自上一章。品牌页脚和 logo 不画。主题 motif 仍画。脸是主题专属的(已定稿的主题不是通用斜体 500 行)。
|
|
17
|
+
|
|
18
|
+
`pull-quote` 是 content 页上的引言页:标题、出处小字、可选 muted 散文。出处优先 quote 的 `attribution`,否则 `subheading`。品牌页脚和 logo 不画。主题 motif 仍画。
|
|
19
|
+
|
|
20
|
+
`verse-chapter` 是居中诗行章首(`type: "chapter"`)。tracking 章号眉、两行标题、可选斜体副题。没有水印大数字,没有 body,没有 footnote,chapter 页的既有边界照旧。logo 不画。主题 motif 仍画。
|
|
21
|
+
|
|
22
|
+
`stat-hero` 是 content 页上的整页数字。英雄位数字优先取自 `kpi_cards` 第一项,否则就是 heading。一行说明,可选出处。最多一个 component。品牌页脚和 logo 不画。主题 motif 仍画。
|
|
23
|
+
|
|
24
|
+
`one-evidence` 是 content 页上的断言加一条证据。标题是一句完整主张。最多一个 component,渲成那条证据(一张 chart、一张表或一张图)。品牌页脚和 logo 不画。主题 motif 仍画。
|
|
25
|
+
|
|
26
|
+
`mono-bleed` 是 content 页上的满版品牌色底,字当图。容量 0:字写在 heading 里,没有 body component。品牌页脚和 logo 不画。主题 motif 仍画。
|
|
27
|
+
|
|
28
|
+
### 稀排页合同
|
|
29
|
+
|
|
30
|
+
一份 deck 是拿来讲的。幻灯片装不下的字写进 `slide.notes`。如果文件必须作为文档独立站住,建议用 PDF,不要把画布塞满。
|
|
31
|
+
|
|
32
|
+
这不是新的 `pacing` 档。枚举仍是 `dense` / `balanced` / `spacious`。合同靠版式点名、`notes` 和 deck `branding` 实现。
|
|
33
|
+
|
|
34
|
+
高潮页、金句页、证据页,在主题提供这些版式时显式钉 pinOnly 极简版式。点名:`statement`、`pull-quote`、`verse-chapter`、`stat-hero`、`one-evidence`、`mono-bleed`。不要把这些页交给自动选型。某一页真的只剩一句话时,即使 pacing 是 `dense` 也仍然钉。crayon、classroom、enterprise、pulse、runway、ember 不提供这些版式。如果 `validate` 警告这个钉子不是该主题提供的稀排页,就去掉钉子,改写普通内容页。
|
|
35
|
+
|
|
36
|
+
访谈或请求选了 `spacious`:收紧页上预算。标题就是主视觉。钉住的极简页最多一个 body component(一行出处、一个数字、一张图或一张表)。这些页零 bullet。装不下就拆页。
|
|
37
|
+
|
|
38
|
+
`balanced` 或 `dense`:按 pacing 预算写。某一页是一句话、一个数字、一句引语或一条证据时,仍然钉极简版式。
|
|
39
|
+
|
|
40
|
+
讲稿写进 `slide.notes`。`render` 导出成原生 PowerPoint 演讲者备注(View → Notes,演讲者视图可见)。讲稿从不画到画布上。
|
|
41
|
+
|
|
42
|
+
品牌框 omit/full 写在 `references/branding.md`。
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Spec writing and page types
|
|
2
|
+
|
|
3
|
+
Read this when writing `deck.spec.json`, choosing page types (`cover` / `chapter` / `content` / `ending`), or running the narrative interview.
|
|
4
|
+
|
|
5
|
+
### Phase 1 — Read the vocabulary (do this fresh every session)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pptwise schema # IR JSON Schema: the single source of truth
|
|
9
|
+
pptwise schema --spec # deck spec schema
|
|
10
|
+
pptwise narratives --json # named narrative presets (strategy/pacing/audience axes + theme recommendations)
|
|
11
|
+
pptwise themes --json # built-in themes (id + label)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Never write IR or a spec from memory of a previous session or from this file — the schema evolves and `schema`/`narratives`/`themes` output always wins.
|
|
15
|
+
|
|
16
|
+
Also scan the workspace before asking anyone anything. Facts the files can answer are not questions:
|
|
17
|
+
|
|
18
|
+
- An existing confirmed `deck.spec.json` already locks narrative, theme, and branding. Do not re-interview. Route follow-ups through phase 6.
|
|
19
|
+
- A `theme.json`, a pinned `pptwise.config.json` theme, a user-named theme id, or a supplied `.thmx` / `.potx` / branded `.pptx` is a brand signal. Extract or honor it. Do not ask whether a template exists.
|
|
20
|
+
- Request text that already names the audience, argument style, or density has derived that axis. Do not re-ask it.
|
|
21
|
+
|
|
22
|
+
A brand signal answers what the deck should look like, never how it should argue. The full rule lives in `references/branding.md`.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
**Boundary-page rule — learn this now, it is the single most common mistake:** `chapter` and `ending` pages never render `components` or `footnote`. `cover` pages never render `footnote`. A `cover` may carry `components` only when its locked layout declares a slot for them. Today that is `verdict-index` (consulting), which reads the first `bullets` block as up to three numbered arguments. Every other cover layout still drops components. Put body content on a `content` page unless you are filling that consulting argument row. `validate` catches a stray field with `"<type>" slides do not render components/footnote — move this content to a content slide or remove it`.
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
// pages/closing.json — spec type "ending" — WRONG: components never render on an ending page
|
|
29
|
+
{ "components": [{ "type": "bullets", "items": ["Thank you", "Questions? sales@example.com"] }] }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
// pages/wrap-up.json — spec type "content", inserted right before the ending page — CORRECT
|
|
34
|
+
{ "components": [{ "type": "bullets", "items": ["Thank you", "Questions? sales@example.com"] }] }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
// pages/closing.json — spec type "ending" — stays bare, nothing to move here
|
|
39
|
+
{}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`docs/deck-projects.md`'s boundary-page render surface table has the full per-type accounting.
|
|
43
|
+
|
|
44
|
+
### Phase 2 — Spec and confirm
|
|
45
|
+
|
|
46
|
+
Propose and confirm before writing any page content.
|
|
47
|
+
|
|
48
|
+
- Lock a narrative package first: named preset (or explicit axes), theme id, branding posture, and a type-scale band (how large cover / chapter / speech headings render: `regular` omit/1, `display` 1.3, `hero` 1.5). This is a decision layer above theme, not a visual choice. Use the Narrative interview below when any axis is still unknown and a user is present. Do not silently pick a preset in that case.
|
|
49
|
+
- Density (leave air vs pack the page) is decided in that interview (or derived). Follow the Sparse-page contract in `references/layouts.md` when you pin climax, quote, and evidence layouts and write `notes`. `pacing` does not grow a fourth value for this.
|
|
50
|
+
- Theme id comes from the chosen narrative's `themeRecommendations` in `narratives --json` (or from `themes` output if none fit — a recommendation, never a constraint). If the interview's brand question returned a template, extract it first — see `references/branding.md`.
|
|
51
|
+
- Write the confirmed `narrative`, `theme`, and `branding` into `deck.spec.json` as soon as the user agrees, before drafting any page. Do not hold them in the conversation and reconstruct them once pages exist.
|
|
52
|
+
- Draft `deck.spec.json`: one entry per page (`id`, `type`, `heading`, optionally `beat`/`focus`/`summary`) — opens on `cover`, closes on `ending`, everything in between is `content` or `chapter`. Write `narrative` as a preset id string when the three axes match a preset exactly, otherwise as `{strategy, pacing, audience}`. Never write `{id, pacing}` mixed shapes. Omit `branding` by default. Write `branding: "full"` only when every content page needs the brand footer (and whenever `meta.confidentiality` is `confidential` or `restricted`). Do not invent a `typeScale` field on the spec — it does not exist. The band is a recommendation. Only a bare IR (spec skipped) may put `theme.style.shape.typeScale` on the IR itself.
|
|
53
|
+
- Run `pptwise spec validate deck.spec.json` and fix whatever it reports until it prints `OK` — the hard gates (boundary pages, heading length, beat rotation, page count vs. pacing) all fire here, before a single page is written
|
|
54
|
+
- Once `spec validate` prints `OK`, set a `seed` (any integer) in `deck.spec.json` for revision stability — write one now, or run `pptwise assemble` once in phase 3 and copy the `generated seed …` value it prints into the spec. Without a persisted seed, editing one page's heading later can reshuffle every other page's auto-picked layout
|
|
55
|
+
|
|
56
|
+
**After the user confirms the validated spec, do not re-spec.** Restructuring a confirmed spec (reordering, retyping, dropping pages) silently wastes the user's review. If new information genuinely forces a change, say so and re-confirm first, then re-run `spec validate`.
|
|
57
|
+
|
|
58
|
+
### Narrative interview (at most one round)
|
|
59
|
+
|
|
60
|
+
When a user is present and any of audience, how it is told / strategy, or pacing is still unknown, relay the unresolved questions below in **one** message, then stop. Do not fill them in. Do not say "I'll assume". If the harness has a multiple-choice question tool, use it and pass the options verbatim.
|
|
61
|
+
|
|
62
|
+
Open that message with one sentence naming the deck you are about to build: who it is for, how the argument is told, how full a page runs, which theme, footer on or off. Build that sentence only out of what the request and the workspace actually said. Where a signal is missing, say it is missing and name the ★ option as a default, not as a read of their situation. Never dress a default as a conclusion about their meeting. Keep axis names (`pyramid`, `spacious`, `executive`) out of that sentence and out of the options. Close the message with the three ways out: take it as-is, change an option, or say none of these fit.
|
|
63
|
+
|
|
64
|
+
Skip the whole interview (zero questions) when: a confirmed spec already exists; the user said to skip questions / just generate / batch; there is nobody in this run at all; or the request already locks audience, argument style, and density. A complete brief still gets a one-line narrative package before you write the spec — that is the existing spec confirmation, not a second interview round.
|
|
65
|
+
|
|
66
|
+
Having no multiple-choice tool is not the same as having no user. In a plain conversation the user is present: the questions are the entire message and the stop still applies. Only a run with nobody in it (CI, batch, a script with no conversation) skips the pause, and there you still put the package, the reason, and what would change it in the visible output, then proceed on it. A later objection reopens the choice, and you re-run `spec validate` after changing it.
|
|
67
|
+
|
|
68
|
+
Skip only the derived axes. An empty workspace (no spec, no `theme.json`, no pinned config theme, nothing derivable in the request) asks Q1–Q4 together. A workspace with no brand signal asks Q4 even if it is not otherwise empty.
|
|
69
|
+
|
|
70
|
+
If the user skips an option, answers "anything", or replies off-list: fill the missing axis with the ★ default, name that fill in the recommendation reason, and do not follow up. "None of these fit" gets exactly one question back — which single axis is wrong — and nothing else. A veto of the package gets the prepared second candidate, not a new interview.
|
|
71
|
+
|
|
72
|
+
<!-- Maintainer note, not an instruction to relay: Q1 earns its place today only through the lookup below and the tone of the prose. The `audience` axis still changes nothing on the render surface. If a future wave stops reading `audience` in that lookup, delete Q1 rather than keep asking a question whose answer changes no deliverable. -->
|
|
73
|
+
|
|
74
|
+
**Q1 — Who is this for?** `executive` board / VP (conclusion first) · `technical` engineers who will check the numbers · `customer` ★ buyers, users, a pitch room · `public` mixed or public.
|
|
75
|
+
|
|
76
|
+
**Q2 — How should it be told?** This is the reading of the deck. Q1 and Q3 only tune it. `talk-pyramid` ★ one conclusion per page (`pyramid`) · `talk-showcase` one image or number per page (`showcase`) · `read-brief` a packed brief, evidence first (`briefing`) · `teach` a training walkthrough (`instructional`). Derive `storytelling` from 年报 / brand-film / situation-to-resolution language. Do not add it as a fifth option.
|
|
77
|
+
|
|
78
|
+
**Q3 — Sparse or packed?** `spacious` ★ leave air, few words per page · `balanced` a normal mix · `dense` pack the evidence, the page stands alone.
|
|
79
|
+
|
|
80
|
+
**Q4 — Brand template?** Only when there is no brand signal. `extract` yes, they will hand over a `.thmx` / `.potx` / branded `.pptx` · `builtin` ★ no, use a built-in theme · `later` built-in now, brand later (treat as `builtin`, do not open a second round). Whether a `theme.json` is already in the workspace is something you check, never something you ask.
|
|
81
|
+
|
|
82
|
+
End that message with this block, verbatim, one line per axis, a derived value filled in and every unresolved axis left as `?`:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
NARRATIVE_INTERVIEW
|
|
86
|
+
audience: ?
|
|
87
|
+
tell: ?
|
|
88
|
+
pacing: ?
|
|
89
|
+
brand: ?
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The block is the gate, not your self-discipline: while any line still reads `?`, you may not create or edit `deck.spec.json`, a page file, or a bare IR. Only the user's reply clears a `?` — or, once they have replied, the ★ default for an axis they left open. In a run with nobody in it, fill every line yourself and print the block with `(no user in this run)` on the first line, so the choice is visible and reversible.
|
|
93
|
+
|
|
94
|
+
After the reply, emit one package and one backup, one sentence of reason, one clause for what would change it, then wait for confirmation:
|
|
95
|
+
|
|
96
|
+
`recommend: <preset-or-axes> × <theme> × branding omit|full × typeScale regular|display|hero`
|
|
97
|
+
`what would change it: <one clause>` — most often: this will be forwarded without a speaker, so put the extra words in notes, or recommend a PDF instead of packing the slide.
|
|
98
|
+
|
|
99
|
+
Lookup (theme = first `themeRecommendations` entry from `narratives --json` for that preset, or for the nearest preset when writing axes). Omit the field by default. Write `"full"` when `meta.confidentiality` is `confidential` or `restricted`, or every content page needs the brand footer. `customer` + `talk-pyramid` + `spacious` → `pitch` / omit / display. `executive` + `talk-pyramid` + `spacious` → `boardroom-report` / omit / display. `customer` + `talk-showcase` + `spacious` → `product-launch` / omit / display. `technical` + `teach` + `balanced` → `training` / omit / regular. `technical` + `read-brief` + `dense` → `weekly-brief` / omit / regular. `executive` + `read-brief` + `dense` → axes `{pyramid, dense, executive}` / omit / regular, theme from `boardroom-report`. `public` + storytelling + `balanced` → `annual-review` / omit / regular. Else write the axes object and take the nearest preset's theme list: `pyramid`+`executive` → `boardroom-report`, `pyramid`+`customer` → `pitch`, `showcase` → `product-launch`, `instructional` → `training`, `briefing`+`dense` → `weekly-brief`, `storytelling` → `annual-review`, else `general`.
|
|
100
|
+
|
|
101
|
+
Type-scale band: `regular` when `dense` or `balanced`. `display` when `spacious`. `hero` only on a repaint that switches the theme to `stage`. Do not retarget a boardroom deck to `stage` just to enlarge titles. Do not write `typeScale` onto `deck.spec.json`. Do not edit a repo-root `pptwise.config.json` for one deck. On a bare IR (spec skipped) a non-`regular` band may be written as `theme.style.shape.typeScale` 1.3 or 1.5.
|
|
102
|
+
|
|
103
|
+
The second candidate ships with the package, prepared in advance, and it has to differ in mechanism: flip density (`spacious` ↔ `dense`, type-scale follows), or flip what leads the argument (`pitch` ↔ `product-launch`, `training` ↔ the same material as a dense handout). The same three axes in a different theme is a repaint, not a candidate — offer that only when the user rejected the look, and say the narrative did not move. `stage` × `hero` is the repaint for a showcase that wanted bigger titles. Do not flip all three axes at once.
|
|
104
|
+
|
|
105
|
+
This interview settles the three narrative axes, not whether the request should be a deck at all. If that larger question is open, say so plainly and let the user answer it before you spec.
|
|
106
|
+
|
|
107
|
+
A very small deck may still skip the spec file and write a single IR. It may not skip this interview when axes are unknown. Write the same decisions onto the IR's `narrative` / `theme` / `branding`.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: 'skills/pptwise/references/spec.md 的中文阅读镜像'
|
|
3
|
+
mirror_of: skills/pptwise/references/spec.md
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Spec 写法与页型
|
|
7
|
+
|
|
8
|
+
何时读:写 `deck.spec.json`、选页型(`cover` / `chapter` / `content` / `ending`)、或做叙事访谈时。
|
|
9
|
+
|
|
10
|
+
### Phase 1 — 读词汇表(每个 session 都要重新读一遍)
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pptwise schema # IR JSON Schema: the single source of truth
|
|
14
|
+
pptwise schema --spec # deck spec schema
|
|
15
|
+
pptwise narratives --json # named narrative presets (strategy/pacing/audience axes + theme recommendations)
|
|
16
|
+
pptwise themes --json # built-in themes (id + label)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
永远不要凭上一个 session 的记忆、或凭这份文件本身的记忆去写 IR 或 spec——schema 会演进,`schema`/`narratives`/`themes` 的实际输出永远优先。
|
|
20
|
+
|
|
21
|
+
动手问人之前,先扫工作区。文件能回答的事实不要问人:
|
|
22
|
+
|
|
23
|
+
- 已有确认过的 `deck.spec.json` 已经锁死 narrative、theme、品牌框。不要重做访谈。后续请求走阶段六
|
|
24
|
+
- 已有 `theme.json`、项目 `pptwise.config.json` 钉死的 theme、用户点名的 theme id、或用户递来的 `.thmx` / `.potx` / 带品牌 `.pptx`,都是品牌信号。抽取或沿用。不要再问有没有模板
|
|
25
|
+
- 请求原文已经点名受众、论证方式或疏密,这一轴就算推导出来了。不要再问
|
|
26
|
+
|
|
27
|
+
品牌信号回答的是这份 deck 长什么样,从来不回答它该怎么论证。完整规则在 `references/branding.md`。
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
**边界页规则——现在就记住,这是最常见的错误:** `chapter` 和 `ending` 永远不渲染 `components` 或 `footnote`。`cover` 永远不渲染 `footnote`。封面只有在锁定版式声明了对应槽位时才能带 `components`。今天这只发生在 `verdict-index`(consulting):它读第一个 `bullets` 块,画成最多三条编号论据。其余封面版式仍会丢掉 components。正文放到 `content` 页,除非你在填 consulting 封面那三列论据。`validate` 会用 `"<type>" slides do not render components/footnote — move this content to a content slide or remove it` 抓住多余字段。
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
// pages/closing.json — spec type "ending" — WRONG: components never render on an ending page
|
|
34
|
+
{ "components": [{ "type": "bullets", "items": ["Thank you", "Questions? sales@example.com"] }] }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
// pages/wrap-up.json — spec type "content", inserted right before the ending page — CORRECT
|
|
39
|
+
{ "components": [{ "type": "bullets", "items": ["Thank you", "Questions? sales@example.com"] }] }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
// pages/closing.json — spec type "ending" — stays bare, nothing to move here
|
|
44
|
+
{}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`docs/deck-projects.md` 里的边界页渲染面表(boundary-page render surface table)有按页型划分的完整对照。
|
|
48
|
+
|
|
49
|
+
### Phase 2 — 定 spec 并确认
|
|
50
|
+
|
|
51
|
+
写任何页面内容之前,先提议并确认。
|
|
52
|
+
|
|
53
|
+
- 先锁定叙事包:具名预设(或显式三轴)、theme id、品牌框姿态、以及 typeScale 档(封面 / 章 / 演讲页标题有多大:`regular` 省略/1,`display` 1.3,`hero` 1.5)。这是位于 theme 之上的一层决策,不是视觉选择。任一轴仍未知且用户在场时,走下方「叙事访谈」。这种情况下不要自己静默挑一个预设
|
|
54
|
+
- 疏密(留白还是铺满)在访谈里判定(或从请求推导)。钉高潮页、金句页、证据页版式和写 `notes` 时走 `references/layouts.md` 的稀排页合同。`pacing` 不会为此多出第四档
|
|
55
|
+
- 再定 theme id:从 `narratives --json` 里该预设的 `themeRecommendations` 取(如果都不合适,就从 `themes` 输出里挑一个贴合这份 deck 调性的。这只是推荐,从不构成约束)。访谈的品牌问如果返回了模板,先抽成自定义 theme,见 `references/branding.md`
|
|
56
|
+
- 用户一点头,立刻把确认下来的 `narrative`、`theme`、`branding` 写进 `deck.spec.json`,再起草任何一页。不要把答案留在对话里,等页面写完再凭记忆补
|
|
57
|
+
- 起草 `deck.spec.json`:每页一条记录(`id`、`type`、`heading`,可选加 `beat`/`focus`/`summary`)——以 `cover` 开篇,以 `ending` 收尾,中间的每一页都是 `content` 或 `chapter`。三轴与某个预设完全相等时,`narrative` 写预设 id 字符串,否则写 `{strategy, pacing, audience}`。不要写 `{id, pacing}` 这种混形。默认省略 `branding`。只有每一页内容页都需要品牌页脚时才写 `branding: "full"`(`meta.confidentiality` 为 `confidential` 或 `restricted` 时同样写 `"full"`)。不要在 spec 上发明 `typeScale` 字段,那个字段不存在。档是推荐。只有跳过 spec、直接写 IR 时,才允许把 `theme.style.shape.typeScale` 写进 IR
|
|
58
|
+
- 跑 `pptwise spec validate deck.spec.json`,把它报出的问题都修掉,直到打印 `OK`——边界页、标题长度、beat 轮换、页数是否匹配 pacing 这些硬门都在这一步触发,早于任何一页正文的写作
|
|
59
|
+
- `spec validate` 打印 `OK` 之后,在 `deck.spec.json` 里设一个 `seed`(任意整数)以保证修订稳定——现在就写一个,或者在阶段三跑一次 `pptwise assemble`,把它打印出的 `generated seed …` 值抄进 spec。没有固化的 seed,之后改一页的标题就可能打乱其余每一页自动选出的 layout
|
|
60
|
+
|
|
61
|
+
**用户确认过校验通过的 spec 之后,不要再重新定 spec。** 改动一份已确认的 spec(调整顺序、改页型、删页)会悄悄浪费用户已经做过的审阅。如果确有新信息迫使必须改动,先说明理由并重新取得确认,再重新跑一次 `spec validate`。
|
|
62
|
+
|
|
63
|
+
### 叙事访谈(最多一轮)
|
|
64
|
+
|
|
65
|
+
用户在场,且受众、怎么讲 / strategy、pacing 任一轴仍未知时,把所有未决的问放进**一条**消息转达给人,然后停。不要自己填。不要说「我按常见情况先选」。宿主有选择题工具就用它,选项原文照传。
|
|
66
|
+
|
|
67
|
+
这条消息开头先写一句话,说出你打算建的这份 deck:给谁、论证怎么讲、每页多满、哪个主题、页脚开还是关。这句话只能用请求和工作区真说过的东西搭。缺信号的地方就说缺,并把 ★ 点明成默认,不是对用户处境的读数。不要把默认打扮成结论。这句话和选项里都不要出现 `pyramid`、`spacious`、`executive` 这类轴名。结尾给三条出路:不改就说「就这样」,要改就挑选项,或者说「都不对」。
|
|
68
|
+
|
|
69
|
+
整段跳过访谈(零问):已有确认过的 spec。用户说跳过问题、直接生成或批量。这一轮里根本没有人。请求已经同时锁定受众、论证方式、疏密。完整 brief 仍要在写 spec 之前甩一句叙事包。那是原来的 spec 确认,不是第二轮访谈。
|
|
70
|
+
|
|
71
|
+
没有选择题工具,不等于没有用户。普通文本对话里用户是在场的:问题就是整条消息,停照旧。只有真的没有人的运行(CI、批量、无对话脚本)才免掉这次停顿,而且仍要把包、一句理由、一句改口条件写进可见输出,然后按包继续。事后用户任何一条反对都重开这个决定,改完重跑 `spec validate`。
|
|
72
|
+
|
|
73
|
+
只跳过已推导的轴。空 workspace(无 spec、无 `theme.json`、无钉死的 config theme、请求里什么都推不出)把 Q1–Q4 一起问。没有品牌信号的工作区即使别的文件很多,也要问 Q4。
|
|
74
|
+
|
|
75
|
+
用户跳过某选项、说「都行」、或回了表外的话:用 ★ 默认补齐,在推荐理由里写明补了哪一轴,不要追问。用户说「都不对」:只回一句「三轴里哪一根不对」,别的都不问。用户否决推荐包:抛出事先准备的第二候选,不要重开访谈。
|
|
76
|
+
|
|
77
|
+
<!-- 维护者注记,不要转达给用户:Q1 今天的价值全部来自下面那张查表和正文口吻,`audience` 轴在渲染面上仍然什么都不做。如果将来查表不再读 `audience`,应该删掉 Q1,而不是留着一个答案改变不了交付物的问题。 -->
|
|
78
|
+
|
|
79
|
+
**Q1 这页是讲给谁的?** `executive` 董事会 / 高管(结论先行) · `technical` 会核对数字的技术同事 · `customer` ★ 客户、买家、路演现场 · `public` 公开或不特定。
|
|
80
|
+
|
|
81
|
+
**Q2 你想怎么讲这件事?** 这一问才是这份 deck 的读法,Q1 和 Q3 只是把它调准。`talk-pyramid` ★ 一页一个结论(`pyramid`) · `talk-showcase` 一页一个画面或数字(`showcase`) · `read-brief` 一页铺满证据(`briefing`) · `teach` 按步骤教(`instructional`)。年报 / 品牌片 / 情境到解决的说法直接推导 `storytelling`,不要把它加成第五选项。
|
|
82
|
+
|
|
83
|
+
**Q3 页上要留白还是铺满?** `spacious` ★ 留白,一页少字 · `balanced` 普通疏密 · `dense` 铺满证据,页自己把话说完。
|
|
84
|
+
|
|
85
|
+
**Q4 有没有公司模板可以抽成主题?** 仅当没有品牌信号时问。`extract` 有,用户会给出 `.thmx` / `.potx` / 带品牌 `.pptx` · `builtin` ★ 没有,用内置主题 · `later` 先用内置,稍后补(当作 `builtin`,不开第二轮)。工作区里有没有 `theme.json`,是自己查的事,永远不问。
|
|
86
|
+
|
|
87
|
+
这条消息的结尾原样附上下面这个块,一轴一行,已推导的轴填上值,未决的轴留 `?`:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
NARRATIVE_INTERVIEW
|
|
91
|
+
audience: ?
|
|
92
|
+
tell: ?
|
|
93
|
+
pacing: ?
|
|
94
|
+
brand: ?
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
这个块就是闸,不靠自觉:只要还有一行是 `?`,就不许新建或修改 `deck.spec.json`、页面文件或裸 IR。清掉一个 `?` 只有两条路:用户回答,或者用户已经回复、只是留空了某一轴,那一轴用 ★ 默认补。真的没有人的运行里,自己把每一行填满,并在块的第一行标上 `(no user in this run)`,让这个选择可见、可推翻。
|
|
98
|
+
|
|
99
|
+
用户回复之后,立刻给一个推荐包和一个第二候选,一句理由,一句改口条件,然后等确认:
|
|
100
|
+
|
|
101
|
+
`推荐:<预设或三轴> × <theme> × branding 省略|full × typeScale regular|display|hero`
|
|
102
|
+
`改口条件:<一句>`。最常见的一条:这份会在没有主讲人的情况下被转发,把多出来的字写进 notes,或者建议改用 PDF,不要把幻灯片塞满。
|
|
103
|
+
|
|
104
|
+
查表(theme = `narratives --json` 里该预设 `themeRecommendations` 的第一项。写三轴对象时改取最靠近预设的名单)。默认省略该字段。`meta.confidentiality` 为 `confidential` 或 `restricted`,或每一页内容页都需要品牌页脚时,才写 `"full"`。`customer` + `talk-pyramid` + `spacious` → `pitch` / 省略 / display。`executive` + `talk-pyramid` + `spacious` → `boardroom-report` / 省略 / display。`customer` + `talk-showcase` + `spacious` → `product-launch` / 省略 / display。`technical` + `teach` + `balanced` → `training` / 省略 / regular。`technical` + `read-brief` + `dense` → `weekly-brief` / 省略 / regular。`executive` + `read-brief` + `dense` → 三轴 `{pyramid, dense, executive}` / 省略 / regular,theme 取 `boardroom-report`。`public` + storytelling + `balanced` → `annual-review` / 省略 / regular。其余写三轴对象,最靠近预设:`pyramid`+`executive` → `boardroom-report`,`pyramid`+`customer` → `pitch`,`showcase` → `product-launch`,`instructional` → `training`,`briefing`+`dense` → `weekly-brief`,`storytelling` → `annual-review`,否则 `general`。
|
|
105
|
+
|
|
106
|
+
typeScale 档:`dense` 或 `balanced` 用 `regular`。`spacious` 用 `display`。`hero` 只出现在把 theme 换成 `stage` 的那种换皮上。不要为了把标题加大,把董事会 deck 改成 `stage`。不要在 `deck.spec.json` 上写 `typeScale`。不要为了一个 deck 去改仓库根上的 `pptwise.config.json`。跳过 spec、直接写 IR 时,非 `regular` 的档可以写成 `theme.style.shape.typeScale` 1.3 或 1.5。
|
|
107
|
+
|
|
108
|
+
第二候选跟着推荐包一起抛,事先准备,而且必须在机制上不同:翻疏密(`spacious` ↔ `dense`,type-scale 跟着翻),或者换由什么领头论证(`pitch` ↔ `product-launch`,`training` ↔ 同样内容的密页讲义)。同样三根轴换个主题是换皮,不算候选,只在用户否的是皮时才给,并说清叙事没动。showcase 想要更大标题时,`stage` × `hero` 属于这种换皮。不要三轴一起翻。
|
|
109
|
+
|
|
110
|
+
这一轮只定三根叙事轴,不负责判断这件事该不该做成 deck。那个更大的问题还开着,就直说,让用户先答,再定 spec。
|
|
111
|
+
|
|
112
|
+
很小的 deck 仍可跳过 spec 文件、直接写一份 IR。轴未知时不可跳过这场访谈。把同样的决策写到 IR 的 `narrative` / `theme` / `branding` 上。
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Validate loop
|
|
2
|
+
|
|
3
|
+
Read this when running assemble / validate / audit / preview / serve, or revising a page.
|
|
4
|
+
|
|
5
|
+
### Phase 3 — Fill pages in batches of at most 4, validate immediately
|
|
6
|
+
|
|
7
|
+
For each page in the confirmed spec, write `pages/<page-id>.json` with its content (`components`, and optionally `layout`/`arrangement`/`background`/`image_side`/`footnote`/`notes` — never `type`/`heading`, those are locked by the spec). Remember Phase 1's boundary-page rule while drafting `cover`/`chapter`/`ending` pages — do not give them `components` or `footnote` and then have to move it. `notes` is speaker notes prose for whoever presents the deck — writing a good speaking script is a model strength. Draft `notes` whenever the page needs a spoken walkthrough beyond what is on the slide (Sparse-page contract). That is the default, not optional.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pptwise assemble deck-dir/ # materializes deck.json — catches structural drift: orphan page files, locked-field violations, a broken spec
|
|
11
|
+
pptwise validate deck-dir/ # content-quality gate: heading length, density, bullets budget (warnings) + unknown theme, boundary-page content, and a bullet item past render-safety (hard errors)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Fix whatever either command reports as an error and re-run until both print `OK`. `validate` can print `OK` alongside `warning:` lines (e.g. a long heading or a dense slide) — tighten those too when practical, they read better, but they do not block. Only an error stops `OK` from printing. A spec page with no page file yet is a placeholder (heading only) — assemble and validate both accept that. Leaving some pages as placeholders between batches is normal, not an error. `assemble` also prints `note: N layouts auto-selected into deck.json` whenever a page's `layout` was left to auto-selection — informational, not an error. Pin `layout` in a page file only when a specific pick needs to be locked — a `pinOnly` layout like `quote-stage`, `statement`, `pull-quote`, `verse-chapter`, `stat-hero`, `one-evidence`, or `mono-bleed` needs this pin every single time, since it never comes up through auto-selection at all (see `references/layouts.md`). Climax, quote, and evidence pages pin those by default (see `references/layouts.md`).
|
|
15
|
+
|
|
16
|
+
### Phase 4 — Render
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pptwise render deck-dir/
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The `.pptx` lands in `.pptwise/<deck>/`. The command prints the absolute path. Report that line to the user.
|
|
23
|
+
|
|
24
|
+
`--theme <id>` overrides the deck theme without editing the spec. `--style <path>` layers a style-token override on top (re-color without forking a theme, schema: `pptwise schema --style`). Render refuses a deck with unfilled placeholder pages unless you add `--draft` — reach for that only when the user explicitly wants a look before every page is done. It also refuses a deck where a page holds more than fits, so the layout left blocks out with nothing on the slide to say so: the error names the pages and how many blocks each lost. Fix it by shortening that page or splitting it in two, and re-render — `--allow-dropped-content` ships the file with the content missing, so only pass it if the user says to.
|
|
25
|
+
|
|
26
|
+
If the project has a `pptwise.config.json`, its theme/style are project defaults — do not fight them with `--theme` unless the user asks. Any page `notes` you wrote in phase 3 export as native PowerPoint speaker notes (View → Notes in PowerPoint/Keynote) — never drawn onto the slide itself.
|
|
27
|
+
|
|
28
|
+
### Phase 5 — Audit and optional visual self-check
|
|
29
|
+
|
|
30
|
+
Once every page is filled (no placeholders left), run the deterministic geometry audit:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pptwise audit deck-dir/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Zero-token, zero-variance — it renders each page off-screen and checks overflow, out-of-bounds, low-contrast, overlap, content-truncated (an ellipsis cut real text), and content-dropped (an item or whole component silently clamped out, tagged data-dropped in the SVG), exiting 1 when it finds anything (0 when clean). Each finding names its page (and id) and carries a fix. Fix the flagged page's content — same "restructure, don't delete" discipline as a `validate` error — then re-run `pptwise audit deck-dir/` alone (no need to re-render) until it exits 0. This is the deck's visual QA. Do not rely on eyeballing a screenshot instead.
|
|
37
|
+
|
|
38
|
+
If any page has a cover/chapter photo background, add `--pixels` — it rasterizes the page and samples real pixels to catch text sitting directly on an unscrimmed photo, the one case the SVG-only checks above can't see.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pptwise preview deck-dir/ --html
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Writes one standalone SVG per slide plus a self-contained `preview.html` into `.pptwise/<deck>/`, never gated on placeholder pages. The command prints the absolute path. Report that line to the user. Read a few SVGs yourself (they are plain text files) to sanity-check layout and density before delivering, especially for image-heavy decks. Hand `preview.html` (thumbnail strip, keyboard navigation, placeholder badges) to the user for their own look instead. When every page is filled, `preview.html` also overlays the same `audit` findings (per-page badges + a findings panel) so the reviewer sees them without a terminal. A deck with any placeholder page shows a one-line "audit skipped" notice instead. `preview.html` is read-only: it shows the deck, it never edits it. When the reviewer wants something changed, they tell you in the conversation. A screenshot of the page in question is the fastest way for both of you, and you route it through phase 6.
|
|
45
|
+
|
|
46
|
+
### Showing the deck to the user
|
|
47
|
+
|
|
48
|
+
How you hand a deck over depends on what the harness can render. Take the first one that applies.
|
|
49
|
+
|
|
50
|
+
**If a `pptwise_preview` tool exists, call it.** It renders the deck and puts a real slide preview in the conversation: a thumbnail strip in the tool card, full size on click, arrow keys to page. The user sees the deck without leaving the thread and without opening anything. Never fall back to handing over a file path or a URL when this tool is present. That is the experience it was built to replace. The tool reports only a summary line back to you (page count, audit state). That is deliberate: the deck itself goes to the user's screen, not into your context.
|
|
51
|
+
|
|
52
|
+
**If the harness has a built-in browser (VS Code, Cursor, and similar), preview to a file.** Run `pptwise preview deck-dir/ --html`. The command prints the absolute path of `preview.html`. Give the user that path so they can open it in the built-in browser. Re-run the same command after each revision: the path does not change, they refresh. No port, no background process.
|
|
53
|
+
|
|
54
|
+
**Otherwise, serve it.** Most harnesses have no way to draw a slide in the transcript, so the review happens in the user's own browser. Never try to substitute by pasting a thumbnail or a screenshot of one page into the conversation. Serve the whole thing and let the user page through it at full size. Start the server as a background task (in DSH, follow the background-job convention and note the job id so you can stop it later):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pptwise serve deck-dir/ --no-open
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Then run the round in this order:
|
|
61
|
+
|
|
62
|
+
1. Always pass `--no-open`. There is no browser to auto-open in an agent environment.
|
|
63
|
+
2. Report the exact localhost URL it prints (default `http://127.0.0.1:4400`) to the user, so they can open it themselves. That one line is the whole handoff.
|
|
64
|
+
3. The user pages through the deck and tells you what needs changing, in the conversation. A screenshot of the offending page is the fastest hand-off — you see exactly what they see.
|
|
65
|
+
4. Route each request through phase 6's revision flow. The page live-reloads on every file you save, so each revision lands in the tab the user already has open. No new link, no re-export, nothing for them to click.
|
|
66
|
+
5. Stay in the loop while they keep looking. When the round is over, stop the serve process (kill the background job). Never leave it running after the task ends.
|
|
67
|
+
|
|
68
|
+
### Phase 6 — Revision: edit one page, re-assemble
|
|
69
|
+
|
|
70
|
+
A revision touches the smallest file that captures it:
|
|
71
|
+
|
|
72
|
+
- Content change ("punch up the KPI page") → edit that page's `pages/<id>.json` only, then repeat phase 3's `assemble` + `validate` pair, and phase 5's `audit`, before re-rendering. Never regenerate pages nobody asked you to touch.
|
|
73
|
+
- Structural change (reorder, add/remove a page, change a page's type or heading) → edit `deck.spec.json` instead, re-run `pptwise spec validate` first (phase 2's no-respeccing rule still applies: only do this when the user actually asked for a structural change).
|
|
74
|
+
- A change the reviewer asked for in conversation (usually with a screenshot of the page) → find that page's `pages/<id>.json` by matching what they described against `deck.spec.json`/`pages/`, and treat their words as a requirement to interpret, not a patch to apply verbatim: they are describing a rendered slide, not writing page-file JSON. Translate it into a concrete content edit, then run the same content-change loop above (`assemble` + `validate` + `audit`) for every page you touched. Preview stays read-only end to end: nothing writes into `pages/*.json` except your own deliberate edit.
|
|
75
|
+
|
|
76
|
+
## Routing a follow-up request
|
|
77
|
+
|
|
78
|
+
Once a deck project exists, a follow-up message routes into exactly one of three branches — decide which before doing anything:
|
|
79
|
+
|
|
80
|
+
1. **Edit a page** ("change slide 3", "make the KPI page punchier", or a screenshot with a note) → phase 6: edit that page's file, re-assemble, re-validate, re-audit. Never touch pages nobody asked about.
|
|
81
|
+
2. **A new deck** (a different topic, audience, or an explicit request to start over) → phase 1: a new deck project directory, fresh narrative/theme decision, fresh spec.
|
|
82
|
+
3. **Unrelated to deck generation** (a question about the content, anything with no connection to slides) → do not invoke pptwise at all.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: 'skills/pptwise/references/validate.md 的中文阅读镜像'
|
|
3
|
+
mirror_of: skills/pptwise/references/validate.md
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 排错与 validate 循环
|
|
7
|
+
|
|
8
|
+
何时读:跑 assemble / validate / audit / preview / serve,或修订某一页时。
|
|
9
|
+
|
|
10
|
+
### Phase 3 — 分批填页面(每批至多 4 页),随填随 validate
|
|
11
|
+
|
|
12
|
+
对已确认 spec 里的每一页,写一个 `pages/<page-id>.json` 存放它的内容(`components`,以及可选的 `layout`/`arrangement`/`background`/`image_side`/`footnote`/`notes`——绝不写 `type`/`heading`,这两个字段被 spec 锁定)。撰写 `cover`/`chapter`/`ending` 页面时记住 Phase 1 的边界页规则——不要先给它们塞 `components` 或 `footnote`,然后再回头搬走。`notes` 是给主讲人看的演讲稿——写一份好的讲稿是模型的强项。只要页面需要一段超出幻灯片本身的口头讲解,就起草 `notes`(稀排页合同)。这是默认动作,不是可选项。
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pptwise assemble deck-dir/ # materializes deck.json — catches structural drift: orphan page files, locked-field violations, a broken spec
|
|
16
|
+
pptwise validate deck-dir/ # content-quality gate: heading length, density, bullets budget (warnings) + unknown theme, boundary-page content, and a bullet item past render-safety (hard errors)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
把两个命令报出的错误都修掉,重新跑,直到两者都打印 `OK`。`validate` 可能在打印 `OK` 的同时带着 `warning:` 行(比如标题太长、某页太密)——条件允许时也应该收紧,读起来会更好,但它们不拦渲染。只有 error 才会让 `OK` 打印不出来。spec 里某一页如果还没有对应的页面文件,就是一个占位页(只有标题)——assemble 和 validate 都接受这种情况。分批之间留一些占位页是正常状态,不是错误。只要某一页的 `layout` 被留给自动选型,`assemble` 也会打印 `note: N layouts auto-selected into deck.json`——这只是提示,不是错误。只有当某个具体选型结果需要被锁定时,才在页面文件里显式钉死 `layout`——像 `quote-stage`、`statement`、`pull-quote`、`verse-chapter`、`stat-hero`、`one-evidence`、`mono-bleed` 这种 `pinOnly` 版式每次都需要这个钉子,因为它从来不会通过自动选型出现(见 `references/layouts.md`)。高潮页、金句页、证据页默认就要钉(见 `references/layouts.md`)。
|
|
20
|
+
|
|
21
|
+
### Phase 4 — 渲染
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pptwise render deck-dir/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`.pptx` 落在 `.pptwise/<deck>/`。命令会打印绝对路径,把那一行报给用户。
|
|
28
|
+
|
|
29
|
+
`--theme <id>` 在不改动 spec 的前提下覆盖 deck 的 theme。`--style <path>` 在其上叠加一层 style-token 覆盖(不用分叉 theme 就能重新配色,schema 见 `pptwise schema --style`)。deck 里还有未填的占位页时,render 会拒绝导出,除非加上 `--draft`——只有当用户明确想在所有页面都写完之前先看一眼时,才用它。某一页装不下、版面丢掉了放不下的块而页面上毫无提示时,render 同样拒绝导出,报错会写清哪几页各丢了几块。正确做法是把那一页缩短或拆成两页再重新渲染,`--allow-dropped-content` 会带着缺失的内容出片,只有用户明确要求时才用。
|
|
30
|
+
|
|
31
|
+
如果项目里有 `pptwise.config.json`,它的 theme/style 就是项目默认值——除非用户要求,不要用 `--theme` 跟它对着干。阶段三里写的任何页面 `notes` 都会导出成原生 PowerPoint 演讲者备注(PowerPoint/Keynote 里的 View → Notes)——从不会画到幻灯片本身上。
|
|
32
|
+
|
|
33
|
+
### Phase 5 — 审查,可选的视觉自查
|
|
34
|
+
|
|
35
|
+
所有页面都填完(没有占位页剩下)之后,跑一次确定性几何审查:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pptwise audit deck-dir/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
零 token、零方差——它离屏渲染每一页,检查溢出(overflow)、越界(out-of-bounds)、低对比度(low-contrast)、重叠(overlap)、内容截断(content-truncated,省略号截掉了真实文字)、内容丢失(content-dropped,某个条目或整个 component 被静默截掉,SVG 里标成 data-dropped),发现问题就 exit 1(干净则是 0)。每条 finding 都标出所在页面(和 id),并带一个修法。修那一页被标出的内容——和处理 `validate` 报错一样遵循「重组,不要删除」的纪律——然后单独重跑一次 `pptwise audit deck-dir/`(不用重新渲染)直到 exit 0。这是这份 deck 的视觉 QA。不要用肉眼看截图来代替它。
|
|
42
|
+
|
|
43
|
+
如果有页面用了 cover/chapter 照片背景,加上 `--pixels`——它会把该页光栅化并采样真实像素,抓住文字直接压在一张没有遮罩的照片上的情况,这是上面纯 SVG 检查唯一看不到的一种。
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pptwise preview deck-dir/ --html
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
为每张 slide 各写一个独立 SVG,外加一个自包含的 `preview.html`,都落在 `.pptwise/<deck>/`,永远不受占位页拦截。命令会打印绝对路径,把那一行报给用户。交付之前自己读几个 SVG(它们就是纯文本文件),核对 layout 与密度是否合理,图片较多的 deck 尤其要看。把 `preview.html`(缩略图条、键盘翻页、占位页角标)交给用户自己看,而不是代替这一步。所有页面都填完时,`preview.html` 还会叠加同一份 `audit` 检查结果(每页一个角标 + 一个 findings 面板),让审查者不用打开终端就能看到问题。deck 里如果还有占位页,则改为显示一行「audit skipped」的提示。`preview.html` 是只读的:它只负责把 deck 呈现出来,从不改动它。审查者想改什么,直接在对话里告诉你。把那一页截图发给你是最快的交接方式,你再走阶段六处理。
|
|
50
|
+
|
|
51
|
+
### 把 deck 拿给用户看
|
|
52
|
+
|
|
53
|
+
怎么交付取决于 harness 能画什么。按下面的顺序,用第一条成立的。
|
|
54
|
+
|
|
55
|
+
**如果存在 `pptwise_preview` 工具,就调它。** 它渲染完直接把幻灯片预览放进对话:卡片里是缩略图条,点开看全尺寸,方向键翻页。用户不用离开对话,也不用打开任何东西。**这个工具在场时绝不要退回去甩一个文件路径或 URL 给用户**。它就是为了取代那个体验才存在的。工具只回给你一行摘要(页数、审计状态),这是刻意的:deck 去用户屏幕,不进你的上下文。
|
|
56
|
+
|
|
57
|
+
**如果 harness 有内置浏览器(VS Code、Cursor 一类),就预览成文件。** 跑 `pptwise preview deck-dir/ --html`。命令会打印 `preview.html` 的绝对路径,把那条路径给用户,让他在内置浏览器里打开。每轮修订后重跑同一条命令,路径不变,用户刷新即可。不占端口,不留常驻进程。
|
|
58
|
+
|
|
59
|
+
**否则就起服务。** 大多数 harness 没办法在对话里画出一页幻灯片,审阅就发生在用户自己的浏览器里。绝不要用「贴一张缩略图或某一页的截图」来代替。把整份 deck 服务出去,让用户全尺寸自己翻。启动服务(在 DSH 里遵循后台任务的规矩,记下 job id,方便之后停掉):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pptwise serve deck-dir/ --no-open
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
然后按这个顺序走完这一轮:
|
|
66
|
+
|
|
67
|
+
1. 必须带 `--no-open`。agent 环境里没有可以自动打开的浏览器。
|
|
68
|
+
2. 把它打印的 localhost URL(默认 `http://127.0.0.1:4400`)原样报给用户,让用户自己打开。这一行就是全部交付动作。
|
|
69
|
+
3. 用户翻完整份 deck,在对话里告诉你哪里要改。把出问题的那一页截图发过来是最快的交接方式——你看到的和他看到的完全一致。
|
|
70
|
+
4. 把每一条请求都走阶段六的修订流程。你每保存一次文件页面就实时重渲染,每一次修订都直接落在用户已经打开的那个标签页里。不用发新链接,也不用让他点任何东西。
|
|
71
|
+
5. 用户还在继续看就留在这个循环里。这一轮结束时停掉 serve 进程(kill 掉那个后台任务)。任务结束后绝不留着它继续跑。
|
|
72
|
+
|
|
73
|
+
### Phase 6 — 修订:改一页,重新 assemble
|
|
74
|
+
|
|
75
|
+
一次修订,只改能承载这次改动的最小那份文件:
|
|
76
|
+
|
|
77
|
+
- 内容改动(「把 KPI 那页写得更有冲击力」)→ 只改那一页的 `pages/<id>.json`,然后重复阶段三的 `assemble` + `validate` 组合,以及阶段五的 `audit`,再重新渲染。没人要求你改的页面,绝不重新生成。
|
|
78
|
+
- 结构性改动(调整顺序、增删页面、改某页的 type 或 heading)→ 改 `deck.spec.json`,先重新跑一次 `pptwise spec validate`(阶段二的「不要重新定 spec」规则依然适用:只有在用户确实要求结构性改动时才这么做)。
|
|
79
|
+
- 审查者在对话里提出的改动(通常附一张页面截图)→ 对照他描述的内容在 `deck.spec.json`/`pages/` 里找到那一页的 `pages/<id>.json`。把他的话当成一条需要你去理解的需求,而不是可以照抄的补丁:他描述的是渲染出来的 slide,不是在写页面文件 JSON——你自己要把它翻译成具体的内容改动,然后对每一页你动过的页面跑上面同一套内容改动流程(`assemble` + `validate` + `audit`)。preview 全程只读:除了你自己主动做出的编辑之外,没有任何环节会写入 `pages/*.json`。
|
|
80
|
+
|
|
81
|
+
## 后续请求怎么分流
|
|
82
|
+
|
|
83
|
+
一旦 deck 项目已经存在,后续消息恰好分流进三条分支之一——动手之前先判断走哪一条:
|
|
84
|
+
|
|
85
|
+
1. **改一页**(「改一下第 3 页」「把 KPI 那页写得更有冲击力」,或者一张截图加一句说明)→ 走阶段六:改那一页的文件,重新 assemble、重新 validate、重新 audit。没人问起的页面绝不去碰。
|
|
86
|
+
2. **一份新 deck**(不同的主题、不同的受众,或明确要求重新开始)→ 走阶段一:新建一个 deck 项目目录,重新决定 narrative/theme,重新起一份 spec。
|
|
87
|
+
3. **和 deck 生成无关**(关于内容本身的问题,或任何和 slides 没有关联的事)→ 完全不要调用 pptwise。
|