| 1 | --- |
| 2 | description: Generate profile for 1:1, content-faithful re-layout of an existing deck through Default or explicit Quick execution. |
| 3 | --- |
| 4 | |
| 5 | # Beautify PPTX (Re-layout) Profile |
| 6 | |
| 7 | > Generate profile, not a top-level route. [`template-fill-pptx.md`](../template-fill-pptx.md) reuses a deck's design and swaps in new content; this profile keeps a deck's content and redoes its layout. |
| 8 | |
| 9 | Re-lays-out an existing `.pptx`: the text is preserved **verbatim**, the source deck's visual identity (palette / fonts) is **inherited as truth**, and only layout, hierarchy, and whitespace are redesigned. Output is a brand-new native deck generated through the standard SVG pipeline — not a patch over the original. |
| 10 | |
| 11 | **Trigger**: the user supplies a `.pptx` and asks to beautify / re-layout / 重新排版 / 美化 while keeping the content. Explicit intent + a provided file only; never auto-infer. |
| 12 | |
| 13 | **Hard rule — select one runtime before continuing**: when the same request |
| 14 | also meets [`quick-generate.md`](./quick-generate.md)'s explicit trigger, load |
| 15 | that runtime and do not load `generate-pptx.md`. Otherwise load |
| 16 | [`generate-pptx.md`](../generate-pptx.md) and do not load Quick. The 1:1 |
| 17 | Beautify constraints in this file apply in either runtime. |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ## 1. When to Run |
| 22 | |
| 23 | | Pattern | Example | |
| 24 | |---|---| |
| 25 | | Existing `.pptx` + beautify intent | "把这份 PPT 美化一下" / "make this deck look better" | |
| 26 | | Existing `.pptx` + re-layout intent | "重新排版这份 PPT,内容别动" / "re-layout this, keep the wording" | |
| 27 | | Existing `.pptx` + paste-back intent | "重排后我要把元素贴回原来的模板" | |
| 28 | |
| 29 | **Hard rule — content is frozen**: every text string from the source is preserved exactly (no add / remove / reword / reorder). Beautification freedom lives only in layout, hierarchy, spacing, and visual rhythm. |
| 30 | |
| 31 | **Hard rule — not a patch, not a fill**: this regenerates a native deck through the selected Default or Quick SVG → PPTX runtime. It does **not** edit the source file in place, and it is **not** [`template-fill-pptx`](../template-fill-pptx.md) (which clones source slides and replaces text). It also does not parse an arbitrary third-party template for text-only substitution (the rejected #53 direction) — it builds every page from scratch. |
| 32 | |
| 33 | **Distinct from mirror templates**: `replication_mode: mirror` ([`executor-structured.md`](../../references/executor-structured.md) §1.1) keeps layout + visuals verbatim and edits text. Beautify is the inverse — content verbatim, layout redone, identity inherited. |
| 34 | |
| 35 | **When this profile is wrong — re-architecture belongs to ordinary Generate**: this profile preserves the source's page count and page order 1:1. It is for "keep this deck, just lay it out better". When the user instead wants the original page breakdown reconsidered — merge / split / reorder pages, re-outline the structure, build a *better deck* from the same content rather than a prettier version of the same pages — do not activate this profile. This includes re-pagination for fit: "keep every word but split a crowded page so it reads better" changes page count. Convert the deck with [`ppt_to_md`](../../scripts/source_to_md/ppt_to_md.py) and use ordinary Quick when Quick was explicit, otherwise the Default main pipeline. The deciding question: is the source's page split information to preserve, or just the previous author's structure to improve? Preserve → activate this profile; improve → ordinary Generate in the selected runtime. |
| 36 | |
| 37 | --- |
| 38 | |
| 39 | ## 2. Inputs |
| 40 | |
| 41 | 🚧 **GATE**: the user has provided: |
| 42 | |
| 43 | | Input | Required | Notes | |
| 44 | |---|---:|---| |
| 45 | | Source PPTX | Yes | The deck to re-lay-out | |
| 46 | | Beautify scope | Optional | Density / emphasis preference — never content rewrites, and never page drops (v1 is strict 1:1) | |
| 47 | |
| 48 | --- |
| 49 | |
| 50 | ## 3. Create the Project Workspace |
| 51 | |
| 52 | Match the canvas to the source so 1:1 pages and paste-back align. Determine the source aspect first — before the project exists, run `beautify_identity.py <source.pptx>` to **stdout** and read `canvas.aspect` (the formal standard intake bundle is written in Step 4, after `init`) — then `init` with the matching format: |
| 53 | |
| 54 | | Source aspect | Format | |
| 55 | |---|---| |
| 56 | | ≈1.778 (16:9) | `ppt169` | |
| 57 | | ≈1.333 (4:3) | `ppt43` | |
| 58 | | other | nearest format in [`canvas-formats.md`](../../references/canvas-formats.md); record the source pixel size in the spec | |
| 59 | |
| 60 | ```bash |
| 61 | # Default runtime: |
| 62 | python3 ${SKILL_DIR}/scripts/project_manager.py init <project_name> --format <format> |
| 63 | |
| 64 | # Quick runtime instead: |
| 65 | python3 ${SKILL_DIR}/scripts/project_manager.py init <project_name> --format <format> --quick-generate |
| 66 | |
| 67 | # Both runtimes then import once: |
| 68 | python3 ${SKILL_DIR}/scripts/project_manager.py import-sources <project_path> <source.pptx> |
| 69 | ``` |
| 70 | |
| 71 | Run exactly one `init` command: the Quick form only when Quick was selected. |
| 72 | |
| 73 | --- |
| 74 | |
| 75 | ## 4. Extract Identity and Data; Assemble Inventory |
| 76 | |
| 77 | Use the standard PPTX intake bundle from Step 3. `project_manager.py import-sources` already writes it under `analysis/` for PPTX-family inputs. If the bundle is missing because the project predates this workflow, generate it once: |
| 78 | |
| 79 | ```bash |
| 80 | python3 ${SKILL_DIR}/scripts/pptx_intake.py <project_path>/sources/<source.pptx> -o <project_path>/analysis |
| 81 | ``` |
| 82 | |
| 83 | **Content + images — already produced by Step 3.** `import-sources` ran `ppt_to_md` on the deck, so the **frozen content contract** is `sources/<stem>.md` (one source slide per block, in order). If the source deck contains pictures, they are already propagated to `images/` with per-slide binding in `images/image_manifest.json` (`occurrences[].slide_index`). Do **not** re-run `ppt_to_md` — it would duplicate the conversion and write images to `analysis/<stem>_files/` instead of `images/`. |
| 84 | |
| 85 | **Visual identity (theme + observed sample + canvas)**: read `<project_path>/analysis/<stem>.identity.json` (intake prefixes per-deck artifacts by source-file stem). |
| 86 | |
| 87 | | Field | Use | |
| 88 | |---|---| |
| 89 | | `theme.palette.background` / `text` / `primary` / `accent1..6` | the deck's *declared* colors | |
| 90 | | `theme.fonts.title` / `body` (`latin` / `ea` / `cs`; `scripts` maps `Hans` / `Hant` / `Jpan` / `Hang` supplemental faces) | the deck's *declared* fonts; use the matching script when `ea` is empty | |
| 91 | | `theme.sizes.title` / `body` (pt) | the deck's *declared* placeholder sizes (master `txStyles`) — the size a run inherits when it sets no explicit `sz`; `body` is the **level-1** default (coarsest, commonly over-reads) | |
| 92 | | `theme.sizes.body_levels` (pt list) | the full master `bodyStyle` ramp (lvl1..lvl9, e.g. `[32, 28, 24, 20, …]`) — **reference context** so you can read a deeper level than the over-reading level-1, not an auto-seed | |
| 93 | | `observed.colors` / `observed.fonts` (`latin` / `ea`, frequency-ranked) | a usage **sample / frequency hint** — run-level fonts + explicit `srgbClr` fills across slides | |
| 94 | | `observed.sizes_pt` (pt, frequency-ranked) | a usage **sample** of run-level explicit point sizes — the **size the deck actually renders at** when it overrides the placeholder default; the source for the Step 5 `body_size` recommendation | |
| 95 | | `layout_sizes_pt` (pt, frequency-ranked) | **reference fact only**, NOT an auto-seed — the level-1 sizes that the in-use slide layouts' body placeholders declare. Usually empty (decks rely on runs / master) and ambiguous when present; use it as a hint when judging the body size, never as the authoritative seed | |
| 96 | | `canvas.aspect` | drives the Step 3 format choice | |
| 97 | |
| 98 | > Note: `theme` is what the deck declares; `observed` is a frequency sample of run-level overrides (not a complete style resolution — it misses `schemeClr` and master/layout inheritance, and counts chart/gradient fills). A hand-edited deck can diverge from `theme` — Step 5 recommends which to inherit and the user confirms. |
| 99 | |
| 100 | **Chart + table data (for regeneration)**: read `<project_path>/analysis/<stem>.slide_library.json`. It contains the source chart and table *data* so they can be redrawn natively in the inherited style: |
| 101 | |
| 102 | | `<stem>.slide_library.json` field | Use | |
| 103 | |---|---| |
| 104 | | `slides[].charts[]` (`chart_type` / `categories` / `series[].values`) | regenerate as a native SVG chart; use the §VII catalog key only when recall selects a real reference, otherwise plan the custom chart in §IX | |
| 105 | | `slides[].tables[]` (`row_count` / `column_count` / cell text) | regenerate as a native SVG table | |
| 106 | |
| 107 | **Hard rule — regenerate visuals, do not carry them over**: charts / tables / images are rebuilt from their data in the inherited style, never spliced in byte-for-byte. This keeps the deck style-consistent and natively editable. **Data values are frozen** (categories / series / cell text / numbers unchanged); only their rendering is the deck's own. Pictures (`ppt_to_md`-extracted files) are reused but re-laid-out — position / crop / size follow the new layout, not the source slot. A user who wants an original element verbatim copies it across themselves. |
| 108 | |
| 109 | **Optional source-SVG visual reference**: when the source deck has complex vector decoration, distinctive page chrome, or a visual language that cannot be captured by `<stem>.identity.json` colors/fonts alone, create a read-only SVG reference package under `analysis/`. This is for understanding style only; it is not a carry-over asset path. |
| 110 | |
| 111 | ```bash |
| 112 | python3 ${SKILL_DIR}/scripts/pptx_to_svg.py <project_path>/sources/<source.pptx> -o <project_path>/analysis/source_svg_import |
| 113 | python3 ${SKILL_DIR}/scripts/extract_svg_assets.py <project_path>/analysis/source_svg_import/svg-flat \ |
| 114 | --icons-dir <project_path>/analysis/source_svg_import/icons \ |
| 115 | --icon-namespace imported \ |
| 116 | --inplace --id-prefix source_flat --min-decoration-bytes 3000 --clean-stale |
| 117 | ``` |
| 118 | |
| 119 | Use the cleaned `analysis/source_svg_import/svg-flat/slide_*.svg` files plus `analysis/source_svg_import/svg-flat_vector_asset_inventory.json` in Step 5/Strategist. Extraction is required for inspection when complex vectors exist: it creates a candidate pool the AI can index, compare, and judge for possible reuse without reading every heavy vector body. Read an individual `analysis/source_svg_import/icons/imported/*.svg` only when the cleaned page and inventory indicate that candidate may be promoted or materially affects the style decision. These candidates are analysis artifacts first, not automatic output assets. |
| 120 | |
| 121 | Default: do **not** copy these candidates into the project `icons/`, do **not** list them as reusable output assets, and do **not** preserve original vector decorations byte-for-byte in the beautified deck. The Executor still regenerates fresh native shapes from the confirmed plan. |
| 122 | |
| 123 | Optional reuse gate: if a candidate is a non-text brand/logo/motif/decorative asset that should survive the beautification, list it in the Step 5 plan with source slide, candidate filename, intended reuse, and dependency notes from the inventory. Wait for user confirmation. Only confirmed candidates may be promoted into `<project_path>/icons/imported/` and referenced from generated SVGs with `<use data-icon="imported/<name>"/>`; `finalize_svg.py` then re-inlines them as native shapes. Never promote text-bearing groups, charts/tables, source page layouts, or dense slide composites as reusable assets. |
| 124 | |
| 125 | **Assemble the inventory** — the deterministic join into one per-slide ledger, `analysis/beautify_inventory.json`, the contract Step 5 confirms and Step 7 verifies against: |
| 126 | |
| 127 | ```bash |
| 128 | python3 ${SKILL_DIR}/scripts/beautify_inventory.py <project_path>/analysis/<stem>.slide_library.json \ |
| 129 | --images <project_path>/images/image_manifest.json -o <project_path>/analysis/beautify_inventory.json |
| 130 | ``` |
| 131 | |
| 132 | If `images/image_manifest.json` does not exist because the source deck has no extracted pictures, omit `--images`. The script joins per slide: `text_blocks` (slot text + geometry), `tables` (cell grid), `charts` (categories + series values), `diagrams` (SmartArt nodes + hierarchy/connections + source layout), and `images` (bound via `image_manifest` `occurrences[].slide_index`, with geometry / `usage_count`). The **frozen source values are inlined**, so the inventory is a self-contained contract, not a pointer back to `slide_library.json`. It emits `ignored` and `needs_confirmation` as **empty arrays** — fill them with judgment before Step 5: |
| 133 | |
| 134 | | Field | Fill with | |
| 135 | |---|---| |
| 136 | | `ignored` | hidden slides / shapes, master-only text, image crop / opacity / rotation / mask (not captured upstream) | |
| 137 | | `needs_confirmation` | unreadable SmartArt data; combo / dual-axis / waterfall charts; merged-cell or multi-header tables; density-outlier pages — **either** overcrowded **or** near-empty / title-only | |
| 138 | |
| 139 | **SmartArt output boundary**: Preserve its extracted wording and semantic relationships, then redraw it through SVG as ordinary editable PowerPoint shapes. Do not attempt to regenerate a native SmartArt object or reuse persisted-drawing text as a second content source. |
| 140 | |
| 141 | ```markdown |
| 142 | ## ✅ Extraction Complete |
| 143 | |
| 144 | - [x] `sources/<stem>.md` (from Step 3) holds every source slide's text, in order; extracted pictures, if any, are in `images/` + `images/image_manifest.json` |
| 145 | - [x] `analysis/<stem>.identity.json` has theme + observed identity + canvas aspect |
| 146 | - [x] `analysis/<stem>.slide_library.json` holds chart + table data and SmartArt semantic structure for regeneration |
| 147 | - [x] `analysis/source_profile.json` (multi-deck index) summarizes the source facts in its `decks[]` entry |
| 148 | - [x] `analysis/beautify_inventory.json` ledgers per-slide text / images / data + ignored + needs-confirmation |
| 149 | - [ ] **Next**: Step 5 — resolve Beautify decisions in the selected runtime |
| 150 | ``` |
| 151 | |
| 152 | --- |
| 153 | |
| 154 | ## 5. Beautify Decisions |
| 155 | |
| 156 | ### Quick branch |
| 157 | |
| 158 | When Quick was selected, do not run the Default confirmation flow below. Apply |
| 159 | the same inventory interpretation, source-identity judgment, and body-size |
| 160 | method documented in this section, but make the decisions directly in the |
| 161 | active context. Explicit user requirements remain authoritative; otherwise use |
| 162 | the source identity as the default. Resolve `ignored` and `needs_confirmation` |
| 163 | without creating a confirmation payload, Design Spec, lock, or substitute |
| 164 | plan. If a flagged complex object cannot be regenerated without losing frozen |
| 165 | facts, stop as a hard prerequisite instead of simplifying it. Then continue to |
| 166 | the Quick branch in §6. |
| 167 | |
| 168 | ### Default branch — Recommend & Confirm |
| 169 | |
| 170 | ⛔ **BLOCKING**: the scope is not hard-coded — same spirit as the Strategist confirmation stage. Recommend each item below from what the deck actually contains (the Step 4 inventory), present the plan, and **wait for the user to confirm or adjust** before writing any spec. Use Generate Step 4's selected surface for the full visual confirmation; keep the structural-scope decisions in chat. Values confirmed through either channel are honored identically. |
| 171 | |
| 172 | This step has two halves: |
| 173 | - **Visual re-confirm via the selected confirmation surface** — the **full** Step 4 field set (below), seeded from the source so every targeted-confirmation field (canvas, mode, visual style, palette, icons, typography incl. body baseline, image strategy, generation mode) is **pre-filled with the inherited / source-derived default and left editable**. Beautify *recommends* keeping the source's identity, but never removes the user's place to override any field — you may choose not to change a value, but you must not deny the place to change it. This is also where the deck's text size is confirmed: `<stem>.identity.json` now carries size hints — `observed.sizes_pt` (the point sizes the deck actually renders at) and `theme.sizes` (the declared placeholder defaults) — so the `body_size` recommendation **follows the source's own font size** rather than a blind canvas default; the user still confirms or overrides it here. |
| 174 | - **Structural scope** — the inventory-driven list decisions below (ignored, reuse, needs-confirmation, verification level) stay in **chat**; they have no confirm-UI widget. |
| 175 | |
| 176 | | Plan item | Recommend from | Default lean | |
| 177 | |---|---|---| |
| 178 | | Identity source | `<stem>.identity.json` `theme` vs `observed` | present **both as color / typography candidates in the selected confirmation surface** so the user picks the one that looks right (theme first when the deck is theme-driven; observed first when slides override heavily) — recommend a default ordering and say why | |
| 179 | | Preserve scope | inventory `text_blocks` / `images` / `charts` / `tables` / `diagrams` | all text verbatim; data values and SmartArt relationships frozen; pictures reused | |
| 180 | | Ignored | inventory `ignored` | name them so the user sees what drops (hidden / master-only text / image crop / rotation) | |
| 181 | | Needs confirmation | inventory `needs_confirmation` | flag complex charts + overcrowded pages explicitly; ask how to handle | |
| 182 | | Verification level | deck size / risk | recommend the Step 7 per-page checks; user sets strictness | |
| 183 | |
| 184 | **Hard rule — content is frozen, not the scope decisions**: text strings and chart/table/table-cell data values are non-negotiable (verbatim). *Which* identity to inherit, what to ignore, and how to treat flagged items are recommend-then-confirm, never silently decided. |
| 185 | |
| 186 | **Recommend honestly — name the v1 ceiling**: |
| 187 | |
| 188 | | Item | What v1 delivers | |
| 189 | |---|---| |
| 190 | | Overcrowded source page | layout / hierarchy / whitespace improve **within the page as-is** — v1 does **not** relieve information overload (that needs re-pagination / rewrite, deferred). Flag such pages; the user may accept or note them for manual split | |
| 191 | | Paste-back into the original | regenerated elements share the inherited palette + fonts, so they **blend visually** when pasted. v1 does **not** guarantee a seamless coordinate-level drop-in (slide coordinates, master placeholders, font availability are the original deck's, not ours) | |
| 192 | | Complex charts / merged-cell tables | best-effort from the captured data; combo / dual-axis / waterfall lose the un-captured plots — flagged for the user | |
| 193 | |
| 194 | **Visual re-confirm — full confirmation seeded from the source**: |
| 195 | |
| 196 | Apply [`generate-pptx`](../generate-pptx.md) Step 4's surface decision first. In |
| 197 | the default UI branch, use |
| 198 | `<project_path>/confirm_ui/recommendations.stage1.json` and |
| 199 | `recommendations.stage2.json` at the same two handoffs and launch the same |
| 200 | confirm server. In the chat branch, present the same two stages and fields without launching the server or requiring |
| 201 | `result.json`. The active, unconfirmed UI stage may be overwritten for a |
| 202 | requested regeneration; normal progression leaves confirmed earlier stages |
| 203 | intact. Do **not** hide fields: seed **every** targeted-confirmation field with |
| 204 | the inherited / source-derived default so the user sees the recommendation and |
| 205 | keeps the place to change it. Schema → |
| 206 | [`scripts/docs/confirm_ui.md`](../../scripts/docs/confirm_ui.md). |
| 207 | |
| 208 | The typography rows below show the non-English shape; omit `english` for an English source. |
| 209 | |
| 210 | ```json |
| 211 | { |
| 212 | "primary_language": "<source main language>", |
| 213 | "recommend": { |
| 214 | "canvas": "<step3-canvas-id>", |
| 215 | "mode": "briefing", |
| 216 | "visual_style": "<closest visual-style id to the source look>", |
| 217 | "icons": "<sensible default icon library>", |
| 218 | "image_usage": ["provided"] |
| 219 | }, |
| 220 | "page_count": { "value": "<source-slide-count>" }, |
| 221 | "audience": { "value": "<carry over from the deck's apparent audience, or state a concrete provisional audience>" }, |
| 222 | "communication_intent": { "value": "<open prose inferred from the deck; preserve multiple purposes and their relationship>" }, |
| 223 | "audience_outcome": { "value": "<what the audience should know, understand, decide, or do>" }, |
| 224 | "core_message": { "value": "<the deck-wide claim / ask / action already present in the source>" }, |
| 225 | "delivery_context": { "value": "<primary presenter-led / reader-led / hybrid / recorded; hybrid names its lead and secondary use; occasion if inferable>" }, |
| 226 | "artifact_afterlife": { "value": "<review / approval / archive / hand-off / reuse / none planned>" }, |
| 227 | "content_divergence": { "value": "keep source wording and page structure verbatim", "locked": true }, |
| 228 | "color": { "selected": 0, "candidates": [ |
| 229 | { "name_zh": "复刻源 PPT(推荐)", "name_en": "Source replica (recommended)", "name_ja": "元PPTを再現(推奨)", "palette": { "background": "#...", "secondary_bg": "#...", "primary": "#...", "accent": "#...", "secondary_accent": "#...", "body_text": "#..." } }, |
| 230 | { "name_zh": "实际用色(observed)", "name_en": "Observed palette", "name_ja": "実際の使用色(observed)", "palette": { "background": "#...", "secondary_bg": "#...", "primary": "#...", "accent": "#...", "secondary_accent": "#...", "body_text": "#..." } }, |
| 231 | { "name_zh": "备选配色 A", "name_en": "Alternative palette A", "name_ja": "代替配色A", "palette": { "background": "#...", "secondary_bg": "#...", "primary": "#...", "accent": "#...", "secondary_accent": "#...", "body_text": "#..." } } |
| 232 | ] }, |
| 233 | "typography": { "selected": 0, "candidates": [ |
| 234 | { "name_zh": "复刻源 PPT(推荐)", "name_en": "Source replica (recommended)", "name_ja": "元PPTを再現(推奨)", "heading": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body_size": <dominant observed.sizes_pt × 4/3, as px> }, |
| 235 | { "name_zh": "备选字体 A", "name_en": "Alternative pairing A", "name_ja": "代替ペアリングA", "heading": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body_size": <canvas-appropriate baseline> }, |
| 236 | { "name_zh": "备选字体 B", "name_en": "Alternative pairing B", "name_ja": "代替ペアリングB", "heading": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body": { "primary": "...", "english": "...", "css": "<PPT-safe stack>" }, "body_size": <canvas-appropriate baseline> } |
| 237 | ] } |
| 238 | } |
| 239 | ``` |
| 240 | |
| 241 | - **Recommend keep, allow override**: pre-fill the open communication contract from the source's apparent audience and purpose, preserving composite purposes in prose; also pre-fill canvas / mode / visual style / icons / image strategy with the source-faithful default (canvas = Step 3 format, mode = `briefing`, image_usage = `provided`). The purpose examples are hints, never a `primary_job` selector. Beautify's only true non-choices are frozen text and strict 1:1 page count (changing either means routing to the main pipeline). Seed `content_divergence` to verbatim preservation with `locked: true`; the Confirm UI renders it read-only and the server restores the locked value on every staged submit. A request to reshape wording or page structure routes to the main pipeline instead of weakening this profile. |
| 242 | - **Our recommendation is the pre-selected default = the source replica**: for color and typography, author **several candidates** like the from-scratch flow. The pre-selected default (`selected: 0`, the first card) is what beautify recommends — the candidate that **best replicates the source deck's style** (the truest reading of `theme` / `observed`). Replicate-by-default. |
| 243 | - **Judge the other alternatives exactly as the from-scratch flow does — fonts as much as colors**: don't invent a beautify-specific rule. Author each non-replica candidate with the **same content-driven judgment the Strategist uses when generating from scratch** (color §e, typography §g), applied to the material this project provides — the source document's content and subject, the company's own theme colors, and any brand signal. Pick the palette **and** the font pairing by what fits *this* deck's content; fonts are chosen by content fit, not just defaulted to a safe face. Reach **≥3 meaningful candidates total**; reasonable font repetition is non-blocking, so never manufacture a different pairing just to satisfy a quota. `primary` always follows the source deck's main language; include `english` only when that language is not English. |
| 244 | - **`body_size` is the load-bearing field, and the replica follows the source's own size**: seed the replica candidate's `body_size` from the source's actual body size — take the dominant `observed.sizes_pt` value (the most frequent run-level size, the **body proxy**) and **convert it to px (`× 4/3`)** before seeding, since the system is px-only and the source measures in pt: a source 20pt body becomes `26.67`px, so the replica renders at the source's true size (seeding the bare `20` as px would shrink it ~25% — the pt-as-px trap). Whichever source value you land on below (observed mode, or `theme.sizes.body`) gets the same `× 4/3` conversion. The confirm page writes that px to `result.json` (`body_size`); the chat branch retains the same px in its visible final summary. Neither path performs another conversion or adds `body_size_pt` provenance (pt never enters the contract). The "most frequent = body" read is a proxy, not a guarantee — `observed.sizes_pt` counts every explicit run size (titles, captions, footnotes, chart/label text included, no placeholder-type resolution), so a deck dense with small labels can let a caption size outrank true body; cross-check the proxy against the page's actual body blocks and the sanity range below before trusting it, and prefer the size the body paragraphs visibly render at over the raw mode when the two disagree. Fall back to `theme.sizes.body` (the declared placeholder size) when `observed.sizes_pt` is empty, and to a PPT consumption-mode baseline (`text` 20 / `balanced` 24 / `presentation` 32 px — one fixed value per mode) only when neither is present. Note `theme.sizes.body` is the master `bodyStyle` **level-1 declared default** — a coarse value that commonly **over-reads** the real body density (decks often render body at a deeper outline level or override it smaller), so when you land on this fallback treat it as an upper-ish guess and run it through the sanity check below, never as a precise body size. `theme.sizes.body_levels` and `layout_sizes_pt` are **reference context, not extra fallback tiers**: consult them to judge a saner body value when the deck is theme-driven (`observed` empty) — e.g. a deeper `body_levels` entry or a `layout_sizes_pt` hint may read truer than level-1 — but do not auto-seed from them; the seed chain stays `observed → theme.sizes.body → consumption-mode baseline`, and a theme-driven deck whose body size genuinely can't be pinned cleanly is exactly the case the sanity check is for. The canvas hint stays a **sanity range**, not the seed: if the source's own size lands far outside it (a dense source doc reads tiny on a projection canvas), surface that to the user rather than silently snapping — the replica recommendation is the source's size, the user confirms or overrides. Non-replica alternatives may use the consumption-mode baseline. This is what prevents the deck from exporting at an unintentionally small size while still honoring the source. |
| 245 | |
| 246 | Run Generate Step 4's confirmation orchestration unchanged, including its |
| 247 | pre-launch surface decision and the UI branch's pre-wait Stage-1 chat handoff. |
| 248 | |
| 249 | In the UI branch, after the final wait returns, read |
| 250 | `<project_path>/confirm_ui/result.json` exactly once. In the chat or delegated |
| 251 | branch, retain the visible final summary instead and require no UI result. After |
| 252 | any launched UI path, run `--shutdown` before Step 6; do not assume `5050`. |
| 253 | |
| 254 | On confirmation, enter [`generate-pptx`](../generate-pptx.md) Step 4 as Strategist with the plan pre-resolved. The two beautify invariants always hold: the content-faithful clause ([`strategist.md`](../../references/strategist.md) §d Layer 1) and page count = source slide count (strict 1:1). Write the retained final confirmation state completely into `design_spec.md` — `mode` (recommended `briefing`), canvas, `visual_style`, color (e) + typography (g) incl. `body_size` (the reviewed values; skip both recommendation flows) — honoring whatever the user kept or overrode. Do not reopen UI evidence afterward. §VII contains only `Page | Template | Usage` rows for selected catalog references; unmatched chart/table plans stay in their §IX page blocks. §VIII contains source pictures for re-layout. |
| 255 | |
| 256 | **Hard rule — §IX is verbatim and 1:1**: each source slide becomes exactly one page, in source order, its text transcribed word-for-word from `sources/<stem>.md`. Do not merge, split, drop, or rewrite. Complete and audit `design_spec.md` first, then author `spec_lock.md` from that Design Spec plus the source/page/template context per `strategist.md` §6 before handing off to the Executor. |
| 257 | |
| 258 | --- |
| 259 | |
| 260 | ## 6. Author + Export |
| 261 | |
| 262 | **Quick**: follow [`quick-generate.md`](./quick-generate.md) §3–4. The |
| 263 | Beautify inventory is the exact page roster and frozen-content contract; keep |
| 264 | its source order, hand-author every page, run the lockless Quick final checker, |
| 265 | and export with `--quick-generate`. Do not run Confirm UI, write a Design Spec |
| 266 | or lock, run the Default first-page gate, or call `finalize_svg.py`. |
| 267 | |
| 268 | **Default**: run the standard pipeline as follows. |
| 269 | |
| 270 | Run the standard pipeline ([`generate-pptx`](../generate-pptx.md) Steps 6–7). The Executor re-lays-out each page — hierarchy, spacing, alignment, page rhythm — using the semantic anchors in `spec_lock.md` plus current page/source/template context; valid page-local colors, gradients, effects, and export-safe display faces need not be added to the lock. It regenerates charts / tables as native SVG from the extracted data and re-lays-out the source pictures. |
| 271 | |
| 272 | Follow [`generate-pptx`](../generate-pptx.md) Step 7 for the canonical serial |
| 273 | post-processing commands, gates, success criteria, and export artifacts. |
| 274 | |
| 275 | --- |
| 276 | |
| 277 | ## 7. Validate Output |
| 278 | |
| 279 | ```bash |
| 280 | python3 ${SKILL_DIR}/scripts/source_to_md/ppt_to_md.py <project_path>/exports/<output.pptx> |
| 281 | ``` |
| 282 | |
| 283 | | Check | Expected | |
| 284 | |---|---| |
| 285 | | Text fidelity | every source text string appears in the output, unaltered | |
| 286 | | Data fidelity | chart categories / series / table cells match the source exactly | |
| 287 | | Page count | output slide count equals the source slide count | |
| 288 | | Regenerated visuals | charts / tables are native SVG re-themed to the inherited palette | |
| 289 | | Identity | generated text / shapes use only `<stem>.identity.json` colors + fonts | |
| 290 | | Paste-back | copying a beautified element into the original deck looks native | |
| 291 | |
| 292 | ```markdown |
| 293 | ## ✅ Beautify Complete |
| 294 | |
| 295 | - [x] Content + data values verbatim (read-back Markdown matches the source) |
| 296 | - [x] 1:1 page count preserved |
| 297 | - [x] Source-derived or explicitly overridden colors + fonts applied consistently |
| 298 | - [x] Charts / tables regenerated as native SVG in the inherited style |
| 299 | - [x] Native PPTX exported to `exports/` |
| 300 | ``` |
| 301 | |
| 302 | --- |
| 303 | |
| 304 | ## Current Boundary |
| 305 | |
| 306 | | Capability | Status | |
| 307 | |---|---| |
| 308 | | Re-layout with verbatim text | Supported | |
| 309 | | Inherit source palette / fonts as truth | Supported | |
| 310 | | Strict 1:1 page mapping | Supported | |
| 311 | | Regenerate charts / tables as native SVG from extracted data | Supported | |
| 312 | | Re-lay-out source pictures | Supported | |
| 313 | | Re-pagination (split dense / merge sparse) | Not in v1 | |
| 314 | | Carry source charts / tables / images over byte-for-byte | Out of scope — user copies originals manually if wanted | |
| 315 | | Free visual-style application / cleanup deviating from source identity | Not in v1 | |
| 316 | | Batch / multi-deck beautification | Not in v1 | |
| 317 |