#!/usr/bin/env python """ Generate a celebratory SVG image for Aider reaching 30,000 GitHub stars. This creates a shareable social media graphic with confetti animation. """ import argparse import base64 import math import os import random from pathlib import Path # Default colors for the celebration image AIDER_GREEN = "#14b014" AIDER_BLUE = "#4C6EF5" DARK_COLOR = "#212529" LIGHT_COLOR = "#F8F9FA" GOLD_COLOR = "#f1c40f" # Default dimensions for social sharing DEFAULT_WIDTH = 1200 DEFAULT_HEIGHT = 630 def embed_font(): """Returns base64 encoded font data for the GlassTTYVT220 font.""" # Path to the font file font_path = ( Path(__file__).parent.parent / "aider" / "website" / "assets" / "Glass_TTY_VT220.ttf" ) # If font file doesn't exist, return empty string if not font_path.exists(): print(f"Warning: Font file not found at {font_path}") return "" # Read and encode the font file with open(font_path, "rb") as f: font_data = f.read() # Return base64 encoded font data return base64.b64encode(font_data).decode("utf-8") def generate_confetti(count=150, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT): """Generate SVG confetti elements for the celebration.""" confetti = [] colors = [AIDER_GREEN, AIDER_BLUE, GOLD_COLOR, "#e74c3c", "#9b59b6", "#3498db", "#2ecc71"] # Define text safe zones # Main content safe zone (centered area) safe_zone_x_min = width * 0.2 safe_zone_x_max = width * 0.8 safe_zone_y_min = height * 0.25 safe_zone_y_max = height * 0.75 # Footer safe zone (for GitHub URL) footer_safe_zone_x_min = width * 0.25 footer_safe_zone_x_max = width * 0.75 footer_safe_zone_y_min = height - 100 # 100px from bottom footer_safe_zone_y_max = height # Bottom of image # Keep trying until we have enough confetti pieces attempts = 0 confetti_count = 0 while confetti_count < count and attempts < count * 3: attempts += 1 # Generate random position x = random.randint(0, width) y = random.randint(0, height) # Skip if the position is in either of the safe zones if ((safe_zone_x_min < x < safe_zone_x_max) and (safe_zone_y_min < y < safe_zone_y_max)) or \ ((footer_safe_zone_x_min < x < footer_safe_zone_x_max) and (footer_safe_zone_y_min < y < footer_safe_zone_y_max)): continue confetti_count += 1 size = random.randint(5, 15) color = random.choice(colors) rotation = random.randint(0, 360) delay = random.uniform(0, 2) duration = random.uniform(1, 3) # Randomly choose between rect (square), circle, and star shapes shape_type = random.choice(["rect", "circle", "star"]) if shape_type == "rect": shape = f""" """ elif shape_type == "circle": shape = f""" """ else: # star # Create a simple 5-point star points = [] for j in range(5): angle = j * 2 * 3.14159 / 5 x_point = x + (size * 0.5) * math.cos(angle) y_point = y + (size * 0.5) * math.sin(angle) points.append(f"{x_point},{y_point}") # Inner points of the star inner_angle = angle + 3.14159 / 5 inner_x = x + (size * 0.2) * math.cos(inner_angle) inner_y = y + (size * 0.2) * math.sin(inner_angle) points.append(f"{inner_x},{inner_y}") points_str = " ".join(points) shape = f""" """ confetti.append(shape) return "\n".join(confetti) def generate_celebration_svg(output_path=None, width=DEFAULT_WIDTH, height=DEFAULT_HEIGHT): """Generate a celebratory SVG for 30K GitHub stars.""" # Font embedding font_data = embed_font() font_face = f""" @font-face {{ font-family: 'GlassTTYVT220'; src: url(data:font/truetype;charset=utf-8;base64,{font_data}) format('truetype'); font-weight: normal; font-style: normal; }} """ if font_data else "" # Generate confetti elements confetti = generate_confetti(count=150, width=width, height=height) # Create the SVG content svg_content = f""" {confetti} 30,000 GitHub stars! Thank you to our amazing community! github.com/Aider-AI/aider """ # Write to file if output path is specified if output_path: with open(output_path, "w") as f: f.write(svg_content) print(f"Celebration SVG saved to {output_path}") return svg_content if __name__ == "__main__": parser = argparse.ArgumentParser( description="Generate a celebration SVG for Aider's 30K GitHub stars" ) parser.add_argument( "--output", "-o", type=str, default="aider-30k-stars.svg", help="Output file path (default: aider-30k-stars.svg)", ) parser.add_argument( "--width", "-w", type=int, default=DEFAULT_WIDTH, help=f"Image width in pixels (default: {DEFAULT_WIDTH})", ) parser.add_argument( "--height", "-ht", type=int, default=DEFAULT_HEIGHT, help=f"Image height in pixels (default: {DEFAULT_HEIGHT})", ) args = parser.parse_args() # Generate the SVG generate_celebration_svg(args.output, args.width, args.height)