consulting-deck-design · git:20261008.3f4aefe · 2026-10-08 · sha256 c4555c89017dd260

consulting-deck-design git:20261008.3f4aefeA

Immutable. This exact content never changes and is served at /api/v1/blob/c4555c89017dd260.

---
name: consulting-deck-design
description: Use when generating a dense, professional consulting/government-style slide deck with @office-kit/pptx (McKinsey/BCG/METI-council-caliber — cover, section dividers, executive summary, exhibits, appendix). Invoked when the user asks for a "McKinsey-style", "consulting-grade", or "board deck" presentation, or says the output looks "too generic" / "too much like a template" / "still too simple / thin compared to the real thing". Covers the visual design system, the chart-authoring pitfalls that make output look amateurish, and the verification workflow — not just "use gradients".
---

# Consulting-grade deck design with @office-kit/pptx

A deck that is schema-valid and opens without repair is a _correct_ deck. It is not
automatically a deck that reads as real consulting/government work. The gap between
"technically fine slide deck" and "looks like it came out of a real engagement" is
almost entirely in restraint: fewer decorative flourishes, fewer colors, more
whitespace, and text that states a conclusion instead of a topic — **and** in the
density of substantiation per exhibit (analysis columns, footnotes, superscript
citations) that a first pass tends to skip.

This skill is written from hands-on comparison against two real McKinsey
deliverables:

- **Reference A** — a Japanese METI advisory-council submission (cover, ~10
  exhibits, appendix). Terse, internal-working-deck register: minimal chrome, no
  rule under the headline, action-title-only.
- **Reference B** — a Japanese-language, 68-page public COVID-19 client briefing.
  Richer, external-publication register: rule-under-headline as the default,
  serif headlines, a letter-prefixed "governing thought" convention, four-column
  exhibits, pull-quotes, chevron timelines, and a numbered TOC spine reused per
  section.

Treat every rule below as "here's what we saw break (or land) when compared side by
side with the real thing," not a style preference. Where the two references
disagree (rule-under-headline being the clearest case), the section below says so
explicitly and gives a decision rule instead of picking one silently.

## Before you start: get a reference if you can

If the user has (or can share) an actual example of the target firm's / client's
deck, **read it first** — page through every slide. A generic "corporate blue +
gold" palette invented from scratch reads as generic-corporate, not
McKinsey-specific. Real firm decks have surprisingly little color (near-monochrome
brand-blue family + semantic red/green), and surprisingly little decorative
flourish. If you don't have a reference, default to the palette in this skill
rather than picking your own "premium" colors — gold/orange reads as generic
luxury branding, not strategy consulting.

## Visual language

### Palette

Deep navy → bright blue, plus one teal accent. No gold. Semantic red (risk /
negative) and green (positive) are fine even inside an otherwise blue-monochrome
palette — real decks use them for exactly that purpose, but **sparingly**: across
68 pages of Reference B, red appears on exactly two slides (a legal-disclaimer
line and one "increasing" trend arrow) — it is not a general-purpose "bad news"
data color, it is reserved for the single most alarming signal on the page.

```
NAVY_DARK    #0A1628   — darkest gradient stop, divider/cover/TOC background
NAVY         #132A4D   — solid navy for boxes (org-chart nodes, roadmap headers)
BLUE         #1E4FFF   — primary accent, gradient bright stop, "highlighted" data
TEAL         #00B8D9   — secondary accent
ACCENT_LIGHT #5B9EFF   — tertiary tint for a 4th KPI card / chart series
SLATE        #7A8699   — neutral / "current state" / de-emphasized bars
PANEL_GRAY   #E8E8E8   — light-gray secondary surface (see below)
RED          #D64545   — reserved for risk/negative data points and disclaimers —
                          use on at most one exhibit per section, not as a
                          recurring category color
GREEN        #2E9E6C   — positive, recommended, upside
INK          #111827   — headline / body text (not pure black)
MUTED        #5B6673   — captions, footers, eyebrow labels
```

