// The menu bar's own glyph — Claude's asterisk over a coat's collar and // shoulders. Drawn here rather than scaled down from the app icon, which is // what the menu bar used to show: at 18pt the app icon's three coats, lapels // and pockets collapse into a smudge, and its colours fight the menu bar // instead of following it. // // Returned as a *template* image, which is what makes it track the system // theme with no code of ours involved. A template carries only an alpha // channel; macOS supplies the colour — dark on a light menu bar, light on a // dark one, inverted again while the menu is open — and re-tints it on the fly // when the theme switches. That also dictates the drawing: no fills of our // own, and any internal detail has to be a hole punched through the alpha. import AppKit enum MenuBarIcon { // Six rays rather than the app icon's eight. At 18pt an eight-ray asterisk // has under a pixel of gap between arms, so they merge into a blob; six // resolve as separate arms. Lengths stay slightly uneven, as on the app // icon, so it doesn't read as a snowflake. private static let rayCount = 6 private static let rayLengths: [CGFloat] = [1.0, 0.88, 0.97, 0.86, 1.0, 0.9] private static let rayRadius: CGFloat = 22 private static let rayWidth: CGFloat = 7.2 private static let asteriskCentre = NSPoint(x: 50, y: 28) static func image(pointSize: CGFloat = 18) -> NSImage { let image = NSImage(size: NSSize(width: pointSize, height: pointSize)) image.lockFocusFlipped(false) // Authored y-down like the app icon; flip once rather than mirroring // every coordinate. let flip = NSAffineTransform() flip.translateX(by: 0, yBy: pointSize) flip.scaleX(by: pointSize / 100, yBy: -pointSize / 100) flip.concat() NSColor.black.setStroke() asterisk().stroke() NSColor.black.setFill() coat().fill() image.unlockFocus() image.isTemplate = true return image } private static func asterisk() -> NSBezierPath { let path = NSBezierPath() for index in 0.. NSBezierPath { let path = NSBezierPath() path.move(to: NSPoint(x: 15, y: 72)) // left shoulder path.line(to: NSPoint(x: 27, y: 60)) // slight tilt up path.line(to: NSPoint(x: 40, y: 60)) // flat collar top path.line(to: NSPoint(x: 50, y: 78)) // valley at the neck path.line(to: NSPoint(x: 60, y: 60)) path.line(to: NSPoint(x: 73, y: 60)) path.line(to: NSPoint(x: 85, y: 72)) // right shoulder path.line(to: NSPoint(x: 85, y: 94)) path.line(to: NSPoint(x: 15, y: 94)) path.close() return path } }