diff --git a/lyra/web/gen_icons.py b/lyra/web/gen_icons.py new file mode 100644 index 0000000..6650122 --- /dev/null +++ b/lyra/web/gen_icons.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +"""Generate Lyra PWA icons with no third-party deps (pure stdlib PNG writer). + +Design: RTO warm/low-glow — near-black field, a soft orange ambient glow, and a +luminous gold-orange ring (the "orb/portal"). iOS masks corners itself, so icons +are full-bleed squares. Run from anywhere; writes PNGs into ./static. +""" +import math +import os +import struct +import zlib + +HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static") + +BG = (7, 7, 7) # #070707 +ORANGE = (255, 122, 0) # #ff7a00 accent +GOLD = (255, 179, 71) # #ffb347 hot core + + +def _png(width, height, rgb_rows): + def chunk(tag, data): + return (struct.pack(">I", len(data)) + tag + data + + struct.pack(">I", zlib.crc32(tag + data) & 0xFFFFFFFF)) + + raw = bytearray() + for row in rgb_rows: + raw.append(0) # filter type 0 (None) + raw.extend(row) + ihdr = struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0) # 8-bit RGB + return (b"\x89PNG\r\n\x1a\n" + + chunk(b"IHDR", ihdr) + + chunk(b"IDAT", zlib.compress(bytes(raw), 9)) + + chunk(b"IEND", b"")) + + +def render(n): + c = (n - 1) / 2.0 + sigma_glow = n * 0.30 + ring_r = n * 0.30 + ring_w = n * 0.050 + core_sigma = n * 0.11 + rows = [] + for y in range(n): + row = bytearray() + for x in range(n): + dx, dy = x - c, y - c + d = math.hypot(dx, dy) + r, g, b = BG + # ambient orange glow + glow = math.exp(-(d * d) / (2 * sigma_glow * sigma_glow)) * 0.50 + # soft hot core + core = math.exp(-(d * d) / (2 * core_sigma * core_sigma)) * 0.45 + # luminous ring + rr = d - ring_r + ring = math.exp(-(rr * rr) / (2 * ring_w * ring_w)) + r += ORANGE[0] * glow + GOLD[0] * (ring + core) + g += ORANGE[1] * glow + GOLD[1] * (ring + core) + b += ORANGE[2] * glow + GOLD[2] * (ring + core) + row += bytes((min(255, int(r)), min(255, int(g)), min(255, int(b)))) + rows.append(row) + return rows + + +def write(name, n): + rows = render(n) + with open(os.path.join(HERE, name), "wb") as f: + f.write(_png(n, n, rows)) + print(f"wrote {name} ({n}x{n})") + + +if __name__ == "__main__": + write("icon-512.png", 512) + write("icon-192.png", 192) + write("apple-touch-icon.png", 180) + write("icon-maskable-512.png", 512) diff --git a/lyra/web/static/apple-touch-icon.png b/lyra/web/static/apple-touch-icon.png new file mode 100644 index 0000000..2a53470 Binary files /dev/null and b/lyra/web/static/apple-touch-icon.png differ diff --git a/lyra/web/static/icon-192.png b/lyra/web/static/icon-192.png new file mode 100644 index 0000000..dc79f75 Binary files /dev/null and b/lyra/web/static/icon-192.png differ diff --git a/lyra/web/static/icon-512.png b/lyra/web/static/icon-512.png new file mode 100644 index 0000000..64f7d81 Binary files /dev/null and b/lyra/web/static/icon-512.png differ diff --git a/lyra/web/static/icon-maskable-512.png b/lyra/web/static/icon-maskable-512.png new file mode 100644 index 0000000..64f7d81 Binary files /dev/null and b/lyra/web/static/icon-maskable-512.png differ diff --git a/lyra/web/static/index.html b/lyra/web/static/index.html index 801a93b..df3670e 100644 --- a/lyra/web/static/index.html +++ b/lyra/web/static/index.html @@ -5,10 +5,14 @@ Lyra Core Chat - + + + + + @@ -55,6 +59,8 @@ + Lyra +