fix(icons): stop macOS drawing the app icon on a legacy plate (#40)
On macOS 26+ the Dock and any launcher that resolves app icons through
NSWorkspace.icon(forFile:) (Spotlight, Vicinae, Raycast, ...) drew a grey
rounded-square "legacy plate" behind Gridline's icon, i.e. a white border
around the app icon at every render size below ~72px.
Reproduced outside any launcher: NSWorkspace.icon(forFile:) on
Gridline.app returns the plated icon at 16-64px and the clean icon at
>=72px. The trigger lives in icon.icns, not in the app -- moving that file
into Zed.app reproduces the border, moving Zed's icns into Gridline.app
removes it.
Two things in the file cause it:
- ic12 (64x64) -> plates the 40-64px range
- is32/s8mk (16x16 RGB+mask)
il32/l8mk (32x32 RGB+mask) -> plates the 16-32px range
macOS treats padded small representations as legacy, and this icns carries
them in both places.
Fix, in two parts.
1. Strip those chunks. scripts/fix-icns.mjs does it; `tauri icon` re-emits
them on every run, so it has to be a committed, repeatable step.
scripts/verify-app-icon.mjs is the regression check: it builds a
throwaway .app around the committed icon.icns, asks AppKit to render it
at 16..512px and fails if any size comes back plated. It fails (6/11
plated) on the previous icns and passes on this one.
2. Regenerate the raster set from icon.svg via
scripts/regenerate-icons.sh, so the icons directory matches its source
of truth again. The SVG has been full-bleed since the initial commit
(md5 unchanged at d872e42/3dab09f/6854d88/HEAD) while the rasters were
replaced with a hand-tuned padded version at v0.2.0 and had drifted
from it ever since. The script generates into a temp dir because
`tauri icon` only takes one output directory and would otherwise drop
generated android/ and ios/ trees into the desktop-only icons dir.
No visual change on macOS: IconServices normalizes app-icon artwork when
rendering, so padded and full-bleed sets come out pixel-identical there
(same bbox and art fraction at 48/128/512px).
Windows and Linux do consume the PNG/ICO directly, so the icon there does
change from padded to full-bleed -- consistent with the SVG, but a
visible difference worth eyeballing before release.
Verified: verify-app-icon passes at 16, 24, 32, 40, 48, 64, 72, 96, 128,
256, 512px; iconutil and `file` still decode the new .icns and .ico
(6 sizes); frontend tests pass (131 files / 1134 tests).
This commit is contained in:
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Regenerate desktop/src-tauri/icons/* from icons/icon.svg.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/regenerate-icons.sh
|
||||
#
|
||||
# `icon.svg` is the source of truth for the app icon; the PNG/ICNS/ICO set next
|
||||
# to it is generated output and must be regenerated whenever the SVG changes.
|
||||
#
|
||||
# Always regenerate through this script rather than calling `tauri icon`
|
||||
# directly, for two reasons:
|
||||
#
|
||||
# 1. `tauri icon` only supports a single output directory for all platforms, so
|
||||
# running it in place would also drop generated `android/` and `ios/` icon
|
||||
# trees into the (desktop-only) icons directory. This generates into a temp
|
||||
# dir and copies back just the desktop set.
|
||||
#
|
||||
# 2. `tauri icon` emits the legacy `is32`/`s8mk`/`il32`/`l8mk` and `ic12`
|
||||
# representations, which make macOS 26+ draw the app icon on a grey
|
||||
# "legacy plate" at small sizes (a white border in the Dock and in any
|
||||
# launcher that uses NSWorkspace). fix-icns.mjs strips them — see that file
|
||||
# for the details and the measurements.
|
||||
#
|
||||
# The committed icon set was last regenerated because those stale rasters meant
|
||||
# the shipped icon no longer matched icon.svg at all.
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
DESKTOP_DIR="$REPO_ROOT/desktop"
|
||||
ICONS_DIR="$DESKTOP_DIR/src-tauri/icons"
|
||||
SOURCE_SVG="$ICONS_DIR/icon.svg"
|
||||
|
||||
if ! command -v bun >/dev/null 2>&1; then
|
||||
echo "error: bun is required (https://bun.sh)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$SOURCE_SVG" ]; then
|
||||
echo "error: missing icon source $SOURCE_SVG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Files `tauri icon` produces for the desktop/Windows/macOS targets. The
|
||||
# android/ and ios/ output is intentionally ignored.
|
||||
DESKTOP_ICON_FILES=(
|
||||
32x32.png
|
||||
64x64.png
|
||||
128x128.png
|
||||
128x128@2x.png
|
||||
icon.png
|
||||
icon.icns
|
||||
icon.ico
|
||||
Square30x30Logo.png
|
||||
Square44x44Logo.png
|
||||
Square71x71Logo.png
|
||||
Square89x89Logo.png
|
||||
Square107x107Logo.png
|
||||
Square142x142Logo.png
|
||||
Square150x150Logo.png
|
||||
Square284x284Logo.png
|
||||
Square310x310Logo.png
|
||||
StoreLogo.png
|
||||
)
|
||||
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP_DIR"' EXIT
|
||||
|
||||
echo "==> rendering $SOURCE_SVG with tauri icon"
|
||||
( cd "$DESKTOP_DIR" && bunx tauri icon "src-tauri/icons/icon.svg" -o "$TMP_DIR" )
|
||||
|
||||
for file in "${DESKTOP_ICON_FILES[@]}"; do
|
||||
if [ ! -f "$TMP_DIR/$file" ]; then
|
||||
echo "error: tauri icon did not produce $file" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp "$TMP_DIR/$file" "$ICONS_DIR/$file"
|
||||
echo " updated icons/$file"
|
||||
done
|
||||
|
||||
echo "==> stripping legacy ICNS representations"
|
||||
bun "$REPO_ROOT/scripts/fix-icns.mjs" "$ICONS_DIR/icon.icns"
|
||||
|
||||
echo
|
||||
echo "icons regenerated. Verify with:"
|
||||
echo " bun $REPO_ROOT/scripts/verify-app-icon.mjs"
|
||||
Reference in New Issue
Block a user