Replace the default Flutter icon with a stylised cloud

The app shipped the Flutter template's blue F, which said nothing about what it
does and did not match the interface. The launcher icon is now a white cloud on
the same seed blue the app themes itself with, so the two read as one product.

The icon is drawn rather than hand-edited: tool/generate_icon.py renders it from
signed distance fields — a union of three circles and a rounded box — using only
the standard library, so regenerating it needs no image toolchain. The shape's
framing is derived from its own bounding box, which is what keeps it centred;
maintaining the bounds separately from the shape had it drifting off-centre.

Adds the adaptive icon and the Android 13 monochrome layer, which were missing
entirely. The generator frames the cloud against the 72dp the launcher mask
always keeps and adaptive_icon_foreground_inset is 0, so the layer is not shrunk
twice and the icon reads at the same size as its neighbours on a home screen.

Verified on the emulator: the cloud appears in the app drawer and holds its shape
down to 48px. docs/architecture.md records how to regenerate it, including the
flutter_launcher_icons 0.14.4 bug that writes a string into a boolean Xcode
setting and needs reverting by hand afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 22:44:33 +02:00
co-authored by Claude Opus 5
parent aa91b457ed
commit f434a68155
46 changed files with 473 additions and 81 deletions
@@ -1,122 +1,158 @@
{
"images" : [
"images": [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
"size": "20x20",
"idiom": "iphone",
"filename": "Icon-App-20x20@3x.png",
"scale": "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
"size": "29x29",
"idiom": "iphone",
"filename": "Icon-App-29x29@3x.png",
"scale": "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
"size": "40x40",
"idiom": "iphone",
"filename": "Icon-App-40x40@3x.png",
"scale": "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
"size": "57x57",
"idiom": "iphone",
"filename": "Icon-App-57x57@1x.png",
"scale": "1x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
"size": "57x57",
"idiom": "iphone",
"filename": "Icon-App-57x57@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@2x.png",
"scale": "2x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
"size": "60x60",
"idiom": "iphone",
"filename": "Icon-App-60x60@3x.png",
"scale": "3x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@1x.png",
"scale": "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
"size": "20x20",
"idiom": "ipad",
"filename": "Icon-App-20x20@2x.png",
"scale": "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@1x.png",
"scale": "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
"size": "29x29",
"idiom": "ipad",
"filename": "Icon-App-29x29@2x.png",
"scale": "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@1x.png",
"scale": "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
"size": "40x40",
"idiom": "ipad",
"filename": "Icon-App-40x40@2x.png",
"scale": "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
"size": "50x50",
"idiom": "ipad",
"filename": "Icon-App-50x50@1x.png",
"scale": "1x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
"size": "50x50",
"idiom": "ipad",
"filename": "Icon-App-50x50@2x.png",
"scale": "2x"
},
{
"size": "72x72",
"idiom": "ipad",
"filename": "Icon-App-72x72@1x.png",
"scale": "1x"
},
{
"size": "72x72",
"idiom": "ipad",
"filename": "Icon-App-72x72@2x.png",
"scale": "2x"
},
{
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@1x.png",
"scale": "1x"
},
{
"size": "76x76",
"idiom": "ipad",
"filename": "Icon-App-76x76@2x.png",
"scale": "2x"
},
{
"size": "83.5x83.5",
"idiom": "ipad",
"filename": "Icon-App-83.5x83.5@2x.png",
"scale": "2x"
},
{
"size": "1024x1024",
"idiom": "ios-marketing",
"filename": "Icon-App-1024x1024@1x.png",
"scale": "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"info": {
"version": 1,
"author": "xcode"
}
}