feat(clock): add MEGA Clock icon set

This commit is contained in:
DEls 2026-09-12 00:17:25 +02:00
parent 3d211e9121
commit d8ae2ba094
5 changed files with 130 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

@ -162,6 +162,126 @@ function chatMaskableSvg(size, fontPx) {
</svg>`;
}
// Non-maskable clock icon (192 and 512). Transparent background.
// Layout: orange clock ring with tick marks, cube mark as the centre
// hub, "CLOCK" wordmark underneath — same brand DNA as the dashboard
// and chat icons.
function clockSvg(size, fontPx) {
const cx = 256;
const cy = 190;
const r = 130;
const cubeSize = 90;
const cubeX = cx - cubeSize / 2;
const cubeY = cy - cubeSize / 2;
const wordY = 420;
const ticks = [];
for (let i = 0; i < 12; i++) {
const angle = (i * Math.PI * 2) / 12;
const inner = r - 14;
const outer = r - 2;
const x1 = cx + inner * Math.sin(angle);
const y1 = cy - inner * Math.cos(angle);
const x2 = cx + outer * Math.sin(angle);
const y2 = cy - outer * Math.cos(angle);
ticks.push(
`<line x1="${x1.toFixed(1)}" y1="${y1.toFixed(1)}" x2="${x2.toFixed(1)}" y2="${y2.toFixed(1)}" stroke="${palette.black}" stroke-width="6" stroke-linecap="round"/>`,
);
}
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 512 512">
<defs>
<style type="text/css">
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 800;
src: url(data:font/woff;base64,${fontB64}) format('woff');
}
</style>
</defs>
<!-- Clock ring -->
<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${palette.orange}" stroke-width="18"/>
${ticks.join("\n ")}
<!-- Cube mark (dashboard DNA) as the clock's centre hub -->
<g transform="translate(${cubeX}, ${cubeY})">
<rect x="0" y="0" width="${cubeSize}" height="${cubeSize}" rx="16" fill="${palette.black}"/>
<rect x="9" y="9" width="${cubeSize - 18}" height="${cubeSize - 18}" rx="10" fill="${palette.orange}"/>
<path d="M ${cubeSize / 2} 21 L ${cubeSize - 24} ${cubeSize / 2} L ${cubeSize / 2} ${cubeSize - 21} L 24 ${cubeSize / 2} Z" fill="${palette.black}"/>
<circle cx="${cubeSize / 2}" cy="${cubeSize / 2}" r="8" fill="${palette.orange}"/>
</g>
<!-- Wordmark -->
<text x="256" y="${wordY}" font-family="Inter, system-ui, sans-serif" font-size="${fontPx}" font-weight="800" letter-spacing="6" text-anchor="middle" fill="${palette.black}">CLOCK</text>
</svg>`;
}
// Maskable variant — orange fills the whole canvas. Content lives
// inside the centre ~40% safe-zone (~205x205 inside a 512 canvas).
function clockMaskableSvg(size, fontPx) {
const scale = 205 / 512;
const offset = (512 - 205) / 2;
const cx = offset + 102;
const cy = offset + 75;
const r = 55 * (scale / scale); // keep in the 205-wide safe zone
const cubeSize = 38;
const cubeX = cx - cubeSize / 2;
const cubeY = cy - cubeSize / 2;
const wordY = offset + 175;
const ticks = [];
for (let i = 0; i < 12; i++) {
const angle = (i * Math.PI * 2) / 12;
const inner = r - 6;
const outer = r - 1;
const x1 = cx + inner * Math.sin(angle);
const y1 = cy - inner * Math.cos(angle);
const x2 = cx + outer * Math.sin(angle);
const y2 = cy - outer * Math.cos(angle);
ticks.push(
`<line x1="${x1.toFixed(1)}" y1="${y1.toFixed(1)}" x2="${x2.toFixed(1)}" y2="${y2.toFixed(1)}" stroke="${palette.black}" stroke-width="2.5" stroke-linecap="round"/>`,
);
}
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 512 512">
<defs>
<style type="text/css">
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 800;
src: url(data:font/woff;base64,${fontB64}) format('woff');
}
</style>
</defs>
<!-- Full-bleed orange background (OS-safe) -->
<rect width="512" height="512" fill="${palette.orange}"/>
<!-- Clock ring (negative-space: black on orange) -->
<circle cx="${cx}" cy="${cy}" r="${r}" fill="none" stroke="${palette.black}" stroke-width="7"/>
${ticks.join("\n ")}
<!-- Cube mark -->
<g transform="translate(${cubeX}, ${cubeY})">
<rect x="0" y="0" width="${cubeSize}" height="${cubeSize}" rx="7" fill="${palette.black}"/>
<rect x="4" y="4" width="${cubeSize - 8}" height="${cubeSize - 8}" rx="4" fill="${palette.orange}"/>
<path d="M ${cubeSize / 2} 10 L ${cubeSize - 11} ${cubeSize / 2} L ${cubeSize / 2} ${cubeSize - 10} L 11 ${cubeSize / 2} Z" fill="${palette.black}"/>
<circle cx="${cubeSize / 2}" cy="${cubeSize / 2}" r="3.5" fill="${palette.orange}"/>
</g>
<!-- Wordmark (negative-space: black on orange) -->
<text x="256" y="${wordY}" font-family="Inter, system-ui, sans-serif" font-size="${fontPx}" font-weight="800" letter-spacing="3" text-anchor="middle" fill="${palette.black}">CLOCK</text>
</svg>`;
}
async function renderSvg(svg, outPath, size) {
const buf = Buffer.from(svg);
await sharp(buf, { density: 144 })
@ -207,4 +327,14 @@ await renderAppleIcon(
path.join(ROOT, "src/app/apple-icon.png"),
);
// MEGA Clock icon set (non-maskable 192/512, maskable 512)
await renderSvg(clockSvg(512, 80), path.join(ROOT, "public/icons/clock-icon-512.png"), 512);
await renderSvg(clockSvg(192, 30), path.join(ROOT, "public/icons/clock-icon-192.png"), 192);
await renderSvg(clockMaskableSvg(512, 38), path.join(ROOT, "public/icons/clock-maskable-512.png"), 512);
await renderAppleIcon(
path.join(ROOT, "public/icons/clock-icon-512.png"),
path.join(ROOT, "src/app/clock/apple-icon.png"),
);
console.log("All icons rendered.");

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB