update readme and add icons

This commit is contained in:
2026-03-29 23:40:07 -07:00
parent 52da360804
commit 79b89da023
25 changed files with 865 additions and 198 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

BIN
resources/icon_1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

142
resources/make_icons.py Normal file
View File

@@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Generate icon files from an SVG source.
Workflow:
SVG → 1024×1024 PNG (master, saved as icon_1024.png)
→ scaled PNGs: 512, 256, 128, 64, 32, 16
→ resources/icon.icns (macOS, via iconutil)
→ resources/icon.ico (Windows, via Pillow)
Usage:
python resources/make_icons.py path/to/icon.svg
Requires:
pip install pillow
brew install librsvg # provides rsvg-convert (SVG → PNG)
macOS: iconutil # pre-installed
"""
import argparse
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path
try:
from PIL import Image
except ImportError:
sys.exit("Pillow is required: pip install pillow")
RESOURCES = Path(__file__).resolve().parent
# Sizes derived from the 1024 master. 16 is added for the .icns iconset.
SCALED_SIZES = [512, 256, 128, 64, 32, 16]
# macOS iconset: filename → source pixel size
ICONSET_MAP = {
"icon_16x16.png": 16,
"icon_16x16@2x.png": 32,
"icon_32x32.png": 32,
"icon_32x32@2x.png": 64,
"icon_128x128.png": 128,
"icon_128x128@2x.png": 256,
"icon_256x256.png": 256,
"icon_256x256@2x.png": 512,
"icon_512x512.png": 512,
"icon_512x512@2x.png": 1024,
}
# Sizes embedded in the .ico file (Windows; standard ICO max is 256)
ICO_SIZES = [256, 128, 64, 32, 16]
def find_rsvg_convert() -> str | None:
if path := shutil.which("rsvg-convert"):
return path
# Homebrew puts it here even when not on PATH
for prefix in ("/opt/homebrew", "/usr/local"):
candidate = Path(prefix) / "bin" / "rsvg-convert"
if candidate.exists():
return str(candidate)
return None
def svg_to_png(rsvg: str, svg_path: Path, out_path: Path, size: int) -> None:
subprocess.run(
[rsvg, "-w", str(size), "-h", str(size), str(svg_path), "-o", str(out_path)],
check=True,
)
def main() -> None:
parser = argparse.ArgumentParser(description="Generate .icns and .ico from an SVG.")
parser.add_argument("svg", type=Path, help="Source SVG file")
args = parser.parse_args()
svg_path = args.svg.resolve()
if not svg_path.exists():
sys.exit(f"SVG not found: {svg_path}")
rsvg = find_rsvg_convert()
if rsvg is None:
sys.exit(
"rsvg-convert not found.\n"
"Install it with: brew install librsvg"
)
RESOURCES.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as _tmp:
tmp = Path(_tmp)
# ── 1. Render SVG → 1024×1024 master PNG ──────────────────────
master = tmp / "icon_1024.png"
print("Rendering SVG → 1024×1024 PNG…")
svg_to_png(rsvg, svg_path, master, 1024)
shutil.copy(master, RESOURCES / "icon_1024.png")
print(" saved icon_1024.png")
# ── 2. Scale down to all needed sizes ─────────────────────────
print("Scaling…")
pngs: dict[int, Path] = {1024: master}
with Image.open(master) as base:
for size in SCALED_SIZES:
out = tmp / f"icon_{size}.png"
base.resize((size, size), Image.LANCZOS).save(out)
pngs[size] = out
print(f" {size:>4}×{size}")
# ── 3. Build .icns (macOS) ─────────────────────────────────────
icns_out = RESOURCES / "icon.icns"
if shutil.which("iconutil"):
iconset = tmp / "icon.iconset"
iconset.mkdir()
for filename, size in ICONSET_MAP.items():
shutil.copy(pngs[size], iconset / filename)
subprocess.run(
["iconutil", "-c", "icns", str(iconset), "-o", str(icns_out)],
check=True,
)
print(" saved icon.icns")
else:
print(" iconutil not found — skipping icon.icns (run on macOS to generate it)")
# ── 4. Build .ico (Windows) ────────────────────────────────────
ico_out = RESOURCES / "icon.ico"
images = [Image.open(pngs[s]).convert("RGBA") for s in ICO_SIZES]
images[0].save(
ico_out,
format="ICO",
sizes=[(s, s) for s in ICO_SIZES],
append_images=images[1:],
)
print(" saved icon.ico")
print("Done.")
if __name__ == "__main__":
main()

View File

@@ -8,7 +8,7 @@
version="1.1"
id="svg1"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
sodipodi:docname="tono.svg"
sodipodi:docname="argonode.svg"
inkscape:export-filename="tono.png"
inkscape:export-xdpi="130.05"
inkscape:export-ydpi="130.05"
@@ -28,7 +28,7 @@
inkscape:document-units="mm"
inkscape:clip-to-page="false"
inkscape:zoom="0.52383534"
inkscape:cx="272.03205"
inkscape:cx="272.98655"
inkscape:cy="333.11995"
inkscape:window-width="1470"
inkscape:window-height="890"
@@ -49,28 +49,28 @@
height="194.43169"
x="2.5203834"
y="2.9819231"
rx="60.325001"
ry="60.325001" />
rx="52.916668"
ry="52.916668" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.95095;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 78.923283,116.954 85.556777,-87.012977 4.46561,16.665896 -16.7032,-4.47561"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:8.251;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 80.438549,119.47945 85.556771,-87.012984 4.46561,16.665896 -16.7032,-4.47561"
id="path6"
sodipodi:nodetypes="cccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.95096;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 130.73507,63.406954 H 100.71909 L 47.805771,117.40532 77.48181,116.89278"
d="M 133.7656,68.457841 H 103.74962 L 50.836303,122.45621 80.512342,121.94367"
id="path7"
sodipodi:nodetypes="cccc" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:68.9567px;line-height:0;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.75827;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
x="22.05061"
y="162.24162"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;line-height:0;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;writing-mode:lr-tb;direction:ltr;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.75827;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
x="18.009901"
y="172.8485"
id="text8"><tspan
sodipodi:role="line"
id="tspan8"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:68.9567px;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2.75827;stroke-dasharray:none"
x="22.05061"
y="162.24162">argo</tspan></text>
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:80px;font-family:Futura;-inkscape-font-specification:'Futura, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:2.75827;stroke-dasharray:none"
x="18.009901"
y="172.8485">tono</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB