M5 ship infrastructure: icon, version, release script, README

- scripts/make-icon.py: generates a 1024x1024 source.png — dark
  rounded square + 2x2 tile grid with one active-blue tile and one
  broadcast-orange tile (matches the in-app accent colors).
  Regenerated all desktop icon sizes via 'pnpm tauri icon';
  pruned iOS/Android/UWP outputs.
- Version bump 0.0.1 -> 0.1.0 across package.json, Cargo.toml,
  tauri.conf.json. First real release.
- scripts/release.sh: takes vX.Y.Z, sanity-checks (clean tree,
  on main, in sync, tag matches package.json, installer exists,
  tag not already present), tags + pushes, uploads NSIS .exe to
  Forgejo via tea releases create --asset.
- README rewritten: Install section pointing at Forgejo releases,
  Using-it cheatsheet for all M2-M4 features (splits, broadcast,
  palette, etc.), Develop/Test/Release triplet for the WSL<->Windows
  workflow, icon regen instructions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-05-22 13:38:29 +01:00
parent b1412287be
commit dd1cf282e6
14 changed files with 270 additions and 59 deletions

79
scripts/make-icon.py Normal file
View file

@ -0,0 +1,79 @@
"""
Regenerate src-tauri/icons/source.png dark rounded square + 2×2 tile grid
with one tile in the active-blue and one in the broadcast-orange. Matches
the running app's visual identity (the colors used for .leaf.active and
.leaf.broadcasting borders).
Run from the project root:
python3 scripts/make-icon.py
pnpm tauri icon src-tauri/icons/source.png # generates ico/icns/etc
"""
import sys
from pathlib import Path
try:
from PIL import Image, ImageDraw
except ImportError:
sys.stderr.write("Pillow not installed: pip install --user Pillow\n")
sys.exit(2)
SIZE = 1024
# Background: app's dark theme, slightly tinted blue
BG = (12, 14, 20, 255)
BG_RADIUS = 180
BG_PAD = 40
# Inner 2x2 grid
TILE_PAD = 170 # distance from outer edge to first tile
TILE_GAP = 36 # gap between tiles
TILE_RADIUS = 44 # rounded corner of each tile
# Tile colors — match tiletopia's UI accents
TILE_MUTED = (44, 48, 58, 255) # quiet tile (dark gray-blue)
TILE_ACTIVE = (90, 140, 216, 255) # .leaf.active blue
TILE_BCAST = (224, 152, 56, 255) # .leaf.broadcasting orange
def main(out: Path) -> None:
img = Image.new("RGBA", (SIZE, SIZE), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
# Outer rounded square (the app body)
draw.rounded_rectangle(
[BG_PAD, BG_PAD, SIZE - BG_PAD, SIZE - BG_PAD],
radius=BG_RADIUS,
fill=BG,
)
# 2x2 tile grid inside
inner_left = TILE_PAD
inner_top = TILE_PAD
inner_right = SIZE - TILE_PAD
inner_bottom = SIZE - TILE_PAD
tile_size = ((inner_right - inner_left) - TILE_GAP) // 2
positions = [
(inner_left, inner_top, TILE_ACTIVE), # TL: active
(inner_left + tile_size + TILE_GAP, inner_top, TILE_MUTED), # TR
(inner_left, inner_top + tile_size + TILE_GAP, TILE_MUTED), # BL
(inner_left + tile_size + TILE_GAP, # BR: broadcasting
inner_top + tile_size + TILE_GAP, TILE_BCAST),
]
for (x, y, color) in positions:
draw.rounded_rectangle(
[x, y, x + tile_size, y + tile_size],
radius=TILE_RADIUS,
fill=color,
)
out.parent.mkdir(parents=True, exist_ok=True)
img.save(out, "PNG")
print(f"wrote {out} {SIZE}x{SIZE}")
if __name__ == "__main__":
here = Path(__file__).resolve().parent.parent
main(here / "src-tauri" / "icons" / "source.png")

85
scripts/release.sh Normal file
View file

@ -0,0 +1,85 @@
#!/usr/bin/env bash
#
# Tag a release, find the most recent NSIS installer, and upload it to Forgejo.
#
# Prereqs:
# 1. You've bumped the version in package.json, src-tauri/Cargo.toml and
# src-tauri/tauri.conf.json and committed + pushed to origin/main.
# 2. You've run `pnpm tauri build` on the Windows host so the installer
# exists at src-tauri/target/release/bundle/nsis/*.exe.
# 3. `tea login list` shows the `rdx4` login is active.
#
# Usage:
# scripts/release.sh v0.1.0
#
set -euo pipefail
TAG="${1:-}"
if [[ -z "$TAG" ]]; then
echo "usage: $0 <vX.Y.Z>" >&2
exit 1
fi
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "tag must look like v0.1.0 (got: $TAG)" >&2
exit 1
fi
cd "$(dirname "$0")/.."
# Sanity checks
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "working tree dirty — commit or stash first" >&2
exit 1
fi
branch="$(git rev-parse --abbrev-ref HEAD)"
if [[ "$branch" != "main" ]]; then
echo "not on main (you're on '$branch') — bail" >&2
exit 1
fi
git fetch origin --quiet
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then
echo "HEAD is out of sync with origin/main — push or pull first" >&2
exit 1
fi
# Verify the tag's version matches package.json (catches "I forgot to bump")
pkg_version="$(node -p "require('./package.json').version" 2>/dev/null || true)"
expected_tag="v${pkg_version}"
if [[ "$TAG" != "$expected_tag" ]]; then
echo "package.json says version $pkg_version → expected tag $expected_tag, got $TAG" >&2
echo "bump package.json + src-tauri/Cargo.toml + src-tauri/tauri.conf.json first" >&2
exit 1
fi
# Find the installer
nsis_dir="src-tauri/target/release/bundle/nsis"
if [[ ! -d "$nsis_dir" ]]; then
echo "$nsis_dir not found — did you run 'pnpm tauri build' on Windows yet?" >&2
exit 1
fi
installer="$(ls -1t "$nsis_dir"/*-setup.exe 2>/dev/null | head -n1 || true)"
if [[ -z "$installer" || ! -f "$installer" ]]; then
echo "no *-setup.exe found in $nsis_dir" >&2
exit 1
fi
echo "Installer: $installer"
echo "Size: $(du -h "$installer" | cut -f1)"
# Tag and push
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "tag $TAG already exists locally — bail (delete it first if intentional)" >&2
exit 1
fi
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"
# Create the release with the installer attached
tea releases create \
--login rdx4 \
--tag "$TAG" \
--title "$TAG" \
--note "tiletopia $TAG. Download the .exe below, run it, accept SmartScreen (\"More info → Run anyway\") — installer isn't code-signed." \
--asset "$installer"
echo
echo "✓ released $TAG → https://git.rdx4.com/megaproxy/tiletopia/releases/tag/$TAG"