75 lines
3.4 KiB
Python
75 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
||
"""Render the real Ratatui layout with fictional sessions. Never reads user history.
|
||
|
||
uv run --with 'pillow==11.3.0' python scripts/render_demo.py
|
||
|
||
Use --font /path/to/monospace.ttf to override the locally available font.
|
||
The font is rasterized into the PNG, not bundled or redistributed.
|
||
"""
|
||
import argparse
|
||
import json
|
||
from pathlib import Path
|
||
import subprocess
|
||
|
||
from PIL import Image, ImageDraw, ImageFont
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
PALETTE = {
|
||
"Black": "#11151e", "White": "#eef2fa", "DarkGray": "#7c879d",
|
||
"Gray": "#b8c1d4", "Cyan": "#65d9df", "Magenta": "#b89cff",
|
||
"Yellow": "#edbd80", "Green": "#9bd39f", "Blue": "#8fb9ff",
|
||
"LightMagenta": "#e2a1dc",
|
||
}
|
||
BG = "#11151e"
|
||
FG = "#dbe2ef"
|
||
|
||
|
||
def main():
|
||
parser = argparse.ArgumentParser(description=__doc__)
|
||
parser.add_argument("--font", type=Path)
|
||
args = parser.parse_args()
|
||
candidates = [args.font, Path("/System/Library/Fonts/Menlo.ttc"),
|
||
Path("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf")]
|
||
font_path = next((p for p in candidates if p and p.is_file()), None)
|
||
if not font_path:
|
||
parser.error("Provide a monospace font using --font")
|
||
font = ImageFont.truetype(str(font_path), 28)
|
||
small = ImageFont.truetype(str(font_path), 23)
|
||
subprocess.run(["cargo", "test", "--locked", "--release", "ui::demo::render_demo",
|
||
"--", "--ignored", "--exact"], cwd=ROOT, check=True)
|
||
data = json.loads((ROOT / "target/demo-screen.json").read_text())
|
||
columns, rows = data["width"], data["height"]
|
||
cell_w, cell_h = round(font.getlength("M")), 42
|
||
margin, padding, chrome = 48, 32, 78
|
||
window_w = columns * cell_w + padding * 2
|
||
window_h = rows * cell_h + padding * 2 + chrome
|
||
image = Image.new("RGB", (window_w + margin * 2, window_h + margin * 2), "#090c13")
|
||
draw = ImageDraw.Draw(image)
|
||
box = (margin, margin, margin + window_w, margin + window_h)
|
||
draw.rounded_rectangle(box, radius=22, fill=BG, outline="#2b3344", width=2)
|
||
for i, color in enumerate(["#ef7474", "#e6be68", "#83c995"]):
|
||
x, y = margin + 32 + i * 31, margin + 35
|
||
draw.ellipse((x, y - 9, x + 18, y + 9), fill=color)
|
||
title = "cont — one picker, five agents"
|
||
draw.text((image.width / 2, margin + 35), title, font=small, fill="#929db3", anchor="mm")
|
||
draw.line((margin + 1, margin + chrome, margin + window_w - 1, margin + chrome), fill="#252c3c", width=2)
|
||
left, top = margin + padding, margin + chrome + padding
|
||
for i, cell in enumerate(data["cells"]):
|
||
x, y = left + (i % columns) * cell_w, top + (i // columns) * cell_h
|
||
# ANSI colors are terminal-theme dependent. Use a readable dark palette;
|
||
# selection background is a darker rendition of the terminal's gray.
|
||
bg = "#303b50" if cell["bg"] == "DarkGray" else PALETTE.get(cell["bg"], BG)
|
||
fg = PALETTE.get(cell["fg"], FG)
|
||
if bg != BG:
|
||
draw.rectangle((x, y, x + cell_w - 1, y + cell_h - 1), fill=bg)
|
||
if cell["text"].strip():
|
||
draw.text((x, y + cell_h / 2), cell["text"], font=font, fill=fg, anchor="lm",
|
||
stroke_width=1 if cell["bold"] else 0)
|
||
destination = ROOT / "docs/assets/resume.png"
|
||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||
image.save(destination, optimize=True)
|
||
print(f"Wrote {destination.relative_to(ROOT)} ({image.width}×{image.height}); all session data is fictional.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|