app-icon-rasterize — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited app-icon-rasterize (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Use when a designer hands off the icon as SVG and you need the PNG that AppIcon.appiconset/Contents.json references.
This is the gap discovered during first-pass icon production on a real project — the SVG → 1024 PNG step was undocumented (only the downstream Pillow Lanczos downscale to the macOS ladder was written up). Each appearance — Light, Dark, Tinted — is a single 1024 universal PNG produced by exactly one rasterize step, documented here. (Tinted is now a standard third appearance alongside Light and Dark; all apps in the reference project ship AppIcon-Tinted.png.)
light.svg + dark.svg + tinted.svg matching the icon specAppIcon-Light.png + AppIcon-Dark.png in <app>/Assets.xcassets/AppIcon.appiconset/rsvg-convert / inkscape / imagemagick and no Homebrew — qlmanage (QuickLook) ships with macOS and is the rasteriser of record here (this skill exists precisely for the no-Homebrew case)<filter> blurs, <text>, embedded fonts, or other features QuickLook's SVG generator may render unreliably. Re-author the SVG with flat shapes first.As of Xcode 26 / macOS Sequoia, macOS app icons still require the explicit 16/32/128/256/512 ladder — "Single Size" is iOS-only. (Re-verify against your current Xcode; Apple could add single-size macOS support in a later release.) The Appearances Inspector for macOS targets does not expose a single-asset option. Without the ladder, Xcode emits "AppIcon has N unassigned children" on the macOS target because the universal idiom does not satisfy AppKit's expected slots.
After producing the 1024 master:
SRC=<App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Light.png
DST=<App>/Assets.xcassets/AppIcon-macOS.appiconset
mkdir -p "$DST"
cp "$SRC" "$DST/[email protected]" # 1024
sips -Z 512 "$SRC" --out "$DST/[email protected]" # 512
sips -Z 512 "$SRC" --out "$DST/icon_512x512.png" # 512
sips -Z 256 "$SRC" --out "$DST/[email protected]" # 256
sips -Z 256 "$SRC" --out "$DST/icon_256x256.png" # 256
sips -Z 128 "$SRC" --out "$DST/icon_128x128.png" # 128
sips -Z 64 "$SRC" --out "$DST/[email protected]" # 64
sips -Z 32 "$SRC" --out "$DST/icon_32x32.png" # 32
sips -Z 32 "$SRC" --out "$DST/[email protected]" # 32
sips -Z 16 "$SRC" --out "$DST/icon_16x16.png" # 16sips -Z <max> resizes the longest dimension to <max> (Lanczos-equivalent quality). Each downscale is from the 1024 master, not the previous step.
Project.swift needs the SDK-scoped override so iOS targets keep the universal AppIcon and macOS targets pick up the ladder:
let appTargetSettings: SettingsDictionary = swiftSettings.merging([
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIcon",
"ASSETCATALOG_COMPILER_APPICON_NAME[sdk=macosx*]": "AppIcon-macOS",
]) { _, new in new }The designer's SVG must NOT bake rounded corners into the artwork. Apple's compositor applies the squircle mask at render time (iOS Springboard, macOS Dock, every preview surface). Baking corners produces a double-mask look — the icon shows up smaller than its peers with visible inner padding.
Common mistakes that cause this:
<!-- WRONG — corners baked into the artwork via clipPath -->
<defs>
<clipPath id="iconMask">
<rect width="1024" height="1024" rx="246" ry="246"/>
</clipPath>
</defs>
<g clip-path="url(#iconMask)">
<rect width="1024" height="1024" fill="#FAF8F3"/>
...
</g>
<!-- ALSO WRONG — rx/ry directly on the background rect -->
<rect width="1024" height="1024" rx="246" ry="246" fill="#FAF8F3"/><!-- RIGHT — background fills 1024×1024 to the edges, no clip, no rx/ry -->
<rect x="0" y="0" width="1024" height="1024" fill="#FAF8F3"/>
<!-- artwork on top, also no clip -->After rasterize, sips -g hasAlpha …png will still report yes because QuickLook writes 8-bit RGBA — but every pixel including the corners must be opaque. Quick check: open the PNG in Preview at 100%, hover the corners — Digital Color Meter should report the background color (e.g. #FAF8F3), not transparency.
This rule applies to Light, Dark, and Tinted variants. There is no platform on which the artwork should pre-apply its own squircle.
# 1. Designer writes SVG to ../tmp/ (project-scope scratch
# dir, NOT /tmp). Each SVG must declare
# width="1024" height="1024" viewBox="0 0 1024 1024".
ls -la ../tmp/<app>-icon-light.svg ../tmp/<app>-icon-dark.svg
# 2. Rasterize via QuickLook thumbnail generator.
# -t thumbnail mode
# -s 1024 thumbnail size (square)
# -o <dir> output directory (-o cannot rename the file, see step 3)
qlmanage -t -s 1024 -o ../tmp \
../tmp/<app>-icon-light.svg \
../tmp/<app>-icon-dark.svg \
../tmp/<app>-icon-tinted.svg
# 3. qlmanage's quirk: it APPENDS `.png` to the source filename instead of
# swapping the extension. So `light.svg` becomes `light.svg.png`. Rename
# directly into the asset catalog so the .svg.png artifact never lingers.
mv ../tmp/<app>-icon-light.svg.png \
<App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Light.png
mv ../tmp/<app>-icon-dark.svg.png \
<App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Dark.png
mv ../tmp/<app>-icon-tinted.svg.png \
<App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Tinted.png
# 4. Verify dimensions + format.
file <App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Light.png
# expected: PNG image data, 1024 x 1024, 8-bit/color RGBA, non-interlaced
sips -g pixelWidth -g pixelHeight <App>/Assets.xcassets/AppIcon.appiconset/AppIcon-Light.png
# expected: pixelWidth: 1024 / pixelHeight: 1024
# 5. Commit the SVG source-of-truth alongside, under docs/app-store/icons/.
mkdir -p docs/app-store/icons/<app>/
cp ../tmp/<app>-icon-light.svg docs/app-store/icons/<app>/light.svg
cp ../tmp/<app>-icon-dark.svg docs/app-store/icons/<app>/dark.svg
cp ../tmp/<app>-icon-tinted.svg docs/app-store/icons/<app>/tinted.svgOpen the produced PNGs in Preview.app and confirm:
#FAF8F3 background#15171A — replace with your project's dark background hex); pixel-meter the corners against it<filter> effects (rare with QuickLook, but inspect the highlight + spark ring areas)If any check fails, the fix lives in the SVG, not in a post-process pass — re-edit, re-rasterize.
AppIcon.appiconset/Contents.json must reference both PNGs as universal idiom (no "platform": "ios"), so Apple auto-adapts the 1024 master across iOS + macOS:
{
"images" : [
{
"filename" : "AppIcon-Light.png",
"idiom" : "universal",
"size" : "1024x1024"
},
{
"appearances" : [
{ "appearance" : "luminosity", "value" : "dark" }
],
"filename" : "AppIcon-Dark.png",
"idiom" : "universal",
"size" : "1024x1024"
}
],
"info" : { "author" : "xcode", "version" : 1 }
}Tinted entry present — AppIcon-Tinted.png, appearance: luminosity / value: tinted, universal idiom. For iOS only — the universal single PNG does NOT satisfy AppKit's macOS slots. macOS targets must use a separate AppIcon-macOS.appiconset with the explicit size ladder (see "macOS ladder reality check" above).
| Tool | Reason rejected |
|---|---|
rsvg-convert (librsvg) | Requires Homebrew, not installed on this Mac |
inkscape --export-png | Requires Homebrew or .app install |
imagemagick convert | Requires Homebrew |
sips | Does not read SVG input on macOS as of Sequoia |
cairosvg (Python) | Requires Homebrew (Cairo system lib) |
| Pillow | No SVG support natively |
| Swift + WebKit CLI | Works but ~80 LOC of bespoke code for a one-step thumbnail render that qlmanage already does |
| Browser screenshot | Manual, unreproducible across machines |
qlmanage ships with macOS, takes one command, outputs the exact PNG shape Apple wants. The trade-off is that QuickLook's SVG generator may diverge slightly from full-spec SVG 1.1 — keep the SVG simple (flat shapes, no filters, no text) and the output is faithful.
The macOS size-ladder downscale workflow is documented in the "macOS ladder reality check" section above; it is superseded by the universal single-PNG approach for new projects, but remains useful as a reference for older Xcode targets that still require the explicit size ladder.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.