#!/usr/bin/env zx import 'zx/globals'; import sharp from 'sharp'; import png2icons from 'png2icons'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PROJECT_ROOT = path.resolve(__dirname, '..'); const ICONS_DIR = path.join(PROJECT_ROOT, 'resources', 'icons'); const BRAND_DIR = path.join(PROJECT_ROOT, 'resources', 'brand'); const ICON_SOURCE = path.join(ICONS_DIR, 'icon.svg'); const PLAIN_ICON_SOURCE = path.join(ICONS_DIR, 'icon-plain.svg'); const MARK_SOURCE = path.join(BRAND_DIR, 'makelore-mark.svg'); const WORDMARK_SOURCE = path.join(BRAND_DIR, 'makelore-wordmark.svg'); const BRAND_SHEET_SOURCE = path.join(BRAND_DIR, 'makelore-brand-sheet.svg'); const DMG_SOURCE = path.join(PROJECT_ROOT, 'resources', 'dmg-background.svg'); echo`Generating Makelore icons using Node.js...`; if (!fs.existsSync(ICON_SOURCE)) { echo`Icon source not found: ${ICON_SOURCE}`; process.exit(1); } await fs.ensureDir(ICONS_DIR); await fs.ensureDir(BRAND_DIR); try { const masterPngBuffer = await sharp(ICON_SOURCE) .resize(1024, 1024, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 }, }) .png() .toBuffer(); await fs.writeFile(path.join(ICONS_DIR, 'icon-source.png'), masterPngBuffer); echo`Created icon-source.png (1024x1024)`; await sharp(masterPngBuffer) .resize(512, 512) .toFile(path.join(ICONS_DIR, 'icon.png')); echo`Created icon.png (512x512)`; const icoBuffer = png2icons.createICO(masterPngBuffer, png2icons.HERMITE, 0, false); if (icoBuffer) { fs.writeFileSync(path.join(ICONS_DIR, 'icon.ico'), icoBuffer); echo`Created icon.ico`; } else { echo(chalk.red`Failed to create icon.ico`); } const icnsBuffer = png2icons.createICNS(masterPngBuffer, png2icons.HERMITE, 0); if (icnsBuffer) { fs.writeFileSync(path.join(ICONS_DIR, 'icon.icns'), icnsBuffer); echo`Created icon.icns`; } else { echo(chalk.red`Failed to create icon.icns`); } const linuxSizes = [16, 32, 48, 64, 128, 256, 512]; for (const size of linuxSizes) { await sharp(masterPngBuffer) .resize(size, size) .toFile(path.join(ICONS_DIR, `${size}x${size}.png`)); } echo`Created ${linuxSizes.length} Linux PNG icons`; await sharp(MARK_SOURCE) .resize(1024, 750, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .png() .toFile(path.join(BRAND_DIR, 'makelore-mark.png')); await sharp(WORDMARK_SOURCE) .resize(1600, 340, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .png() .toFile(path.join(BRAND_DIR, 'makelore-wordmark.png')); await sharp(BRAND_SHEET_SOURCE) .resize(1600, 1000) .png() .toFile(path.join(BRAND_DIR, 'makelore-brand-sheet.png')); await sharp(MARK_SOURCE) .resize(512, 375, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .png() .toFile(path.join(PROJECT_ROOT, 'src', 'assets', 'logo.png')); await sharp(MARK_SOURCE) .resize(512, 375, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } }) .png() .toFile(path.join(PROJECT_ROOT, 'public', 'logo.png')); await sharp(ICON_SOURCE) .resize(64, 64) .png() .toFile(path.join(PROJECT_ROOT, 'public', 'favicon.png')); await sharp(DMG_SOURCE) .resize(540, 380) .png() .toFile(path.join(PROJECT_ROOT, 'resources', 'dmg-background.png')); echo`Created Makelore brand PNG exports and renderer assets`; const trayAlpha = await sharp(PLAIN_ICON_SOURCE) .resize(22, 22, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 }, }) .ensureAlpha() .extractChannel('alpha') .toBuffer(); await sharp({ create: { width: 22, height: 22, channels: 3, background: '#000000', }, }) .joinChannel(trayAlpha) .png() .toFile(path.join(ICONS_DIR, 'tray-icon-Template.png')); echo`Created tray-icon-Template.png (22x22)`; echo`Icon generation complete. Files located in: ${ICONS_DIR}`; } catch (error) { echo(chalk.red`Fatal Error: ${error.message}`); process.exit(1); }