1#!/usr/bin/env node
2
3/**
4 * Screenshot Anti-Pattern Examples
5 *
6 * Takes 1080x1080 screenshots of each anti-pattern example for LinkedIn sharing.
7 * Requires the dev server to be running on localhost:3000
8 */
9
10import { chromium } from 'playwright';
11import path from 'path';
12import fs from 'fs';
13import { fileURLToPath } from 'url';
14
15const __filename = fileURLToPath(import.meta.url);
16const __dirname = path.dirname(__filename);
17const ROOT_DIR = path.resolve(__dirname, '..');
18const EXAMPLES_DIR = path.join(ROOT_DIR, 'public', 'antipattern-examples');
19const OUTPUT_DIR = path.join(ROOT_DIR, 'public', 'antipattern-images');
20
21async function screenshotAntipatterns() {
22 // Ensure output directory exists
23 if (!fs.existsSync(OUTPUT_DIR)) {
24 fs.mkdirSync(OUTPUT_DIR, { recursive: true });
25 }
26
27 // Get all HTML files in the examples directory
28 const files = fs.readdirSync(EXAMPLES_DIR)
29 .filter(f => f.endsWith('.html'));
30
31 if (files.length === 0) {
32 console.log('No HTML files found in', EXAMPLES_DIR);
33 return;
34 }
35
36 console.log(`📸 Taking screenshots of ${files.length} anti-pattern example(s)...\n`);
37
38 const browser = await chromium.launch();
39 const context = await browser.newContext({
40 viewport: { width: 1200, height: 1200 },
41 deviceScaleFactor: 2, // 2x for high-res output
42 });
43
44 for (const file of files) {
45 const name = path.basename(file, '.html');
46 const url = `http://localhost:3000/antipattern-examples/${file}`;
47 const outputPath = path.join(OUTPUT_DIR, `${name}.png`);
48
49 console.log(` ${name}...`);
50
51 const page = await context.newPage();
52 await page.goto(url, { waitUntil: 'networkidle' });
53
54 // Wait for fonts to load
55 await page.waitForTimeout(500);
56
57 // Screenshot the .container element (1080x1080)
58 const container = await page.$('.container');
59 if (container) {
60 await container.screenshot({
61 path: outputPath,
62 type: 'png',
63 });
64 console.log(` ✓ Saved to ${path.relative(ROOT_DIR, outputPath)}`);
65 } else {
66 // Fallback: screenshot full page cropped
67 await page.screenshot({
68 path: outputPath,
69 type: 'png',
70 clip: { x: 0, y: 0, width: 1080, height: 1080 },
71 });
72 console.log(` ✓ Saved (full page crop) to ${path.relative(ROOT_DIR, outputPath)}`);
73 }
74
75 await page.close();
76 }
77
78 await browser.close();
79 console.log(`\n✨ Done! Screenshots saved to ${path.relative(ROOT_DIR, OUTPUT_DIR)}/`);
80}
81
82// Check if dev server is running
83async function checkServer() {
84 try {
85 const response = await fetch('http://localhost:3000');
86 return response.ok;
87 } catch {
88 return false;
89 }
90}
91
92async function main() {
93 const serverRunning = await checkServer();
94 if (!serverRunning) {
95 console.error('❌ Dev server not running. Please start it with: bun run dev');
96 process.exit(1);
97 }
98
99 await screenshotAntipatterns();
100}
101
102main().catch(console.error);