Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
13 kB · 288 lines
Swift
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289// WizardRoster.swift — the "wizard of wizards" roster, folded into DateWizard so// the calendar daemon IS the one menu-bar wizard. Ported from the standalone// wizard-wizard app: a hand-pixeled wizard guy for the menu-bar face, plus the// roster of sibling wizards it can summon. DateWizard is NOT in the list — the// date is built into this daemon now.import AppKitimport UniformTypeIdentifiers
// Our own little wizard guy — hand-placed pixels, no emoji. Purple hat, gold// star, gray beard. Drawn at integer scales so he stays crisp.let wizardGrid = [ "......X......", ".....XX......", ".....XXX.....", "....XXXX.....", "....XXXXX....", "...XXXXXX....", "...XX*XXXX...", "..XXXXXXXX...", ".XXXXXXXXXXX.", "...FFFFFF....", "...FEFFEF....", "..WFFFFFFW...", "..WWFFFFWW...", "...WWWWWW....", "....WWWW.....", ".....WW......",]
let wizardPalette: [Character: NSColor] = [ "X": NSColor(calibratedRed: 0.42, green: 0.32, blue: 0.85, alpha: 1), // hat "*": NSColor(calibratedRed: 1.00, green: 0.80, blue: 0.20, alpha: 1), // star "F": NSColor(calibratedRed: 0.95, green: 0.78, blue: 0.60, alpha: 1), // face "E": NSColor(calibratedRed: 0.15, green: 0.12, blue: 0.10, alpha: 1), // eyes "W": NSColor(calibratedRed: 0.72, green: 0.72, blue: 0.75, alpha: 1), // beard]
func wizardGuy(scale s: CGFloat) -> NSImage { let w = CGFloat(wizardGrid[0].count) * s let h = CGFloat(wizardGrid.count) * s return NSImage(size: NSSize(width: w, height: h), flipped: true) { _ in for (y, row) in wizardGrid.enumerated() { for (x, ch) in row.enumerated() { guard let c = wizardPalette[ch] else { continue } c.setFill() NSRect(x: CGFloat(x) * s, y: CGFloat(y) * s, width: s, height: s).fill() } } return true }}
// The menu-bar face: a plain black magic wand. It's a *template* image, so macOS// tints it to match the bar (black on light, white on dark) exactly like Menu// Band's note glyph — unlike the multicolored wizardGuy, which stays a costume// for the About window and the summon roster. SF Symbol so it stays crisp at any// bar thickness; wizardGuy is the fallback if the symbol is ever missing.//// With a `badge` string (e.g. "2h", "45m", "3d") the wand carries the countdown// to the next appointment as small H:MM:SS text sitting to the LEFT of the glyph,// raised toward the wand's tip — no pill, no outline, and it never overlaps the// wand. The text is tinted to THIS MACHINE's system accent color// (NSColor.controlAccentColor) so each box's wand reads as its own. A colored// badge can't ride a template image (macOS recolors those// wholesale), so in that case we return a *non-template* image and tint the wand// (dark ? white : black) ourselves.//// `dot` is the middle rung of the menu-bar-fit ladder: when the bar is a little// crowded we drop the countdown text but keep a small day-colored presence dot// (left of the wand) so you still see "there's something coming up." `badge`// wins over `dot` when both are supplied; neither → the plain template wand.func wandGlyph(pointSize: CGFloat = 15, badge: String? = nil, dot: Bool = false, dark: Bool = false) -> NSImage { let cfg = NSImage.SymbolConfiguration(pointSize: pointSize, weight: .regular) let symbol = NSImage(systemSymbolName: "wand.and.stars", accessibilityDescription: "Wizard")? .withSymbolConfiguration(cfg) ?? wizardGuy(scale: 1)
let hasBadge = (badge?.isEmpty == false) guard hasBadge || dot else { symbol.isTemplate = true return symbol }
let tinted = tintedImage(symbol, color: dark ? .white : .black) let accent = NSColor.controlAccentColor // this machine's system accent let gap: CGFloat = 2 // clear space between badge and wand
// Presence-dot rung: a small day-colored dot, left of the wand (no overlap). if !hasBadge { let dotD: CGFloat = 6 let size = NSSize(width: dotD + gap + tinted.size.width, height: max(tinted.size.height, dotD)) let out = NSImage(size: size) out.lockFocus() accent.setFill() NSBezierPath(ovalIn: NSRect(x: 0, y: (size.height - dotD) / 2, width: dotD, height: dotD)).fill() tinted.draw(at: NSPoint(x: dotD + gap, y: (size.height - tinted.size.height) / 2), from: .zero, operation: .sourceOver, fraction: 1) out.unlockFocus() out.isTemplate = false return out } let badge = badge!
// Countdown rung: small white text to the RIGHT of the wand, raised toward // its tip (top-aligned), no pill/outline. (Plain white/black — not accent — // reads cleaner at this size; the accent stays on the presence dot.) let font = NSFont.systemFont(ofSize: 7.5, weight: .bold) let textColor = dark ? NSColor.white : NSColor.black let textAttrs: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: textColor] let textSize = (badge as NSString).size(withAttributes: textAttrs) let size = NSSize(width: tinted.size.width + gap + textSize.width, height: max(tinted.size.height, textSize.height)) let out = NSImage(size: size) out.lockFocus() tinted.draw(at: NSPoint(x: 0, y: (size.height - tinted.size.height) / 2), from: .zero, operation: .sourceOver, fraction: 1) (badge as NSString).draw(at: NSPoint(x: tinted.size.width + gap, y: size.height - textSize.height), withAttributes: textAttrs) out.unlockFocus() out.isTemplate = false return out}
// Recolor a (usually template) symbol image by drawing it and filling// source-atop — keeps the glyph's alpha, swaps its color.private func tintedImage(_ image: NSImage, color: NSColor) -> NSImage { let out = NSImage(size: image.size) out.lockFocus() let rect = NSRect(origin: .zero, size: image.size) image.draw(in: rect) color.set() rect.fill(using: .sourceAtop) out.unlockFocus() return out}
struct WizardEntry { let dir: String // package dir under the repo root let exe: String // executable / target name let blurb: String let needsSpec: Bool // WaveWizard quits without a spec.json — ask for one
var slug: String { exe.lowercased() } func mascot(in repo: URL) -> URL { repo.appendingPathComponent("\(dir)/Sources/\(exe)/Assets/\(slug)-mascot.png") }}
// The sibling wizards this daemon can summon. DateWizard is omitted — it lives// here now (the date is built in).let siblingWizards = [ WizardEntry(dir: "clip-wizard", exe: "ClipWizard", blurb: "audition, pick, and stitch motion takes into a /pop cut", needsSpec: false), WizardEntry(dir: "glyph-wizard", exe: "GlyphWizard", blurb: "parametric type authoring from glyph skeletons", needsSpec: false), WizardEntry(dir: "juke-wizard", exe: "JukeWizard", blurb: "play, rate, and annotate the whole /pop library", needsSpec: false), WizardEntry(dir: "shot-wizard", exe: "ShotWizard", blurb: "storyboard shots and watch the sequence play through", needsSpec: false), WizardEntry(dir: "wave-wizard", exe: "WaveWizard", blurb: "record labelled audio samples from a spec", needsSpec: true),]
// Owns repo discovery + summon/launch + the "Our Wizards" about window, so// MenuBarDays can stay focused on the calendar strip.final class WizardRoster: NSObject { // Binary lives at <repo>/date-wizard/.build/<config>/DateWizard — walk up to // the repo, falling back to ~/aesthetic-computer. let repo: URL = { var u = URL(fileURLWithPath: CommandLine.arguments[0]).resolvingSymlinksInPath() for _ in 0..<4 { u.deleteLastPathComponent() } if FileManager.default.fileExists(atPath: u.appendingPathComponent("juke-wizard").path) { return u } return URL(fileURLWithPath: NSHomeDirectory() + "/aesthetic-computer") }() private var aboutWindow: NSWindow?
func mascotImage(_ w: WizardEntry, side: CGFloat) -> NSImage { if let img = NSImage(contentsOf: w.mascot(in: repo)) { img.size = NSSize(width: side, height: side) return img } // no mascot yet — our own guy stands in let img = wizardGuy(scale: max(1, (side / CGFloat(wizardGrid.count)).rounded())) img.size = NSSize(width: side * 13 / 16, height: side) return img }
@objc func summon(_ sender: NSMenuItem) { guard sender.tag >= 0, sender.tag < siblingWizards.count else { return } let w = siblingWizards[sender.tag] var arg: String? = nil if w.needsSpec { let panel = NSOpenPanel() panel.title = "Pick a \(w.exe) spec" panel.directoryURL = repo.appendingPathComponent("\(w.dir)/samples") panel.allowedContentTypes = [.json] NSApp.activate(ignoringOtherApps: true) guard panel.runModal() == .OK, let url = panel.url else { return } arg = url.path } launch(w, arg: arg) }
func launch(_ w: WizardEntry, arg: String?) { let pkg = repo.appendingPathComponent(w.dir).path let launcher = "\(pkg)/bin/\(w.slug)" let quotedArg = arg.map { " \"\($0)\"" } ?? "" // Prefer the wizard's own bin launcher; fall back to a cached build + run. let cmd: String if FileManager.default.fileExists(atPath: launcher) { cmd = "\"\(launcher)\"\(quotedArg)" } else { cmd = "swift build -c release --package-path \"\(pkg)\" && exec \"\(pkg)/.build/release/\(w.exe)\"\(quotedArg)" } let p = Process() p.executableURL = URL(fileURLWithPath: "/bin/sh") p.arguments = ["-c", "( \(cmd) ) >/tmp/wizard-\(w.slug).log 2>&1 &"] try? p.run() }
// "Our Wizards" — the roster, mascots and all. @objc func showAbout() { if let win = aboutWindow { win.makeKeyAndOrderFront(nil); NSApp.activate(ignoringOtherApps: true); return }
let stack = NSStackView() stack.orientation = .vertical stack.alignment = .leading stack.spacing = 10 stack.edgeInsets = NSEdgeInsets(top: 20, left: 24, bottom: 20, right: 24)
let titleRow = NSStackView() titleRow.orientation = .horizontal titleRow.alignment = .centerY titleRow.spacing = 10 titleRow.addArrangedSubview(NSImageView(image: wizardGuy(scale: 3))) let title = NSTextField(labelWithString: "Our Wizards") title.font = .systemFont(ofSize: 20, weight: .bold) titleRow.addArrangedSubview(title) stack.addArrangedSubview(titleRow)
let sub = NSTextField(labelWithString: "Small native tools from Aesthetic Inc — one craft each. The date lives here.") sub.font = .systemFont(ofSize: 12) sub.textColor = .secondaryLabelColor stack.addArrangedSubview(sub)
for w in siblingWizards { let row = NSStackView() row.orientation = .horizontal row.alignment = .centerY row.spacing = 12 let face = NSImageView(image: mascotImage(w, side: 44)) face.widthAnchor.constraint(equalToConstant: 44).isActive = true face.heightAnchor.constraint(equalToConstant: 44).isActive = true row.addArrangedSubview(face) let col = NSStackView() col.orientation = .vertical col.alignment = .leading col.spacing = 1 let name = NSTextField(labelWithString: w.exe) name.font = .systemFont(ofSize: 14, weight: .semibold) let blurb = NSTextField(labelWithString: w.blurb) blurb.font = .systemFont(ofSize: 11) blurb.textColor = .secondaryLabelColor col.addArrangedSubview(name) col.addArrangedSubview(blurb) row.addArrangedSubview(col) stack.addArrangedSubview(row) }
let foot = NSTextField(labelWithString: "aesthetic.computer") foot.font = .systemFont(ofSize: 10) foot.textColor = .tertiaryLabelColor stack.addArrangedSubview(foot)
let win = NSWindow(contentRect: .zero, styleMask: [.titled, .closable], backing: .buffered, defer: false) win.title = "Our Wizards" win.contentView = stack win.setContentSize(stack.fittingSize) win.isReleasedWhenClosed = false win.center() aboutWindow = win win.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) }}