"""Icon renderer: Claude starburst logo + circular usage arc.""" import math from PIL import Image, ImageDraw SIZE = 128 CENTER = SIZE // 2 ARC_WIDTH = 16 ARC_RADIUS = (SIZE - ARC_WIDTH) // 2 # inner edge of arc # Color thresholds for the usage arc (10% increments) _COLORS = [ (10, "#4CAF50"), # green (20, "#43A047"), # green (darker) (30, "#7CB342"), # light green (40, "#C0CA33"), # lime (50, "#FDD835"), # yellow (60, "#FFC107"), # amber (70, "#FFB300"), # amber (darker) (80, "#FF9800"), # orange (90, "#FF5722"), # deep orange (100, "#F44336"), # red ] def _hex_to_rgba(hex_color, alpha=255): h = hex_color.lstrip("#") return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16), alpha) def _arc_color(pct): for threshold, color in _COLORS: if pct <= threshold: return color return _COLORS[-1][1] def _draw_starburst(img): """Draw 8-petal starburst logo at 50% opacity.""" layer = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) draw = ImageDraw.Draw(layer) num_petals = 8 # Petal geometry: elongated ellipse approximated as polygon petal_length = 38 petal_width = 10 for i in range(num_petals): angle = math.radians(i * (360 / num_petals)) # Build petal as 4-point diamond shape # Tip of petal (far from center) tip_x = CENTER + math.cos(angle) * petal_length tip_y = CENTER + math.sin(angle) * petal_length # Base points (perpendicular to petal direction, near center) perp = angle + math.pi / 2 base_offset = 6 # distance from center to base of petal bx = CENTER + math.cos(angle) * base_offset by = CENTER + math.sin(angle) * base_offset left_x = bx + math.cos(perp) * (petal_width / 2) left_y = by + math.sin(perp) * (petal_width / 2) right_x = bx - math.cos(perp) * (petal_width / 2) right_y = by - math.sin(perp) * (petal_width / 2) # Inner point (towards center, slight taper) inner_x = CENTER - math.cos(angle) * 2 inner_y = CENTER - math.sin(angle) * 2 polygon = [(inner_x, inner_y), (left_x, left_y), (tip_x, tip_y), (right_x, right_y)] draw.polygon(polygon, fill=(255, 255, 255, 128)) # Center dot dot_r = 4 draw.ellipse( [CENTER - dot_r, CENTER - dot_r, CENTER + dot_r, CENTER + dot_r], fill=(255, 255, 255, 128), ) img = Image.alpha_composite(img, layer) return img def _draw_arc(img, pct): """Draw circular progress arc from 12 o'clock, clockwise.""" if pct <= 0: return img layer = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) draw = ImageDraw.Draw(layer) color = _hex_to_rgba(_arc_color(pct)) pct = min(pct, 100) # Pillow arc: 0 = 3 o'clock, angles go counter-clockwise for arc() # We want: start at 12 o'clock (-90), sweep clockwise # Pillow draws counter-clockwise from start to end, so we use: # start = -90, end = -90 + (pct/100)*360 start_angle = -90 end_angle = -90 + (pct / 100) * 360 margin = ARC_WIDTH // 2 bbox = [margin, margin, SIZE - margin, SIZE - margin] draw.arc(bbox, start_angle, end_angle, fill=color, width=ARC_WIDTH) img = Image.alpha_composite(img, layer) return img def render_icon(pct): """Render a 128x128 RGBA icon with starburst + usage arc. Args: pct: Usage percentage (0-100). Arc is invisible at 0. Returns: PIL.Image.Image (RGBA) """ img = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0)) img = _draw_starburst(img) img = _draw_arc(img, pct) return img