diff --git a/README.md b/README.md index 3f88b54..ad90f88 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Search is case- and accent-insensitive. Ranking is exact name, prefix, substring 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 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. +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/Sources/Conjure/LauncherWindowController.swift b/Sources/Conjure/LauncherWindowController.swift index 61724f4..02aed07 100644 --- a/Sources/Conjure/LauncherWindowController.swift +++ b/Sources/Conjure/LauncherWindowController.swift @@ -61,9 +61,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe content.material = .hudWindow content.blendingMode = .behindWindow content.state = .active - content.wantsLayer = true - content.layer?.cornerRadius = 24 - content.layer?.masksToBounds = true + roundMaterialCorners(content, radius: 24) content.layer?.borderWidth = 0.5 window.contentView = content let background = LauncherBackground(frame: content.bounds) @@ -164,9 +162,7 @@ final class LauncherWindowController: NSWindowController, NSWindowDelegate, NSSe actionPill.material = .popover actionPill.blendingMode = .withinWindow actionPill.state = .active - actionPill.wantsLayer = true - actionPill.layer?.cornerRadius = 18 - actionPill.layer?.masksToBounds = true + roundMaterialCorners(actionPill, radius: 18) actionPill.layer?.borderWidth = 0.5 for view in [openButton, returnKey] { view.translatesAutoresizingMaskIntoConstraints = false @@ -432,3 +428,19 @@ private final class LauncherRowView: NSTableRowView { selection.stroke() } } + +@MainActor +private func roundMaterialCorners(_ view: NSVisualEffectView, radius: CGFloat) { + let size = NSSize(width: radius * 2 + 1, height: radius * 2 + 1) + let mask = NSImage(size: size, flipped: false) { rect in + NSColor.black.setFill() + NSBezierPath(roundedRect: rect, xRadius: radius, yRadius: radius).fill() + return true + } + mask.capInsets = NSEdgeInsets(top: radius, left: radius, bottom: radius, right: radius) + mask.resizingMode = .stretch + view.wantsLayer = true + view.layer?.cornerRadius = radius + view.layer?.masksToBounds = true + view.maskImage = mask +}