97d3a02a3c
- Master SVGs + generator in scripts/icon/ (icon.svg full design, icon-foreground.svg cards-only for the Android adaptive layer, gen-icons.mjs via sharp). - Web/PWA: regenerated favicon.ico (16/32/48), src/app/apple-icon.png, public/icon.svg, icon-192/512, icon-maskable-512; manifest now lists png + maskable icons. - Android (Capacitor): ic_launcher / ic_launcher_round / ic_launcher_foreground for all densities + ic_launcher-playstore 512; adaptive background switched from flat white to a navy radial-gradient drawable (matches the icon), foreground = the gold card fan. Design: navy field, gold rounded frame, three fanned cards with a gold spade — on-brand with the in-app "Persian luxury" look. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
80 lines
3.2 KiB
JavaScript
80 lines
3.2 KiB
JavaScript
// Generates every app/website/Android icon asset from the two master SVGs:
|
|
// scripts/icon/icon.svg — full design (navy bg + gold frame + fanned cards)
|
|
// scripts/icon/icon-foreground.svg — cards only, transparent (Android adaptive foreground)
|
|
// Run: node scripts/icon/gen-icons.mjs
|
|
import sharp from "sharp";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
const root = path.resolve(here, "..", "..");
|
|
const fullSvg = fs.readFileSync(path.join(here, "icon.svg"));
|
|
const fgSvg = fs.readFileSync(path.join(here, "icon-foreground.svg"));
|
|
|
|
const R = (p) => path.join(root, p);
|
|
const ensure = (p) => fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
|
|
async function png(svg, size) {
|
|
return sharp(svg, { density: 384 }).resize(size, size, { fit: "contain", background: { r: 0, g: 0, b: 0, alpha: 0 } }).png().toBuffer();
|
|
}
|
|
async function write(svg, size, dest) {
|
|
ensure(R(dest));
|
|
fs.writeFileSync(R(dest), await png(svg, size));
|
|
console.log(" ", dest, `(${size})`);
|
|
}
|
|
|
|
// PNG-in-ICO container (16/32/48), accepted by all modern browsers.
|
|
function buildIco(entries) {
|
|
const header = Buffer.alloc(6);
|
|
header.writeUInt16LE(0, 0); header.writeUInt16LE(1, 2); header.writeUInt16LE(entries.length, 4);
|
|
const dir = Buffer.alloc(16 * entries.length);
|
|
let offset = 6 + 16 * entries.length;
|
|
entries.forEach((e, i) => {
|
|
const b = i * 16;
|
|
dir.writeUInt8(e.size >= 256 ? 0 : e.size, b);
|
|
dir.writeUInt8(e.size >= 256 ? 0 : e.size, b + 1);
|
|
dir.writeUInt16LE(1, b + 4); dir.writeUInt16LE(32, b + 6);
|
|
dir.writeUInt32LE(e.buf.length, b + 8); dir.writeUInt32LE(offset, b + 12);
|
|
offset += e.buf.length;
|
|
});
|
|
return Buffer.concat([header, dir, ...entries.map((e) => e.buf)]);
|
|
}
|
|
|
|
const ANDROID = [
|
|
["mipmap-mdpi", 48, 108],
|
|
["mipmap-hdpi", 72, 162],
|
|
["mipmap-xhdpi", 96, 216],
|
|
["mipmap-xxhdpi", 144, 324],
|
|
["mipmap-xxxhdpi", 192, 432],
|
|
];
|
|
|
|
async function run() {
|
|
console.log("Web / PWA:");
|
|
// public/icon.svg = the vector master (manifest references it)
|
|
fs.copyFileSync(path.join(here, "icon.svg"), R("public/icon.svg"));
|
|
console.log(" public/icon.svg (vector)");
|
|
await write(fullSvg, 192, "public/icon-192.png");
|
|
await write(fullSvg, 512, "public/icon-512.png");
|
|
await write(fullSvg, 512, "public/icon-maskable.png");
|
|
await write(fullSvg, 180, "public/apple-touch-icon.png");
|
|
await write(fullSvg, 180, "src/app/apple-icon.png");
|
|
|
|
// favicon.ico (16/32/48)
|
|
const ico = buildIco(await Promise.all([16, 32, 48].map(async (s) => ({ size: s, buf: await png(fullSvg, s) }))));
|
|
ensure(R("src/app/favicon.ico"));
|
|
fs.writeFileSync(R("src/app/favicon.ico"), ico);
|
|
console.log(" src/app/favicon.ico (16/32/48)");
|
|
|
|
console.log("Android (Capacitor):");
|
|
for (const [dir, launcher, fg] of ANDROID) {
|
|
await write(fullSvg, launcher, `android/app/src/main/res/${dir}/ic_launcher.png`);
|
|
await write(fullSvg, launcher, `android/app/src/main/res/${dir}/ic_launcher_round.png`);
|
|
await write(fgSvg, fg, `android/app/src/main/res/${dir}/ic_launcher_foreground.png`);
|
|
}
|
|
await write(fullSvg, 512, "android/app/src/main/ic_launcher-playstore.png");
|
|
|
|
console.log("Done.");
|
|
}
|
|
run().catch((e) => { console.error(e); process.exit(1); });
|