### Three background modes, used deliberately

Both references converge on exactly three slide-background treatments, each with a
distinct job. Don't invent a fourth (e.g. a mid-blue panel) — it reads as
decoration rather than information hierarchy.

- **White** — the default surface for analytical/exhibit slides (charts, tables).
- **Light gray** (`PANEL_GRAY`, distinctly lighter than white but clearly not
  white) — a secondary "commentary" surface: right-margin "so what" columns,
  contrast callout boxes, a full-panel implications sidebar. Never the primary
  background of a whole deck section — it marks "supporting", not "main".
- **Dark navy** (`NAVY_DARK`/`NAVY`) — cover, section dividers, the TOC/agenda
  spine, "governing thought" framework slides, and (occasionally) a full
  commentary sidebar instead of gray, when the slide wants more visual weight on
  the takeaway than on the exhibit.

A two-panel slide (e.g. white exhibit + gray or navy sidebar) usually needs **no
rule line at the seam at all** — the hard color-block edge already reads as a
divider. Save rule lines for dividing regions that share the same background
(see below).

### Cover and section-divider slides: gradient, not flat fill

Flat navy reads as a corporate template. A real cover uses a diagonal navy→blue
gradient across the full slide. In @office-kit/pptx:

```ts
const bg = addSlideShape(slide, {
  preset: 'rect',
  x: inches(0),
  y: inches(0),
  w: PAGE_W,
  h: PAGE_H,
});
setShapeGradientFill(bg, {
  stops: [
    { offset: 0, color: NAVY_DARK },
    { offset: 1, color: BLUE },
  ],
  angleDeg: 15, // shallow diagonal — the bright stop concentrates toward the right
});
```

Layer white/light-blue title text on top, generous vertical whitespace (the title
block sits roughly at the vertical center, not crammed to the top).

### Headlines: bold weight + size for hierarchy, and (usually) a rule underneath

Both references use a visibly different, heavier headline treatment than the
sans-serif body/bullets/table text beneath. `setShapeRunFormat`'s `font` field
only sets the _Latin_ typeface (`<a:latin>`); Japanese glyphs render through a
separate East Asian typeface (`<a:ea>`), settable per-run via the `fontEastAsian`
field (a third slot, `fontComplexScript` / `<a:cs>`, covers Arabic / Hebrew /
Thai and is irrelevant to a Japanese deck):

```ts
setShapeRunFormat(headlineBox, 0, 0, {
  font: 'Georgia', // Latin glyphs (ASCII digits, English loanwords) — serif is fine here
  fontEastAsian: 'Meiryo UI', // CJK glyphs
  bold: true,
  size: 19,
  color: INK,
});
// Body/bullets/table text stays a lighter weight, same typeface:
setShapeRunFormat(bodyBox, i, 0, { font: 'Arial', fontEastAsian: 'Meiryo UI', size: 13 });
```

**Don't use a serif CJK typeface (e.g. 游明朝/Yu Mincho) for headlines, even
though the reference decks visually appear to use one.** A first pass tried
exactly that — it matched the reference decks' look in a LibreOffice-rendered
preview, but read as visibly wrong once the user opened the actual file outside
the preview pipeline. Font substitution for CJK serif faces is inconsistent
across presentation apps and OS installations in a way Latin serif faces aren't;
`Meiryo UI` is the safe, universally-available choice. Carry the headline/body
typographic hierarchy through **size and weight only** — a bigger, bolder
`fontEastAsian: 'Meiryo UI'` headline next to a smaller, regular-weight
`fontEastAsian: 'Meiryo UI'` body reads as distinctly "headline" without the
CJK-serif risk. Latin-only display words (a "Contents" TOC spine word, an
English loanword like "Resolve" used as a chapter name) can still use a Latin
serif (`font: 'Georgia'`) safely, since that risk is CJK-specific.

