feat(clock): add MEGA Clock icon set
This commit is contained in:
parent
3d211e9121
commit
d8ae2ba094
5 changed files with 130 additions and 0 deletions
BIN
public/icons/clock-icon-192.png
Normal file
BIN
public/icons/clock-icon-192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
BIN
public/icons/clock-icon-512.png
Normal file
BIN
public/icons/clock-icon-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
BIN
public/icons/clock-maskable-512.png
Normal file
BIN
public/icons/clock-maskable-512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
|
|
@ -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.");
|
||||
BIN
src/app/clock/apple-icon.png
Normal file
BIN
src/app/clock/apple-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
Loading…
Reference in a new issue