| name | playwright-banner-generator |
| description | Generate text-heavy graphics (banners, social images, OG images) using Playwright to render HTML with real web fonts. Perfect for branded collateral where typography matters. |
Playwright Banner Generator
Generate pixel-perfect graphics with real web fonts using Playwright. Unlike AI image generators, this approach renders actual fonts (Google Fonts, etc.) with perfect fidelity.
When to Use This Skill
- LinkedIn banners (personal or company)
- OG images / social cards
- Email headers
- Any graphic where typography must be exact
Dimension Presets
| Type | Dimensions | Notes |
|---|
| LinkedIn Personal | 1584×396 | Account for profile photo in bottom-left |
| LinkedIn Company | 1128×191 | Account for company logo on left |
| OG Image | 1200×630 | Standard social sharing size |
| Twitter Header | 1500×500 | Twitter/X profile banner |
Workflow
Step 1: Create or Modify HTML Template
Create an HTML file with:
- Google Fonts loaded via
<link>
- Full viewport styling (
width: 100%; height: 100%)
- Your content and styling
Template location: ~/.claude/skills/playwright-banner-generator/templates/
Example structure:
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Inter:wght@400;500&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
background: #0d0d0d;
font-family: 'Inter', sans-serif;
overflow: hidden;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 80px;
}
</style>
</head>
<body>
<div class="container">
</div>
</body>
</html>
Step 2: Render with Playwright
Use Playwright MCP tools in this order:
-
Set viewport to 2x dimensions (for retina quality):
browser_resize: width=3168, height=792 # For 1584×396 output
-
Set deviceScaleFactor via CDP (for sharpness):
browser_run_code: async (page) => {
const client = await page.context().newCDPSession(page);
await client.send('Emulation.setDeviceMetricsOverride', {
width: 3168,
height: 792,
deviceScaleFactor: 2,
mobile: false
});
}
-
Navigate to the HTML file:
browser_navigate: file:///path/to/template.html
-
Wait for fonts to load (important!):
browser_run_code: async (page) => {
await page.waitForTimeout(1000);
await document.fonts.ready;
}
-
Take screenshot:
browser_take_screenshot: filename=banner-2x.png
Step 3: Resize to Final Dimensions
Use sips (macOS) to resize to target dimensions:
sips -z 396 1584 banner-2x.png --out final-banner.png
For other platforms, use ImageMagick:
convert banner-2x.png -resize 1584x396 final-banner.png
Complete Example: LinkedIn Personal Banner
- Create/edit HTML at
./linkedin-banner.html:
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=Inter:wght@400;500&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: 100%;
height: 100%;
background: #0d0d0d;
overflow: hidden;
}
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 420px;
}
.wordmark {
font-family: 'Playfair Display', serif;
color: white;
font-size: 36px;
margin-bottom: 24px;
}
.wordmark .stores { font-weight: 500; }
.wordmark .data { font-style: italic; font-weight: 400; }
.headline {
font-family: 'Playfair Display', serif;
color: white;
font-size: 72px;
font-weight: 500;
line-height: 1.1;
white-space: nowrap;
}
.headline em {
font-style: italic;
font-weight: 400;
}
</style>
</head>
<body>
<div class="container">
<div class="wordmark">
<span class="stores">Stores</span><span class="data">Data</span>
</div>
<h1 class="headline">
Invite-Only <em>Ecommerce Intelligence</em>
</h1>
</div>
</body>
</html>
-
Render with Playwright:
- Resize browser to 3168×792
- Set deviceScaleFactor: 2
- Navigate to file
- Wait for fonts
- Screenshot to
banner-2x.png
-
Resize:
sips -z 396 1584 banner-2x.png --out linkedin-banner.png
Tips
Font Loading
Always wait for fonts to load before screenshotting:
await page.waitForTimeout(1000);
await document.fonts.ready;
LinkedIn-Specific Adjustments
- Personal banner: Add
padding-left: 420px to clear profile photo
- Company banner: Add
padding-left: 280px to clear company logo
- Use
white-space: nowrap to prevent text wrapping
Typography
- Use italic (
<em>) for typographic variety
- Playfair Display works well: regular weight for body, italic for emphasis
- High contrast (white on dark) for impact
Quality
- Always render at 2x dimensions with deviceScaleFactor: 2
- Resize down for final output = sharper result
- PNG format preserves text sharpness
Templates
Pre-built templates are available in ~/.claude/skills/playwright-banner-generator/templates/:
banner.html - Generic banner template (customize for any use)
og-image.html - Standard OG image template (1200×630)