From Design I/O & QA
Exports HTML to vector PDF via Playwright Chromium for slides and landing pages. Maintains selectable text, reasonable file size, and correct slide breaks.
How this skill is triggered — by the user, by Claude, or both
Slash command
/design-io:export-pdfWhen to use
Юзер просит «сделай PDF», «отправлю в Telegram», «один файл для презентации». После slides или standalone-html.
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Playwright headless Chromium → векторный PDF. Текст копируется, размер ~200KB-2MB.
Playwright headless Chromium → векторный PDF. Текст копируется, размер ~200KB-2MB.
scripts/export-pdf.js:
const { chromium } = require('playwright');
const path = require('path');
async function exportPdf(htmlPath, opts = {}) {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(`file://${path.resolve(htmlPath)}`, { waitUntil: 'networkidle' });
await page.waitForTimeout(opts.wait || 1000);
const out = opts.out || htmlPath.replace(/\.html$/, '.pdf');
await page.pdf({
path: out,
format: opts.format || 'A4',
landscape: opts.landscape ?? false,
printBackground: true,
margin: opts.margin || { top: '0', right: '0', bottom: '0', left: '0' },
preferCSSPageSize: true,
scale: opts.scale || 1,
});
await browser.close();
return out;
}
if (require.main === module) {
const args = process.argv.slice(2);
const html = args[0];
const isSlides = args.includes('--slides');
exportPdf(html, isSlides ? { format: { width: '1920px', height: '1080px' }, landscape: true } : {})
.then(out => console.log(`✓ ${out}`));
}
module.exports = { exportPdf };
node scripts/export-pdf.js artifact.html
node scripts/export-pdf.js deck.html --slides
Если артефакт — slides:
page-break-after: always в CSS.slide {
width: 1920px;
height: 1080px;
page-break-after: always;
break-after: always; /* modern */
break-inside: avoid;
}
@media print {
body { background: #fff; }
.deck { display: block !important; }
.slide {
position: static;
opacity: 1 !important;
transform: none !important;
pointer-events: auto;
}
}
В JS (slides каркас) для PDF-режима:
// Активировать все слайды для PDF
if (new URL(location).searchParams.get('print') === '1') {
document.querySelectorAll('.slide').forEach(s => s.classList.add('active'));
}
И передавать ?print=1 в URL при экспорте.
Континуальный документ — без page-break. Просто весь HTML на A4 portrait.
await page.pdf({
path: 'landing.pdf',
format: 'A4',
printBackground: true,
margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
});
В HTML:
@page {
size: 1920px 1080px;
margin: 0;
}
@page :first {
margin-top: 0;
}
И preferCSSPageSize: true в Playwright options.
Web fonts через CDN иногда не embed'ятся. Решение:
await page.evaluateHandle('document.fonts.ready'); // ждать загрузки
await page.waitForTimeout(500); // запас
Или self-host шрифты в fonts/ — гарантированный embed.
Что увеличивает:
Что уменьшает:
printBackground: false (но теряешь градиенты)scale: 0.8 (но теряешь чёткость)Если артефакт = N экранов, и хочешь разные ориентации:
const { PDFDocument } = require('pdf-lib');
const slides = await exportPdf('slides.html', { landscape: true });
const docs = await exportPdf('docs.html');
const merged = await PDFDocument.create();
for (const file of [slides, docs]) {
const src = await PDFDocument.load(fs.readFileSync(file));
const pages = await merged.copyPages(src, src.getPageIndices());
pages.forEach(p => merged.addPage(p));
}
fs.writeFileSync('combined.pdf', await merged.save());
print-styles — добавляет @media print стили для красивой печатиpptx-editable-extractor — альтернатива если нужен PPTX, не PDFverifier — проверяй артефакт перед exportslides / standalone-html — обычно exportим этиdocument.fonts.ready → fallback-шрифт в PDFprintBackground: false на artistic дизайне → потеря всех градиентов и фоновpage.pdf() без waitUntil: 'networkidle' → asset'ы не догруженыnpx claudepluginhub jhamidun/claude-code-config-pack --plugin design-ioProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.