Install
$ agentstack add skill-thatrebeccarae-claude-marketing-pro-deck-builder ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Presentation Designer
VC-backed SaaS design quality for PowerPoint. Think Linear, Attio, Vercel, Raycast — not corporate clip art.
Install
git clone https://github.com/thatrebeccarae/claude-marketing.git && cp -r claude-marketing/skills/pro-deck-builder ~/.claude/skills/
Quick Reference
| Task | Approach | |------|----------| | Create from scratch | Read [REFERENCE.md](REFERENCE.md), use PptxGenJS | | Edit existing / use template | Read [editing.md](editing.md) | | Read/extract content | python -m markitdown presentation.pptx | | Visual overview | python scripts/thumbnail.py presentation.pptx |
Before You Start (Required Steps)
Step 1: Ask the User
Before writing any code, ask:
- Light or dark mode? Dark = premium/keynote feel. Light = reports/data-heavy decks.
- Palette preference? Show the palette table below, or ask if they have brand colors.
- Logo? Ask if they have a logo file to include (PNG/SVG path).
Step 2: Discover Fonts
Check what's installed — premium fonts make a massive difference:
# macOS — list all installed font families
fc-list : family | sort -u
# Search for premium fonts first
fc-list : family | grep -iE "inter|dm.sans|poppins|avenir|futura|geist|sf.pro|sf.mono|jetbrains|fira.code|montserrat|playfair|source.sans"
# Check macOS Font Book directories directly
ls ~/Library/Fonts/ /Library/Fonts/ /System/Library/Fonts/Supplemental/ 2>/dev/null
Priority order for font selection:
- Inter — the gold standard for SaaS UI (if installed, use it for everything)
- DM Sans — geometric, startup-friendly
- Poppins — rounded, approachable
- Avenir / Avenir Next — ships with macOS, Apple-adjacent elegance
- Calibri — safe fallback, always available
For data/mono: JetBrains Mono > Fira Code > SF Mono > Consolas
Design Language: VC-Backed SaaS
Aesthetic Principles
- Depth through layering — Surfaces float above backgrounds. Cards and panels have subtle elevation via shadows and fine borders, not flat colored boxes.
- Bold typography, minimal decoration — Let type hierarchy do the work. No accent lines, no decorative shapes, no clip art.
- Restrained color — One accent color used sparingly (10%). Mostly neutrals. Color = signal, not decoration.
- Generous whitespace — Empty space signals confidence. If a slide feels sparse, make the content bigger, don't add more.
- Every element earns its place — Before adding anything: what does it communicate? If removing it changes nothing, remove it.
Light vs Dark Mode
The user picks one mode for the entire deck. Never mix modes within a deck.
Color System
Dark Mode (Default — Premium/Keynote)
| Token | Value | Use | |-------|-------|-----| | bg-primary | 0A0A0C | Slide backgrounds (deep space black) | | bg-surface | 17181A | Cards, panels (deep slate) | | bg-elevated | 1E1F23 | Elevated surfaces, hover states | | bg-glass | FFFFFF at 4% opacity | Translucent overlays | | text-primary | FFFFFF | Headlines, key content | | text-secondary | A0A0A0 | Body text, descriptions | | text-muted | 5A5A5E | Captions, metadata, labels | | border-subtle | FFFFFF at 8% opacity | Card borders |
Light Mode (Reports/Data-Heavy)
| Token | Value | Use | |-------|-------|-----| | bg-primary | FFFFFF | Slide backgrounds | | bg-surface | F8F9FA | Cards, panels | | bg-elevated | FFFFFF | Elevated surfaces (use shadow) | | text-primary | 111111 | Headlines, key content | | text-secondary | 555555 | Body text, descriptions | | text-muted | 999999 | Captions, metadata, labels | | border-subtle | E8E8E8 | Card borders |
Palette System
Each palette defines one accent color (used at 10%) plus semantic status colors. The accent is the personality — everything else is neutral.
Built-In Palettes
| Name | Accent | Hex | Best For | |------|--------|-----|----------| | Electric Blue | Intense azure | 0055FF | SaaS, tech, product | | Neon Lime | Acid green | 39FF14 | Dev tools, performance | | Hot Coral | Warm energy | FF6B6B | Marketing, creative | | Indigo | Deep purple | 6366F1 | Startups, AI/ML | | Teal Trust | Cool confidence | 0D9488 | Healthcare, finance | | Amber Signal | Warm authority | F59E0B | Consulting, strategy | | Rose | Refined pink | F43F5E | Design, brand, luxury | | Emerald | Growth green | 10B981 | Sustainability, success | | Cyan Edge | Sharp blue-green | 06B6D4 | Data, analytics | | Violet | Creative depth | 8B5CF6 | Education, innovation | | Slate | No accent | 64748B | Minimal, understated | | Gold Standard | Financial premium | D4AF37 | Investor, board decks |
Custom Palette (User Brand Colors)
If the user provides brand colors, build a custom palette:
const palette = {
accent: "0055FF", // primary brand color
accentMuted: "0055FF" + " at 15% opacity", // for tinted backgrounds
positive: "10B981", // good, up, success
warning: "F59E0B", // attention, caution
critical: "EF4444", // bad, down, error
};
Color Application: 85/10/5 Rule
- 85% — Backgrounds + neutral text (bg + text tokens from mode)
- 10% — Accent (key numbers, chart primary, CTAs, active states)
- 5% — Semantic status (positive/warning/critical in KPIs and data)
Typography
Font Priority
Run font discovery (Step 2 above), then pick:
| Priority | Header | Body | Data/Mono | Vibe | |----------|--------|------|-----------|------| | 1st | Inter 700 | Inter 400 | JetBrains Mono | Linear/Vercel | | 2nd | DM Sans 700 | DM Sans 400 | Fira Code | Geometric startup | | 3rd | Avenir Next Bold | Avenir 400 | SF Mono | Apple-adjacent | | 4th | Poppins 700 | Poppins 400 | JetBrains Mono | Friendly modern | | Safe | Calibri Bold | Calibri | Consolas | Always available |
For editorial/financial decks:
| Header | Body | Vibe | |--------|------|------| | DM Serif Display | DM Sans | Sophisticated editorial | | Playfair Display | Source Sans Pro | Luxury, financial | | Georgia | Calibri | Classic corporate |
Size Scale
| Role | Size | Weight | Use | |------|------|--------|-----| | Hero title | 54-72pt | Bold (700) | Title slide only | | Slide title | 32-40pt | Bold (700) | Every content slide | | Section header | 20-24pt | Semibold (600) | Within-slide sections | | Body text | 14-16pt | Regular (400) | Paragraphs, bullets | | Captions/meta | 10-12pt | Regular (400) | Footnotes, sources | | Big KPI number | 48-72pt | Bold (700) | Dashboard callouts | | KPI label | 9-10pt | Semibold, ALL CAPS, +tracking | Below KPI numbers | | Data/numbers | 11-14pt | Mono regular | Tables, data labels |
Typography Rules
- Left-align body text and lists — center ONLY titles and KPI values
- Max 2 font families per deck (+1 mono for data)
- ALL CAPS + charSpacing only for small labels (KPI labels, category tags)
- Line height: 1.3x for body, 1.1x for titles
- Never underline for emphasis — use bold or accent color
Text Fitting (Prevents Overflow)
Big numbers and titles WILL overflow if you use a fixed font size without checking content length. Use these rules:
Big KPI Numbers — scale font to character count:
| Characters | Example | Max Font Size (card) | Max Font Size (standalone) | |------------|---------|---------------------|--------------------------| | 1–4 | $4.2M | 48pt | 72pt | | 5–7 | $5,307K | 36pt | 54pt | | 8–10 | $5,307,540 | 28pt | 44pt | | 11+ | $12,345,678 | 22pt | 36pt |
Rule: prefer abbreviated numbers. $5.3M > $5,307,540. Only use full numbers in tables or footnotes where precision matters.
Slide Titles — max characters before wrapping:
| Font Size | Max Chars (~9" wide) | If Longer | |-----------|---------------------|-----------| | 54pt | ~30 | Reduce to 44pt or rewrite shorter | | 44pt | ~38 | Reduce to 36pt or rewrite shorter | | 36pt | ~46 | Reduce to 32pt or rewrite shorter | | 32pt | ~52 | Use subtitle for overflow |
Rule: count characters before setting fontSize. Never let content slide titles wrap to 2 lines. Section dividers can wrap.
Body Text in Narrow Containers (Insight Panels, Sidebars):
Text overflow in narrow panels (=1000000]"$"#,##0.0,,"M";[>=1000]"$"#,##0.00,"K";"$"#,##0';
values: [2888000, 717734, 425467, 3655], // raw dollar values dataLabelFormatCode: currFmt, // conditional brackets OK here valAxisLabelFormatCode: '"$"#,##0.0,,"M"', // simple format only (no brackets)
```javascript
// ✅ ALSO OK: Pre-scale when all values are same magnitude
values: [2888, 718, 425], // raw values divided by 1000
dataLabelFormatCode: '"$"#,##0"K"',
valAxisLabelFormatCode: '"$"#,##0"K"',
// ❌ WRONG: Raw values with axis-only format
values: [2888000, 718000, 425000],
valAxisLabelFormatCode: "$#,##0,K", // axis may format but data labels show 2888000
// ❌ WRONG: numFmt (not a valid PptxGenJS property)
OOXML conditional format reference (use with RAW values):
| Data Range | Format Code | Renders As | |------------|-------------|------------| | Currency (auto-scale) | '[>=1000000]"$"#,##0.0,,"M";[>=1000]"$"#,##0.00,"K";"$"#,##0' | $2.9M, $540.18K, $500 | | Plain number (auto-scale) | '[>=1000000]#,##0.0,,"M";[>=1000]#,##0.00,"K";#,##0' | 2.9M, 540.18K, 500 | | Percentage | '0%' | 50%, 85% |
Format code syntax: OOXML supports up to 2 conditions in brackets + a default: [condition1]format1;[condition2]format2;defaultFormat. Each trailing , divides by 1,000 (so ,, divides by 1M).
IMPORTANT: valAxisLabelFormatCode does NOT support OOXML conditional brackets [>=1000]. Use a simple format for the axis based on the data range:
| Axis Range | valAxisLabelFormatCode | Renders As | |------------|----------------|------------| | Up to ~999K | '"$"#,##0,"K"' | $0K, $100K, $500K | | Up to ~10M+ | '"$"#,##0.0,,"M"' | $0.0M, $0.5M, $1.0M | | Up to ~999 | '"$"#,##0' | $0, $100, $500 |
Use the conditional currFmt for dataLabelFormatCode (which supports brackets), but a simple format for valAxisLabelFormatCode. Always set showValue: true with dataLabelPosition: "outEnd" on bar charts so readers can see exact values without tracing to the axis.
Spacing
| Token | Value | Use | |-------|-------|-----| | xs | 0.125" | Within grouped elements | | sm | 0.25" | Label to value, icon to text | | md | 0.375" | Between sections within a card | | lg | 0.5" | Between cards, major sections | | xl | 0.75" | Between content zones |
Layout Grid (10" × 5.625")
Margins: 0.5" from all edges
Content area: 9.0" wide × ~4.5" tall
Title zone: y = 0.3"
Content zone: y = 1.0" to y = 5.0"
Footer zone: y = 5.2"
Card gap: 0.25" - 0.3"
Logo Placement
Finding Logos
find ~/Desktop ~/Downloads ~/Documents -maxdepth 3 -iname "*logo*" \( -name "*.png" -o -name "*.svg" -o -name "*.jpg" \) 2>/dev/null
Placement Patterns
| Slide Type | Position | Size | Notes | |------------|----------|------|-------| | Title slide (top-left) | x:0.5, y:0.4 | w:1.5, h:0.5 | Subtle brand mark | | Title slide (centered) | x:4.0, y:0.8 | w:2.0, h:0.7 | Above title text | | Content slides | x:8.5, y:0.2 | w:1.0, h:0.35 | Top-right corner, every slide | | Closing slide | x:3.5, y:1.5 | w:3.0, h:1.0 | Centered, hero size |
Logo Rules
- Always use
sizing: { type: "contain", w, h }to preserve aspect ratio - Content slides: max 1" wide, don't compete with content
- Title/closing: up to 3" wide for brand moment
- Dark mode: use white/light logo variant if available (ask user)
- Slide master: if logo goes on every slide, add it to a master definition
Icons
Pipeline: react-icons → sharp → PNG → PptxGenJS
npm install -g react-icons react react-dom sharp
Prefer Lucide (react-icons/lu) or Feather (react-icons/fi) — they match the Linear/Vercel icon language.
| Package | Import | Style | |---------|--------|-------| | react-icons/lu | Lucide | Linear-style, clean | | react-icons/fi | Feather | Thin, modern | | react-icons/hi2 | Heroicons v2 | Apple-ish | | react-icons/tb | Tabler | Consistent strokes |
Icon Sizes
| Context | Display Size | Color | |---------|-------------|-------| | KPI card icon | 0.35" × 0.35" | Accent on dark, muted on light | | Feature row icon | 0.4" × 0.4" | White inside accent circle | | Section divider | 0.5" × 0.5" | Accent color | | Inline bullet | 0.25" × 0.25" | text-secondary |
Reusable Components
Bottom Callout Box (Standardized)
Many slides end with a highlighted callout box (recommendation, key insight, total impact). These must be visually identical across all slides:
| Property | Value | Notes | |----------|-------|-------| | Box height | 0.6" | Always 0.6" — never 0.5", 0.7", 0.9" | | Text height | 0.5" | Fits inside 0.6" box with padding | | Font size | 11pt | Always 11pt bold — never 12pt or 13pt | | Font | theme.font.body | Bold, left-aligned, valign: "middle" | | Box x/w | x: 0.5, w: 9.0 | Full content width | | Text x/w | x: 0.7, w: 8.6 | Inset 0.2" from box edges | | Text y offset | box y + 0.05" | Centers text vertically in box | | Corner radius | 0.06" | Consistent across all callouts |
// Standard bottom callout — copy this pattern exactly
s.addShape(pres.shapes.RECTANGLE, {
x: 0.5, y: calloutY, w: 9.0, h: 0.6,
fill: { color: "DCFCE7" }, // or theme.accentMuted, "FEF3C7", etc.
line: { color: theme.status.positive, width: 0.75 },
rectRadius: 0.06,
});
s.addText("Callout text here.", {
x: 0.7, y: calloutY + 0.05, w: 8.6, h: 0.5,
fontSize: 11, fontFace: theme.font.body, bold: true,
color: "166534", align: "left", valign: "middle",
});
Table + Callout Layout (Prevents Overlap)
Always calculate the table bottom position before placing a callout below it. PptxGenJS tables don't auto-report their height, so you must compute it:
tableBottom = tableY + (rowCount × rowH)
calloutY = tableBottom + 0.15" // minimum 0.15" gap
**Verify calloutY + 0.6" (callout height) 11pt will overflow.
- ACCENT LINES: Any thin horizontal bars/lines under titles or headings (must be removed)
- CHART DATA LABELS: Raw unformatted numbers on data labels (e.g., "2888000" instead of "$2,889K"). This is the #1 chart bug — valAxisLabelFormatCode does NOT format data labels.
- CHART AXES: Raw unformatted numbers on axes (should be $500K not 500000)
- Overlapping elements, cramped spacing (<0.3"), insufficient margins (<0.5")
- Low contrast, text-only slides, repeated layouts, placeholder text
- Mode inconsistency (light elements on dark or vice versa)
- Big numbers that should be abbreviated ($5.3M not $5,307,540)
- CALLOUT INCONSISTENCY: Bottom callout boxes with different heights, font sizes, or padding across slides (all must be h:0.6", fontSize:11)
- TABLE-CALLOUT OVERLAP: Callout boxes overlapping tables — calculate tableY + (rows × rowH) and verify callout clears it
- CHART FONT INCONSISTENCY: Different dataLabelFontSize, catAxisLabelFontSize, or valAxisLabelFontSize between charts on different slides
Fix → re-render → inspect → repeat until clean. **Complete at least one fix cycle.**
---
## Dependencies
```bash
npm install -g pptxgenjs # Creation
npm install -g react-icons react react-dom sharp # Icons
pip install "markitdown[pptx]" Pillow # Reading + QA
# Also: LibreOffice (soffice) + Poppler (pdftoppm) for visual QA
Implementation
Read [REFERENCE.md](REFERENCE.md) for PptxGenJS API patterns and complete slide composition code for both light and dark modes.
Brand Context (Optional)
If brand-profile.json exists in the working directory, read it before building decks. Override the default RRBC palette
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: thatrebeccarae
- Source: thatrebeccarae/claude-marketing
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.