Skip to content

Commit 6f326fd

Browse files
Axuclaude
authored andcommitted
[C] feat(icon): bundle AppIcon.icns + scripts/make-icon.sh generator
Source: 2048×2048 PNG (devislandlogo) — dark capsule + pixel `D_` display matching the app's notch-bar visual language. scripts/make-icon.sh takes any square PNG and produces all 10 sizes Apple's iconutil expects (16/32/128/256/512 × 1x+2x), then compiles to .icns and drops it at IslandApp/Resources/AppIcon.icns where build-app.sh's existing resource-copy step picks it up automatically. Why commit the .icns rather than regenerate in CI: - Source PNG (2.5MB) bigger than the compiled .icns (955KB) - CI doesn't have to keep ImageMagick / sips invariants in sync - Updating the icon is a one-time event per release, not per-build If we ever need to regenerate (new design pass), drop the new PNG anywhere on disk, run scripts/make-icon.sh <path>, commit the resulting .icns. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 04212bf commit 6f326fd

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

IslandApp/Resources/AppIcon.icns

955 KB
Binary file not shown.

scripts/make-icon.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/usr/bin/env bash
2+
# Convert a square PNG into AppIcon.icns and drop it where build-app.sh
3+
# will pick it up.
4+
#
5+
# Usage:
6+
# scripts/make-icon.sh <path-to-source.png>
7+
#
8+
# Source PNG must be square and at least 512×512 (1024×1024 ideal —
9+
# any smaller and the 512@2x slice gets upscaled and the icon looks
10+
# fuzzy on Retina displays). We don't enforce a hard minimum because
11+
# `sips` will silently upscale if asked, but the script prints a
12+
# warning when source < 1024.
13+
#
14+
# Output: IslandApp/Resources/AppIcon.icns
15+
#
16+
# How `iconutil` works:
17+
#
18+
# It expects a folder named `*.iconset/` containing exactly these 10
19+
# files (Apple's required set per
20+
# https://developer.apple.com/design/human-interface-guidelines/app-icons):
21+
#
22+
# icon_16x16.png icon_16x16@2x.png
23+
# icon_32x32.png icon_32x32@2x.png
24+
# icon_128x128.png icon_128x128@2x.png
25+
# icon_256x256.png icon_256x256@2x.png
26+
# icon_512x512.png icon_512x512@2x.png
27+
#
28+
# `@2x` files are physically twice the listed dimension (so 16x16@2x is
29+
# really 32×32, etc.) — macOS picks the right one based on display
30+
# density at runtime.
31+
#
32+
# We use `sips` (macOS-native) for resizing rather than ImageMagick to
33+
# avoid a brew dependency for icon generation.
34+
35+
set -euo pipefail
36+
37+
if [[ $# -ne 1 ]]; then
38+
echo "Usage: $0 <path-to-source.png>" >&2
39+
exit 64
40+
fi
41+
42+
SRC="$1"
43+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
44+
RES_DIR="${ROOT}/IslandApp/Resources"
45+
OUT_ICNS="${RES_DIR}/AppIcon.icns"
46+
47+
if [[ ! -f "${SRC}" ]]; then
48+
echo "Error: source PNG not found at ${SRC}" >&2
49+
exit 1
50+
fi
51+
52+
# Sanity-check dimensions. sips emits " pixelWidth: NNNN" etc.
53+
WIDTH="$(sips -g pixelWidth "${SRC}" | awk '/pixelWidth:/ {print $2}')"
54+
HEIGHT="$(sips -g pixelHeight "${SRC}" | awk '/pixelHeight:/ {print $2}')"
55+
56+
if [[ "${WIDTH}" != "${HEIGHT}" ]]; then
57+
echo "Warning: source is ${WIDTH}×${HEIGHT}, not square. macOS will" >&2
58+
echo " non-uniformly scale; consider cropping to square first." >&2
59+
fi
60+
if [[ "${WIDTH}" -lt 1024 ]]; then
61+
echo "Warning: source is ${WIDTH}px wide; ideal is 1024+. The" >&2
62+
echo " 512@2x slice (1024×1024) will be upscaled and look" >&2
63+
echo " soft on Retina displays." >&2
64+
fi
65+
66+
# Build the .iconset/ tree in a tmp dir so a failure mid-way doesn't
67+
# leave half-baked output in the repo.
68+
TMP_ICONSET="$(mktemp -d)/AppIcon.iconset"
69+
mkdir -p "${TMP_ICONSET}"
70+
71+
# Pairs of (filename, target-pixel-size). @2x sizes are listed at their
72+
# real pixel dimensions, not the @1x label.
73+
SIZES=(
74+
"icon_16x16.png:16"
75+
"icon_16x16@2x.png:32"
76+
"icon_32x32.png:32"
77+
"icon_32x32@2x.png:64"
78+
"icon_128x128.png:128"
79+
"icon_128x128@2x.png:256"
80+
"icon_256x256.png:256"
81+
"icon_256x256@2x.png:512"
82+
"icon_512x512.png:512"
83+
"icon_512x512@2x.png:1024"
84+
)
85+
86+
echo "==> Generating 10 icon sizes from ${SRC}"
87+
for entry in "${SIZES[@]}"; do
88+
NAME="${entry%%:*}"
89+
PX="${entry##*:}"
90+
sips -z "${PX}" "${PX}" "${SRC}" --out "${TMP_ICONSET}/${NAME}" >/dev/null
91+
done
92+
93+
echo "==> Compiling AppIcon.icns"
94+
mkdir -p "${RES_DIR}"
95+
iconutil -c icns "${TMP_ICONSET}" -o "${OUT_ICNS}"
96+
rm -rf "$(dirname "${TMP_ICONSET}")"
97+
98+
echo "==> Wrote: ${OUT_ICNS}"
99+
ls -lh "${OUT_ICNS}"

0 commit comments

Comments
 (0)