Awesome Deck Pdf Check
v1.0.5Convert PPTX, image, URL, or style keywords into a polished, pixel-perfect HTML slide deck with user-approved design and content, then export as high-quality...
HTML → PDF Slide Workflow
‼️ STOP — Read Before Doing Anything
Before writing a single line of code or HTML, you MUST complete these two confirmation steps in order. Do not proceed until you receive explicit user approval for each.
Confirmation 1 of 2: Design Style
Analyze the user's input (image / URL / keyword / .pptx), then show a design spec summary and ask:
Here's the design style I extracted from [source]:
- Background:
#000dark / Accent:#2997FFblue- Font: SF Pro Display, oversized heading, minimal whitespace
- Style: dark Keynote, glow effects
Does this match what you want? Any changes before I start?
If the user provided a website URL and fetching fails (Fake IP, login wall, etc.):
- Say exactly why it failed
- Ask: "Could you send a few screenshots of the site? I'll analyze the design from those."
- Do NOT assume or default to any style
Wait for explicit approval → then move to Confirmation 2.
Confirmation 2 of 2: Slide Content
Ask the user if they have existing materials:
Do you have reference materials for the content? (existing PPT, doc, data, bullet points — anything works) If yes, send them over. If not, I'll draft an outline for you to review.
Once you receive a reply, prepare a numbered list: slide title + one-line summary per slide. Show it and ask:
Here's the planned structure — does this look right? Anything to add, remove, or change?
Wait for explicit approval → only then begin generating HTML.
If either confirmation is skipped, the workflow is broken. Start over from Confirmation 1.
export_pdf.js auto-detects Chrome in this order:
- Puppeteer bundled Chromium (
npm install puppeteer) - System Chrome/Chromium (macOS:
/Applications/Google Chrome.app, Linux:/usr/bin/chromium) - If neither found → prints a clear error with install instructions, exits
If npm install puppeteer fails (sandbox/network restriction):
# Option A: skip Chromium download, install separately
npm install puppeteer --ignore-scripts
npx puppeteer browsers install chrome
# Option B: use puppeteer-core (no bundled Chrome download)
npm install puppeteer-core
# script will auto-find system Chrome
# Option C: install system Chrome first, then run script
# macOS: brew install --cask google-chrome
# Linux: sudo apt install chromium-browser
npm install puppeteer-core
Do NOT fall back to wkhtmltopdf, pdfkit, weasyprint, or any other tool.
For full installation instructions across OpenClaw, Claude Code, Codex, and Linux/macOS setup, see references/install.md.
Workflow Overview
User input (image / website URL / style keyword / .pptx file)
↓ Step 1: Extract design spec → ⚠️ Confirm with user
↓ Step 2: Outline slide content → ⚠️ Confirm with user
↓ Step 3: Generate HTML → 💾 Save slides.html to disk
↓ Step 4: Run export_pdf.js → 💾 Output slides.pdf
Both slides.html and slides.pdf must exist as final outputs.
⚠️ Two Mandatory Confirmation Gates (never skip)
Gate 1: Design Style
After analyzing the input, show the extracted design spec summary and ask for confirmation:
Here's what I extracted from [source]:
- Background:
#000000black · Accent:#2997FFapple blue- Font: SF Pro Display, oversized centered headline
- Style: dark Keynote, glow effects
Does this match the style you want? Any adjustments?
⚠️ If website fetch fails (e.g. Fake IP / login required):
- Tell the user clearly why it failed
- Ask for screenshots: "Could you send a few screenshots of the site? I'll analyze the design from those."
- Never assume or default to any style — wait for user confirmation before proceeding
Website analysis priority:
- Puppeteer screenshot → visual analysis (most accurate)
web_fetchpage content → CSS/font extraction- Ask user to send screenshots
Gate 2: Slide Content
First ask if the user has existing materials:
Do you have any reference materials for the content? e.g. existing PPT, doc, report, or a list of key points? Send them over and I'll structure the slides — otherwise I'll draft an outline for you to review.
After receiving a reply, prepare a one-line summary per slide and confirm before generating HTML.
Step 1: Extract Design Spec → DESIGN.md
Supported inputs:
| Input | Approach |
|---|---|
| 📂 .pptx template | Parse with python-pptx: extract colors, fonts, backgrounds, placeholder layouts (most accurate) |
| 📎 Image / screenshot | Visual analysis: colors, font style, spacing, component patterns |
| 🌐 Website URL | Puppeteer screenshot + getComputedStyle font/color extraction |
| 💬 Style keyword | Use brand knowledge: Apple → SF Pro, Notion → Inter, Linear → Inter, Google → Google Sans |
Extracting from .pptx:
from pptx import Presentation
prs = Presentation("template.pptx")
slide = prs.slides[0]
for shape in slide.shapes:
if shape.has_text_frame:
for para in shape.text_frame.paragraphs:
for run in para.runs:
print(run.font.name, run.font.size, run.font.color.rgb, run.font.bold)
Fill extracted values into DESIGN.md (see references/DESIGN_TEMPLATE.md):
- Colors: primary bg, secondary bg, text colors, accent, border → CSS variables
- Fonts: heading / body / decorative number — name, weight, size range per level
- Layout: padding, max-width, grid columns, gap, border-radius
- Components: card, badge/label, button, divider, background decoration
- Section list: CSS class + content theme + dark/light tone per slide
Font extraction by input type:
| Input | Method |
|---|---|
.pptx | run.font.name per text run |
| Website | getComputedStyle(el).fontFamily via Puppeteer |
| Image / screenshot | Visual analysis — describe closest match (e.g. "geometric sans, similar to Helvetica") |
| Style keyword | Brand knowledge mapping |
Fonts go into DESIGN.md as CSS variables. Append Chinese fallbacks at the end (never hardcode them as primary):
--font-heading: 'SF Pro Display', 'PingFang SC', 'Helvetica Neue', sans-serif;
--font-body: 'SF Pro Text', 'PingFang SC', 'Helvetica Neue', sans-serif;
Step 2: Generate HTML
⚠️ Save the HTML to a
.htmlfile first. Do not merge HTML generation and PDF export into one step. The HTML file is a required intermediate artifact — it must exist on disk before runningexport_pdf.js.
Generate a single .html file and write it to disk (e.g. slides.html):
- Single file, all CSS inlined, zero external dependencies
- Each slide = one
<section class="...">, fixed width 1440px, height fits content - Fonts from DESIGN.md — Chinese fallback appended, never hardcoded as primary
@media print:page-break-after: alwayson every section
Font consistency check after saving:
grep -n "font-family" slides.html
Only proceed to Step 3 once the .html file is saved and verified.
Step 3 & 4: Export PDF via Puppeteer
⚠️ Only use
export_pdf.js(Puppeteer screenshot-and-compose). Do NOT use any of these alternatives — they all produce broken output:
page.pdf()directly → A4 portrait, white space below every slidewkhtmltopdf→ outdated WebKit engine, broken flexbox/grid/modern CSS- Any other HTML-to-PDF CLI (Prince, WeasyPrint, pdfkit, etc.) → layout incorrect
The screenshot-and-compose approach is the only method that faithfully preserves the rendered layout.
Environment matters
Claude Code / Codex / OpenClaw / local agent (can run shell commands):
- Read
scripts/export_pdf.js, copy it to the project directory, run it:
node export_pdf.js # reads slides.html → slides.pdf (auto-detects <section> elements)
node export_pdf.js my-deck.html # specify a different file
Claude.ai chat / any chat-only interface (cannot run shell commands):
- Your role ends at Step 3: generate the HTML and provide it to the user
- Tell the user: "Here's your
slides.html. To export the PDF, copyscripts/export_pdf.jsfrom the skill folder to the same directory and runnode export_pdf.js." - Do NOT attempt to run Puppeteer, install npm packages, or use any PDF tool in chat
node export_pdf.js # reads slides.html → slides.pdf (auto-detects all <section> elements)
node export_pdf.js my-deck.html # specify a different HTML file
Auto-detection: The script automatically finds all <section> elements in DOM order — no need to manually set SELECTORS. Only configure SELECTORS manually if you need a custom slide order or to merge multiple elements into one slide:
// Optional manual override — leave as [] for auto-detect
const SELECTORS = [
'.cover',
'.section-2',
['.chart', '.stats'], // array = merge into one slide
];
See references/export_pdf_guide.md for details.
Troubleshooting
| Issue | Fix |
|---|---|
| PDF has white space / broken layout | Do not use page.pdf(), wkhtmltopdf, or any CLI PDF tool. Run export_pdf.js only — it uses Puppeteer screenshot-and-compose to preserve layout exactly |
| Chinese text renders as Song/Ming | Add 'PingFang SC' to font stack (available on macOS by default) |
| Inconsistent fonts across slides | Run grep -n "font-family" slides.html and normalize |
| Wrong page count in PDF | Check that SELECTORS covers all sections |
| Detached Frame error | Use the reusable overlayPage pattern — never use newPage()/close() in a loop |
| Website URL fails to fetch | Likely Fake IP proxy — use Puppeteer screenshot instead, or ask user for screenshots |
