import { execFileSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const rootDir = path.resolve(__dirname, ".."); const chromePath = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"; const shotsDir = path.join(rootDir, "src", "assets", "shots"); if (!fs.existsSync(shotsDir)) { fs.mkdirSync(shotsDir, { recursive: true }); } const targets = [ { url: path.join(rootDir, "public", "work", "thursday-flowers", "index.html"), out: path.join(shotsDir, "work-thursday-flowers.png"), altUrl: path.join(rootDir, "public", "work", "thursday-flowers", "index.html"), altOut: path.join(shotsDir, "work-thursday-flowers-2.png"), }, { url: path.join(rootDir, "public", "work", "muwol-coffee", "index.html"), out: path.join(shotsDir, "work-muwol-coffee.png"), altUrl: path.join(rootDir, "public", "work", "muwol-coffee", "index.html"), altOut: path.join(shotsDir, "work-muwol-coffee-2.png"), }, { url: path.join(rootDir, "public", "work", "pulsegate", "index.html"), out: path.join(shotsDir, "work-pulsegate.png"), altUrl: path.join(rootDir, "public", "work", "pulsegate", "index.html"), altOut: path.join(shotsDir, "work-pulsegate-2.png"), }, { url: path.join(rootDir, "public", "work", "form-architecture", "index.html"), out: path.join(shotsDir, "work-form-architecture.png"), altUrl: path.join(rootDir, "public", "work", "form-architecture", "index.html"), altOut: path.join(shotsDir, "work-form-architecture-2.png"), }, { url: path.join(rootDir, "public", "work", "overtone-sound", "index.html"), out: path.join(shotsDir, "work-overtone-sound.png"), altUrl: path.join(rootDir, "public", "work", "overtone-sound", "index.html"), altOut: path.join(shotsDir, "work-overtone-sound-2.png"), }, { url: path.join(rootDir, "public", "work", "font-foundry", "index.html"), out: path.join(shotsDir, "work-font-foundry.png"), altUrl: path.join(rootDir, "public", "work", "font-foundry", "index.html"), altOut: path.join(shotsDir, "work-font-foundry-2.png"), }, { url: path.join(rootDir, "public", "work", "lumina-optics", "index.html"), out: path.join(shotsDir, "work-lumina-optics.png"), altUrl: path.join(rootDir, "public", "work", "lumina-optics", "index.html"), altOut: path.join(shotsDir, "work-lumina-optics-2.png"), webgl: true, // three.js 캔버스 — swiftshader 필요 }, { url: path.join(rootDir, "public", "work", "hyang-incense", "index.html"), out: path.join(shotsDir, "work-hyang-incense.png"), altUrl: path.join(rootDir, "public", "work", "hyang-incense", "index.html"), altOut: path.join(shotsDir, "work-hyang-incense-2.png"), }, { url: path.join(rootDir, "public", "work", "synapse-bci", "index.html"), out: path.join(shotsDir, "work-synapse-bci.png"), altUrl: path.join(rootDir, "public", "work", "synapse-bci", "index.html"), altOut: path.join(shotsDir, "work-synapse-bci-2.png"), }, { url: path.join(rootDir, "public", "work", "baekje-celadon", "index.html"), out: path.join(shotsDir, "work-baekje-celadon.png"), altUrl: path.join(rootDir, "public", "work", "baekje-celadon", "index.html"), altOut: path.join(shotsDir, "work-baekje-celadon-2.png"), }, { url: path.join(rootDir, "public", "work", "orbit-aerospace", "index.html"), out: path.join(shotsDir, "work-orbit-aerospace.png"), altUrl: path.join(rootDir, "public", "work", "orbit-aerospace", "index.html"), altOut: path.join(shotsDir, "work-orbit-aerospace-2.png"), }, { url: path.join(rootDir, "public", "work", "gaon-lms", "index.html"), out: path.join(shotsDir, "work-gaon-lms.png"), altUrl: path.join(rootDir, "public", "work", "gaon-lms", "index.html"), altOut: path.join(shotsDir, "work-gaon-lms-2.png"), }, { url: path.join(rootDir, "public", "work", "dure-enrollment", "index.html"), out: path.join(shotsDir, "work-dure-enrollment.png"), altUrl: path.join(rootDir, "public", "work", "dure-enrollment", "index.html"), altOut: path.join(shotsDir, "work-dure-enrollment-2.png"), }, ]; console.log("📸 Capturing high-resolution screenshots..."); const shot = (t, url, out) => { const flags = t.webgl ? ["--no-sandbox", "--use-angle=swiftshader"] // --disable-gpu 는 WebGL 을 죽인다 : ["--disable-gpu", "--no-sandbox"]; execFileSync(chromePath, [ "--headless=new", "--hide-scrollbars", ...flags, "--force-device-scale-factor=1", "--window-size=1440,900", `--screenshot=${out}`, `file://${url}`, ]); }; for (const t of targets) { console.log(`- Capturing ${path.basename(t.out)}`); try { shot(t, t.url, t.out); } catch (e) { console.error(`Error capturing ${t.out}:`, e.message); } if (t.altOut) { console.log(`- Capturing ${path.basename(t.altOut)}`); try { shot(t, t.altUrl, t.altOut); } catch (e) { console.error(`Error capturing ${t.altOut}:`, e.message); } } } console.log("✅ All screenshots captured successfully!");