**Rule-under-headline — decision rule.** Reference A (terse internal deck) never
draws a rule under the title. Reference B (richer external deck) draws a
full-width thin horizontal rule directly beneath the headline on nearly every
content slide — it is the default there, not an exception. For a general-purpose
"McKinsey-caliber" deck, **default to drawing the rule** (`addSlideLine` full
content width, `LINE` color, ~0.75pt) — it's the more consistent convention across
the larger sample and it gives long decks a stronger sense of structure. Drop it
only for the terser register the user explicitly asked for, or on slides where a
hard color-block seam already does the dividing job (two-panel layouts, full-bleed
navy framework slides).

**Letter-prefixed "governing thought" headlines.** For a slide making one load-
bearing claim (the kind of exhibit a reader might photograph out of context),
prefix the headline with a single bold letter + colon in the accent blue,
sequenced A, B, C… across a chapter's exhibits (mirrors the `pointColors` palette
convention, not literal exam grades): `"A: 東南アジア市場は今後5年間、国内の7倍の
ペースで成長する見込み"`. On a white background render the letter in `BLUE`; on a
full-navy background render it the same white/light color as the rest of the
headline (a colored letter loses contrast and reads as an error, not an accent, on
a dark surface — this is a real inconsistency the reference deck itself
resolves that way, not an oversight to "fix"). Reserve the prefix for a chapter's
primary exhibits; supporting/detail slides in between keep a plain headline with
no letter.

If the deck is long enough to need running navigation, keep a small kicker label
above the headline (~9–10pt, gray, regular weight, unbolded) — a quiet wayfinding
aid, not a second headline.

### Numbered TOC / running agenda spine

A distinctive, highly reusable archetype from Reference B: a narrow (~15% width)
white left strip carries a single word (e.g. "Contents") in bold serif, rotated
90° so it reads bottom-to-top like a book spine (`setShapeTextBodyRotationDeg`).
The remaining ~85% is a full-bleed dark-navy field holding one large bold serif
numeral per chapter (`01`, `02`, `03`…), each with a thin rule and a 1–2 line
label beneath it. The **current** chapter's numeral, rule, and label render in
bright accent blue / white; every other chapter renders in muted gray. Reuse this
exact slide once per chapter (only the "active" index changes) — this is the
"running roadmap" convention real long decks use to keep a 60–100-page document
navigable, and it reads as far more deliberate than a single static agenda slide
shown once.

### Left-sidebar "framework" layout

For a slide whose entire point is one short, bold statement plus 3–4 supporting
bullets (e.g. "this strategic pillar," "this technology map"), use a dark
navy-gradient left rail (~28% width) carrying the bold white statement, with the
bullets in the light area to the right. This is a distinct, recognizable layout
from the header+body formula every other slide type uses — real decks reserve it
for framework/thesis slides specifically, not everything.

**Multi-line text formatting gotcha**: if the statement has embedded `\n` line
breaks, each line becomes its own paragraph — `setShapeRunFormat(box, 0, 0, {...})`
only formats paragraph 0. Loop over every paragraph index or the later lines fall
back to the text box's small default style while only the first line looks styled.

### Multi-column exhibits with vertical rule dividers

Reference B's densest, most "real" pages are 3–4 column layouts separated by thin
vertical rule lines (`addSlideLine`, vertical, `LINE` color, ~0.5–0.75pt),
spanning the full content height. Common column contents: a chart flanked by two
text commentary columns; four icon-badge + header + body columns (e.g. a
"5 R's"-style framework); or a bulleted list column beside a pull-quote column.
This is a different device from the single right-margin analysis column already
in this skill (still valid, still the right call for a plain chart-plus-commentary
slide) — reach for the multi-column-with-rules version when a slide has 3+
genuinely parallel blocks to show side by side, not just one exhibit plus one
comment.

### Pull-quote blocks

