#!/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 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"]
for i in range(count):
x = random.randint(0, width)
y = random.randint(0, height)
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."""
# Import math here to avoid the error in generate_confetti
import math
# 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"""
"""
# 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)