← back to Contact Mailer Ideas

render-slide.py

72 lines

#!/usr/bin/env python3
"""Render a single 1920x1080 PNG slide for a VC pitch video.
Usage: render-slide.py <name> <headline> <score> <output.png>
"""
import sys
from PIL import Image, ImageDraw, ImageFont

if len(sys.argv) != 5:
    print("Usage: render-slide.py <name> <headline> <score> <out.png>")
    sys.exit(1)

name, headline, score, out = sys.argv[1:5]

W, H = 1920, 1080
img = Image.new("RGB", (W, H), (11, 11, 13))
d = ImageDraw.Draw(img)

# Fonts (system Helvetica)
def font(path, size):
    try:
        return ImageFont.truetype(path, size)
    except Exception:
        return ImageFont.load_default()

NAME_FONT = font("/System/Library/Fonts/Supplemental/Arial Bold.ttf", 160)
HEADLINE_FONT = font("/System/Library/Fonts/Supplemental/Arial.ttf", 56)
LABEL_FONT = font("/System/Library/Fonts/Supplemental/Arial Bold.ttf", 28)
FOOTER_FONT = font("/System/Library/Fonts/Supplemental/Arial.ttf", 26)

def center(text, fnt, y, color):
    bbox = d.textbbox((0, 0), text, font=fnt)
    w = bbox[2] - bbox[0]
    d.text(((W - w) // 2, y), text, font=fnt, fill=color)

# Eyebrow label
center("VC PITCH · SCALABILITY", LABEL_FONT, 220, (221, 171, 30))  # accent gold

# Name (big)
center(name, NAME_FONT, 290, (245, 243, 238))  # ink

# Headline (medium gray)
# Word-wrap headline if too wide
def wrap(text, fnt, maxw):
    words = text.split()
    lines, cur = [], ""
    for w in words:
        test = (cur + " " + w).strip()
        bbox = d.textbbox((0, 0), test, font=fnt)
        if (bbox[2] - bbox[0]) > maxw and cur:
            lines.append(cur)
            cur = w
        else:
            cur = test
    if cur:
        lines.append(cur)
    return lines

headline_lines = wrap(headline, HEADLINE_FONT, W - 200)
y = 510
for line in headline_lines[:3]:
    center(line, HEADLINE_FONT, y, (207, 203, 193))
    y += 72

# Score badge
center(f"{score}/40 · OPPORTUNITY-GRADE", LABEL_FONT, 760, (34, 197, 94))

# Footer
center("agentabrams · ideas.agentabrams.com", FOOTER_FONT, 980, (90, 90, 98))

img.save(out, "PNG", optimize=True)
print(f"OK: {out}")