A quotation callout: a small circular badge (solid `NAVY` fill) containing a
large bold quotation-mark glyph (`"` / `"`, U+201C/U+201D, oversized ~20–24pt,
white or `PANEL_GRAY`), positioned above or beside 1–2 sentences of quoted text,
followed by a bold attribution line introduced with an em-dash
(`— 氏名、肩書き`). Use for a single expert-quote moment per section, not on every
slide.

### Icon strategy (no custom vector art)

Real decks use simple monochrome line-art pictograms (a person, a chart, a
lightbulb, a shield). @office-kit/pptx has no custom-path/freeform-geometry authoring API
and no bundled icon set, so **don't attempt hand-drawn vector icons** — the
practical, reliable substitute is a colored circle or rounded-rect "badge"
(`addSlideShape` `ellipse`/`roundRect`) containing a single safe glyph character,
centered, sized large (~18–24pt). Stick to Latin-1/general-punctuation glyphs —
multi-byte emoji/pictograph ranges are the same CJK-tofu-box risk this skill
already warns about for text, since font substitution in LibreOffice and other presentation apps for
emoji is inconsistent across renderers.

```
growth / increase   ▲ or ↑        decrease / decline     ▼ or ↓
success / on-track  ✓             risk / off-track       ! or ✗
insight / idea      ★             direction / next step  →
process step N      a filled circle badge with the bold numeral itself
quote               " / " (U+201C / U+201D), oversized
```

Badge + glyph + header + body is one composite — `groupShapes` it, same as a KPI
card.

### Chart technique: highlight one, gray the rest

The single most-repeated chart device across Reference B: a bar/column series
where **one** category is the narrative subject (bright `BLUE`) and every other
category is a neutral, de-emphasized fill (`SLATE` or a light gray) — not a
categorical rainbow palette. This is authored the same way the pie/doughnut
per-slice override already in this skill works: `pointColors` is a general
series-level field, not restricted to pie/doughnut —

```ts
series: [
  {
    name: '人口100万人当たりの死者数',
    values,
    pointColors: categories.map((c) => (c === 'スウェーデン' ? BLUE : SLATE)),
  },
];
```

Reserve a full multi-hue categorical palette for charts where every category is
equally the subject (e.g. a segment-share pie); use highlight-one-gray-rest when
the slide's headline names a single subject ("A: スウェーデンは…").

### Small provenance tags

Real exhibits mark themselves "非網羅的" ("non-exhaustive") or "例示"
("illustrative") in a small bordered tag in the corner when the chart/table isn't
meant to be a complete list — a plain bordered rect + 8.5pt text in the corner,
not a big banner. Add this to competitive-landscape maps, case-study callouts,
and anything else that is deliberately a sample rather than an exhaustive list.

## Chart authoring — the mistakes that make output look amateurish

These are the actual defects a first pass produces; each one reads as "AI-generated
template" rather than "hand-built exhibit."

### 1. Pie/doughnut charts need explicit per-slice colors

