
Single Page Pdf Export
- 1 installs
- 1 repo stars
- Updated June 13, 2026
- cyberelf/agent_skills
Helps with ai & agent building tasks.
About
single-page-pdf-export is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- single-page-pdf-export
- AI & Agent Building
- AI-coding skill
Single Page Pdf Export by the numbers
- 1 all-time installs (skills.sh)
- Ranked #14,102 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 24, 2026 (Skillselion catalog sync)
npx skills add https://github.com/cyberelf/agent_skills --skill single-page-pdf-exportAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 1 |
| Last updated | June 13, 2026 |
| Repository | cyberelf/agent_skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Single-Page PDF Export Skill
Export an HTML file or loaded page to a single-page PDF whose height is calculated from the rendered content, with no browser header or footer.
Use This Skill For
- Local
.htmlfiles that should become a single long PDF - Pages that should not be split across multiple PDF pages
- Requests to remove browser print headers and footers
- Pages using viewport-height layouts like
min-h-screenthat break normal printing
Inputs To Resolve
Before exporting, determine:
1. The source page:
- Local file path like
/user/test/page.html - Or a
file:///,http://, orhttps://URL
2. The output PDF path:
- If the user does not specify one, default to the source filename plus
-single-page.pdf
Workflow
1. Confirm the source exists if it is a local file. 2. Ensure a Chromium-based browser is installed:
- Prefer Chrome, then Edge
- The asset script checks common Windows install paths and
CHROME_PATH
3. Ensure Node dependencies are available in the current workspace:
- Install
puppeteer-corewithnpm install --no-save puppeteer-core - If you want to verify the resulting page count, also install
pdf-lib
4. Run the bundled exporter:
node ./assets/export-single-page-pdf.mjs "<input>" "<output>"5. Validate the result:
- Confirm the PDF file exists
- If
pdf-libis available, verify page count is1
Validation Command
Use this only when you need to confirm that the PDF is truly single-page:
node --input-type=module -e "import { readFileSync } from 'node:fs'; import { PDFDocument } from 'pdf-lib'; const bytes = readFileSync(process.argv[1]); const pdf = await PDFDocument.load(bytes); console.log('pages=' + pdf.getPageCount());" "<output.pdf>"Notes
- The exporter freezes
h-screenandmin-h-screenutilities to pixel values before printing. This avoids the common feedback loop where print page height changes the layout height and forces pagination. - The exporter disables animations and transitions before measuring the page.
- The exporter sets a custom print page size and zero margins, and disables browser headers and footers.
Troubleshooting
- If
puppeteer-coreis missing, install it in the workspace withnpm install --no-save puppeteer-core. - If Chrome or Edge is installed in a non-standard location, set
CHROME_PATHbefore running the exporter. - If the output still splits across pages, rerun the exporter with the bundled script instead of the browser's normal print dialog.
- If the source is a local file with relative assets, prefer passing the local file path instead of pasting raw HTML into a temporary file.
Expected Outcome
The result should be a single PDF page whose height matches the rendered document, with backgrounds preserved and no header or footer added by the browser.
import { existsSync } from 'node:fs';
import path from 'node:path';
import puppeteer from 'puppeteer-core';
const [, , inputArg, outputArg] = process.argv;
if (!inputArg || !outputArg) {
console.error('Usage: node export-single-page-pdf.mjs <input-html-or-url> <output-pdf>');
process.exit(1);
}
const chromeCandidates = [
process.env.CHROME_PATH,
'C:/Program Files/Google/Chrome/Application/chrome.exe',
'C:/Program Files (x86)/Google/Chrome/Application/chrome.exe',
'C:/Program Files/Microsoft/Edge/Application/msedge.exe',
'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe'
].filter(Boolean);
const executablePath = chromeCandidates.find((candidate) => existsSync(candidate));
if (!executablePath) {
console.error('Chrome or Edge executable was not found. Set CHROME_PATH if needed.');
process.exit(1);
}
const inputPath = path.resolve(inputArg);
const outputPath = path.resolve(outputArg);
function toPageUrl(input) {
if (/^(https?:|file:\/\/)/i.test(input)) {
return input;
}
return `file:///${path.resolve(input).replace(/\\/g, '/')}`;
}
const pageUrl = toPageUrl(inputArg);
const browser = await puppeteer.launch({
executablePath,
headless: true,
args: ['--disable-gpu']
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 1000, deviceScaleFactor: 1 });
await page.goto(pageUrl, { waitUntil: 'networkidle0' });
await page.emulateMediaType('screen');
const viewportHeight = await page.evaluate(() => window.innerHeight);
await page.addStyleTag({
content: `
*, *::before, *::after {
animation: none !important;
transition: none !important;
}
.h-screen {
height: ${viewportHeight}px !important;
}
.min-h-screen {
min-height: ${viewportHeight}px !important;
}
.animate-fade-in {
opacity: 1 !important;
transform: none !important;
}
`
});
await page.evaluate(async () => {
if (document.fonts?.ready) {
await document.fonts.ready;
}
document.querySelectorAll('.animate-fade-in').forEach((element) => {
element.classList.add('visible');
});
window.scrollTo(0, 0);
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
});
const { width, height } = await page.evaluate(() => {
const body = document.body;
const root = document.documentElement;
return {
width: Math.ceil(
Math.max(
body?.scrollWidth ?? 0,
body?.offsetWidth ?? 0,
body?.clientWidth ?? 0,
root.scrollWidth,
root.offsetWidth,
root.clientWidth
)
),
height: Math.ceil(
Math.max(
body?.scrollHeight ?? 0,
body?.offsetHeight ?? 0,
body?.clientHeight ?? 0,
root.scrollHeight,
root.offsetHeight,
root.clientHeight
)
)
};
});
const paddedHeight = Math.ceil(height + Math.max(200, height * 0.08));
await page.addStyleTag({
content: `
@page {
size: ${width}px ${paddedHeight}px;
margin: 0;
}
`
});
await page.pdf({
path: outputPath,
printBackground: true,
displayHeaderFooter: false,
width: `${width}px`,
height: `${paddedHeight}px`,
preferCSSPageSize: true,
margin: {
top: 0,
right: 0,
bottom: 0,
left: 0
}
});
console.log(`Exported single-page PDF: ${outputPath}`);
console.log(`Page size: ${width}px x ${paddedHeight}px`);
} finally {
await browser.close();
}