#!/usr/bin/env python3 """Render the Ash palette swatch images used in the README (blog-style strips). Usage: python3 tools/make_palette_images.py Requires: ImageMagick (convert). """ import subprocess import sys from pathlib import Path SW = 120 # swatch width SH = 80 # swatch height GAP = 14 # horizontal gap COLS = 8 PAD = 24 # outer padding LABEL_H = 40 # two text lines under a swatch ROW_H = SH + LABEL_H VARIANTS = { "light": { "bg": "#e9e3d5", "fg": "#2a2822", "stroke": "#c9c1ad", "rows": [ [("paper", "#e9e3d5"), ("raised", "#f2ecdf"), ("deep", "#dcd5c3"), ("border", "#c9c1ad"), ("muted", "#6f685c"), ("icon", "#5b5449"), ("ink", "#2a2822"), ("ink dark", "#141310")], [("ember", "#a85f1d"), ("gold", "#8a6a24"), ("blood", "#96392a"), ("rot", "#7c4a66"), ("moss", "#5c6631"), ("steel", "#3d6b72"), ("violet", "#6a4c72"), ("rust", "#7d4a2c")], ], }, "dark": { "bg": "#100f12", "fg": "#e6dfd1", "stroke": "#3a383d", "rows": [ [("void", "#100f12"), ("panel", "#1c1b1f"), ("raised", "#29282c"), ("border", "#3a383d"), ("ash", "#6d6a63"), ("stone", "#999187"), ("bone", "#e6dfd1"), ("chalk", "#f3ede1")], [("ember", "#e0914f"), ("gold", "#d6b46a"), ("blood", "#c15c46"), ("rot", "#b47e99"), ("moss", "#8f9a5c"), ("steel", "#7c9aa1"), ("violet", "#a585ac"), ("rust", "#a86a48")], ], }, } def render(variant, cfg, out): width = PAD * 2 + COLS * SW + (COLS - 1) * GAP height = PAD * 2 + len(cfg["rows"]) * ROW_H args = ["convert", "-size", f"{width}x{height}", f"xc:{cfg['bg']}", "-font", "DejaVu-Sans"] for r, row in enumerate(cfg["rows"]): for c, (name, color) in enumerate(row): x = PAD + c * (SW + GAP) y = PAD + r * ROW_H args += ["-fill", color, "-stroke", cfg["stroke"], "-strokewidth", "1", "-draw", f"rectangle {x},{y} {x + SW},{y + SH}"] cx = x + SW // 2 - width // 2 # gravity North anchors at top-center args += ["-stroke", "none", "-fill", cfg["fg"], "-pointsize", "14", "-gravity", "North", "-annotate", f"+{cx}+{y + SH + 6}", name] args += ["-pointsize", "13", "-fill", cfg["fg"], "-stroke", "none", "-gravity", "North", "-annotate", f"+{cx}+{y + SH + 24}", color] args.append(str(out)) subprocess.run(args, check=True) def main(): root = Path(sys.argv[1]).resolve() img_dir = root / "images" img_dir.mkdir(exist_ok=True) for variant, cfg in VARIANTS.items(): out = img_dir / f"ash-{variant}-palette.png" render(variant, cfg, out) print(f"wrote {out.relative_to(root)}") if __name__ == "__main__": main()