-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexport-pdf.mjs
More file actions
103 lines (91 loc) · 3.1 KB
/
export-pdf.mjs
File metadata and controls
103 lines (91 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { chromium } from 'playwright';
import { resolve } from 'path';
const WIDTH = 1440;
const HEIGHT = 1080;
const SLIDE_COUNT = 38;
const OUTPUT = 'in-tech-we-trust-presentation-2026-03-18.pdf';
async function main() {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: WIDTH, height: HEIGHT },
});
const filePath = resolve('in-tech-we-trust-presentation-2026-03-18.html');
await page.goto(`file://${filePath}`, { waitUntil: 'networkidle' });
// Wait for fonts to load
await page.waitForTimeout(2000);
// Disable scroll-snap and smooth scrolling so we can position precisely
await page.addStyleTag({
content: `
html { scroll-snap-type: none !important; scroll-behavior: auto !important; }
.slide { scroll-snap-align: none !important; }
.keyboard-hint { display: none !important; }
.nav-dots { display: none !important; }
.progress-bar { display: none !important; }
/* Make all reveals visible for PDF */
.reveal, .reveal-slow, .reveal-scale {
opacity: 1 !important;
transform: none !important;
transition: none !important;
}
.slide-list li {
opacity: 1 !important;
transform: none !important;
transition: none !important;
}
.slide-section .section-title,
.slide-subsection .subsection-title {
opacity: 1 !important;
transform: none !important;
transition: none !important;
}
`,
});
// Screenshot each slide and combine into PDF
const screenshots = [];
for (let i = 0; i < SLIDE_COUNT; i++) {
// Scroll to exact slide position
await page.evaluate((idx) => {
const slide = document.querySelectorAll('.slide')[idx];
if (slide) slide.scrollIntoView({ behavior: 'instant' });
}, i);
await page.waitForTimeout(300);
const screenshot = await page.screenshot({ type: 'png' });
screenshots.push(screenshot);
process.stdout.write(`Captured slide ${i + 1}/${SLIDE_COUNT}\n`);
}
// Create a new page that lays out all screenshots for PDF printing
const pdfPage = await browser.newPage();
const imagesHtml = screenshots
.map((buf, i) => {
const b64 = buf.toString('base64');
return `<div class="page"><img src="data:image/png;base64,${b64}"></div>`;
})
.join('\n');
await pdfPage.setContent(`
<html>
<style>
* { margin: 0; padding: 0; }
@page { size: ${WIDTH}px ${HEIGHT}px; margin: 0; }
.page {
width: ${WIDTH}px;
height: ${HEIGHT}px;
page-break-after: always;
overflow: hidden;
}
.page:last-child { page-break-after: auto; }
.page img { width: 100%; height: 100%; object-fit: contain; }
</style>
<body>${imagesHtml}</body>
</html>
`, { waitUntil: 'load' });
await pdfPage.pdf({
path: OUTPUT,
width: `${WIDTH}px`,
height: `${HEIGHT}px`,
margin: { top: 0, right: 0, bottom: 0, left: 0 },
printBackground: true,
});
console.log(`\nSaved ${OUTPUT} (${SLIDE_COUNT} slides at ${WIDTH}x${HEIGHT})`);
await browser.close();
}
main().catch(console.error);