diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
index 46c204a..97aee23 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
index cd4c37b..ef80a1c 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index b39b815..97aee23 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
index aaa1b38..28aa636 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
index f689664..306758f 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index b90451d..28aa636 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index 84a426e..533fa7f 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
index be8e877..a036128 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 470fa70..533fa7f 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 92caf1c..f6d6c2d 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
index 3e9dca7..b9efa04 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index ef7f40e..f6d6c2d 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index 3db912b..15cecba 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 6ff7500..2753075 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 9caa7bc..15cecba 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/img/goblin-icon-512.png b/img/goblin-icon-512.png
deleted file mode 100644
index 6c79261..0000000
Binary files a/img/goblin-icon-512.png and /dev/null differ
diff --git a/img/goblin-icon.png b/img/goblin-icon.png
index 52a2c6e..f5b1440 100644
Binary files a/img/goblin-icon.png and b/img/goblin-icon.png differ
diff --git a/img/goblin-mark-black.svg b/img/goblin-mark-black.svg
new file mode 100644
index 0000000..c014090
--- /dev/null
+++ b/img/goblin-mark-black.svg
@@ -0,0 +1,48 @@
+
+
+
diff --git a/img/goblin-mark-white.svg b/img/goblin-mark-white.svg
new file mode 100644
index 0000000..0fd9751
--- /dev/null
+++ b/img/goblin-mark-white.svg
@@ -0,0 +1,48 @@
+
+
+
diff --git a/img/goblin-mask-128.png b/img/goblin-mask-128.png
deleted file mode 100644
index b1b3bbd..0000000
Binary files a/img/goblin-mask-128.png and /dev/null differ
diff --git a/img/goblin-mask-64.png b/img/goblin-mask-64.png
deleted file mode 100644
index 9328d71..0000000
Binary files a/img/goblin-mask-64.png and /dev/null differ
diff --git a/img/goblin-mask-white.png b/img/goblin-mask-white.png
deleted file mode 100644
index a883a9d..0000000
Binary files a/img/goblin-mask-white.png and /dev/null differ
diff --git a/img/goblin-mask.png b/img/goblin-mask.png
deleted file mode 100644
index 890e1f3..0000000
Binary files a/img/goblin-mask.png and /dev/null differ
diff --git a/img/icon.png b/img/icon.png
index f5b1440..f8b32cf 100644
Binary files a/img/icon.png and b/img/icon.png differ
diff --git a/linux/Goblin.AppDir/goblin.png b/linux/Goblin.AppDir/goblin.png
index f5b1440..f8b32cf 100644
Binary files a/linux/Goblin.AppDir/goblin.png and b/linux/Goblin.AppDir/goblin.png differ
diff --git a/macos/Goblin.app/Contents/Resources/AppIcon.icns b/macos/Goblin.app/Contents/Resources/AppIcon.icns
index 108fb20..4677c67 100644
Binary files a/macos/Goblin.app/Contents/Resources/AppIcon.icns and b/macos/Goblin.app/Contents/Resources/AppIcon.icns differ
diff --git a/scripts/gen_icons.sh b/scripts/gen_icons.sh
index 528c596..8ddbe07 100755
--- a/scripts/gen_icons.sh
+++ b/scripts/gen_icons.sh
@@ -1,32 +1,45 @@
#!/usr/bin/env bash
-# Generate all Goblin app icons from img/goblin-icon.png (app icon)
-# and img/goblin-mask.png (black mascot art on transparency).
-# Requires ImageMagick (magick).
+# Regenerate EVERY platform's app icon from two canonical sources:
+# img/goblin-icon.png the gradient app icon (yellow gradient + black mascot)
+# img/goblin-mark-black.svg the black mascot mark, vector, transparent bg
+# (mirror of site/assets/goblin-mark-black.svg)
+#
+# Square icons (desktop window, Linux AppImage, Android launcher, Windows .ico,
+# macOS .icns) come from the gradient PNG. The Android *adaptive* foreground is
+# the black mascot on transparency, composited by the OS over the yellow
+# background color (res/values/ic_launcher_background.xml = #FFD60A) — which
+# reproduces the gradient icon's look.
+#
+# Requires ImageMagick (magick) and python3 (for the .icns container).
set -euo pipefail
cd "$(dirname "$0")/.."
ICON=img/goblin-icon.png
-MASK=img/goblin-mask.png
+MARK=img/goblin-mark-black.svg
RES=android/app/src/main/res
-# Desktop window icon + in-app embeds.
-magick "$ICON" -resize 256x256 img/icon.png
-magick "$ICON" -resize 512x512 img/goblin-icon-512.png
-magick "$MASK" -channel RGB -fill white -colorize 100 img/goblin-mask-white.png
-magick img/goblin-mask-white.png -resize 128x128 img/goblin-mask-128.png
-magick img/goblin-mask-white.png -resize 64x64 img/goblin-mask-64.png
+# --- Desktop window icon (egui, src/main.rs) + Linux AppImage AppDir icon ---
+magick "$ICON" -resize 256x256 PNG32:img/icon.png
+cp img/icon.png linux/Goblin.AppDir/goblin.png
-# Android launcher icons.
-declare -A SIZES=( [mdpi]=48 [hdpi]=72 [xhdpi]=96 [xxhdpi]=144 [xxxhdpi]=192 )
+# --- Android launcher icons (gradient square) + adaptive foreground (mascot) ---
+declare -A SIZES=( [mdpi]=48 [hdpi]=72 [xhdpi]=96 [xxhdpi]=144 [xxxhdpi]=192 )
declare -A FG_SIZES=( [mdpi]=108 [hdpi]=162 [xhdpi]=216 [xxhdpi]=324 [xxxhdpi]=432 )
for d in mdpi hdpi xhdpi xxhdpi xxxhdpi; do
s=${SIZES[$d]}; fg=${FG_SIZES[$d]}
- # mascot occupies ~52% of the adaptive canvas (safe zone is 66%)
- art=$(( fg * 52 / 100 ))
- magick "$ICON" -resize ${s}x${s} "$RES/mipmap-$d/ic_launcher.png"
- magick "$ICON" -resize ${s}x${s} "$RES/mipmap-$d/ic_launcher_round.png"
- magick "$MASK" -resize ${art}x${art} -background none \
- -gravity center -extent ${fg}x${fg} "$RES/mipmap-$d/ic_launcher_foreground.png"
+ # Mascot fills ~60% of the adaptive canvas — inside the ~61% safe zone, so no
+ # launcher mask (circle/squircle) ever clips it.
+ art=$(( fg * 60 / 100 ))
+ magick "$ICON" -resize "${s}x${s}" PNG32:"$RES/mipmap-$d/ic_launcher.png"
+ magick "$ICON" -resize "${s}x${s}" PNG32:"$RES/mipmap-$d/ic_launcher_round.png"
+ magick -background none "$MARK" -resize "${art}x${art}" \
+ -gravity center -extent "${fg}x${fg}" PNG32:"$RES/mipmap-$d/ic_launcher_foreground.png"
done
-echo "icons generated"
+# --- Windows installer + file-type icon (WiX wix/Product.ico) ---
+magick "$ICON" -define icon:auto-resize=256,128,64,48,32,24,16 wix/Product.ico
+
+# --- macOS app bundle icon (Goblin.app) ---
+python3 scripts/make-icns.py "$ICON" macos/Goblin.app/Contents/Resources/AppIcon.icns
+
+echo "icons generated from $ICON + $MARK"
diff --git a/scripts/make-icns.py b/scripts/make-icns.py
new file mode 100755
index 0000000..205b05a
--- /dev/null
+++ b/scripts/make-icns.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+"""Build a macOS .icns from a square PNG, dependency-free.
+
+macOS has `iconutil` and Linux distros have `png2icns`, but neither is reliably
+present, and ImageMagick's own .icns writer only emits a single size. So we
+assemble the multi-resolution PNG-payload .icns container by hand (the format
+macOS 10.7+ accepts): the `icns` magic + big-endian length, then one entry per
+OSType, each carrying an 8-bit PNG. ImageMagick (`magick`) does the resizing.
+
+Usage: make-icns.py
+"""
+
+import struct
+import subprocess
+import sys
+
+# OSType -> pixel size. PNG-payload entries. Sizes above the source are
+# Lanczos-upscaled (soft but acceptable for the few large Dock/Finder slots).
+SLOTS = [
+ (b"icp4", 16),
+ (b"icp5", 32),
+ (b"icp6", 64),
+ (b"ic07", 128),
+ (b"ic08", 256),
+ (b"ic11", 32), # 16@2x
+ (b"ic12", 64), # 32@2x
+ (b"ic13", 256), # 128@2x
+ (b"ic09", 512), # 512
+ (b"ic14", 512), # 256@2x
+]
+
+
+def render(src, size):
+ out = "/tmp/_icns_%d.png" % size
+ subprocess.run(
+ ["magick", src, "-resize", "%dx%d" % (size, size),
+ "-filter", "Lanczos", "-depth", "8", "PNG32:%s" % out],
+ check=True,
+ )
+ return open(out, "rb").read()
+
+
+def main():
+ if len(sys.argv) != 3:
+ sys.exit("usage: make-icns.py ")
+ src, out = sys.argv[1], sys.argv[2]
+ cache, entries = {}, []
+ for ostype, size in SLOTS:
+ if size not in cache:
+ cache[size] = render(src, size)
+ data = cache[size]
+ entries.append(ostype + struct.pack(">I", 8 + len(data)) + data)
+ body = b"".join(entries)
+ with open(out, "wb") as f:
+ f.write(b"icns" + struct.pack(">I", 8 + len(body)) + body)
+ print("wrote %s (%d entries)" % (out, len(entries)))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/wix/Product.ico b/wix/Product.ico
index b470dc4..437a2ee 100644
Binary files a/wix/Product.ico and b/wix/Product.ico differ