cocottetech/@platform/codebase/@features/ai-copilot/macos-fe/scripts/make-icon.swift
Natalie 23de9bd97b feat(ai-copilot): add live connection state tracking
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-08 01:17:07 -07:00

71 lines
3.1 KiB
Swift

// Renders the CocotteAI app icon ( mark on the rose brand background) and writes
// a full .iconset directory. Run on macOS: `swift make-icon.swift <out.iconset>`.
// The shell packager then `iconutil -c icns`s it. Colors match DesignTokens' rose
// accent (r7 #c75872) over the dark canvas (#100c0e).
import AppKit
// Initialize the shared app so AppKit font/graphics services are available in this
// CLI context (no run loop needed we never call run()).
_ = NSApplication.shared
let outDir = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : "AppIcon.iconset"
try? FileManager.default.createDirectory(atPath: outDir, withIntermediateDirectories: true)
func color(_ hex: UInt32) -> NSColor {
NSColor(srgbRed: CGFloat((hex >> 16) & 0xff) / 255,
green: CGFloat((hex >> 8) & 0xff) / 255,
blue: CGFloat(hex & 0xff) / 255, alpha: 1)
}
/// Draw the icon at `size` px (square) into a fresh bitmap context and return PNG
/// data. Draws straight into an NSBitmapImageRep context (not NSImage.lockFocus),
/// which is the reliable path in a command-line tool.
func render(_ size: Int) -> Data {
let s = CGFloat(size)
guard let rep = NSBitmapImageRep(
bitmapDataPlanes: nil, pixelsWide: size, pixelsHigh: size,
bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false,
colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0) else {
fatalError("bitmap alloc failed at \(size)")
}
NSGraphicsContext.saveGraphicsState()
defer { NSGraphicsContext.restoreGraphicsState() }
NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep)
// Rounded-rect canvas with a subtle rose vertical gradient (macOS Big Sur look:
// full-bleed rounded square, the system masks corners on display).
let rect = NSRect(x: 0, y: 0, width: s, height: s)
let radius = s * 0.22
let path = NSBezierPath(roundedRect: rect, xRadius: radius, yRadius: radius)
path.addClip()
NSGradient(colors: [color(0x1c1619), color(0x100c0e)])?.draw(in: rect, angle: -90)
// The mark, rose accent, centered.
let fontSize = s * 0.62
let attrs: [NSAttributedString.Key: Any] = [
.font: NSFont.systemFont(ofSize: fontSize, weight: .semibold),
.foregroundColor: color(0xc75872),
]
let str = NSAttributedString(string: "", attributes: attrs)
let bounds = str.size()
str.draw(at: NSPoint(x: (s - bounds.width) / 2, y: (s - bounds.height) / 2))
guard let png = rep.representation(using: .png, properties: [:]) else {
fatalError("PNG encode failed at size \(size)")
}
return png
}
// Standard macOS iconset matrix.
let specs: [(name: String, size: Int)] = [
("icon_16x16", 16), ("icon_16x16@2x", 32),
("icon_32x32", 32), ("icon_32x32@2x", 64),
("icon_128x128", 128), ("icon_128x128@2x", 256),
("icon_256x256", 256), ("icon_256x256@2x", 512),
("icon_512x512", 512), ("icon_512x512@2x", 1024),
]
for spec in specs {
let url = URL(fileURLWithPath: "\(outDir)/\(spec.name).png")
try! render(spec.size).write(to: url)
}
FileHandle.standardError.write("wrote \(specs.count) icons to \(outDir)\n".data(using: .utf8)!)