eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1#!/usr/bin/swift
2// 🤖 Regenerates a Mac dev-alt icon set from the canonical app icon: the
3// SAME purple "11" tile, hue-rotated so a dev build is unmistakable in the
4// Dock without inventing a new mark (CLAUDE.md: never hand-roll a
5// substitute glyph). Two variants: "dev" (orange, the default) and "live"
6// (green — the convention for a dev build aimed at PRODUCTION home, so two
7// running alts with different aims never share an icon). Run from the repo
8// root:
9//
10// swift tools/make-dev-icon.swift # AppIconDev (orange)
11// swift tools/make-dev-icon.swift live # AppIconDevLive (green)
12//
13// Committed output; re-run only if the canonical icon changes.
14import AppKit
15import CoreImage
16
17// Purple sits ~253°; orange ~30° (-220°), green ~130° (-123°). White and
18// near-white (the "11") are hue-less, so they ride through untouched.
19let variants: [String: (set: String, angle: Double)] = [
20 "dev": ("AppIconDev", -220.0),
21 "live": ("AppIconDevLive", -123.0),
22]
23let name = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : "dev"
24guard let variant = variants[name] else {
25 fatalError("unknown variant \(name) — expected: \(variants.keys.sorted().joined(separator: ", "))")
26}
27
28let src = "ios/LChatMac/Assets.xcassets/AppIcon.appiconset/icon_1024.png"
29let outDir = "ios/LChatMac/Assets.xcassets/\(variant.set).appiconset"
30
31guard let image = CIImage(contentsOf: URL(fileURLWithPath: src)) else {
32 fatalError("can't read \(src) — run from the repo root")
33}
34
35let hue = CIFilter(name: "CIHueAdjust", parameters: [
36 kCIInputImageKey: image,
37 kCIInputAngleKey: NSNumber(value: variant.angle * .pi / 180.0),
38])!
39guard let tinted = hue.outputImage else { fatalError("hue adjust failed") }
40
41let ctx = CIContext()
42guard let full = ctx.createCGImage(tinted, from: tinted.extent) else {
43 fatalError("render failed")
44}
45
46try? FileManager.default.createDirectory(atPath: outDir, withIntermediateDirectories: true)
47
48for size in [16, 32, 64, 128, 256, 512, 1024] {
49 let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: size, pixelsHigh: size,
50 bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true,
51 isPlanar: false, colorSpaceName: .deviceRGB,
52 bytesPerRow: 0, bitsPerPixel: 0)!
53 let nsCtx = NSGraphicsContext(bitmapImageRep: rep)!
54 NSGraphicsContext.saveGraphicsState()
55 NSGraphicsContext.current = nsCtx
56 nsCtx.cgContext.interpolationQuality = .high
57 nsCtx.cgContext.draw(full, in: CGRect(x: 0, y: 0, width: size, height: size))
58 NSGraphicsContext.restoreGraphicsState()
59 let png = rep.representation(using: .png, properties: [:])!
60 try! png.write(to: URL(fileURLWithPath: "\(outDir)/icon_\(size).png"))
61 print("wrote \(outDir)/icon_\(size).png")
62}
63
64let contents = """
65{
66 "images" : [
67 { "idiom" : "mac", "size" : "16x16", "scale" : "1x", "filename" : "icon_16.png" },
68 { "idiom" : "mac", "size" : "16x16", "scale" : "2x", "filename" : "icon_32.png" },
69 { "idiom" : "mac", "size" : "32x32", "scale" : "1x", "filename" : "icon_32.png" },
70 { "idiom" : "mac", "size" : "32x32", "scale" : "2x", "filename" : "icon_64.png" },
71 { "idiom" : "mac", "size" : "128x128", "scale" : "1x", "filename" : "icon_128.png" },
72 { "idiom" : "mac", "size" : "128x128", "scale" : "2x", "filename" : "icon_256.png" },
73 { "idiom" : "mac", "size" : "256x256", "scale" : "1x", "filename" : "icon_256.png" },
74 { "idiom" : "mac", "size" : "256x256", "scale" : "2x", "filename" : "icon_512.png" },
75 { "idiom" : "mac", "size" : "512x512", "scale" : "1x", "filename" : "icon_512.png" },
76 { "idiom" : "mac", "size" : "512x512", "scale" : "2x", "filename" : "icon_1024.png" }
77 ],
78 "info" : { "version" : 1, "author" : "xcode" }
79}
80"""
81try! contents.write(toFile: "\(outDir)/Contents.json", atomically: true, encoding: .utf8)
82print("wrote \(outDir)/Contents.json")
83