from PIL import Image import os def draw_icon(size): img = Image.new("RGBA", (size, size), (0, 0, 0, 0)) BG = (255, 107, 53) CIRC = (30, 58, 138) WHITE = (255, 255, 255) PAD = int(round(24 * size / 512.0)) RX = int(round(104 * size / 512.0)) ccx = size // 2 ccy = size // 2 ccr = int(round(112 * size / 512.0)) # 1. Orange rounded square x1, y1 = PAD, PAD x2, y2 = size - PAD, size - PAD for y in range(y1, y2 + 1): for x in range(x1, x2 + 1): if _in_rrect(x, y, x1, y1, x2, y2, RX): img.putpixel((x, y), BG + (255,)) # 2. Deep blue circle for y in range(ccy - ccr, ccy + ccr + 1): for x in range(ccx - ccr, ccx + ccr + 1): if (x - ccx) ** 2 + (y - ccy) ** 2 <= ccr ** 2: img.putpixel((x, y), CIRC + (255,)) # 3. White play triangle — right-pointing isosceles, apex at circle's right edge # Width-to-height ratio ~2:1 for a balanced play button look # bh=ccr*0.35 ensures the left vertex stays inside the circle # At y=ccy: triangle base spans ~67% of circle diameter (visually balanced) bh = int(round(ccr * 0.35)) w_tri = bh * 2 # width from left vertex to right vertex = 0.7*ccr rx2 = ccx + ccr # right vertex at circle's right edge lx = rx2 - w_tri # left vertex ty_ = ccy - bh by_ = ccy + bh for y in range(ty_, by_ + 1): frac = float(y - ty_) / float(by_ - ty_) if by_ > ty_ else 0.0 xl = lx xr = lx + int(round(w_tri * 2 * frac)) xl, xr = min(xl, xr), max(xl, xr) for x in range(xl, xr + 1): if 0 <= x < size and 0 <= y < size: img.putpixel((x, y), WHITE + (255,)) return img def _in_rrect(px, py, x1, y1, x2, y2, r): if px < x1 or px > x2 or py < y1 or py > y2: return False if px < x1 + r and py < y1 + r: return (px - x1 - r) ** 2 + (py - y1 - r) ** 2 <= r ** 2 if px > x2 - r and py < y1 + r: return (px - x2 + r) ** 2 + (py - y1 - r) ** 2 <= r ** 2 if px < x1 + r and py > y2 - r: return (px - x1 - r) ** 2 + (py - y2 + r) ** 2 <= r ** 2 if px > x2 - r and py > y2 - r: return (px - x2 + r) ** 2 + (py - y2 + r) ** 2 <= r ** 2 return True src_size = 1024 img = draw_icon(src_size) vp = img.load() ccr = int(round(112 * src_size / 512.0)) bh_draw = int(round(ccr * 0.35)) w_tri_draw = bh_draw * 2 rx2_draw = src_size // 2 + ccr lx_draw = rx2_draw - w_tri_draw ty__draw = src_size // 2 - bh_draw by__draw = src_size // 2 + bh_draw print("ccr=%d, w_tri=%d, bh=%d, lx=%d, rx2=%d, ty_=%d, by_=%d" % (ccr, w_tri_draw, bh_draw, lx_draw, rx2_draw, ty__draw, by__draw)) print("Midpoint at y=ccy: %d [expect %d]" % ((lx_draw+rx2_draw)//2, src_size//2)) print("Center(512,512): %s" % str(vp[512, 512])) print("Corner(5,5): %s" % str(vp[5, 5])) # Verify triangle left vertex is inside circle # Left vertex distance from center must be < ccr left_dist = abs(lx_draw - src_size//2) # Also check top-left corner (most likely to be outside) top_lx = lx_draw top_ly = ty__draw tl_dist_sq = (top_lx - src_size//2)**2 + (top_ly - src_size//2)**2 print("Left vertex dist from center: %.1f < ccr=%d: %s" % (left_dist, ccr, left_dist < ccr)) print("Top-left corner dist: %.1f < ccr=%d: %s" % (tl_dist_sq**0.5, ccr, tl_dist_sq**0.5 < ccr)) out_dir = "minimax-output/vector" icons_dir = "client/public/icons" os.makedirs(out_dir, exist_ok=True) img.save(os.path.join(out_dir, "icon-orange-1024.png"), "PNG") for sz in [16, 24, 32, 48, 64, 128, 256, 512]: img.resize((sz, sz), Image.NEAREST).save(os.path.join(icons_dir, "icon-%d.png" % sz), "PNG") img.resize((512, 512), Image.NEAREST).save(os.path.join(icons_dir, "logo.png"), "PNG") img.resize((16, 16), Image.NEAREST).save(os.path.join(icons_dir, "tray-icon.png"), "PNG") img.resize((32, 32), Image.NEAREST).save(os.path.join(icons_dir, "tray-icon@2x.png"), "PNG") print("Done!")