deck-design-pdf · diff
git:20260325.4963761 to git:20260329.1b6bf13
161 added, 719 removed. Audit B to A.
---
name: deck-design-pdf
description: >
Create presentation decks as high-fidelity PDF files using web technology
(HTML, CSS, Tailwind, Font Awesome). Use when the user wants a polished,
pixel-perfect deck with responsive layouts, rich typography, icons, and
modern design. For editable PPTX output, use deck-design-ppt instead.
---
# Deck Design PDF — Operational Playbook
## What This Skill Does
- **Input:** a deck brief + any structured data the user provides.
- **Output:** a **PDF file** — pixel-perfect slides rendered from HTML/CSS via Playwright. Not editable in PowerPoint. This is the high-fidelity, print-ready format.
### When to use this vs deck-design-ppt
| Need | Skill |
|---|---|
| Editable slides (PowerPoint/Keynote/Slides) | `deck-design-ppt` |
| Pixel-perfect PDF — web typography, icons, gradients, CSS layouts | `deck-design-pdf` (this) |
### What the web stack unlocks (beyond pptx)
- CSS Grid and Flexbox — responsive layouts instead of coordinate math
- Google Fonts with optical sizing and variable weights
- Font Awesome 6 icons inline with text
- Gradient backgrounds, box shadows, rounded corners, opacity
- ECharts 5 (SVG renderer) — 21 chart types: bar, line, pie, scatter, waterfall, gauge, sankey, treemap, radar, funnel, heatmap, and more
- Tailwind utility classes — rapid, consistent styling
- ## Phase 1 — Understand
+ ## Phase 1 — Understand and Route
- ### 1. Extract the brief
+ ### 1. Read the room
- | Signal | Examples | Defaults if absent |
+ Before asking the user anything, scan the working directory for artifacts that establish context — briefs, consultant storyboards (`*-ghost.md`, `*-outline.md`), data files, brand specs, existing build scripts. Read what's there and form a working hypothesis about what this deck needs: objective, audience, tone, density, and data.
+
+ Then ask only for what's genuinely ambiguous and would change the deck's argument or audience calibration. Frame questions as choices, not open fields: *"The data suggests a Bain decision-first structure — does that fit, or is this more of an internal working session?"* One sharp question beats five vague ones. Maximum 1–3 questions; zero is fine if the artifacts are clear.
+
+ ### 2. Classify the deck
+
+ This determines how deep the planning phase goes. Two paths:
+
+ | Signal | Path | What happens next |
|---|---|---|
- | **Objective** | "pitch to Series A investors", "board strategy update" | General presentation |
- | **Audience** | "DoD program managers", "VC partners", "internal team" | General professional |
- | **Brand identity** | Logo colors, company name, client palette | Palette defaults |
- | **Tone / firm style** | "McKinsey-style", "clean and modern", "urgent/high-stakes" | Infer from audience + objective |
- | **Density** | "dense and evidence-heavy", "keep it simple", specific L1/L2/L3 | Infer from audience + objective |
- | **Data** | Tables, metrics, timelines, comparisons, evaluations | Build from research or request more |
+ | MBB engagement, strategy consulting, due diligence, cost transformation, M&A, pricing, org restructuring | **Consulting** | Load the full consulting reference library (ghost-deck.md, engagement-archetypes.md, skeletons/, firm-dna.md, evidence-recipes.md, density-adaptation.md). Build a rigorous ghost deck with archetype classification, pillar architecture, transitions, and firm overlay. |
+ | Startup pitch, board update, product narrative, conference talk, investor roadshow, internal update | **General** | Stay in this playbook. Build a ghost deck using the universal quality gates below — governing thought, action titles, helicopter test, exhibit assignment. No archetype classification or skeleton required. |
- Extract what's there, infer what you can, use defaults for the rest. Do not ask the user to fill out a checklist.
+ **Consultant handoff** — if a storyboard from the `consultant` skill already exists (governing thought, pillars, action titles, content descriptions), the argument layer is done. Skip ghost deck construction entirely. Validate the argument (run the helicopter test on the titles), then proceed to the production outline.
- ### 2. Pick style
+ ### 3. Pick style and density
+ **Style:**
+
| If the deck is… | Palette | Surface | Font |
|---|---|---|---|
| Consulting / board / engagement deliverable | `consulting-mckinsey` | Light | Inter |
| Framework evaluation, process-transparent | `consulting-bcg` | Light | DM Sans |
| Diagnostic, decision support, facts-vs-perspectives | `consulting-bain` | Light | Source Sans 3 |
| Startup pitch / product narrative / growth story | `founder` | Light | Plus Jakarta Sans |
| Crisis / urgency / downturn memo / high-stakes | `sequoia` | Dark | Georgia + Inter |
- ### 3. Pick density
+ The fonts above are vendored locally for the default palettes. The agent is not limited to these — any Google Font can be loaded via a `<link>` tag in `headExtra` when the brief calls for a different typeface.
+ **Density:**
+
| Context | Level | What changes |
|---|---|---|
- | Startup pitch, roadshow, board update | **L1 Narrative** | 1 message per slide. Generous whitespace. Large text. |
+ | Startup pitch, roadshow, board update | **L1 Narrative** | 1 message per slide. Fewer elements, each scaled up to fill the body zone. |
| Corporate strategy, business review | **L2 Structured** | Multi-panel layouts. Evidence density moderate. |
| MBB engagement, due diligence, deep analysis | **L3 Dense** | Multi-evidence composites. Chained arguments. |
- **Show deck vs. working deck** — use the `tier` option to shift all text baselines:
-
- | Purpose | Density | `tier` | Text floor (in PDF pt) | When |
- |---|---|---|---|---|
- | **Show deck** — the client sees this | L1–L2 | `'presentation'` | Body ≥15pt, axis ≥14pt. Room-safe. | Board meetings, steering committees, final recommendations |
- | **Working deck** — the team uses this | L2–L3 | `'document'` (default) | Body ≥12pt, axis ≥11pt. Dense but legible. | Working sessions, due diligence backup, internal analysis |
+ **Show deck vs. working deck** — infer from audience and objective, don't ask. "Board presentation" → `tier: 'presentation'` (body ≥15pt, room-safe). "Diligence data room" → `tier: 'document'` (body ≥12pt, dense but legible). The tier shifts ALL text tokens automatically.
- Infer show vs. working from the audience and objective. Don't ask the user — "board update" → `presentation`, "due diligence data room" → `document`. The tier shifts ALL text tokens automatically — you don't adjust individual font sizes.
+ For L2+ consulting decks, apply firm-specific conventions from [firm-dna.md](firm-dna.md). For density adaptation rules, see [density-adaptation.md](density-adaptation.md).
- L2+ consulting decks: apply the firm-specific conventions from [Firm Style](#firm-style) below and [firm-dna.md](firm-dna.md). For full density adaptation rules, see [density-adaptation.md](density-adaptation.md).
+ ## Phase 1.5 — Ghost Deck
- ### 4. Route each slide
+ Before writing any HTML, build the **ghost deck** — the narrative skeleton that precedes all visualization. Charts and code are execution. The ghost deck is the thinking.
- For each slide, determine:
- 1. **Layout** — from the [Composition Routing](#composition-routing) table
- 2. **Exhibit type** — from [chart-taxonomy.md](chart-taxonomy.md), using the decision tree: what does this slide need to prove? → "How big?" / "Why?" / "What to do?" → specific exhibit
- 3. **Firm visual treatment** — the taxonomy's Firm Visual DNA section specifies what each firm tolerates: McKinsey minimal annotation, BCG liberal annotation, Bain one-red-element discipline
- 4. **Data needed** — determined by the exhibit type and the action title's claim
+ The ghost deck process produces two artifacts:
+ - **`{slug}-ghost.md`** — the argument layer: governing thought, action titles, exhibit types. A senior reviewer can approve this without knowing CSS.
+ - **`{slug}-outline.md`** — the execution layer: ghost deck + density tiers, layout geometry, chart dimensions, column alignment. This is what the build phase reads.
- ## Phase 1.5 — Ghost Deck
+ **Process management.** Building a ghost deck requires populating multiple interdependent layers and passing quality gates that may trigger backtracking. Use your task management tools to track which layers are complete, which gates have passed, and what needs revisiting. Externalize this state — don't try to hold it all in one pass.
- Before writing any HTML, build the **ghost deck** — the narrative skeleton that precedes all data and visualization. This is where strategic value gets created. Charts and code are execution. The ghost deck is the thinking.
+ ### Universal quality gates
- **Routing:**
- - **Consulting engagement** (strategy, cost, M&A, pricing, digital, org, commercial) → full ghost deck pipeline below. Load the matching skeleton from `skeletons/`.
- - **Non-consulting deck** (startup pitch, board update, investor roadshow, product launch) → skip to Phase 2. Use [chart-taxonomy.md](chart-taxonomy.md) § Deck Archetypes for exhibit mix guidance. Write action titles and apply the helicopter test, but don't force the 8-archetype classification or skeleton structure.
+ These apply to **every deck** — consulting, startup, board update, conference talk. They are not consulting methodology; they are good deck design.
- The ghost deck methodology (governing thought, pillars, transitions, rising-stakes) is always valuable thinking. For non-consulting decks, apply the principles without requiring a skeleton match.
+ Start from the governing thought — one sentence that states the deck's answer. Build pillars that support it. Write action titles for every slide before you touch any charts. Read the titles in sequence — if they don't tell a complete story, the problem is in the pillars, not the titles. Only assign exhibits once the argument holds. Cut any slide that isn't load-bearing.
- **Reference docs** (all self-contained inside this skill):
+ **What must exist in every ghost deck:**
- | Doc | When to load | Purpose |
+ | Layer | What it is | Depends on |
|---|---|---|
- | [ghost-deck.md](ghost-deck.md) | Always | 5-layer model, governing thought template, quality gates |
- | [engagement-archetypes.md](engagement-archetypes.md) | Archetype selection + transition design | 8 archetypes, 5 transition types, rising-stakes progression |
- | `skeletons/*.md` | After archetype is classified | Governing thought template, pillar architecture, slide-by-slide index, kill conditions, quality gates |
- | [firm-dna.md](firm-dna.md) | Firm overlay (McKinsey/BCG/Bain style) | Epistemology, deck structure, communication signatures |
- | [evidence-recipes.md](evidence-recipes.md) | Exhibit assignment (Layer 5) | 10 data-shape recipes, layering rules, engagement × recipe mapping |
- | [density-adaptation.md](density-adaptation.md) | Density selection + L1↔L2 adaptation | Compression/expansion rules, slide counts, tier mapping |
- | [chart-taxonomy.md](chart-taxonomy.md) | Exhibit type selection | Decision tree, firm visual DNA, annotation grammar |
+ | **Governing thought** | One sentence — the deck's answer. If you can't write it, the analysis isn't done. | The brief and data |
+ | **Action titles** | Full-sentence conclusion for every slide. "Revenue grew 12% driven by pricing power" — not "Revenue Overview." | Governing thought |
+ | **Helicopter test** | Read all titles in sequence. Complete, persuasive story in 2 minutes? If not, fix the titles. | Action titles |
+ | **Exhibit assignment** | What visual proves each slide's claim. Use [chart-taxonomy.md](chart-taxonomy.md): "What does this slide need to prove?" → exhibit type. | Helicopter test passed |
+ | **Dead slide test** | Can any slide be removed without breaking the argument? If yes, remove it. | All of the above |
- **When receiving a consultant artifact:**
+ **Common deck patterns.** For non-consulting decks, [chart-taxonomy.md](chart-taxonomy.md) § Deck Archetypes provides narrative arcs and exhibit mixes for common formats — investor/roadshow (Problem → Solution → Traction → Market → Model → Team → Ask), board updates (Headlines → KPIs → Progress → Risks → Decisions), due diligence memos, transformation roadmaps, and more. Use these as starting points for the slide sequence, then write action titles and apply the quality gates above. Don't force a pattern that doesn't fit the brief — adapt or combine as the argument requires.
- If a storyboard from the consultant skill is provided (governing thought, pillars, action titles, content descriptions, structured data), this skill inherits the argument architecture and focuses on production:
+ **Backtracking, not patching.** If the helicopter test fails, the problem is upstream — the pillars don't support the governing thought, or the titles are topic labels instead of conclusions. Go back to where the argument breaks. Don't patch titles to paper over a structural gap.
- 1. **Validate the argument** — run the helicopter test on the provided action titles. If titles read as topic labels rather than conclusions, strengthen them.
- 2. **Classify the archetype** — load the matching skeleton from `skeletons/` to verify pillar coverage and identify missing analytical slides.
- 3. **Run exhibit selection** — for each slide, use the content description + [chart-taxonomy.md](chart-taxonomy.md) decision tree to select exhibit types. The consultant describes WHAT each slide proves; this skill decides HOW to visualize it.
- 4. **Complete the production outline** — add Layout, Exhibit, and Evidence layers to each slide entry per the [Outline format](#outline-format) Path A spec. Then proceed to Phase 2 (Build).
+ **When the brief supports multiple valid governing thoughts** — surface the options and let the user choose before proceeding. Otherwise, commit to the strongest hypothesis and work forward.
- This skill may strengthen the consultant's artifact: tightening action titles, adding transition slides, adjusting slide count for density, or restructuring for visual rhythm. The consultant's governing thought and pillar architecture are authoritative; exhibit selection and layout composition belong to this skill.
+ ### Consulting path
- **Build sequence** (when constructing the ghost deck independently):
+ For MBB engagements and strategy consulting, the ghost deck goes deeper. Load the full reference library:
- 1. **Governing thought** — one sentence stating the deck's answer (see [ghost-deck.md](ghost-deck.md) Layer 1). If you can't write this sentence, the analysis isn't done.
- 2. **Deck archetype** — classify using [engagement-archetypes.md](engagement-archetypes.md) selection logic. Then **load the skeleton** from `skeletons/` for that archetype — it provides the governing thought template, pillar architecture, slide-by-slide index with action title templates, kill conditions, and quality gates.
- 3. **Pillar architecture** — use the skeleton's pillar table as starting point. Customize pillars to the specific brief. Work backward from the governing thought: "What must be true?" (Layer 2).
- 4. **Action titles** — write a full-sentence title for every slide BEFORE selecting any charts. Each title is a claim that advances the argument. "Revenue grew 12% driven by pricing power in mid-tier" — not "Revenue Overview."
- 5. **Helicopter test** — read all action titles in sequence. Do they tell a complete, persuasive story? If not, fix the titles. Don't touch charts until this passes.
- 6. **Transition architecture** — select transition types from [engagement-archetypes.md](engagement-archetypes.md) for each pillar boundary. Verify rising-stakes progression: Recognition → Clarity → Conviction → Urgency.
- 7. **Exhibit assignment** — select exhibit types using [chart-taxonomy.md](chart-taxonomy.md)'s decision tree + [evidence-recipes.md](evidence-recipes.md) for data-shape composition. Each exhibit must be SUFFICIENT proof of its title's claim and MINIMAL — no extra elements.
- 8. **Firm overlay** — if McKinsey/BCG/Bain style, apply conventions from [firm-dna.md](firm-dna.md): opening/closing sequence, communication signature, density preference.
- 9. **Dead slide test** — can any slide be removed without breaking the argument? If yes, remove it.
- 10. **Density check** — does the content fill each slide without overflow or sparseness? Apply [density-adaptation.md](density-adaptation.md) rules for the target level.
+ | Doc | Purpose |
+ |---|---|
+ | [ghost-deck.md](ghost-deck.md) | 5-layer model, quality gates, anti-patterns |
+ | [engagement-archetypes.md](engagement-archetypes.md) | 8 archetypes, 5 transition types, rising-stakes progression |
+ | `skeletons/*.md` | Pillar architecture, slide-by-slide index, kill conditions per archetype |
+ | [firm-dna.md](firm-dna.md) | McKinsey/BCG/Bain epistemology, communication signatures |
+ | [evidence-recipes.md](evidence-recipes.md) | 10 data-shape recipes, layering rules |
+ | [density-adaptation.md](density-adaptation.md) | L1/L2/L3 compression/expansion rules |
- Save as `{slug}-outline.md` alongside the build script.
+ On top of the universal quality gates, the consulting path adds:
- ### Outline format
+ - **Archetype classification** — classify the engagement using [engagement-archetypes.md](engagement-archetypes.md), then load the matching skeleton from `skeletons/`. The skeleton provides a pillar architecture and slide-by-slide index as a starting point — customize it to the specific brief.
+ - **Pillar architecture** — 3–5 MECE pillars supporting the governing thought. Work backward: "What must be true for the governing thought to hold?"
+ - **Transition architecture** — at each pillar boundary, select a transition type (Pivot, Narrowing, Escalation, Synthesis, Decision Gate). Verify rising-stakes progression: Recognition → Clarity → Conviction → Urgency.
+ - **Firm overlay** — apply [firm-dna.md](firm-dna.md) conventions for the target firm style. This affects header structure, communication signature, and composition patterns — not the argument itself.
+ - **Evidence recipes** — for each exhibit, check [evidence-recipes.md](evidence-recipes.md) for the standard composition: primary chart + supporting elements + annotation layers, governed by density level.
- The outline is the contract between the thinking layer and the production layer. Two input paths lead to the same production-ready outline:
+ These layers have dependencies — you can't design transitions until pillars exist, and you can't assign evidence recipes until exhibits are selected — but the agent decides the working order based on what the brief gives it. A brief with strong data might start from what the data proves and work backward to the governing thought. A brief with a clear strategic question might start top-down.
- **Path A — Self-generated** (this skill builds the ghost deck independently):
+ ### Consultant handoff
- Every slide entry has the full production spec:
+ When a storyboard from the `consultant` skill already exists (governing thought, pillars, action titles, content descriptions, structured data), the argument layer is done. This skill inherits it and focuses on production:
- ```
- N. **Action title — full sentence conclusion**
- - Layout: [composition type from § Composition Routing]
- - Exhibit: [chart type from chart-taxonomy.md decision tree]
- - Data: [specific data points needed, with sources if known]
- - Evidence layers: [1 for L1, 1-2 for L2, 2-4 for L3]
- ```
+ 1. Run the helicopter test on the provided action titles. If titles read as topic labels rather than conclusions, strengthen them.
+ 2. For each slide, use the content description + [chart-taxonomy.md](chart-taxonomy.md) decision tree to select exhibit types. The consultant describes WHAT each slide proves; this skill decides HOW to visualize it.
+ 3. This skill may tighten action titles, add transition slides, or adjust slide count for density. The consultant's governing thought and pillar architecture are authoritative; exhibit selection and layout composition belong to this skill.
- **Path B — Consultant handoff** (receiving a storyboard from the consultant skill):
+ ### Presenting the ghost deck
- The consultant provides argument architecture without visualization decisions:
+ Once the ghost deck is complete, present it to the user as the **storyline** — just the action titles in sequence. This is the helicopter test output:
- ```
- N. **Action title — full sentence conclusion**
- - Content: [what the slide argues, what it proves, the analytical question]
- - Data: [structured data in markdown tables/lists]
- ```
+ > *Here is the argument this deck makes, read top to bottom:*
+ > *1. [Action title]*
+ > *2. [Action title]*
+ > *...*
+ > *Does this story hold? Anything missing, out of order, or unconvincing?*
- When receiving a consultant artifact, run **exhibit selection** before building:
- 1. For each slide, read the action title and content description
- 2. Map to [chart-taxonomy.md](chart-taxonomy.md)'s decision tree: "What does this slide need to prove?" → exhibit type
- 3. Select layout from [§ Composition Routing](#composition-routing) based on exhibit + density
- 4. Determine evidence layers from density level
- 5. Produce the full production outline (Path A format), then proceed to build
+ Don't print the full outline with density tiers and exhibit types — that's implementation detail. The user's job is to validate the argument, not review the geometry. If they approve, proceed to the production outline. If they redirect, revise and present again.
- The consultant's content description tells you WHAT to prove. This skill's taxonomy tells you HOW to visualize it.
+ ### Production outline
- **Example** (production-ready, from a real Bain engagement):
- ```
- 1. **OpenAI should choose a 2027 IPO path and shift 2026 investment toward enterprise monetization.**
- - Layout: decision brief (full-bleed hero)
- - Exhibit: recommendation card + why-now KPI trio
- - Data: $157B valuation, $12.7B ARR, 3 strategic options
- - Evidence layers: 2
+ The production outline (`{slug}-outline.md`) extends the ghost deck by adding geometry to every slide. This is the contract between thinking and building — the build phase copies these numbers, no sizing reasoning required at code time.
- 5. **Anthropic's coding dominance (54% share) poses the most immediate competitive threat to enterprise positioning.**
- - Layout: asymmetric split (3fr + 2fr)
- - Exhibit: clustered bars (market share by segment) + horizontal bars (benchmark scores)
- - Data: SWE-bench scores, coding market share, Cursor/Copilot adoption figures
+ For every slide in the ghost deck, add:
+ - **Density tier** — which CSS class governs typography
+ - **Layout** — composition type + percentage split (e.g., "asymmetric split — left 60% / right 40%")
+ - **Column alignment** — `items-start` when columns differ in content height; `items-center` only for visually balanced columns
+ - **Chart spec** — explicit dimensions derived from the space budget (see § Space audit below)
+ - **Evidence layers** — 1 for L1, 1–2 for L2, 2–4 for L3
+
+ ```
+ N. **Action title — full sentence conclusion**
+ - Density: sd-medium
+ - Layout: asymmetric split — left 60% / right 40%
+ - Column alignment: items-start
+ - Exhibit: clustered bars (market share by segment)
+ - Chart spec: 700px × 480px — body 600px − 120px (top labels + gap) = 480px
+ - Data: SWE-bench scores, coding market share
- Evidence layers: 2
```
- **Outlines that omit exhibit types** produce decks dominated by KPI cards and text bullets — the most common quality failure. Whether self-generated or received from consultant, the production outline must have Layout + Exhibit before the build starts.
-
- ### Golden Trace — Profitability Example
-
- **Brief:** "Acme Corp's EBITDA margins declined 420bps over 3 years. The CEO wants a cost transformation plan for the board."
+ Save as `{slug}-outline.md`. The ghost deck is not modified — it remains the clean argument document.
- **Step 1 — Governing thought:**
- "Acme can improve EBITDA margin by 340bps through 5 cost levers across procurement and operations, capturing $180M in annualized savings within 18 months, because structural cost gap to peers creates addressable opportunity."
+ **Outlines that omit exhibit types** produce decks dominated by KPI cards and text bullets — the most common quality failure. The outline must have Layout + Exhibit before the build starts.
- **Step 2 — Archetype:** Profitability → load `skeletons/profitability.md`
+ ### Space audit
- **Step 3 — Pillars** (customized from skeleton):
- 1. Benchmark the Gap — "How does Acme's cost structure compare?"
- 2. Explain the Gap — "What root causes drive the disparity?"
- 3. Size the Prize — "Which levers, how much each?"
- 4. Prove the P&L Math — "Phased financial impact"
+ Before writing any code, run a space audit on every slide that contains a chart or diagram. The slide canvas is 1280×720px. After header (~76px) and footer (~44px), the body zone is **≈ 600px tall, ≈ 1168px wide** (56px margins each side). In a two-column layout, each column is ≈ 576px.
- **Step 4 — Action titles** (sample):
- - S2: "Margin improvement of 340bps ($180M) achievable through 5 levers over 18 months"
- - S4: "Acme trails peer median by 420bps on EBITDA, ranking 9th of 12 peers"
- - S7: "Procurement drives 45% of addressable gap — supplier consolidation is primary mechanism"
- - S10: "Total addressable opportunity is $180M across 5 levers, with procurement at $82M"
+ For each chart slide: subtract any non-chart content (card rows, KPI strips, table rows, gaps) from the 600px body height. The remainder is the chart height. Write this math in the outline — the build agent copies the number directly.
- **Step 5 — Helicopter test:** Read S2, S4, S7, S10, S16, S19 titles in sequence → complete cost story in 90 seconds. Pass.
+ ```
+ body height 600px − top content Apx − bottom content Bpx = chart height
+ ```
- **Step 6 — Transitions:** Pivot (P1→P2) → Narrowing (P2→P3) → Escalation (P3→P4)
+ **Key rules:**
+ - If chart height > chart width for that column, the chart is portrait. That's correct — portrait orientation eliminates blank space structurally.
+ - If two columns have different content heights, set `align-items:start`. Don't default to center.
+ - If the computed chart height exceeds the density class default, override it. The space budget wins.
- **Step 7 — Exhibits:** S4 = benchmark bars, S7 = driver tree, S10 = waterfall bridge, S11 = priority matrix
+ **Estimation reference (1280×720):**
- **Step 8 — Firm overlay:** McKinsey palette. Verdict-first titles. Exhibit numbering. Methodology to appendix.
+ | Content element | Estimated height |
+ |---|---|
+ | 3-card row (compact) | ~120px |
+ | KPI metric strip (3–4 numbers) | ~80px |
+ | Table (5 rows) | ~180px |
+ | Gap between elements | 16–24px |
## Phase 2 — Build
### How to build slides
- You are composing **custom HTML for each slide** based on the user's actual data and the ghost deck's argument. You are NOT filling in a template. The examples under `examples/*.js` are visual pattern references — study their approach, then write original HTML that serves the specific argument.
+ Read `{slug}-outline.md`. Each slide entry has an action title, exhibit type, layout, and chart dimensions. The build phase executes these specs — it does not re-derive them. Sizing decisions were made in the outline; the build agent copies the numbers.
- **For each slide in the ghost deck:**
+ You are composing **custom HTML for each slide** based on the user's actual data and the outline's argument. You are NOT filling in a template. The examples under `examples/*.js` are visual pattern references — study their approach, then write original HTML that serves the specific argument.
- 1. **Set the tier** — `'presentation'` for any deck projected in a room or read by executives. `'document'` (default) for working sessions and analysis. The tier shifts all text baselines automatically. Do not adjust individual font sizes.
- 2. The action title tells you **what to prove**. The exhibit type tells you **how to prove it**.
+ **Space budget reference.** At 1280×720, the available zones are:
+
+ | Zone | Pixels | Notes |
+ |---|---|---|
+ | Slide canvas | 720px tall, 1280px wide | Fixed |
+ | Header zone | ~76px | Section label + title + accent bar + padding |
+ | Footer zone | ~44px | Source line, fixed by grid shell |
+ | **Body height** | **≈ 600px** | What remains — this is your working space |
+ | Horizontal margin | 56px each side | Tailwind `px-14` |
+ | **Content width** | **≈ 1168px** | 1280 − 112px margins |
+ | Each column (2-col) | ≈ 576px | (1168 − gap) ÷ 2 |
+
+ **For each slide in the outline:**
+
+ 1. **Set the tier** — `'presentation'` for any deck projected in a room or read by executives. `'document'` (default) for working sessions and analysis. The tier shifts all text baselines automatically. Do not adjust individual font sizes. Infer from audience and objective — don't ask.
+ 2. The action title tells you **what to prove**. The exhibit type tells you **how to prove it**. The chart spec tells you the **exact dimensions**.
3. Read the relevant example file to learn the visual pattern — the ECharts config structure, the CSS layout approach, the annotation placement. Do not copy its data or dimensions.
4. Compose the slide HTML with the user's real data. Use the slide shell (header → body → footer). Apply palette CSS custom properties — never hardcode brand colors.
- 5. Size text and spacing through the token system (`tokens.adapt()`, `getFigureTypography()`, `getChartChrome()`), not hardcoded pixels. This ensures consistency across the deck and responsiveness across canvas sizes.
+ 5. Size text and spacing through the token system (`tokens.adapt()`, `getFigureTypography()`, `getChartChrome()`), not hardcoded pixels.
**What to learn from each example:**
| Look at | To understand |
|---|---|
| ECharts `setOption({...})` structure | Which config keys produce this chart type |
| `tokens.adapt(compact, preferred, wide)` calls | How geometry responds to canvas size |
| `getFigureTypography(tokens)` roles | Axis labels, data labels, annotations — what size/weight/color |
| `getChartChrome(tokens)` fragments | Axis lines, gridlines, legends — the shared chrome |
| Semantic color usage | Accent for focus, gray for context, green/red for deltas |
| The `proves` field | What analytical question this pattern answers |
**What NOT to copy from examples:**
- Sample data ("$4.2B", "12.4M units") — use the user's actual numbers
- Action titles and section labels — write new ones from the ghost deck
- Hardcoded hex colors for palette roles — use `var(--accent)`, `var(--text)`, etc.
- - Fixed dimensions — adapt to the content density and slide count
+ - Fixed dimensions — adapt to the content density and slide count. Examples follow a roughly landscape aspect ratio; your slide's body space may demand a portrait or square chart. Fill the available body height first, then constrain only if content overflows.
+ **Fill-first orientation.** When sizing a chart or visual exhibit, start from the body height (≈ 600px), subtract any labels, gaps, or card rows above/below the chart, and set the chart to that remaining height. Do not start from an example's hardcoded height and stretch slightly. A chart that fills the body zone vertically eliminates blank space structurally — no bottom padding hack required. Portrait charts (height > width) are valid and preferred over leaving empty space at the slide bottom.
+
**Choosing between visual patterns:**
When two exhibit types could work, choose based on the **argument**, not the visual appeal:
- Waterfall answers "what drove the change?" — use when the audience needs to see sequential drivers
- Driver tree answers "what multiplies into what?" — use when the audience needs to see the structural decomposition
- Horizontal bars answer "who is ahead?" — use when ranking is the point
- Distribution answers "how spread out?" — use when the variance is the insight, not the average
If the taxonomy's decision tree doesn't clearly route to one pattern, default to the simplest exhibit that proves the title's claim. A single bold number is often more powerful than a chart. Simplicity is not laziness — it's restraint.
- ### Build script template
-
- For decks with more than 5 slides, define a CSS class system in `headExtra` rather than repeating inline Tailwind on every slide. This is more token-efficient, more consistent, and easier to fix globally.
-
- ```javascript
- const { createDeck } = require('./skills/deck-design-pdf/engine');
-
- createDeck({
- palette: 'consulting-mckinsey',
- title: 'Strategy Update Q1 2026',
- output: 'strategy-update.pdf',
- tier: 'document', // 'document' (default) or 'presentation' for show decks
- width: 1280, // optional
- height: 720, // optional
- headExtra: `<style>
- /* Slide shell — CSS Grid prevents footer overflow */
- .deck-shell { height: 100%; display: grid; grid-template-rows: auto minmax(0,1fr) 48px; }
- .deck-header { padding: 28px 56px 8px 56px; border-top: 4px solid var(--accent); }
- .deck-body { min-height: 0; overflow: hidden; padding: 12px 56px 8px 56px; }
- .deck-footer { display: flex; align-items: center; justify-content: space-between;
- padding: 0 56px; font-size: 11px; color: var(--text-fine);
- border-top: 1px solid rgba(0,0,0,0.06); font-family: var(--font-body); }
- .deck-section { margin: 0 0 4px; font-size: 11px; letter-spacing: 0.2em;
- text-transform: uppercase; color: var(--accent); font-weight: 700; }
- .deck-title { margin: 0 0 8px; font-size: 28px; line-height: 1.15; letter-spacing: -0.03em;
- color: var(--text); font-family: var(--font-heading); font-weight: 700; }
- .deck-rule { height: 3px; border-radius: 2px; background: var(--accent); margin-top: 4px; }
- </style>`,
- slides: [
- // Each string is the inner HTML of one slide.
- // The engine wraps each in <section class="slide">.
- `<div class="deck-shell">
- <div class="deck-header">
- <p class="deck-section">Section Label</p>
- <h2 class="deck-title">Action title — full sentence conclusion</h2>
- <div class="deck-rule"></div>
- </div>
- <div class="deck-body">
- <!-- content -->
- </div>
- <div class="deck-footer">
- <span>Source: Analysis, 2026</span>
- <span>Confidential</span>
- </div>
- </div>`,
- ],
- });
- ```
-
- Run: `node build-{slug}.js` → produces the PDF directly.
-
- **Why `headExtra` CSS classes over inline Tailwind for the shell:**
- - One change to `.deck-title` fixes all 20+ slides — vs editing each slide's `text-[28px] font-semibold leading-snug tracking-tight`
- - The grid shell guarantees footer placement structurally
- - Token-efficient: a class name is ~15 chars vs ~80 chars of Tailwind utilities per slide
- - Tailwind is still used for body content layout (grids, gaps, cards) — only the shell is CSS classes
-
- **ECharts formatter warning:** Inside JavaScript template literals (backtick strings), `'${value}'` is interpreted as JS interpolation. Use `function(v) { return '$' + v + 'B'; }` instead. This applies to all `formatter`, `axisLabel.formatter`, and `label.formatter` properties.
-
- ### Atomic exhibits vs wrapped slides
-
- The reusable production unit is the **atomic exhibit**: graph/table/visual only, with no header or footer baked into the template. Examples under `examples/*.js` export:
-
- ```javascript
- {
- id,
- title,
- tier,
- proves,
- data,
- sectionLabel,
- actionTitle,
- source,
- exhibitId,
- responsiveSpec, // optional: chart ranges or layout QA samples
- renderExhibit({ checkpoint, width, height, tokens }) { ... }
- }
- ```
-
- Use the shared helpers in `examples/_shared.js` to render:
-
- - an exhibit-only QA artifact
- - a wrapped slide reference artifact
-
- Treat `examples/_shared.js` as the internal standards layer. Share only reusable typography, text roles, chart chrome, and repeated semantic colors. Keep exhibit geometry, data mapping, label placement, and one-off visual emphasis inside each template.
-
- ### Wrapped slide shell
-
- When a full slide is required, wrap the exhibit with the shell below. The shell uses **CSS Grid with fixed row heights** — this structurally prevents footer overflow, which is the most common layout failure in deck production.
-
- ```html
- <div style="height: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr) 48px;">
- <!-- HEADER ZONE — action title with accent bar -->
- <div class="px-14 pt-8 pb-2 border-t-4 border-[var(--accent)]">
- <p class="text-[11px] font-semibold tracking-widest uppercase text-[var(--accent)] mb-1">
- Section Label
- </p>
- <h2 class="text-[28px] font-semibold leading-snug tracking-tight text-[var(--text)]"
- style="font-family: var(--font-heading)">
- Action title — full sentence conclusion
- </h2>
- </div>
-
- <!-- BODY ZONE — all content lives here; overflow is clipped, never pushes footer -->
- <div class="px-14 py-3" style="min-height: 0; overflow: hidden;">
- <!-- Layout primitives go here (grids, cards, charts, etc.) -->
- </div>
-
- <!-- FOOTER ZONE — fixed 48px row, cannot be displaced -->
- <div class="px-14 flex items-center justify-between
- text-[11px] text-[var(--text-fine)]"
- style="font-family: var(--font-body); border-top: 1px solid var(--accent-light, #ccc)33;">
- <span>Source: Analysis team, 2026</span>
- <span>Confidential</span>
- </div>
- </div>
- ```
-
- **Why grid, not flex:** The `grid-template-rows: auto minmax(0, 1fr) 48px` layout guarantees three things:
- 1. Header takes its natural height (`auto`)
- 2. Body fills remaining space but **cannot push the footer off-slide** (`minmax(0, 1fr)`)
- 3. Footer is always exactly 48px from the bottom, regardless of body content
-
- The older `flex flex-col h-full` + `flex-1` approach allowed body overflow to push the footer off the slide — a failure that required manual QA to catch.
-
- Cover slides and dividers replace this shell with a full-bleed layout (see [Compositions](#compositions)).
-
- ### Slide layout anti-patterns
-
- Common failures in deck production. Avoid these:
-
- | Anti-pattern | What happens | Fix |
- |---|---|---|
- | **`flex-1` on cards inside a grid** | Cards stretch to fill the grid cell height, leaving huge empty zones between content and metadata | Don't use `flex-1` on cards. Let cards be `auto`-height. Use `items-start` on the grid. |
- | **`flex-1` on body zone** | If body content is short, it expands with whitespace. If content is long, it pushes the footer off-slide. | Use the CSS Grid shell above. The `minmax(0, 1fr)` body row handles both cases. |
- | **`absolute` positioning for diagrams** | Elements float at hardcoded pixel offsets, break at different content sizes, don't respond to overflow. | Use CSS Grid or Flexbox for all diagrams. The flywheel, process flows, and relationship maps should use `grid-cols-3 grid-rows-3`. |
- | **Template literal `${value}` in ECharts formatters** | Inside a JS backtick string, `'${value}'` evaluates as JavaScript (returning empty string or variable value), not as an ECharts template. | Use `function(v) { return v + '%'; }` for formatters, never `'${value}'` or `'{value}'` inside template literals. |
- | **`mt-auto` on card metadata** | Pushes metadata to the absolute bottom of a stretched card, leaving a visual gap between the last bullet and the metadata section. | Use `mt-4` (fixed margin). The metadata should follow the content, not float to the card bottom. |
- | **Rounded corners everywhere** | Excessive `rounded-xl` and `rounded-2xl` creates a product/SaaS aesthetic, not a consulting aesthetic. | Use `rounded-lg` (8px) maximum for cards. For MBB-style decks, prefer `rounded` (4px) or sharp corners. |
- | **ECharts chart too small in its container** | Chart div has `flex-1` but the container has excessive padding, leaving the chart cramped. | Give chart divs explicit minimum heights or use `style="min-height: 0"` to allow proper flex shrinking. |
-
- ### Responsive Support Model
-
- Do not author examples against hardwired `sm/md/lg` buckets. The reference canvas remains `1280×720`, but responsiveness should follow the actual target `width` and `height`.
-
- Use one of two contracts:
-
- 1. **Chart / figure templates**
-
- ```javascript
- responsiveSpec: {
- templateClass: 'chart',
- exhibitRange: {
- min: { width: 960, height: 540 },
- preferred: { width: 1280, height: 720 },
- max: { width: 1600, height: 900 },
- },
- slideRange: {
- min: { width: 1024, height: 576 },
- preferred: { width: 1280, height: 720 },
- max: { width: 1600, height: 900 },
- },
- rationale: 'end labels become unreadable below the declared minimum',
- }
- ```
-
- Use this when the exhibit has a real legibility floor.
-
- 2. **Layout / content templates**
-
- ```javascript
- responsiveSpec: {
- templateClass: 'layout',
- previewSamples: [
- { label: 'compact', width: 1024, height: 576 },
- { label: 'preferred', width: 1280, height: 720 },
- { label: 'wide', width: 1440, height: 810 },
- ],
- agentSizingNotes: 'agent should split or simplify if width falls below the compact QA sample',
- }
- ```
-
- Use this for tables, roadmaps, flows, and card grids where the agent should determine the best composition on the fly rather than inherit a rigid supported-size matrix.
-
- The preview bench should:
-
- - render `min / preferred / max` checkpoints for chart templates
- - render representative QA samples for layout templates
- - verify text remains legible at the compact checkpoint for both tiers
-
- ### Design tokens
-
- Every palette provides these CSS custom properties. Use via Tailwind arbitrary values.
-
- | Token | Purpose | Tailwind |
- |---|---|---|
- | `--surface` | Default slide background | `bg-[var(--surface)]` |
- | `--surface-dark` | Cover / divider background | `bg-[var(--surface-dark)]` |
- | `--surface-muted` | Cards, evidence panels | `bg-[var(--surface-muted)]` |
- | `--accent` | Brand color, header bars, highlights | `text-[var(--accent)]` / `border-[var(--accent)]` |
- | `--accent-light` | Borders, light tint | `border-[var(--accent-light)]` |
- | `--text` | Primary text | `text-[var(--text)]` |
- | `--text-muted` | Secondary text, annotations | `text-[var(--text-muted)]` |
- | `--text-fine` | Footnotes, sources | `text-[var(--text-fine)]` |
- | `--text-on-dark` | Text on dark surfaces | `text-[var(--text-on-dark)]` |
- | `--font-heading` | Heading font family | `style="font-family: var(--font-heading)"` |
- | `--font-body` | Body font family | `style="font-family: var(--font-body)"` |
- | `--chart-primary` | Primary chart/data color | For inline SVG fills |
- | `--chart-secondary` | Secondary chart color | For inline SVG fills |
-
- ### Typography scale
-
- Two systems exist for typography sizing:
-
- 1. **Slide HTML** — use the Tailwind lookup table below. Pick a role, use its class. No guessing.
- 2. **ECharts exhibits** — use the responsive tokens from `examples/_shared.js` (`tokens.bodyText`, `tokens.smallText`, etc.). These scale with canvas size automatically.
-
- #### Tailwind type roles — slide HTML
-
- Every text element in slide HTML must use one of these roles. The table gives both the **Tailwind class** (what you write) and the **rendered px** (what you get) at 1280×720.
-
- | Role | Tailwind class | Rendered | Weight | Extras | Use for |
- |---|---|---|---|---|---|
- | **Cover title** | `text-[44px]` | 44px / 33pt | `font-bold` | `tracking-tight` | Title slide headline |
- | **Action title** | `text-[28px]` | 28px / 21pt | `font-semibold` | `tracking-tight leading-snug` | Slide conclusion sentence |
- | **Section label** | `text-[11px]` | 11px / 8pt | `font-semibold` | `tracking-widest uppercase` | "MOMENTUM DIAGNOSTIC" above title |
- | **Subtitle** | `text-lg` | 18px / 13.5pt | `font-normal` | — | Cover subtitle, context line |
- | **Body** | `text-[15px]` | 15px / 11pt | `font-normal` | `leading-relaxed` | Paragraphs, bullet descriptions, card body text |
- | **Body small** | `text-[13px]` | 13px / 10pt | `font-normal` | `leading-relaxed` | Secondary descriptions, table cells, annotations |
- | **Card metric** | `text-[26px]` | 26px / 19.5pt | `font-bold` | `tracking-tight leading-none` | "$240B", "200%+", large KPI numbers |
- | **Card label** | `text-[13px]` | 13px / 10pt | `font-semibold` | — | Metric name below the number |
- | **Card detail** | `text-[12px]` | 12px / 9pt | `font-normal` | — | Trend indicators, supplementary data below label |
- | **Panel header** | `text-[11px]` | 11px / 8pt | `font-bold` | `tracking-widest uppercase` | "KEY METRICS", "PERSPECTIVES" — mini-headers |
- | **Callout body** | `text-[13px]` | 13px / 10pt | `font-normal` | `leading-relaxed` | Text inside insight/callout boxes |
- | **Data label** | `text-xs` | 12px / 9pt | `font-medium` | — | Chart annotations, axis labels in HTML |
- | **Footer / source** | `text-[11px]` | 11px / 8pt | `font-normal` | — | Source line, confidentiality notice |
- | **Tag / badge** | `text-[10px]` | 10px / 7.5pt | `font-medium` | `px-2 py-0.5 rounded-full` | Pill labels inside cards |
-
- **Legibility floor:** No text below `text-[11px]` except tags/badges. Body-readable text (anything the audience is expected to *read*, not just *see*) must be ≥`text-[13px]` (13px / 10pt). Below that, text serves as a label or decoration, not content.
-
- **Tailwind ↔ px mapping for reference** (Tailwind CDN defaults):
-
- | Class | px | pt |
- |---|---|---|
- | `text-xs` | 12px | 9pt |
- | `text-sm` | 14px | 10.5pt |
- | `text-base` | 16px | 12pt |
- | `text-lg` | 18px | 13.5pt |
- | `text-xl` | 20px | 15pt |
- | `text-2xl` | 24px | 18pt |
- | `text-3xl` | 30px | 22.5pt |
-
- When a role falls between Tailwind breakpoints (e.g., 13px, 15px, 26px, 28px), use `text-[Npx]` arbitrary value syntax. This is intentional — the consulting typography scale doesn't align with Tailwind's default ramp.
-
- #### ECharts exhibit tokens
-
- For chart/exhibit JavaScript (inside `<script>` blocks or example files), use the responsive token system from `examples/_shared.js`:
-
- - `tokens.bodyText` / `tokens.smallText` / `tokens.microText` — text sizes that scale with canvas
- - `tokens.adapt(compact, preferred, wide)` — continuous interpolation for geometry
- - `tokens.textAdapt(compact, preferred, wide)` — slower compression for text legibility
- - `getFigureTypography(tokens)` — axis, legend, label, annotation, metric role presets
- - `getChartChrome(tokens)` — shared axis/gridline/legend config fragments
-
- Use token roles wherever the styling is standard. Do not abstract geometry, chart-specific layout, or exhibit-specific emphasis into shared helpers.
-
- ### Spatial constants
-
- | Zone | Value | Note |
- |---|---|---|
- | Horizontal padding | `px-14` (56px) | Content never touches slide edges |
- | Header top padding | `pt-10` (40px) | Space above section label / title |
- | Header accent bar | `border-t-4` (4px) | Top border in accent color |
- | Body vertical padding | `py-4` (16px) | Breathing room in body zone |
- | Column gap | `gap-6` – `gap-8` | Between grid columns (24–32px) |
- | Card gap | `gap-3` – `gap-4` | Between card items (12–16px) |
- | Card border radius | `rounded-lg` | Consistent card rounding |
- | Footer height | `py-2` (~40px) | Compact, fine text |
-
- ### Icons — Font Awesome 6
-
- Font Awesome 6 Free is vendored locally. Use `<i>` tags inline with text or as standalone decorators only when the glyph is render-stable in PDF output.
-
- **Common icons for consulting slides:**
-
- | Category | Icons |
- |---|---|
- | Trends | `fa-arrow-trend-up`, `fa-arrow-trend-down`, `fa-arrow-right` |
- | Status | `fa-circle-check`, `fa-circle-xmark`, `fa-triangle-exclamation` |
- | Metrics | `fa-chart-line`, `fa-chart-bar`, `fa-chart-pie`, `fa-percent` |
- | Financial | `fa-dollar-sign`, `fa-coins`, `fa-money-bill-trend-up` |
- | Org | `fa-building`, `fa-users`, `fa-user-tie`, `fa-sitemap` |
- | Strategy | `fa-bullseye`, `fa-lightbulb`, `fa-rocket`, `fa-chess` |
- | Process | `fa-gears`, `fa-arrows-spin`, `fa-diagram-project` |
- | Risk | `fa-shield-halved`, `fa-lock`, `fa-bug` |
- | Time | `fa-clock`, `fa-calendar`, `fa-hourglass-half` |
- | Data | `fa-database`, `fa-server`, `fa-cloud` |
-
- **Usage pattern:**
- ```html
- <!-- Inline with text -->
- <span class="text-[var(--accent)]"><i class="fa-solid fa-arrow-trend-up mr-2"></i>12% YoY</span>
-
- <!-- Card decorator (large) -->
- <i class="fa-solid fa-chart-line text-3xl text-[var(--accent)] mb-3"></i>
-
- <!-- Status indicator -->
- <i class="fa-solid fa-circle-check text-emerald-500 mr-1"></i>
- <i class="fa-solid fa-triangle-exclamation text-amber-500 mr-1"></i>
- <i class="fa-solid fa-circle-xmark text-red-500 mr-1"></i>
- ```
-
- Icons work best as visual anchors on KPI cards, process steps, and list items. Do not over-decorate. If a glyph is unstable in PDF output, replace it with a text badge or inline SVG.
-
- ### Data Visualization — ECharts 5
-
- ECharts 5 is vendored locally with **SVG renderer** (mandatory — `<canvas>` blanks in Playwright PDF). It provides 21 chart types with consulting-quality aesthetics when configured correctly.
-
- For exhibit selection, load [chart-taxonomy.md](chart-taxonomy.md) — it provides a decision tree (what does this slide prove? → exhibit type), firm-specific visual DNA (what each firm tolerates on charts), deck archetypes (exhibit mix by deck purpose), and annotation grammar. Use it BEFORE choosing any chart type.
-
- **Chart container pattern:**
- ```html
- <!-- In the slide HTML, place a div with explicit dimensions -->
- <div id="chart-1" style="width: 100%; height: 340px;"></div>
-
- <!-- After ALL slides, add a <script> block that initializes charts -->
- <script>
- document.addEventListener('DOMContentLoaded', () => {
- // Bar chart
- const chart1 = echarts.init(document.getElementById('chart-1'), null, { renderer: 'svg' });
- chart1.setOption({
- animation: false, // mandatory for static PDF
- // ... option config
- });
- });
- </script>
- ```
-
- **Important:** The `<script>` block goes **inside the slide HTML string** (after the layout HTML but before the closing backtick). The engine wraps each slide in a `<section>`, so scripts within a slide will execute in the browser.
-
- For **multi-chart slides**, use unique IDs (`chart-1`, `chart-2`, etc.) and initialize all charts in a single `<script>` block at the end of that slide's HTML.
-
- **MBB chart aesthetics — the configuration that makes charts look consulting-quality:**
-
- ```javascript
- // Universal ECharts config for MBB-quality output
- {
- animation: false, // static PDF — no animation
- grid: {
- left: 48, right: 24, top: 32, bottom: 40,
- containLabel: true,
- },
- textStyle: {
- fontFamily: 'Inter, system-ui, sans-serif',
- fontSize: 12,
- color: '#4E6176', // muted axis labels
- },
- title: {
- show: false, // title is in the slide header, not the chart
- },
- tooltip: { show: false }, // no interactive tooltips in PDF
- legend: {
- bottom: 0,
- textStyle: { fontSize: 11, color: '#4E6176' },
- itemWidth: 12, itemHeight: 12,
- itemGap: 16,
- },
- xAxis: {
- axisLine: { lineStyle: { color: '#C7D5E5' } },
- axisTick: { show: false },
- axisLabel: { fontSize: 11, color: '#4E6176' },
- splitLine: { show: false },
- },
- yAxis: {
- axisLine: { show: false },
- axisTick: { show: false },
- axisLabel: { fontSize: 11, color: '#4E6176' },
- splitLine: { lineStyle: { color: '#E4EDF7', type: 'dashed' } },
- },
- }
- ```
-
- **Chart type routing — which ECharts type for each consulting use case:**
-
- | Consulting use case | ECharts type | Key config |
- |---|---|---|
- | Revenue/metric comparison | `type: 'bar'` | Vertical bars, accent color primary, gray secondary |
- | Trend over time | `type: 'line'` | `smooth: false` for MBB (no curves), `areaStyle` for area |
- | Market share / composition | `type: 'pie'` | `radius: ['40%', '70%']` for donut, `label.position: 'outside'` |
- | Scatter / positioning | `type: 'scatter'` | `symbolSize` by value for bubble effect |
- | Revenue bridge / delta | `type: 'bar'` (stacked) | Invisible base + colored delta — waterfall pattern |
- | Performance meter | `type: 'gauge'` | `detail.formatter`, clean arc, no animation |
- | Flow / allocation | `type: 'sankey'` | `orient: 'horizontal'`, `nodeWidth: 20` |
- | Hierarchy / budget | `type: 'treemap'` | `visibleMin: 300`, `label.fontSize: 12` |
- | Multi-criteria radar | `type: 'radar'` | `indicator` array, filled area |
- | Pipeline / conversion | `type: 'funnel'` | `sort: 'descending'`, label inside |
- | Correlation matrix | `type: 'heatmap'` | With `visualMap` for color mapping |
-
- **Waterfall chart pattern (MBB signature):**
- ```javascript
- // Waterfall = stacked bar with invisible base
- series: [
- { name: 'base', type: 'bar', stack: 'waterfall',
- data: [0, 3800, 3800, 4100, 3900], // running base
- itemStyle: { color: 'transparent' },
- emphasis: { itemStyle: { color: 'transparent' } },
- },
- { name: 'delta', type: 'bar', stack: 'waterfall',
- data: [3800, 500, 300, -200, 300], // deltas (neg = red)
- itemStyle: {
- color: (params) => params.data >= 0 ? '#123A63' : '#CC4444',
- },
- label: {
- show: true, position: 'top',
- formatter: (p) => (p.data >= 0 ? '+' : '') + p.data,
- fontSize: 11, fontWeight: 'bold',
- },
- },
- ]
- ```
-
- **Color discipline for charts:**
- - Primary series: `var(--chart-primary)` or the hex value from the palette
- - Secondary series: `var(--chart-secondary)` — always gray
- - Positive delta: accent color or `#2E9E5A` (green)
- - Negative delta: `#CC4444` (red)
- - Never more than 4 colors in one chart. MBB charts are restrained.
+ Load [build-reference.md](build-reference.md) for the full slide construction reference — build script template, slide shell, layout primitives, content primitives, typography scale, design tokens, spatial constants, icons, ECharts configuration, composition routing, and layout anti-patterns.
- **CSS-only bar charts (no ECharts needed for simple bars):**
- ```html
- <!-- Horizontal bar — pure CSS, no JavaScript -->
- <div class="flex items-center gap-3 mb-2">
- <span class="w-24 text-[13px] text-[var(--text)] text-right shrink-0">Revenue</span>
- <div class="flex-1 bg-[var(--surface-muted)] rounded-full h-6 overflow-hidden">
- <div class="h-full bg-[var(--accent)] rounded-full" style="width: 78%"></div>
- </div>
- <span class="text-[13px] font-semibold text-[var(--text)] w-12">78%</span>
- </div>
- ```
+ ### Key build principles
- Use CSS-only bars for simple progress/comparison visuals. Use ECharts for anything with axes, legends, or complex data.
+ - **Use CSS Grid for the slide shell** (`grid-template-rows: auto minmax(0,1fr) 48px`). This structurally prevents footer overflow. Do not use `flex flex-col` with `flex-1`.
+ - **Fill-first orientation.** Start from body height (≈ 600px), subtract surrounding elements, set the chart to the remainder. Portrait charts (height > width) are valid and preferred over leaving empty space.
+ - **Use palette tokens** (`var(--accent)`, `var(--text)`, etc.), not hardcoded hex.
+ - **Use `headExtra` CSS classes** for the shell on decks >5 slides. Use Tailwind for body content layout.
+ - **For decks >10 slides**, consider modular authoring — one file per slide, assembled by `build.js`.
+ - **ECharts: SVG renderer only** (`{ renderer: 'svg' }`). Canvas blanks in Playwright PDF. Always set `animation: false`.
## Firm Style
- Conventions for L2+ consulting decks. These govern LAYOUT and COMPOSITION per firm. For chart-level visual treatment and firm identity details, see [chart-taxonomy.md](chart-taxonomy.md) § Firm Visual Identity.
-
- **The real differentiator between firms is communication structure, not chart selection.** All three firms use the same foundational charts (waterfalls, bars, lines, stacked bars). What differs is how the slide is organized and how the argument flows.
-
- ### McKinsey — Verdict-First
-
- Rooted in the Pyramid Principle (Barbara Minto, McKinsey, 1960s–70s): conclusion leads, evidence follows.
-
- **Header:** Two-tier — section label (small, accent color, uppercase) above action title (large, bold, dark). No rule below.
-
- **Action titles:** Full-sentence conclusions. "Revenue grew 12% driven by pricing power in mid-tier" — not "Revenue Overview". Read all titles in sequence: they must tell the complete argument (the "helicopter test").
-
- **Composition:** Conclusion-first. Evidence is clean, minimal annotation. Navy palette, single blue hue at different lightness levels for data series. Exhibit numbering ("Exhibit 1.2") creates formal reference system.
-
- ### BCG — Framework-First
-
- Rooted in analytical transparency (Growth-Share Matrix tradition, Bruce Henderson, 1970): show the reasoning, then the conclusion.
-
- **Header:** Section label (dark green, uppercase) → action title (black, bold) → green rule (~3px, full width below title).
-
- **Action titles:** Framework-anchored claims. "Three of five capability dimensions exceed peer median" — not "Capabilities Assessment".
-
- **Composition:** Analytical structure is visible. Panel mini-headers on multi-panel slides. Evaluation matrices with RAG cell fills (green/amber/red washes at low opacity) for criteria-based assessment. Green accent system.
-
- ### Bain — Decision-First
-
- Rooted in Results Delivery (NPS tradition, Fred Reichheld, 2003): every exhibit connects to a specific decision and measurable outcome.
-
- **Header:** Action title (bold, black) → red rule (~3px, full width below title). No section label above. Simpler than McKinsey/BCG.
-
- **Action titles:** Decision-oriented. "Cost structure supports 15% price reduction without margin erosion" — always answers "so what should we do?"
-
- **Composition:** Facts-vs-perspectives split is the distinctive layout: left (~55%) shows data and evidence, right (~45%) shows interpretation and recommended action. This is the one genuinely firm-specific visual convention — it separates what the data shows from what the firm recommends. Red accent marks the focal element per slide.
-
- ## Compositions
-
- ### Layout primitives
-
- Six layout structures for the body zone. Combine with the [three-zone shell](#slide-anatomy--the-three-zone-shell).
-
- | Layout | Grid | Use when |
- |---|---|---|
- | **Single column** | `flex flex-col gap-4` | Narrative text, ordered list, simple argument |
- | **Two-column** | `grid grid-cols-2 gap-8` | Chart + bullets, comparison, evidence + sidebar |
- | **Asymmetric split** | `grid grid-cols-[3fr_2fr] gap-8` | Main exhibit + sidebar (55/45) |
- | **Three-column** | `grid grid-cols-3 gap-6` | KPI cards, feature comparison, triple evidence |
- | **Card grid** | `grid grid-cols-3 gap-4` (or 2/4) | Scorecards, team, feature tiles |
- | **Full bleed** | No shell — direct child of `<section>` | Cover, divider, hero image |
-
- ### Content primitives
-
- Small HTML components to compose inside layout primitives.
-
- **KPI Metric Card:**
- ```html
- <div class="bg-[var(--surface-muted)] rounded-lg p-5 flex flex-col">
- <i class="fa-solid fa-chart-line text-2xl text-[var(--accent)] mb-3"></i>
- <span class="text-[28px] font-bold tracking-tight text-[var(--text)]">$4.2B</span>
- <span class="text-[13px] font-semibold text-[var(--text)] mt-1">Revenue</span>
- <span class="text-xs text-[var(--text-muted)] mt-1">
- <i class="fa-solid fa-arrow-trend-up text-emerald-500 mr-1"></i>↑ 12% YoY
- </span>
- </div>
- ```
-
- **Evidence Panel (bordered):**
- ```html
- <div class="border border-[var(--accent-light)]/40 rounded-lg p-5">
- <h3 class="text-xs font-bold tracking-widest uppercase text-[var(--accent)] mb-3">
- Key Drivers
- </h3>
- <ul class="space-y-2 text-[14px] text-[var(--text)]" style="font-family: var(--font-body)">
- <li class="flex items-start gap-2">
- <i class="fa-solid fa-chevron-right text-[10px] text-[var(--accent)] mt-1.5 shrink-0"></i>
- <span>Market share grew 3pp driven by pricing advantage in mid-tier segment</span>
- </li>
- </ul>
- </div>
- ```
-
- **Data Table:**
- ```html
- <table class="w-full text-[13px]" style="font-family: var(--font-body)">
- <thead>
- <tr class="border-b-2 border-[var(--accent)]">
- <th class="text-left py-2 font-semibold text-[var(--text)]">Metric</th>
- <th class="text-right py-2 font-semibold text-[var(--text)]">2024</th>
- <th class="text-right py-2 font-semibold text-[var(--text)]">2025</th>
- <th class="text-right py-2 font-semibold text-[var(--text)]">Delta</th>
- </tr>
- </thead>
- <tbody class="text-[var(--text)]">
- <tr class="border-b border-[var(--accent-light)]/30">
- <td class="py-2">Revenue</td>
- <td class="text-right py-2 tabular-nums">$3.8B</td>
- <td class="text-right py-2 tabular-nums">$4.2B</td>
- <td class="text-right py-2 font-semibold text-emerald-600">+11%</td>
- </tr>
- </tbody>
- </table>
- ```
-
- **Callout Box:**
- ```html
- <div class="bg-[var(--accent)]/5 border-l-4 border-[var(--accent)] px-5 py-4 rounded-r-lg">
- <p class="text-[14px] font-medium text-[var(--text)]">
- <i class="fa-solid fa-lightbulb text-[var(--accent)] mr-2"></i>
- Key insight or recommendation text here
- </p>
- </div>
- ```
-
- ### Composition routing
-
- Map each slide's communication move to a layout composition.
+ For L2+ consulting decks only. All three firms use the same charts. What differs is communication structure.
- | User intent / data shape | Layout | Content primitives | Notes |
+ | Firm | Header | Composition signature | Accent |
|---|---|---|---|
- | Cover / title page | Full bleed | Centered title + subtitle on dark surface | No shell — full `h-full` |
- | Section divider | Full bleed | Section number (large) + title on dark | Page break rhythm |
- | Agenda / TOC | Single column | Numbered list items, active item highlighted | Accent color on active |
- | 4–6 KPIs / metrics | Card grid (3-col or 2×3) | KPI metric cards | Icons + trend indicators |
- | Claim + chart evidence | Asymmetric split | Chart (left) + evidence panel (right) | SVG chart or CSS bars |
- | Binary choice (A vs B) | Two-column | Comparison cards with criteria rows | Highlight recommended |
- | Process / mechanism | Single column | Numbered step cards with icons | Horizontal or vertical |
- | Data comparison table | Single column | Data table + optional callout box | Color-coded deltas |
- | Timeline / milestones | Single column | Horizontal timeline with markers | CSS flex with dots |
- | Waterfall / bridge | Single column | CSS bar chart + interpretation panels | Start → deltas → end |
- | Evaluation matrix | Single column | Grid table with RAG cell fills | Color-coded ratings |
- | Facts vs perspectives | Two-column | Left: fact bullets + chart. Right: perspective bullets | Bain signature |
- | Multi-evidence composite | Asymmetric split | Main chart + metric cards below + sidebar | L3 density |
- | Team / founders | Card grid (4-col) | Name + role + bio cards | Optional photo/icon |
- | Closing / recommendation | Full bleed or single | Centered recommendation + next steps list | Clean, authoritative |
- | Workplan / Gantt | Single column | CSS grid calendar with colored spans | Time periods as columns |
-
- ### Firm-specific composition rules
+ | **McKinsey** | Section label + action title. No rule. | Verdict-first — conclusion in title, evidence below. Exhibit numbering. | Navy |
+ | **BCG** | Section label + action title + green rule below. | Framework-first — analytical structure visible, panel mini-headers. | Green |
+ | **Bain** | Action title + red rule below. No section label. | Decision-first — facts-vs-perspectives split (left 55% data, right 45% interpretation). | Red |
- | Firm | Layout signature | Communication signature |
- |---|---|---|
- | McKinsey | Two-tier header (section label + action title). Exhibit numbering. | Verdict-first — conclusion in title, evidence below. |
- | BCG | Green rule below action title. Panel mini-headers on multi-panel slides. | Framework-first — analytical structure visible, then conclusion. |
- | Bain | Red rule below action title. Facts-vs-perspectives split. | Decision-first — data separated from interpretation. |
+ For full firm conventions, load [firm-dna.md](firm-dna.md). For chart-level visual treatment, see [chart-taxonomy.md](chart-taxonomy.md) § Firm Visual Identity.
## Composition Rules
- **Start** with a cover slide. Use section dividers for chapter breaks in decks >8 slides.
- **One slide = one argument.** Every action title advances a distinct claim.
- **Dead slide test.** If you can remove a slide and the argument still works, remove it. Every slide must be load-bearing.
- **Do not repeat the same layout back-to-back.** Alternate between layout types.
- **Helicopter test.** Read all action titles in sequence — they must tell a complete, persuasive story without any exhibit bodies.
- **Density level governs composition.** Do not use L3 multi-evidence composites on an L1 pitch deck.
- **Chart variety.** Do not use the same chart type on consecutive slides.
- **Icon restraint.** One icon per card or list item. No icon walls. Use accent color, not rainbow.
- **Section rhythm.** For decks >8 slides, group into 3–4 sections. Open each with agenda (active item) or divider. Close with synthesis before the next section.
- **Content fit.** Content must fill the body zone without overflow or sparseness. If a slide looks empty, add evidence layers. If it's crowded, split into two slides.
- **Visual balance.** Content is vertically centered in the body zone by Flexbox — let `flex-1` handle distribution. Do not force absolute positioning.
- **Color discipline.** Use palette tokens, not hardcoded hex. Semantic colors (emerald/amber/red) only for status indicators, never for decoration.
- **Annotation is value, not decoration.** See chart-taxonomy.md's Annotation Grammar. The callout that says "This 15% gap = $340M unrealized" is why the engagement costs what it costs.
## Output Organization
Save deliverables to the current working directory (or user-specified folder). Kebab-case naming:
- `{slug}.pdf` — the deliverable
- `build-{slug}.js` — the build script (reproducible)
- - `{slug}-outline.md` — the deck outline
+ - `{slug}-ghost.md` — the argument layer (governing thought, action titles, exhibits)
+ - `{slug}-outline.md` — the execution layer (ghost deck + geometry)
## Architecture
Self-contained: `package.json` + `node_modules/` are inside the skill folder. All `require()` calls resolve locally.
- | File | Purpose |
- |---|---|
- | `engine/index.js` | `createDeck(options)` — assembles HTML document, calls renderer |
- | `engine/render.js` | Playwright Chromium → `page.pdf()` at configurable dimensions |
- | `engine/canvas.css` | Slide container, print-color-adjust, CSS custom property defaults |
- | `palettes/*.css` | CSS custom properties per style (colors, fonts) |
- | `ghost-deck.md` | Ghost deck methodology: 5-layer model, governing thought, quality gates |
- | `engagement-archetypes.md` | 8 engagement archetypes + 5 transition patterns + rising-stakes progression |
- | `firm-dna.md` | McKinsey/BCG/Bain epistemology, deck structure, communication signatures |
- | `evidence-recipes.md` | 10 data-shape recipes, layering rules, engagement × recipe mapping |
- | `density-adaptation.md` | L1/L2/L3 adaptation rules, compression/expansion, slide counts |
- | `skeletons/*.md` | 8 engagement skeletons: governing thought, pillars, slide index, kill conditions, quality gates |
- | `chart-taxonomy.md` | Exhibit design playbook: decision tree, firm visual DNA, annotation grammar |
- | `examples/_shared.js` | Typography tokens, chart chrome, responsive sizing — the internal standards layer |
- | `examples/*.js` | 46 visual pattern references covering Tier 1–4 exhibits + consulting compositions |
+ | File | When to load | Purpose |
+ |---|---|---|
+ | `build-reference.md` | Phase 2 (Build) | Slide shell, typography, ECharts, layout primitives, anti-patterns |
+ | `chart-taxonomy.md` | Exhibit selection | Decision tree, firm visual DNA, deck archetypes, annotation grammar |
+ | `ghost-deck.md` | Consulting path | 5-layer model, dependencies, quality gates, golden trace |
+ | `engagement-archetypes.md` | Consulting path | 8 archetypes, transitions, rising-stakes progression |
+ | `skeletons/*.md` | Consulting path | Pillar architecture, slide index, kill conditions per archetype |
+ | `firm-dna.md` | Consulting path | McKinsey/BCG/Bain epistemology, communication signatures |
+ | `evidence-recipes.md` | Consulting path | 10 data-shape recipes, layering rules |
+ | `density-adaptation.md` | Consulting path | L1/L2/L3 compression/expansion rules |
+ | `engine/index.js` | Always | `createDeck(options)` — assembles HTML, calls renderer |
+ | `engine/render.js` | Always | Playwright Chromium → `page.pdf()` |
+ | `palettes/*.css` | Always | CSS custom properties per style (colors, fonts) |
+ | `examples/_shared.js` | Build reference | Typography tokens, chart chrome, responsive sizing |
+ | `examples/*.js` | Build reference | 46 visual pattern references — read-only, not imported at runtime |
**How examples relate to deck building:** The agent does NOT import or call example files at runtime. Examples exist as **read-only references** — the agent reads them to learn visual patterns, then writes original HTML in the build script. The build script uses only `engine/index.js` (`createDeck`). The examples use `_shared.js` to demonstrate best practices for token usage, but the agent composes slide HTML directly.
The engine handles: HTML document assembly, vendored font loading, Font Awesome injection, ECharts (SVG renderer), Tailwind injection, palette CSS injection, Playwright launch, `page.pdf()` rendering. All assets are local — zero network dependency at build time.
## What NOT To Do
**Rendering constraints:**
- Do not use `<canvas>` for charts — canvas elements blank in Playwright's PDF pipeline. Use ECharts SVG renderer or CSS-only visuals.
- Do not add animation, transitions, or hover states. The output is static PDF.
- Do not use `@media print` overrides — the engine uses `emulateMedia('screen')`.
- Use CSS Grid (`grid-template-rows: auto minmax(0,1fr) 48px`) for the slide shell, not `flex flex-col` with `flex-1`. See § Wrapped slide shell and § Slide layout anti-patterns.
**Architecture constraints:**
- Do not create separate HTML files per slide. All slides go in one build script, one HTML document, one PDF.
- Do not generate interactive presentations (Reveal.js, Slidev). Output is always static PDF.
- Do not hardcode palette colors — use CSS custom properties (`var(--accent)`, `var(--text)`, etc.) so palette switching works.
**Design discipline:**
- Do not copy example data into real decks. Example numbers ($4.2B, 12.4M units) are illustrative — use the user's actual data.
- Do not choose exhibit types by visual appeal. Choose by what the slide's argument needs to prove. A bold number can be more powerful than a chart.
- Do not over-decorate. No icon walls, no rainbow colors, no gradients on data elements. Consulting aesthetics come from restraint, not embellishment.
- Do not use the same exhibit type on consecutive slides. Alternate to maintain visual rhythm.
**Agent behavior:**
- Do not ask the user to pick a chart type. The taxonomy's decision tree and the ghost deck's action titles determine the exhibit. You make the visual decision.
- Do not ask the user for show vs. working deck preference. Infer from audience and objective — "board presentation" is show, "diligence data room" is working.
- Do not present multiple layout options for approval. Commit to the best composition based on the content density and argument structure. The user reviews the output PDF, not a menu of choices.