Build presentation slides as HTML/CSS with Puppeteer screenshot loop. Use when the user mentions 'make slides,' 'create slides,' 'presentation,' 'slide deck,' or 'make-slides.'
Build polished presentation slides as HTML/CSS, with a Puppeteer measure → screenshot → iterate loop to ensure pixel-perfect output.
All slides are 1920×1080px (16:9 standard presentation).
Before starting, confirm you have:
If content is missing or unclear, ask before proceeding.
'Inter', 'Outfit', system-ui, sans-serif#0f172a background, #f8fafc text, one accent color#ffffff background, #1e293b text, one accent colorFrom the content, outline:
Slide 1: [Title slide — topic + speaker]
Slide 2: [Key question or hook]
Slide 3: [First main point]
...
Slide N: [Closing / CTA]
Present the outline to the user for approval before building.
Create one HTML file per slide in the project folder. Structure:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
.slide {
width: 1920px;
height: 1080px;
overflow: hidden;
position: relative;
font-family: 'Inter', system-ui, sans-serif;
padding: 80px 100px;
/* colors as CSS variables */
--bg: #0f172a;
--text: #f8fafc;
--accent: #3b82f6;
background: var(--bg);
color: var(--text);
}
</style>
</head>
<body style="background:#1e1e1e; display:flex; justify-content:center; align-items:center; min-height:100vh;">
<div class="slide">
<!-- Slide content -->
</div>
</body>
</html>
Start the local server and verify with Puppeteer:
cd PROJECT_DIR && python3 -m http.server 8765 &
Measure overflow:
node -e "
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });
await page.goto('http://localhost:8765/SLIDE_FILE.html', { waitUntil: 'networkidle0' });
const m = await page.evaluate(() => {
const el = document.querySelector('.slide');
return {
containerH: el.offsetHeight,
contentH: el.scrollHeight,
overflow: el.scrollHeight - el.offsetHeight,
containerW: el.offsetWidth,
contentW: el.scrollWidth,
overflowW: el.scrollWidth - el.offsetWidth
};
});
console.log(JSON.stringify(m, null, 2));
await browser.close();
})();
"
Target: overflow = 0 in both dimensions.
node -e "
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 2 });
await page.goto('http://localhost:8765/SLIDE_FILE.html', { waitUntil: 'networkidle0' });
const el = await page.\$('.slide');
await el.screenshot({ path: 'slide-NN.png' });
console.log('Screenshot saved');
await browser.close();
})();
"
Each round: measure → screenshot → evaluate → edit → measure again.
Check each slide for:
Show all slide screenshots in order. Ask for feedback. Iterate as needed.
When done:
pkill -f "python3 -m http.server" 2>/dev/null