How I Built a Claude Design → Google Slides Converter in a Weekend
Claude Code can generate beautiful HTML designs. But getting those designs into Google Slides meant copy-pasting screenshots and manually recreating layouts. There had to be a better way.
So I built one. Paste a Claude Design URL. Get a Google Slides file delivered to your Drive — with automatic sharing, watermark gating, and Lemon Squeezy subscriptions. All in a weekend.
Here's exactly how it works, from download to delivery.
The Stack
A single Express server. No React. No database migrations. No microservices. Sometimes the best architecture is the simplest one that works.
- Express — handles conversion requests, SSE progress streaming, webhook endpoints
- Puppeteer — headless Chrome renders Claude's HTML design and captures slides as images
- pptxgenjs — builds PowerPoint files from rendered slide images
- Google Drive API — uploads PPTX, converts to Google Slides, handles sharing and permissions
- Google OAuth — users sign in, we upload directly to their Drive. They own the file natively.
- Lemon Squeezy — subscription billing, license key generation, webhook processing
- SQLite — zero-config database for license keys and conversion tracking
- nginx + Let's Encrypt — reverse proxy with auto-renewing HTTPS
Architecture: One Request, One Pipeline
The entire conversion is a single async pipeline. No job queues. No workers. Just one function that does everything in sequence:
User pastes URL + Gmail
↓
1. Fetch tar bundle from api.anthropic.com/v1/design/h/...
↓
2. Extract HTML from tar.gz
↓
3. Render in Puppeteer with watermark overlay
↓
4. Screenshot each slide individually (show/hide loop)
↓
5. Build PPTX from images using pptxgenjs
↓
6. Upload to user's Google Drive via their OAuth token
↓
7. Convert to Google Slides format
↓
8. All done — file is in their Drive, they own it
Every step emits an SSE event. The frontend listens and shows a real-time progress checklist. No polling. No spinners. Just a smooth stream of updates.
The Watermark Gate
This was the trickiest design decision. I needed a free tier that was useful enough to try, but gated enough to convert.
Solution: pixel-baked watermarks. Free users get every slide rendered as a flat PNG with "PREVIEW — SUBSCRIBE TO REMOVE" permanently baked into the pixels. Not a deletable DOM overlay. Not a text box. An actual part of the image.
if (hasLicense) {
// Clean path: dom-to-pptx for editable output
await page.addScriptTag({ url: domToPptxBundle });
const blob = await exportToPptx(sections);
} else {
// Watermarked path: screenshot each slide as PNG
for (const section of sections) {
section.style.display = ''; // show one at a time
const png = await page.screenshot();
screenshots.push(png);
section.style.display = 'none';
}
// Build PPTX from flat images
for (const img of screenshots) {
slide.addImage({ data: img, x: 0, y: 0, w: '100%', h: '100%' });
}
}
To remove the watermark, you'd need Photoshop — not a right-click. The difference between free and paid is the difference between a screenshot and an editable presentation.
Google OAuth: Users Own Their Files
Early versions uploaded everything to my Drive account, then tried to share and transfer ownership. That broke. A lot. Google's API doesn't allow ownership transfer to consumer Gmail accounts — only Workspace domains.
The fix: upload directly to the user's Drive. One Google Sign-In button. The user grants Drive file scope. We use their OAuth token for the upload. They're the native owner from the moment the file is created. No sharing gymnastics. No permission errors.
// User signs in via Google Identity Services
const tokenClient = google.accounts.oauth2.initTokenClient({
client_id: GOOGLE_CLIENT_ID,
scope: 'https://www.googleapis.com/auth/drive.file',
callback: (response) => {
googleToken = response.access_token;
// Include token with conversion request
fetch('/convert', { body: JSON.stringify({ designURL, googleToken }) });
},
});
Lemon Squeezy: Zero Payment UI
I didn't build a payment form. Lemon Squeezy handles checkout, tax compliance, recurring billing, and license key delivery. Our job is just one webhook endpoint:
app.post('/webhook/ls', (req, res) => {
res.json({ ok: true }); // ack immediately
if (event !== 'order_created') return;
const key = 'pptx-sk-' + crypto.randomBytes(8).toString('hex');
db.createLicense({ key, email, tier, maxMonthly, expiresAt });
// Lemon Squeezy emails the key to user
});
User pays → webhook fires → key stored in SQLite → emailed to user. That's the entire payment infrastructure.
Concurrency: One at a Time
Puppeteer is hungry. A single conversion can spike to 500MB RAM. On a modest VPS, two simultaneous conversions means an OOM kill.
The fix isn't a fancy queue system. It's a counter and an array:
let activeJobs = 0;
const MAX_CONCURRENT = 1;
const jobQueue = [];
if (activeJobs >= MAX_CONCURRENT) {
jobQueue.push({ id, designURL, ... });
} else {
activeJobs++;
processJob(id, designURL, ...)
.finally(() => {
activeJobs--;
if (jobQueue.length > 0) {
const next = jobQueue.shift();
activeJobs++;
processJob(next.id, next.designURL, ...);
}
});
}
What I'd Do Differently
Stream the upload. Currently we build the entire PPTX in memory before uploading. For presentations with 50+ slides and heavy images, this could be a problem. A streaming approach would keep memory flat.
Add analytics. I shipped without any usage tracking. Can't optimize conversion rates if you don't know where users drop off. Even a simple counter on each SSE stage would help.
Pre-render previews. The thumbnail generation is basic. A proper multi-slide preview carousel would make the free tier more compelling.
Ship It
The entire thing — Express server, Puppeteer rendering, Google OAuth, Drive upload, watermark gate, payment webhooks, and landing page — was built and deployed in a weekend.
You don't need a microservice architecture for a SaaS that does one thing well. You need a pipeline that works, a payment provider that handles the boring stuff, and a watermark that can't be deleted.
Try it yourself at pptx.nerdstudio.online
Paste a Claude Design URL. Preview is free.
Source code: github.com/AbahKili/nerdstudio-pptx — MIT licensed, open source.