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