deadhead-space-freight-tycoon/apps/web/scripts/icons.mjs

51 lines
1.8 KiB
JavaScript

// Generates the PWA and browser icons (Step 11.1) from the Courier sprite on the
// app's space background. Placeholder art until the user supplies a logo.
//
// node scripts/icons.mjs writes public/icons/*.png
import { mkdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import sharp from "sharp";
const webRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
const outDir = join(webRoot, "public/icons");
/** --color-space-900 in src/index.css: the theme and background color. */
export const BACKGROUND = "#080d1d";
/**
* Each icon: size in px and how much of it the ship fills. Maskable icons keep
* the ship inside the central 80 % safe zone, so they fill less.
*/
export const ICONS = [
{ file: "icon-192.png", size: 192, fill: 0.78 },
{ file: "icon-512.png", size: 512, fill: 0.78 },
{ file: "maskable-512.png", size: 512, fill: 0.56 },
{ file: "apple-touch-icon.png", size: 180, fill: 0.7 },
{ file: "favicon-32.png", size: 32, fill: 0.9 },
];
sharp.cache(false);
mkdirSync(outDir, { recursive: true });
const source = readFileSync(join(webRoot, "public/assets/map/ship-courier.png"));
const trimmed = await sharp(source).trim().toBuffer();
for (const { file, size, fill } of ICONS) {
const box = Math.round(size * fill);
const ship = await sharp(trimmed)
.resize(box, box, { fit: "inside" })
.toBuffer({ resolveWithObject: true });
await sharp({
create: { width: size, height: size, channels: 4, background: BACKGROUND },
})
.composite([
{
input: ship.data,
left: Math.round((size - ship.info.width) / 2),
top: Math.round((size - ship.info.height) / 2),
},
])
.png({ compressionLevel: 9 })
.toFile(join(outDir, file));
}
console.log(`icons: wrote ${ICONS.length} files to ${outDir}`);