diff --git a/Makefile b/Makefile
index ccc3484..097509f 100644
--- a/Makefile
+++ b/Makefile
@@ -5,9 +5,11 @@ INSTALL_DIR ?= /Applications
build:
swift build -c release
- mkdir -p $(APP)/Contents/MacOS
+ mkdir -p $(APP)/Contents/MacOS $(APP)/Contents/Resources
cp .build/release/Conjure $(APP)/Contents/MacOS/Conjure
cp Resources/Info.plist $(APP)/Contents/Info.plist
+ swift Scripts/icon.swift .build/Conjure.iconset
+ iconutil -c icns .build/Conjure.iconset -o $(APP)/Contents/Resources/Conjure.icns
codesign --force --sign - $(APP)
run: build
diff --git a/README.md b/README.md
index 7d14c5f..26dee49 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,8 @@ Applications with identical display names show a muted containing-folder hint be
The launcher keeps its Raycast-inspired 750 × 474-point, titlebar-free rounded panel, large borderless search field, compact icon rows, right-aligned application labels, and bottom-right launch pill. Its Sunset palette uses a dark brown background, soft amber and rust glows, warm cream text, and orange accents on the caret, selection, and action outline.
+The application icon uses the same orange `sparkles` SF Symbol on a self-contained, rounded dark-brown tile. `Scripts/icon.swift` renders every standard and Retina icon size, and `make build` packages the resulting `.icns` in the signed bundle for Finder and other system icon surfaces. Conjure remains an accessory app; adding an application icon does not add a Dock or app-switcher entry.
+
The brown tint is 35% opaque over an active, behind-window `NSVisualEffectView` using the native HUD material. This exposes macOS's blurred backdrop while retaining the warm palette and glows; the system material supplies an opaque fallback when Reduce Transparency is enabled. Both the panel and launch pill use native rounded alpha masks alongside layer clipping, keeping material inside its rounded outline and making the window shadow follow the same shape.
AppKit still provides text editing, table navigation, scrolling, application icons, controls, menus, fonts, and visual-effect materials. The background uses cached native radial gradients that fade to transparent: static soft blobs, without animations, timers, image assets, blur filters, or third-party UI dependencies. Decorative drawing does not intercept clicks. Increased-contrast settings strengthen the selection outline, and text colors are tuned for readability across the glows and selection.
diff --git a/Resources/Info.plist b/Resources/Info.plist
index 210ae4e..10db57c 100644
--- a/Resources/Info.plist
+++ b/Resources/Info.plist
@@ -14,6 +14,8 @@
Conjure
CFBundleDisplayName
Conjure
+ CFBundleIconFile
+ Conjure.icns
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/Scripts/icon.swift b/Scripts/icon.swift
new file mode 100644
index 0000000..6668c33
--- /dev/null
+++ b/Scripts/icon.swift
@@ -0,0 +1,55 @@
+import AppKit
+
+// Render the launcher's SF Symbol directly at every macOS icon resolution.
+precondition(CommandLine.arguments.count == 2, "Usage: swift Scripts/icon.swift ")
+let directory = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
+try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
+let accent = NSColor(srgbRed: 0.95, green: 0.58, blue: 0.23, alpha: 1)
+guard let symbol = NSImage(systemSymbolName: "sparkles", accessibilityDescription: nil)?
+ .withSymbolConfiguration(NSImage.SymbolConfiguration(paletteColors: [accent])) else {
+ fatalError("The sparkles SF Symbol is unavailable.")
+}
+let gradient = NSGradient(starting: NSColor(srgbRed: 0.27, green: 0.19, blue: 0.13, alpha: 1),
+ ending: NSColor(srgbRed: 0.12, green: 0.09, blue: 0.08, alpha: 1))!
+
+for size in [16, 32, 128, 256, 512] {
+ for scale in [1, 2] {
+ let pixels = size * scale
+ let bitmap = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: pixels, pixelsHigh: pixels,
+ bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true,
+ isPlanar: false, colorSpaceName: .deviceRGB,
+ bytesPerRow: 0, bitsPerPixel: 0)!
+ NSGraphicsContext.saveGraphicsState()
+ NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: bitmap)
+ let context = NSGraphicsContext.current!.cgContext
+ context.scaleBy(x: CGFloat(pixels) / 1024, y: CGFloat(pixels) / 1024)
+ let tile = NSBezierPath(roundedRect: NSRect(x: 100, y: 100, width: 824, height: 824),
+ xRadius: 184, yRadius: 184)
+ NSGraphicsContext.saveGraphicsState()
+ let shadow = NSShadow()
+ shadow.shadowColor = NSColor.black.withAlphaComponent(0.28)
+ shadow.shadowBlurRadius = 24
+ shadow.shadowOffset = NSSize(width: 0, height: -12)
+ shadow.set()
+ NSColor(srgbRed: 0.12, green: 0.09, blue: 0.08, alpha: 1).setFill()
+ tile.fill()
+ NSGraphicsContext.restoreGraphicsState()
+ gradient.draw(in: tile, angle: -90)
+ NSColor.white.withAlphaComponent(0.10).setStroke()
+ tile.lineWidth = 2
+ tile.stroke()
+
+ let glyphHeight: CGFloat = 540
+ let glyphWidth = glyphHeight * symbol.size.width / symbol.size.height
+ symbol.draw(in: NSRect(x: (1024 - glyphWidth) / 2, y: (1024 - glyphHeight) / 2,
+ width: glyphWidth, height: glyphHeight),
+ from: .zero, operation: .sourceOver, fraction: 1)
+ NSGraphicsContext.restoreGraphicsState()
+ let suffix = scale == 2 ? "@2x" : ""
+ let output = directory.appendingPathComponent("icon_\(size)x\(size)\(suffix).png")
+ guard let png = bitmap.representation(using: .png, properties: [:]) else {
+ fatalError("Could not encode \(output.lastPathComponent).")
+ }
+ try png.write(to: output)
+ }
+}