Files
gemini-nexus/scripts/generate-assets.ts

150 lines
4.5 KiB
TypeScript

import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { Rocket } from 'lucide-react';
import sharp from 'sharp';
import icongen from 'icon-gen';
import path from 'path';
import fs from 'fs';
const IMAGES_DIR = path.join(process.cwd(), 'images');
// Colors
const BACKGROUND_COLOR = '#0f172a'; // slate-900 / primary
const ICON_COLOR = '#f8fafc'; // slate-50 / primary-foreground
const ICON_SIZE = 1024;
const PADDING = 0.25; // 25% padding
async function generate() {
console.log('Generating assets...');
// 1. Generate SVG String
// We want the icon to be centered and sized appropriately.
// The canvas is 1024x1024.
// We will create an SVG with the background rect and the icon centered.
// Lucide icons are 24x24 by default.
// We will scale it up.
const iconSize = ICON_SIZE * (1 - PADDING * 2);
const padding = ICON_SIZE * PADDING;
const iconSvg = renderToStaticMarkup(
React.createElement(Rocket, {
size: iconSize,
color: ICON_COLOR,
strokeWidth: 1.5, // Thicker stroke for larger icon? Or keep 2? 1.5 might look elegant.
}),
);
// Construct the full SVG
// We place the icon at (padding, padding)
const fullSvg = `
<svg width="${ICON_SIZE}" height="${ICON_SIZE}" viewBox="0 0 ${ICON_SIZE} ${ICON_SIZE}" xmlns="http://www.w3.org/2000/svg">
<rect width="${ICON_SIZE}" height="${ICON_SIZE}" fill="${BACKGROUND_COLOR}" />
<g transform="translate(${padding}, ${padding})">
${iconSvg}
</g>
</svg>
`;
// 2. Generate Base PNG
const pngBuffer = await sharp(Buffer.from(fullSvg)).png().toBuffer();
const iconPngPath = path.join(IMAGES_DIR, 'icon.png');
await sharp(pngBuffer).toFile(iconPngPath);
console.log(`Generated ${iconPngPath}`);
// 3. Generate ICO and ICNS using icon-gen
// icon-gen takes the png directory or file and outputs to destination
// Create a temporary directory for input if needed, but icon-gen works with a file path usually?
// Checking icon-gen docs or usage. commonly: icongen(input, destination, options)
// Input can be a path to a png image.
// Clean up old directories and files
const itemsToClean = [
'android',
'ios',
'icon.iconset',
'icon_master_squircle.png',
'storealogo.png',
'tray-icon.png', // incorrectly named
// Clean up "Square" logos as they appear unused
'Square30x30Logo.png',
'Square44x44Logo.png',
'Square71x71Logo.png',
'Square89x89Logo.png',
'Square107x107Logo.png',
'Square142x142Logo.png',
'Square150x150Logo.png',
'Square284x284Logo.png',
'Square310x310Logo.png',
'StoreLogo.png',
]; // checking casing or existence
for (const item of itemsToClean) {
const itemPath = path.join(IMAGES_DIR, item);
if (fs.existsSync(itemPath)) {
fs.rmSync(itemPath, { recursive: true, force: true });
console.log(`Removed old item: ${itemPath}`);
}
}
const options = {
report: true,
ico: {
name: 'icon',
sizes: [16, 24, 32, 48, 64, 128, 256],
},
icns: {
name: 'icon',
sizes: [16, 32, 64, 128, 256, 512, 1024],
},
favicon: {
name: 'favicon-',
pngSizes: [32, 57, 72, 96, 120, 128, 144, 152, 195, 228],
icoSizes: [16, 24, 32, 48, 64],
},
};
await icongen(iconPngPath, IMAGES_DIR, options);
console.log('Generated ICO, ICNS, and Favicon files');
// Generate standard PNGs only
const standardSizes = [
{ name: '32x32.png', size: 32 },
{ name: '64x64.png', size: 64 },
{ name: '128x128.png', size: 128 },
{ name: '[email protected]', size: 256 },
];
for (const { name, size } of standardSizes) {
await sharp(pngBuffer).resize(size, size).toFile(path.join(IMAGES_DIR, name));
console.log(`Generated ${name}`);
}
// Generate tray.png (Matched to code requirement)
const TRAY_SIZE = 24;
// Code uses 'tray.png'
const trayIconSvg = renderToStaticMarkup(
React.createElement(Rocket, {
size: TRAY_SIZE,
color: ICON_COLOR, // White
strokeWidth: 2,
}),
);
const trayPngPath = path.join(IMAGES_DIR, 'tray.png');
await sharp(Buffer.from(trayIconSvg)).png().toFile(trayPngPath);
console.log('Generated tray.png');
// Sync to src/assets
const SRC_ASSETS_DIR = path.join(process.cwd(), 'src', 'assets');
if (fs.existsSync(SRC_ASSETS_DIR)) {
fs.copyFileSync(iconPngPath, path.join(SRC_ASSETS_DIR, 'icon.png'));
fs.copyFileSync(trayPngPath, path.join(SRC_ASSETS_DIR, 'tray.png'));
console.log('Synced icon.png and tray.png to src/assets/');
}
}
generate().catch(console.error);