Skip to content
32 linesCodeBlameRaw
1// Draws the app's icons from the g1t mark (packages/theme/mark.svg):
2// `npm run icons -w @g1t/mobile` after the mark or the background changes.
3//
4// - icon.png: the store and iOS icon, the mark on g1t's background.
5// - android-icon-foreground.png: the adaptive icon's mark, inside the
6// middle 66% Android keeps whatever the launcher's mask.
7// - android-icon-monochrome.png: the same in white, for themed icons.
8// - splash-icon.png: the mark alone, on the splash screen's background.
9import { readFile } from "node:fs/promises";
10import { fileURLToPath } from "node:url";
11import sharp from "sharp";
12
13const here = (path) => fileURLToPath(new URL(path, import.meta.url));
14const mark = await readFile(here("../../../packages/theme/mark.svg"), "utf8");
15const BACKGROUND = "#0f0f11";
16
17/** The mark at `scale` of a `size` square, recoloured, on `background` or nothing. */
18async function draw(file, { size, scale, color, background }) {
19 const inner = Math.round(size * scale);
20 const svg = Buffer.from(mark.replace(/#b6a8ff/g, color ?? "#b6a8ff").replace("<svg ", `<svg width="${inner}" height="${inner}" `));
21 const glyph = await sharp(svg, { density: 72 * (inner / 80) }).resize(inner, inner).png().toBuffer();
22 await sharp({ create: { width: size, height: size, channels: 4, background: background ?? { r: 0, g: 0, b: 0, alpha: 0 } } })
23 .composite([{ input: glyph, gravity: "centre" }])
24 .png()
25 .toFile(here(`../assets/images/${file}`));
26}
27
28await draw("icon.png", { size: 1024, scale: 0.62, background: BACKGROUND });
29await draw("android-icon-foreground.png", { size: 1024, scale: 0.46 });
30await draw("android-icon-monochrome.png", { size: 1024, scale: 0.46, color: "#ffffff" });
31await draw("splash-icon.png", { size: 512, scale: 0.9 });
32console.log("Drew icon.png, android-icon-foreground.png, android-icon-monochrome.png and splash-icon.png.");