`varyColors: true` (or @office-kit/pptx's default on pie/doughnut, which already sets it)
only _requests_ that the renderer assign distinct colors per slice. It does not
guarantee every viewer actually cycles through a palette — some render every slice
in the same single color, which makes the chart useless. Always pass explicit
`pointColors` cycling through your accent palette:

```ts
series: [{ ...series[0], pointColors: categories.map((_, i) => PALETTE[i % PALETTE.length]) }];
```

### 2. Every multi-series or pie/doughnut chart needs a visible legend

`ChartSpec.legend` is `undefined` by default (no legend authored at all) — @office-kit/pptx
doesn't add one automatically. Without it, a reader can't tell which color means
which series/category. Add `legend: { position: 'r' }` to any chart with more than
one series, or any pie/doughnut (where "categories" function like series). A
single-series bar/line chart can skip the legend — its category-axis labels already
say what each bar/point is, and a legend there is redundant chrome.

### 3. Never plot two series with mismatched scales on one axis

Revenue in the hundreds and a margin percentage in single digits on the same axis
means the percentage line collapses to a flat line near zero — unreadable.
@office-kit/pptx's `ChartSpec` has no secondary axis. Don't try to fake one. Split into two
independent single-metric charts side by side instead — same slide, same story, each
chart properly scaled.

### 4. Don't overlay hand-drawn annotations on top of a native chart

It's tempting to draw dashed reference lines / inline value labels directly on a
chart (mimicking real decks that mark "2030 (48%)" right on the plot). **Don't try
to compute the plot area's pixel position and overlay shapes on it.** A chart's
internal plot rectangle is inset by however much room its own axis labels, legend,
and title need — that inset is decided by the rendering engine (desktop presentation apps,
LibreOffice and Keynote all differ) and isn't knowable at authoring time. An overlay
aimed at "where category index 3 should be" will drift out of alignment, sometimes
badly (labels landing on top of the y-axis, or off the right edge past the legend).

Instead, put the annotation **beside** the chart, not on it: chart on the left
~68% of the slide width, a right-margin column of 2–4 substantive "so what"
sentences (one per paragraph, a thin colored accent bar to its left) on the
remaining ~28%. This is what both reference decks' own market-growth exhibits
actually do — the "annotations on the chart" look you're copying is itself mostly
a right-margin (or multi-column) text block, not a plot overlay.

## Footnotes and source citations

Real exhibits substantiate every number, and keep two conventions **visually
separate** rather than merging them into one line:

- **Numbered footnotes** (methodology/assumption notes): a small gray numbered
  list ("1.", "2."…) at the bottom of the slide, each tied to a **superscript
  digit** placed inline at the exact claim it qualifies — in a headline, an axis
  label, or mid-bullet (e.g. `"投資回収期間が18ヶ月と最も短く¹"`). Since the
  simple text-authoring API is one run per paragraph (no supported way to mix a
  normal-weight run and a superscript run within a single paragraph), use the
  literal Unicode superscript digit characters (`¹ ² ³` U+00B9/U+00B2/U+00B3,
  `⁴ ⁵ ⁶…` U+2074+) typed directly into the paragraph text — they render as
  normal glyphs in any font, no run-splitting required, and read as true
  superscript footnote markers.
- **Source line**: a separate line beginning `資料:` (or `Source:`), listing
  citations comma-separated. Don't invent per-word hyperlink styling (blue +
  underline on only some words in the line) — that needs multiple differently-
  formatted runs in one paragraph, which the authoring API doesn't support.
  Style the whole line uniformly instead: either plain `MUTED` gray (the more
  common convention — most citation lines in both references are plain, not
  hyperlinked) or, if you want the "clickable source" look, the whole line in a
  muted blue with underline.

Every chart/table exhibit should carry at least a source line; add the numbered-
footnote block whenever a number depends on a stated assumption (survey sample
size, calculation basis, exchange-rate assumption) — this is what separates a
"real" exhibit from a bare chart. See "Composition and structure" below for how
this pairs with a right-margin/multi-column analysis block.

## Composition and structure

- **Group composite elements.** A KPI card (rounded rect + accent tab + big number
  - label), a roadmap node (header bar + numbered badge + title), or an icon
    badge (circle + glyph + header + body) should be one `groupShapes` unit, not
    four independent shapes a future edit could misalign.
- **A real deck's shape**: cover → confidentiality/handling notice → agenda (as a
  reusable numbered TOC spine, not a single static list) → executive summary
  (headline finding, KPI dashboard, 3-pillar recommendation, financial-impact
  chart, roadmap preview) → numbered sections, each opening on a divider slide (or
  the TOC spine with that chapter active) → appendix (detailed tables, glossary,
  sources, disclaimers) → closing. Long decks (60–100+ slides) are normal for a
  real internal working deck; don't compress everything onto 10 slides just
  because a reference example you saw was short — that one may have been a
  client-facing extract, not the full working deck.
