Html to pdf
Skill t0ddharris/compound-marketing/.claude/skills/html-to-pdf
Scale your marketing without sacrificing quality.
npx -y skills add t0ddharris/compound-marketing --skill html-to-pdfAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Export HTML pages to print-quality vector PDFs using Playwright's page.pdf() API. Trigger with /html-to-pdf or when the user wants to export an HTML page to PDF, create a print-ready PDF from HTML, or generate a PDF of a handout, card, flyer, or any HTML design.
SKILL.md
7.7 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
HTML to PDF — Print-Quality Export
Export HTML pages to high-quality, print-ready vector PDFs using Playwright's page.pdf() API.
When to Use
Trigger with /html-to-pdf or when the user asks to:
- Export an HTML page to PDF
- Create a print-ready PDF from HTML
- Generate a PDF of a handout, card, flyer, or any HTML design
Critical Rules
-
NEVER screenshot-to-PDF. Never render HTML as a screenshot (PNG) and convert to PDF. This rasterizes text into pixels — unacceptable for print. Always use Playwright's
page.pdf()which produces vector PDFs with selectable, scalable text. -
Always emulate screen media. Chromium's PDF renderer defaults to
printmedia which washes out colors (dark backgrounds turn grey, accents look dull). Forcescreenmedia to preserve exact browser colors:await page.emulateMedia({ media: 'screen', colorScheme: 'dark' }); -
Always set
printBackground: true. Without this, backgrounds are stripped entirely. -
RGB output only. Generate RGB PDFs. the user handles CMYK conversion in Adobe Acrobat with proper ICC profiles. Pillow's RGB→CMYK conversion produces off colors — never attempt it programmatically.
How It Works
The skill uses Playwright (Node.js) via a temporary script to:
- Launch headless Chromium
- Set viewport to match the HTML page dimensions
- Emulate screen media + dark color scheme for accurate color rendering
- Navigate to the local HTML file
- Export as PDF with exact page dimensions, zero margins, backgrounds enabled
Page Size — Pixels vs. Physical Units
Critical: Playwright's page.pdf() interprets pixel dimensions at 96 DPI. If your HTML body is 1056×1632px and you pass width: '1056px', the PDF page will be 11"×17" (1056÷96 = 11).
To get the correct physical size, you need two things:
- Physical units (
in,mm,cm) inpage.pdf()for the page dimensions scalefactor to shrink the viewport content to fit the smaller page
The viewport renders at the full HTML pixel size (e.g. 1056×1632). Without scale, the content overflows the smaller physical page. The scale factor = physical size ÷ (pixel size / 96).
Example: HTML body is 1056×1632px, target is 5.5"×8.5" at 192 DPI:
- PDF page at 96 DPI = 528×816 CSS px, but viewport is 1056×1632
- Scale = 528/1056 = 0.5 (equivalently: target DPI 96 ÷ design DPI 192 = 0.5)
- Result:
width: '5.5in', height: '8.5in', scale: 0.5
Quick formula: scale = 96 / designDPI. For 192 DPI → 0.5. For 144 DPI → 0.667. For 96 DPI → 1.0 (no scaling needed).
Export Script
Create this script at /tmp/pdf-export.mjs and run it with cd /tmp && node pdf-export.mjs:
import { chromium } from 'playwright-core';
// ── Configure these per export ──
const exports = [
// { name: 'descriptive-name', file: 'filename-without-extension' },
];
const baseDir = './marketing/events'; // adjust per job
const pageWidth = 1056; // match the HTML body width (px)
const pageHeight = 1632; // match the HTML body height (px)
const pdfWidth = '5.5in'; // physical page width — use in/mm/cm, NOT px
const pdfHeight = '8.5in'; // physical page height — use in/mm/cm, NOT px
// ─────────────────────────────────
const browser = await chromium.launch();
for (const p of exports) {
const context = await browser.newContext({
viewport: { width: pageWidth, height: pageHeight },
colorScheme: 'dark',
forcedColors: 'none',
});
const page = await context.newPage();
// Force screen media — critical for accurate colors
await page.emulateMedia({ media: 'screen', colorScheme: 'dark' });
await page.goto(`file://${baseDir}/${p.file}.html`, { waitUntil: 'networkidle' });
await page.pdf({
path: `${baseDir}/${p.file}.pdf`,
width: pdfWidth,
height: pdfHeight,
scale: 0.5, // 96 / designDPI — adjust if DPI changes
printBackground: true,
preferCSSPageSize: false,
margin: { top: '0', right: '0', bottom: '0', left: '0' },
});
console.log(`${p.name}: PDF saved → ${p.file}.pdf`);
await context.close();
}
await browser.close();
Step-by-Step Workflow
-
Read the HTML file to get the page dimensions from the CSS (
body { width: Xpx; height: Ypx; }). -
Create the export script at
/tmp/pdf-export.mjswith the correct:exportsarray (one entry per HTML file)baseDirpointing to the folder containing the HTML filespageWidthandpageHeightmatching the HTML body dimensions
-
Ensure playwright-core is installed:
cd /tmp && npm list playwright-core 2>/dev/null || npm install playwright-core -
Run the export:
cd /tmp && node pdf-export.mjs -
Open the PDF for review:
open /path/to/output.pdf -
Verify quality: Colors should match the browser exactly. Text should be selectable and crisp at any zoom level. Dark backgrounds should be true black, not washed-out grey.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Washed-out / grey backgrounds | Print media default | Add page.emulateMedia({ media: 'screen' }) |
| No backgrounds at all | Missing flag | Add printBackground: true |
| PDF is wrong physical size (e.g. 11×17 instead of 5.5×8.5) | Using px units in page.pdf(), or missing scale | Use physical units (in, mm) for width/height AND set scale: 96/designDPI (e.g. 0.5 for 192 DPI). Physical units alone cause clipping; scale alone leaves wrong page metadata. |
| Content clipped on right | Viewport too narrow | Match viewport.width to HTML body width exactly |
| Fonts not rendering | Google Fonts not loaded | Use waitUntil: 'networkidle' |
| Colors dull after printing | RGB→CMYK shift | Convert to CMYK in Adobe Acrobat with ICC profiles (not programmatic) |
Figma Handoff (Optional Post-Export Step)
After exporting to PDF, you can push the HTML design into Figma for team editing and visual refinement:
- Serve the HTML locally — The HTML file needs to be accessible via URL for Figma capture.
- Capture into Figma — Use
mcp__figma-remote-mcp__generate_figma_designto import the rendered page as a Figma design. - Choose output mode:
newFile— creates a fresh Figma file (good for new documents)existingFile— adds to an existing Figma file (good for adding pages to an ongoing project)
What this gives you: The design imports as a visual snapshot that the team can annotate, adjust typography, reposition elements, or polish in Figma's editor.
What it doesn't give you: Fully editable Figma components with proper text layers. The capture is a high-fidelity visual import, not a native Figma rebuild. For most whitepaper/datasheet workflows, this is the right trade-off: the HTML/CSS file remains the source of truth for content and layout, while Figma handles collaborative visual refinement.
When to use: Whitepapers, datasheets, one-pagers, or any multi-page branded document where the team wants to review or refine the design collaboratively in Figma before final delivery.
Output Location
Output saves alongside the source file.
Dependencies
- playwright-core (npm) — installed locally in
/tmp/node_modules/ - No global install needed;
cd /tmp && npm install playwright-coreis sufficient - Uses system Chromium bundled with Playwright
Gives 0 of the 12 instructions most pdf office docs skills give in ~1.9k tokens
Counted across 635 of the 690 authors here whose files we hold, read 2026-08-06
- extract text using pdfplumberin 92 of 635, across 25 files
- create PDFs using reportlabin 83 of 635, across 16 files
- read FORMS.md to fill out PDF formsin 80 of 635, across 13 files
- OCR scanned PDFs using pytesseractin 77 of 635, across 10 files
- merge or split PDFs using qpdfin 70 of 635, across 3 files
- use Excel formulas instead of hardcoded calculated valuesin 68 of 635, across 12 files
- unpack edit xml and repack existing documentsin 63 of 635, across 8 files
- document sources for hardcoded valuesin 61 of 635, across 9 files
- write minimal python code without unnecessary commentsin 59 of 635, across 7 files
- run the recalculation script after adding or modifying formulasin 58 of 635, across 6 files
- fix all identified formula errors and recalculatein 58 of 635, across 6 files
- format years as text stringsin 57 of 635, across 5 files
Said here and by no other author read
- use Playwright page.pdf() for export
- emulate screen media and dark color scheme
- set printBackground to true
- match viewport to HTML body dimensions
- use physical units for PDF dimensions
- calculate scale factor as 96 divided by design DPI
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.