html-to-pdf — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited html-to-pdf (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Export HTML pages to high-quality, print-ready vector PDFs using Playwright's page.pdf() API.
Trigger with /html-to-pdf or when the user asks to:
page.pdf() which produces vector PDFs with selectable, scalable text.print media which washes out colors (dark backgrounds turn grey, accents look dull). Force screen media to preserve exact browser colors: await page.emulateMedia({ media: 'screen', colorScheme: 'dark' });The skill uses Playwright (Node.js) via a temporary script to:
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:
in, mm, cm) in page.pdf() for the page dimensionsThe 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:
width: '5.5in', height: '8.5in', scale: 0.5Quick formula: scale = 96 / designDPI. For 192 DPI → 0.5. For 144 DPI → 0.667. For 96 DPI → 1.0 (no scaling needed).
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();body { width: Xpx; height: Ypx; })./tmp/pdf-export.mjs with the correct:exports array (one entry per HTML file)baseDir pointing to the folder containing the HTML filespageWidth and pageHeight matching the HTML body dimensions cd /tmp && npm list playwright-core 2>/dev/null || npm install playwright-core cd /tmp && node pdf-export.mjs open /path/to/output.pdf| 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) |
After exporting to PDF, you can push the HTML design into Figma for team editing and visual refinement:
mcp__figma-remote-mcp__generate_figma_design to import the rendered page as a Figma design.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 saves alongside the source file.
/tmp/node_modules/cd /tmp && npm install playwright-core is sufficient~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.