Raw
1 #!/usr/bin/env node
2 /**
3 * Renders App Store visionOS screenshots from HTML templates using Puppeteer.
4 * Apple requires exactly 3840x2160 for Apple Vision Pro screenshots (verify
5 * against the App Store Connect upload panel at build time — see
6 * assets/aso/appstore/shared.md and the app-store-optimization skill).
7 *
8 * Output: assets/aso/appstore/visionos/{01-chat,02-settings}-3840x2160.png
9 *
10 * Usage: node scripts/generate-visionos-graphics.mjs
11 */
12
13 import puppeteer from 'puppeteer';
14 import { fileURLToPath } from 'url';
15 import { dirname, join, resolve } from 'path';
16 import { mkdirSync } from 'fs';
17
18 const __dirname = dirname(fileURLToPath(import.meta.url));
19 const repoRoot = resolve(__dirname, '..');
20 const templateDir = join(__dirname, 'appstore-templates');
21 const outDir = join(repoRoot, 'assets', 'aso', 'appstore', 'visionos');
22
23 mkdirSync(outDir, { recursive: true });
24
25 const WIDTH = 3840;
26 const HEIGHT = 2160;
27
28 const targets = [
29 { template: '01-chat.html', output: '01-chat-3840x2160.png' },
30 { template: '02-settings.html', output: '02-settings-3840x2160.png' },
31 ];
32
33 console.log('Launching browser…');
34 const browser = await puppeteer.launch({
35 headless: true,
36 args: ['--no-sandbox', '--disable-setuid-sandbox'],
37 });
38
39 for (const { template, output } of targets) {
40 const page = await browser.newPage();
41 await page.setViewport({ width: WIDTH, height: HEIGHT, deviceScaleFactor: 1 });
42
43 const url = `file://${join(templateDir, template)}`;
44 await page.goto(url, { waitUntil: 'networkidle0', timeout: 30_000 });
45
46 // Wait a tick for any final layout reflow after font load
47 await new Promise(r => setTimeout(r, 500));
48
49 const outputPath = join(outDir, output);
50 // App Store Connect rejects screenshots with an alpha channel — omitOmitBackground
51 // (default) plus a fully opaque .page background keeps the PNG opaque.
52 await page.screenshot({ path: outputPath, fullPage: false, type: 'png' });
53
54 console.log(`✓ ${output}`);
55 await page.close();
56 }
57
58 await browser.close();
59 console.log(`\nDone — files in assets/aso/appstore/visionos/`);