skills/html-to-pdf/SKILL.md
Convert styled HTML files to high-quality single-page PDFs using headless Chrome via playwright-core. Use this skill whenever the user asks to generate a PDF from HTML, export a webpage to PDF, create a no-page-break long-scroll PDF, convert a pitch deck / BP / report HTML to PDF, or mentions "导出 PDF", "生成 PDF", "HTML 转 PDF", "nopagebreak PDF". Also use when iterating on a document with edit-then-export cycles (edit HTML → regenerate PDF → review → repeat). Also use when an interactive/animated HTML presentation needs to be flattened to a static PDF.
npx skillsauth add kanlac/agent-steroids html-to-pdfInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate single-page (no page break) PDFs from styled HTML using headless Chrome. Designed for pitch decks, reports, and long-scroll documents where the entire content should be one continuous page.
@media print or browser "Save as PDF" produces broken resultsNever modify the original HTML. Always copy to a working file first (e.g., cp original.html original-print.html). If the file came from WeChat or other apps, it may be read-only — chmod u+w the copy before editing.
Interactive HTML presentations (slide decks, scroll-snap pages) contain elements that break PDF rendering. The PDF captures the page at a single moment — animations frozen at their initial state, scroll-snapped slides stacked on one viewport. Before generating a PDF, the HTML must be flattened to a static, continuous-scroll document.
Common dynamic elements that cause blank or broken PDFs:
| Element | Problem in PDF | Fix |
|---------|---------------|-----|
| Scroll snapping (scroll-snap-type: y mandatory) | Each slide fills exactly one viewport, PDF only captures the first | scroll-snap-type: none |
| IntersectionObserver animations (.anim { opacity: 0 }) | Elements are invisible — they only animate in on scroll | .anim { opacity: 1 !important; transform: none !important; } |
| Fixed slide heights (height: 100vh) | Each section is viewport-locked, content can overflow or be clipped | height: auto !important; min-height: auto !important; |
| Navigation UI (nav dots, progress bars, key hints) | Floating UI renders over content | display: none !important |
| Lightbox overlays | Empty overlay markup takes up space or covers content | display: none !important |
| Decorative pseudo-elements (::before, ::after ink splashes) | Can create visual noise or extra whitespace | display: none !important |
| position: absolute on content (footers, slide numbers using bottom: Xvh) | Once 100vh is removed, these float to wrong positions and overlap content | Change to position: relative; margin-top: auto |
How to apply the fix — add a CSS override block at the end of the <style> section (before the closing </style> tag). This is a surgical approach: the original interactive CSS stays intact for browser viewing, while the overrides flatten everything for PDF export. Example pattern:
/* ====== PDF/STATIC OVERRIDES ====== */
html { scroll-snap-type: none; }
.slide { height: auto !important; min-height: auto !important; }
.anim { opacity: 1 !important; transform: none !important; }
.nav-dots, .progress, .lightbox, .ink-splash, #keyHint { display: none !important; }
body::before, .slide::after { display: none !important; }
The specific selectors depend on the HTML — inspect the source to find which classes are used for animations, navigation, and decorative elements. The pattern is always the same: force visible, auto-height, hide interactive UI.
After removing 100vh, check for displaced elements. Any content element using position: absolute; bottom: Xvh (common for slide footers, page numbers) will be mispositioned once slides become auto-height. Convert these to document flow: position: relative; margin-top: 1.5rem; text-align: right.
Chrome's PDF renderer handles most CSS well, but some properties produce artifacts:
| Safe | Unsafe (causes PDF artifacts) |
|------|------|
| color, background-color, background (solid) | background-clip: text + -webkit-text-fill-color: transparent → black horizontal lines |
| border, padding, margin, font-* | backdrop-filter: blur() → ignored or renders incorrectly |
| flex, grid, border-radius | position: fixed → breaks in continuous-scroll layout |
| box-shadow (simple) | Complex filter: chains → may not render |
The background-clip: text pitfall deserves special attention. Gradient text using background-clip: text + -webkit-text-fill-color: transparent renders beautifully in the browser but produces black horizontal line artifacts in Chrome's PDF engine. Replace the gradient with a simple color value.
Use the bundled scripts/html2pdf.js script. It handles browser resolution automatically:
node ${SKILL_PATH}/scripts/html2pdf.js <input.html> [output.pdf] [--width=490] [--buffer=50]
The script resolves playwright-core from agent-browser's bundled copy (no separate install), finds the Chrome binary from the ms-playwright cache (picking the highest available version), and generates a single-page PDF by measuring scrollHeight and adding a buffer to prevent page overflow.
Width selection — determines the visual layout and which CSS breakpoints fire:
| Width | Use case | |-------|----------| | 390-430 | iPhone-sized, very compact | | 490-500 | Mobile pitch deck (sweet spot for BP/路演 documents) | | 768 | Tablet | | 1440 | Desktop full-width |
Test a few widths if the layout looks wrong — width changes can trigger different responsive breakpoints and produce dramatically different layouts.
Buffer — the --buffer parameter (default 50px) adds extra height beyond scrollHeight to prevent a blank second page. Chrome's PDF renderer can round heights slightly differently than the DOM reports. If the output has 2 pages with a blank second page, increase the buffer. If there's too much whitespace at the bottom, decrease it.
Don't install playwright separately. The agent-browser package already bundles playwright-core with a compatible Chrome. Installing a standalone playwright creates version mismatches — the library expects one browser revision while the cache has another. The script resolves this automatically.
Browser version mismatch. If the script reports a missing executable, it means the cached Chrome revision doesn't match what playwright-core expects. The script works around this by scanning the cache for the highest available version. If even that fails, npx playwright install chromium fetches the matching version.
Single-page verification. After generating, verify with mdls -name kMDItemNumberOfPages output.pdf (macOS). If it shows 2 pages, the content overflowed — increase the buffer. The script does this check automatically.
Font loading. The script waits 1.5s after page load for web fonts. If the HTML loads fonts from a CDN that's slow or blocked (e.g., Google Fonts in China), fonts may not render. Self-hosted fonts in the HTML avoid this issue.
Print CSS interference. Some HTML files have @media print rules that hide elements or change layout. The PDF is generated from the print rendering. If elements disappear in the PDF, check for print-specific CSS.
agent-browser pdf doesn't work for this use case. It exports to A4 with white background and pagination — losing dark themes entirely and breaking single-page layout. Always use the bundled playwright script instead.
After generating the PDF, do a visual QA pass before delivering. Open the HTML in a headless browser and take screenshots at the target width to verify:
background-clip: textFor section-by-section inspection, scroll to each major section (scrollIntoView) and take viewport screenshots. This catches issues that full-page screenshots may miss at scale.
When the user is doing edit→export cycles (e.g., iterating on a pitch deck):
devops
自建机场(代理服务端)搭建与运维。涵盖 VPS 初始化/加固、3X-UI 面板、Xray VLESS Reality+Vision 入站、多用户独立订阅(UUID/subId/到期/续期)、把节点渲染成 Clash/Mihomo 订阅 YAML、Profile 显示名与到期时间下发、域名/ACME 证书、出口测速、IP 被墙/被滥用风险判断、备份恢复。用户要在 VPS 上部署或维护自建节点/机场、调试 3X-UI 订阅、Reality 入站、订阅链接显示名/到期、面板安全、证书申请、速度低或 IP 风险时用这个 skill。客户端 Clash Verge / mihomo 的配置即代码、规则不命中、DNS 泄漏排查见 clash-verge-config skill。
development
Generate a local HTML dashboard for auditing installed Skills, token usage, description token budgets, duplicate Skill names, Skill paths, and selected Skill exports. Use when the user wants to inspect many Skills, decide which Skills to disable, compare duplicates, preview SKILL.md contents, sort by token usage, or export selected Skills as JSON.
tools
Turn a YouTube link into a polished single-file bilingual (Chinese + original) transcript reading page. Use when the user gives a YouTube URL and asks to "转录" "做转录稿" "生成转录页面" "中英对照" "bilingual transcript" "transcribe this video", or wants a readable HTML transcript with clickable timestamps, chapter navigation, highlighted key points, and proper-noun annotations. Fetches captions + chapters via yt-dlp, the agent translates and curates, then a script renders the HTML.
development
Use when a user asks the agent to "learn" from a file, example, correction, failed workflow, or feedback and persist that learning into skills or agent instructions. Guides semantic skill refactoring: extract the transferable behavior, update the owning skill so it becomes clearer and easier to execute, avoid append-only note dumping, and decide when not to create new reference files.