| 1 | #!/usr/bin/env node |
| 2 | /** |
| 3 | * Renders Play Store marketing graphics from HTML templates using Puppeteer. |
| 4 | * Output: assets/aso/playstore/{01-chat,02-settings}-1080x1920.png + feature-graphic-1024x500.png |
| 5 | * |
| 6 | * Usage: node scripts/generate-playstore-graphics.mjs |
| 7 | */ |
| 8 | |
| 9 | import puppeteer from 'puppeteer'; |
| 10 | import { fileURLToPath } from 'url'; |
| 11 | import { dirname, join, resolve } from 'path'; |
| 12 | import { mkdirSync } from 'fs'; |
| 13 | |
| 14 | const __dirname = dirname(fileURLToPath(import.meta.url)); |
| 15 | const repoRoot = resolve(__dirname, '..'); |
| 16 | const templateDir = join(__dirname, 'playstore-templates'); |
| 17 | const outDir = join(repoRoot, 'assets', 'aso', 'playstore'); |
| 18 | |
| 19 | mkdirSync(outDir, { recursive: true }); |
| 20 | |
| 21 | const targets = [ |
| 22 | { |
| 23 | template: '01-chat.html', |
| 24 | output: '01-chat-1080x1920.png', |
| 25 | width: 1080, |
| 26 | height: 1920, |
| 27 | }, |
| 28 | { |
| 29 | template: '02-settings.html', |
| 30 | output: '02-settings-1080x1920.png', |
| 31 | width: 1080, |
| 32 | height: 1920, |
| 33 | }, |
| 34 | { |
| 35 | template: 'feature-graphic.html', |
| 36 | output: 'feature-graphic-1024x500.png', |
| 37 | width: 1024, |
| 38 | height: 500, |
| 39 | }, |
| 40 | ]; |
| 41 | |
| 42 | console.log('Launching browser…'); |
| 43 | const browser = await puppeteer.launch({ |
| 44 | headless: true, |
| 45 | args: ['--no-sandbox', '--disable-setuid-sandbox'], |
| 46 | }); |
| 47 | |
| 48 | for (const { template, output, width, height } of targets) { |
| 49 | const page = await browser.newPage(); |
| 50 | await page.setViewport({ width, height, deviceScaleFactor: 1 }); |
| 51 | |
| 52 | const url = `file://${join(templateDir, template)}`; |
| 53 | await page.goto(url, { waitUntil: 'networkidle0', timeout: 30_000 }); |
| 54 | |
| 55 | // Wait a tick for any final layout reflow after font load |
| 56 | await new Promise(r => setTimeout(r, 500)); |
| 57 | |
| 58 | const outputPath = join(outDir, output); |
| 59 | await page.screenshot({ path: outputPath, fullPage: false, type: 'png' }); |
| 60 | |
| 61 | console.log(`✓ ${output}`); |
| 62 | await page.close(); |
| 63 | } |
| 64 | |
| 65 | await browser.close(); |
| 66 | console.log(`\nDone — files in assets/aso/playstore/`); |