swiftship/internal/skills/data/always-macos/macos-patterns/SKILL.md
macOS platform patterns: window management, menu bar, keyboard shortcuts, Settings, drag-and-drop, App Sandbox. Use when building macOS-specific features, handling desktop input, or implementing Mac app patterns. Triggers: macOS, Mac, desktop, menu bar, keyboard shortcut, Settings scene, window management.
npx skillsauth add abdullah4ai/apple-developer-toolkit macos-patternsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Three scene types for Mac apps:
@main
struct MyApp: App {
var body: some Scene {
// Main window — users can open multiple instances
WindowGroup {
ContentView()
}
.defaultSize(width: 900, height: 600)
// Single utility window
Window("Inspector", id: "inspector") {
InspectorView()
}
.defaultSize(width: 300, height: 400)
// Document-based app
DocumentGroup(newDocument: MyDocument()) { file in
DocumentEditor(document: file.$document)
}
}
}
CommandMenu closures run at the App scene level — outside the view hierarchy. They CANNOT access view @State directly. Use @FocusedValue to bridge view state to menu actions.
// 1. Define a FocusedValue key using @Entry
extension FocusedValues {
@Entry var activeDocument: DocumentViewModel?
}
// 2. ViewModel — @Observable only (NOT ObservableObject)
@Observable @MainActor
class DocumentViewModel {
var content = ""
func save() { /* persist */ }
func togglePreview() { /* toggle */ }
}
// 3. Publish from active view using .focusedValue()
struct DocumentView: View {
@State var viewModel = DocumentViewModel()
var body: some View {
EditorContent(viewModel: viewModel)
.focusedValue(\.activeDocument, viewModel) // REQUIRED — publish to menu bar
}
}
// 4. Consume in App via @FocusedValue and wire ALL menu actions
@main
struct MyApp: App {
@FocusedValue(\.activeDocument) private var document
var body: some Scene {
WindowGroup { DocumentView() }
CommandMenu("Document") {
Button("Save") { document?.save() }
.keyboardShortcut("s", modifiers: .command)
.disabled(document == nil)
Button("Toggle Preview") { document?.togglePreview() }
.keyboardShortcut("p", modifiers: [.command, .option])
.disabled(document == nil)
}
CommandGroup(replacing: .newItem) {
Button("New Document") { document?.createNew() }
.keyboardShortcut("n", modifiers: .command)
.disabled(document == nil)
}
}
}
Rules:
@Entry macro.focusedValue(\.key, value) on the active view to publish state@FocusedValue(\.key) private var name in the App struct.disabled(object == nil) on every menu item — menus are active even when no view is focused{} on CommandMenu buttons is unacceptable — every action must call through to the FocusedValueEvery menu item and primary action needs .keyboardShortcut():
// Standard shortcuts
Button("Save") { save() }
.keyboardShortcut("s", modifiers: .command)
Button("Undo") { undo() }
.keyboardShortcut("z", modifiers: .command)
Button("Find") { showSearch() }
.keyboardShortcut("f", modifiers: .command)
// Custom shortcuts
Button("Toggle Sidebar") { toggleSidebar() }
.keyboardShortcut("s", modifiers: [.command, .control])
@main
struct MyApp: App {
var body: some Scene {
WindowGroup { ContentView() }
// Auto-creates "Settings..." in app menu (Cmd+,)
Settings {
SettingsView()
}
}
}
struct SettingsView: View {
var body: some View {
TabView {
GeneralSettingsView()
.tabItem { Label("General", systemImage: "gear") }
AppearanceSettingsView()
.tabItem { Label("Appearance", systemImage: "paintbrush") }
}
.frame(width: 450, height: 300)
}
}
@main
struct StatusApp: App {
var body: some Scene {
MenuBarExtra("Status", systemImage: "circle.fill") {
StatusMenuView()
}
.menuBarExtraStyle(.window)
}
}
// Draggable item
ItemRow(item: item)
.draggable(item)
// Drop destination
FolderView(folder: folder)
.dropDestination(for: Item.self) { items, location in
moveItems(items, to: folder)
return true
}
macOS apps need entitlements for system access:
com.apple.security.files.user-selected.read-writecom.apple.security.network.clientcom.apple.security.device.cameracom.apple.security.device.audio-inputUse for platform-specific code in shared modules:
#if os(macOS)
import AppKit
// macOS-specific code
#elseif os(iOS)
import UIKit
// iOS-specific code
#endif
// Translucent glass backgrounds
VStack { content }
.glassEffect()
// Glass button styles
Button("Action") { }
.buttonStyle(.glass)
Button("Primary") { }
.buttonStyle(.glassProminent)
// Open panel
.fileImporter(
isPresented: $showOpen,
allowedContentTypes: [.json]
) { result in
// handle
}
// Save panel
.fileExporter(
isPresented: $showSave,
document: doc,
contentType: .json
) { result in
// handle
}
.foregroundStyle() not .foregroundColor().clipShape(.rect(cornerRadius:)) not .cornerRadius()@Observable not ObservableObject — never combine both on the same classUIColor / UIImage — use SwiftUI Color / Image insteadWindowGroup, Window, or DocumentGroup for scene typesCommandMenu / CommandGroup for menu bar customization.keyboardShortcut()Settings { } scene for preferences (auto-wires Cmd+,)MenuBarExtra for menu bar apps with .menuBarExtraStyle(.window).draggable() / .dropDestination() for drag-and-drop#if os(macOS) for platform-specific code in shared modulesColor/Image not NSColor/NSImage.foregroundStyle() not .foregroundColor().clipShape(.rect(cornerRadius:)) not .cornerRadius()testing
Use for 3D games: racing, 3D sports, board games, marble maze, tower defense, bowling. SceneKit + SceneView architecture, 3D scene hierarchy, physics, game loop, primitives, materials, cameras, particles, audio.
documentation
Game UI patterns: SwiftUI HUD overlays on SpriteKit, menus (main/pause/game-over), virtual joystick/d-pad, score displays, health bars, tutorial onboarding.
tools
Download free game sprites/textures/3D models and generate procedural assets. Covers nw_download_asset tool, texture factories, sprite atlas organization, 3D model loading, and programmatic asset creation.
testing
Use for 2D games: arcade, puzzle, sports, ping pong, platformer, shooter, 2D racing. SpriteKit + SpriteView architecture, scene hierarchy, physics, game loop, audio, particles, game feel.