diff --git a/README.md b/README.md index 6568afd..408273d 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,22 @@ Harbor palette to Ash. ## Variants +### Ash Dark + +![Ash Dark palette](images/ash-dark-palette.png) + +### Ash Light + +![Ash Light palette](images/ash-light-palette.png) + | Theme dir | Style | Base surfaces | Accent | |------------|-------|----------------------------------|--------| | `ash-dark` | dark | void `#100f12`, panel `#1c1b1f`, raised `#29282c`, bone `#e6dfd1` | ember `#e0914f` | -| `ash-light`| light | paper `#e9e3d5`, raised `#f2ecdf`, deep `#dcd5c3`, ink `#2a2822` | ember `#a85f1d` | +| `ash-light`| light | paper `#e9e3d5` / ink `#2a2822` ยท raised `#f2ecdf`, deep `#dcd5c3` | ember `#a85f1d` | Accents: ember, gold, blood, rot, moss, steel, violet, rust (see `tools/recolor.py` for the exact terminal 16-colour mapping). +Regenerate the swatch images above with `python3 tools/make_palette_images.py .`. ## Install (local) diff --git a/images/ash-dark-palette.png b/images/ash-dark-palette.png new file mode 100644 index 0000000..ee760db Binary files /dev/null and b/images/ash-dark-palette.png differ diff --git a/images/ash-light-palette.png b/images/ash-light-palette.png new file mode 100644 index 0000000..911cc0e Binary files /dev/null and b/images/ash-light-palette.png differ diff --git a/tools/make_palette_images.py b/tools/make_palette_images.py new file mode 100644 index 0000000..52f1d60 --- /dev/null +++ b/tools/make_palette_images.py @@ -0,0 +1,78 @@ +#!/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()