'use strict';
// Slice the whole shipped icon set from the brand master (build-icon.mjs). Renders
// with the ui package's Playwright chromium. See docs/ICONS.md for the target map.
//
// npm i opentype.js && node build-set.mjs
//
// Writes: ui/public/* (web), ui/assets/* (Capacitor layers), ./vk/* and ./store/*
// (manual-upload art). Wiring (manifest, html, Android res) is done separately.
import { execFileSync } from 'node:child_process';
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const DIR = dirname(fileURLToPath(import.meta.url));
const UI = join(DIR, '..', '..', '..', 'ui');
const PUB = join(UI, 'public'), ASSETS = join(UI, 'assets');
const VK = join(DIR, 'vk'), STORE = join(DIR, 'store'), TG = join(DIR, 'tg');
[VK, STORE, TG].forEach(d => mkdirSync(d, { recursive: true }));
// one SVG string for a variant+layer from the reference generator
const svgFor = (variant, layer) =>
execFileSync('node', [join(DIR, 'build-icon.mjs'), '--variant', variant, '--layer', layer], { encoding: 'utf8' });
const pw = await import(join(UI, 'node_modules', '@playwright', 'test', 'index.js'));
const { chromium } = pw.default ?? pw;
const browser = await chromium.launch();
const page = await browser.newPage();
async function pngFromSvg(svg, size, transparent) {
await page.setViewportSize({ width: size, height: size });
await page.setContent(`${svg}`, { waitUntil: 'networkidle' });
return page.locator('svg').screenshot({ omitBackground: !!transparent });
}
async function shootHtml(html, w, h) {
await page.setViewportSize({ width: w, height: h });
await page.setContent(html, { waitUntil: 'networkidle' });
return page.screenshot();
}
function icoFromPNG(png, sizePx) {
const h = Buffer.alloc(22);
h.writeUInt16LE(0, 0); h.writeUInt16LE(1, 2); h.writeUInt16LE(1, 4);
h.writeUInt8(sizePx, 6); h.writeUInt8(sizePx, 7);
h.writeUInt16LE(1, 10); h.writeUInt16LE(32, 12);
h.writeUInt32LE(png.length, 14); h.writeUInt32LE(22, 18);
return Buffer.concat([h, png]);
}
const write = (p, buf) => { writeFileSync(p, buf); console.log('wrote', p.replace(join(DIR, '..', '..', '..'), '.'), buf.length, 'b'); };
// ---- pre-render the SVG sources we need ----
const S = {
fullLight: svgFor('light', 'full'), fullDark: svgFor('dark', 'full'),
flatLight: svgFor('light', 'flat'), flatDark: svgFor('dark', 'flat'),
maskLight: svgFor('light', 'maskable'), maskDark: svgFor('dark', 'maskable'),
bgLight: svgFor('light', 'background'), fgLight: svgFor('light', 'foreground'),
monoLight: svgFor('light', 'monochrome'),
};
// ---- favicon.svg: light + dark in one file, toggled by prefers-color-scheme ----
const inner = svg => svg.replace(/^