- **Every exhibit earns its slide.** A chart or table is never left to speak for
  itself: pair it with a right-margin or multi-column analysis block (2–4
  substantive, numbers-backed sentences — not generic filler) and a footnote/
  source line. A slide with only a bare chart and a one-line caption reads as a
  first draft, not a finished exhibit — information density (not clutter) is
  what makes a page look like it came from a real engagement.
- **Dense but not cluttered**: 3–5 bullets per slide, one action title, one
  exhibit (or one coherent multi-column composition). If you have two unrelated
  exhibits worth showing, that's two slides, not one crowded slide.

## Content craft: what actually reads as AI-generated

Everything above gets the visual language right. A visually correct deck can
still read as AI-generated on close inspection — the tell moves from the
layout to the _content_. This section is written from a real feedback loop:
a generated ~100-slide deck was run through an AI-content detector across
several rounds, and each round's fix sometimes introduced a _new_ tell of a
different flavor. Treat "sounding human" as an ongoing discipline applied
while drafting, not a find-and-replace pass done at the end.

The general storyline, headline and Japanese wording rules live in the
distributable skill: `skill/references/story-document.md`,
`skill/references/writing-ja.md` and `skill/references/review.md` (run
`skill/scripts/deck-text.mjs --mode document` on the exported deck). This
section adds only what is specific to consulting-style exhibits.

### Numeric self-consistency is the single strongest signal

The #1 thing that got a deck flagged as AI-generated was a hard arithmetic
contradiction: one slide stated a 2030 target as a "+340億円 increment," a
different slide's scenario chart showed the same year's base case as an
absolute "900億円." Neither reading reconciled with the deck's own bridge
chart or P&L table. A systematic audit afterward found this wasn't an
isolated typo — the same headline figure had **four** different values across
different slides, a segment's contribution to profit had **three**, an NPV
total didn't equal the sum of its own stated parts, and a stated current-state
margin didn't match the P&L table's own baseline.

This happens naturally when slide content is drafted slide-by-slide — each
slide's numbers are locally plausible at the time they're written, and no one
slide is "wrong" in isolation. The fix is structural, not editorial:

1. **Before writing any slide content**, build one explicit numeric model
   (a plain object/constants block in the generator script) covering every
   quantity that will appear on more than one slide: the P&L path (revenue,
   gross profit, SG&A, operating profit per year), the pillar/segment
   contribution breakdown, scenario spreads, cash-flow figures.
2. **Add a self-check** that runs when the script executes — e.g. assert
   `grossProfit[i] - sga[i] === operatingProfit[i]` for every year, and
   `baseline + sum(pillarContributions[i]) === operatingProfit[i]`. Throw if
   it doesn't hold. This turns "did I introduce a contradiction" from a
   manual audit into something the generator itself refuses to produce.
3. **Derive every slide's numbers from that one model**, never re-typed
   per-slide. Decide once whether a headline figure is an increment or an
   absolute, and never let a different slide imply the other reading.
4. When two slides describe "the same" figure from different angles (a
   segment's standalone P&L vs. its consolidated contribution to a synergy
   bridge; a survey-based scenario vs. a sensitivity-table increment), either
   make them equal or add a one-line footnote naming _why_ they differ
   (overhead allocation, scope difference). An unexplained gap reads as an
   error even when the underlying reason is legitimate.

### Source citations: vary the format, don't invent a fictional institute

A first-pass fix for "sources are too vague" (bare `資料: 部署名` on every
slide) overcorrected into "sources are suspiciously precise" — a uniform
`部署名『Report Title』(Rev.X.X, 2026年M月D日確定版)` template repeated on
40+ slides is itself an AI tell, just a different one. Two concrete fixes:

