1// Renders the Steam library art PNGs from the HTML sources next to this file.2//3// node build/linux/steam-art/render.mjs (needs the playwright package resolvable)4// PLAYWRIGHT=/path/to/node_modules/playwright/index.mjs node build/linux/steam-art/render.mjs5//6// Serves the repo over a local HTTP server so the pages can load the app's fonts and art.js.78import { createServer } from "node:http";9import { readFile } from "node:fs/promises";10import { dirname, extname, join, normalize } from "node:path";11import { fileURLToPath, pathToFileURL } from "node:url";1213const here = dirname(fileURLToPath(import.meta.url));14const root = join(here, "..", "..", "..");15const spec = process.env.PLAYWRIGHT;16const { chromium } = await import(spec ? pathToFileURL(spec).href : "playwright");1718// name: [page, width, height, transparent]; width/height null = size of #art19const ART = {20 capsule: ["capsule.html", 600, 900, false],21 header: ["header.html", 920, 430, false],22 hero: ["hero.html", 3840, 1240, false],23 logo: ["logo.html", null, null, true],24 icon: ["icon.html", 256, 256, true],25};2627const TYPES = { ".html": "text/html", ".css": "text/css", ".js": "text/javascript", ".woff2": "font/woff2", ".png": "image/png" };28const server = createServer(async (req, res) => {29 const path = normalize(decodeURIComponent(new URL(req.url, "http://x").pathname));30 try {31 const body = await readFile(join(root, path));32 res.writeHead(200, { "content-type": TYPES[extname(path)] ?? "application/octet-stream" });33 res.end(body);34 } catch {35 res.writeHead(404).end();36 }37});38await new Promise((ok) => server.listen(0, "127.0.0.1", ok));39const base = `http://127.0.0.1:${server.address().port}/build/linux/steam-art/`;4041const only = process.argv.slice(2);42const browser = await chromium.launch();43try {44 for (const [name, [page, w, h, transparent]] of Object.entries(ART)) {45 if (only.length && !only.includes(name)) continue;46 const ctx = await browser.newContext({ viewport: { width: w ?? 2400, height: h ?? 800 } });47 const tab = await ctx.newPage();48 tab.on("pageerror", (e) => console.error(`${name}: ${e.message}`));49 tab.on("requestfailed", (r) => console.error(`${name}: failed ${r.url()}`));50 await tab.goto(base + page);51 await tab.waitForSelector("body[data-ready]", { timeout: 15000 });52 const out = join(here, `${name}.png`);53 await tab.locator("#art").screenshot({ path: out, omitBackground: transparent });54 const box = await tab.locator("#art").boundingBox();55 console.log(`${name}.png ${Math.round(box.width)}x${Math.round(box.height)}`);56 await ctx.close();57 }58} finally {59 await browser.close();60 server.close();61}