76 lines
3.4 KiB
Python
76 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()
|