- **Deliberately vary format and completeness.** Not every citation needs a
  title + version number + date. Mix in plain department names, a bare
  "業界レポートによる" with no further detail, an occasional named person
  instead of a department, and the fully-dressed form — in whatever
  proportion feels like it was assembled by different people at different
  times, because in a real deck it was.
- **For external market/industry data, cite real research firms and real
  government bodies** (Euromonitor, GfK, Kantar, IMF World Economic Outlook,
  a country's actual investment-promotion agency) rather than inventing a
  plausible-sounding fictional institute (an early draft invented "ARERI —
  アジア流通経済研究所," which read as exactly the kind of too-convenient
  acronym an LLM fabricates). For a fictional company's _internal_ citations
  (hearings, internal working papers), attributing to the company's own
  already-established departments is fine and doesn't have this problem —
  the risk is specifically inventing a _third-party_ organization that
  sounds real but isn't.

### Anonymized examples/case studies should not be structurally uniform

If a deck includes 2–3 anonymized case studies, giving every one of them the
same shape (tidy quote + clean lesson + fully-resolved success) reads as
templated — real case libraries are uneven. Deliberately vary: give one case
a direct quote and a resolved happy ending, give another just data with no
quote, and consider making one case an **ongoing/unresolved** situation
("current state: improving but still below target") rather than a clean win.
The variation in depth and resolution is itself what makes each one read as
independently researched rather than generated from one template.

### Phrasing diversity is a moving target, not a one-time fix

Repeating the same closing-clause formula across many slides (`〜が急務で
ある`, `〜が鍵となる`, `〜を実現する`, `〜見込みである`, defaulting to `最も`
as the only superlative device) reads as LLM-typical vocabulary. The trap:
fixing this by mechanically swapping in a _different_ replacement phrase
(`という計算になる`, `という結果が出ている`, `を起点とする`) just creates a
new repeated tic once that replacement itself gets reused across a dozen
slides. There is no phrase that's safe to reach for by default every time —
the actual fix is sentence-level variety: sometimes state the number and stop
without a closing hedge at all, sometimes lead with the comparison
(`A社の1.6倍`) instead of a verb-based conclusion, sometimes invert
subject/verb order. If you're generating enough content that you can search
your own script afterward for any phrase appearing 4+ times, do that search —
but don't pre-emptively adopt a "safe" replacement vocabulary, since that's
exactly how the previous tic got created.

## Verification workflow — do not skip this

1. **XSD schema validation** on every generated slide/chart XML (see this repo's
   `test/lib/expect-schema-valid.ts` pattern) — catches structural corruption.
2. **Render with a real engine and look at it.** @office-kit/pptx's own bundled preview
   renderer does not ship CJK fonts — Japanese (or other non-Latin) text renders as
   tofu boxes in it even when the underlying XML is completely correct. That is a
   preview-renderer limitation, not a bug in your output, but it means you **cannot
   trust the bundled preview for a CJK deck.** Convert with a real office suite and
   look at actual pages before calling the deck done:
   ```sh
   soffice --headless --convert-to pdf --outdir /tmp/out deck.pptx
   pdftoppm -png -r 150 -f <page> -l <page> /tmp/out/deck.pdf /tmp/out/page
   ```
   Then view the PNG. Do this for at least one slide of every distinct archetype
   you built (cover, divider, TOC spine, chart, pie chart, table, matrix, sidebar
   layout, multi-column exhibit, pull-quote) — each is a different rendering code
   path and bugs are archetype-specific (e.g. a legend bug affects every pie chart
   but not a single-series bar chart; a footer-position bug affects every
   sidebar-layout slide but not plain content slides).
3. **Read what you rendered critically**, the way the user will: does the pie
   chart's legend actually list distinct colors? Does the multi-line sidebar title
   render at a consistent size on every line? Is the "annotation" text actually
   next to the chart, not drifted onto the axis? Does a two-line footnote block
   fit inside the slide bounds, or does the second line clip off the bottom edge?
   Fix what you find and re-render — don't ship the first render un-inspected.