with one click
macos-hig-designer
Design native macOS apps following Apple's Human Interface Guidelines and Liquid Glass design system. Use when building SwiftUI/AppKit macOS apps, validating designs, or implementing macOS-specific patterns.
Menu
Design native macOS apps following Apple's Human Interface Guidelines and Liquid Glass design system. Use when building SwiftUI/AppKit macOS apps, validating designs, or implementing macOS-specific patterns.
A curated collection of 1809+ best OpenClaw skills — AI tools, productivity, marketing, frontend, mobile, backend, DevOps and more. Weekly updated by MyClaw.ai — Powered by MyClaw.ai
AI-powered presentation generation using 2slides API. Create slides from text content, match reference image styles, or summarize documents into presentations. Use when users request to "create a presentation", "make slides", "generate a deck", "create slides from this content/document/image", or any presentation creation task. Supports theme selection, multiple languages, and both synchronous and asynchronous generation modes.
Generate architecture diagrams, flowcharts, and system diagrams with AnyGen AI. Uses dialogue mode to understand structure, components, and relationships before generating. Triggers: draw diagram, architecture diagram, flowchart, system diagram, whiteboard diagram, sequence diagram.
在 OpenClaw 平台执行网页自动 QA 测试(自动操作 + 采证 + 报告 + 修复提示包)。当用户要求做自动化回归、演示级测试、失败证据归档或生成可直接交给下一窗口的修复 Prompt 时使用。
Daily news briefing generator — produces a conversational radio-host-style audio briefing + DOCX document covering weather, X/Twitter trends, web trends, world news, politics, tech, local news, sports, markets, and crypto. macOS only (uses Apple TTS and afplay). Use when user asks for a news briefing, morning briefing, daily update, or similar.
Real-time news aggregator with Discord & Telegram push. Manage Jin10, BlockBeats, RSS, X KOLs, Polymarket, OpenNews via REST API.
| name | macos-hig-designer |
| description | Design native macOS apps following Apple's Human Interface Guidelines and Liquid Glass design system. Use when building SwiftUI/AppKit macOS apps, validating designs, or implementing macOS-specific patterns. |
| domain | design |
| homepage | https://github.com/soponcd/timeflow-skills/tree/main/teams/skills/macos-hig-designer |
| metadata | {"clawdbot":{"emoji":"🖥️"}} |
Design native macOS applications following Apple's Human Interface Guidelines with macOS Tahoe's Liquid Glass design system.
User Request
│
├─► "Review my macOS UI code"
│ └─► Run HIG Compliance Check (Section 11)
│ └─► Report violations with fixes
│
├─► "Modernize this macOS code"
│ └─► Identify deprecated APIs
│ └─► Apply Modern API Replacements (Section 10)
│
└─► "Build [feature] for macOS"
└─► Design with HIG principles first
└─► Implement with modern SwiftUI patterns
| Principle | Description | Implementation |
|---|---|---|
| Hierarchy | Visual layers through Liquid Glass translucency | Use .glassEffect(), materials, and depth |
| Harmony | Concentric alignment between hardware/software | Round corners, consistent radii, flowing shapes |
| Consistency | Platform conventions that adapt to context | Follow standard patterns, respect user preferences |
Liquid Glass combines transparency, reflection, refraction, and fluidity with a frosted aesthetic:
// macOS Tahoe Liquid Glass effect
.glassEffect() // Primary Liquid Glass material
.glassEffect(.regular.tinted) // Tinted variant (26.1+)
// Pre-Tahoe fallback
.background(.ultraThinMaterial)
.background(.regularMaterial)
.background(.thickMaterial)
When to use Liquid Glass:
When NOT to use:
Three-column layout for document-based and content-heavy apps:
struct ContentView: View {
@State private var selection: Item.ID?
@State private var columnVisibility: NavigationSplitViewVisibility = .all
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
// Sidebar (source list)
List(items, selection: $selection) { item in
NavigationLink(value: item) {
Label(item.title, systemImage: item.icon)
}
}
.navigationSplitViewColumnWidth(min: 180, ideal: 220, max: 300)
} content: {
// Content column (optional middle)
ContentListView(selection: selection)
} detail: {
// Detail view
DetailView(item: selectedItem)
}
}
}
// Source list with sections
List(selection: $selection) {
Section("Library") {
ForEach(libraryItems) { item in
Label(item.name, systemImage: item.icon)
.tag(item)
}
}
Section("Collections") {
ForEach(collections) { collection in
Label(collection.name, systemImage: "folder")
.tag(collection)
.badge(collection.count)
}
}
}
.listStyle(.sidebar)
struct DocumentView: View {
@State private var showInspector = true
var body: some View {
MainContentView()
.inspector(isPresented: $showInspector) {
InspectorView()
.inspectorColumnWidth(min: 200, ideal: 250, max: 400)
}
.toolbar {
ToolbarItem {
Button {
showInspector.toggle()
} label: {
Label("Inspector", systemImage: "sidebar.trailing")
}
}
}
}
}
@main
struct MyApp: App {
var body: some Scene {
// Main document window
WindowGroup {
ContentView()
}
.windowStyle(.automatic)
.windowToolbarStyle(.unified)
.defaultSize(width: 900, height: 600)
.defaultPosition(.center)
// Settings window
Settings {
SettingsView()
}
// Utility window
Window("Inspector", id: "inspector") {
InspectorWindow()
}
.windowStyle(.plain)
.windowResizability(.contentSize)
.defaultPosition(.topTrailing)
// Menu bar extra
MenuBarExtra("Status", systemImage: "circle.fill") {
StatusMenu()
}
.menuBarExtraStyle(.window)
}
}
| Style | Use Case |
|---|---|
.automatic | Standard app windows |
.hiddenTitleBar | Content-focused (media players) |
.plain | Utility windows, panels |
.unified | Integrated toolbar appearance |
.unifiedCompact | Compact toolbar height |
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: Set(arrayLiteral: "main"))
.commands {
CommandGroup(replacing: .newItem) {
Button("New Document") {
// Handle new document
}
.keyboardShortcut("n")
}
}
@main
struct DocumentApp: App {
var body: some Scene {
DocumentGroup(newDocument: MyDocument()) { file in
DocumentView(document: file.$document)
}
.commands {
CommandGroup(after: .saveItem) {
Button("Export...") { }
.keyboardShortcut("e", modifiers: [.command, .shift])
}
}
}
}
struct MyDocument: FileDocument {
static var readableContentTypes: [UTType] { [.plainText] }
init(configuration: ReadConfiguration) throws { }
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { }
}
.toolbar {
// Leading items (macOS places these before title)
ToolbarItem(placement: .navigation) {
Button(action: goBack) {
Label("Back", systemImage: "chevron.left")
}
}
// Principal (centered)
ToolbarItem(placement: .principal) {
Picker("View Mode", selection: $viewMode) {
Label("Icons", systemImage: "square.grid.2x2").tag(ViewMode.icons)
Label("List", systemImage: "list.bullet").tag(ViewMode.list)
}
.pickerStyle(.segmented)
}
// Trailing items
ToolbarItemGroup(placement: .primaryAction) {
Button(action: share) {
Label("Share", systemImage: "square.and.arrow.up")
}
Button(action: toggleInspector) {
Label("Inspector", systemImage: "sidebar.trailing")
}
}
}
.toolbarRole(.editor) // or .browser, .automatic
.commands {
// Replace existing menu group
CommandGroup(replacing: .newItem) {
Button("New Project") { }
.keyboardShortcut("n")
Button("New from Template...") { }
.keyboardShortcut("n", modifiers: [.command, .shift])
}
// Add to existing group
CommandGroup(after: .sidebar) {
Button("Toggle Inspector") { }
.keyboardShortcut("i", modifiers: [.command, .option])
}
// Custom menu
CommandMenu("Canvas") {
Button("Zoom In") { }
.keyboardShortcut("+")
Button("Zoom Out") { }
.keyboardShortcut("-")
Divider()
Button("Fit to Window") { }
.keyboardShortcut("0")
}
}
MenuBarExtra("App Status", systemImage: statusIcon) {
VStack(alignment: .leading, spacing: 8) {
Text("Status: \(status)")
.font(.headline)
Divider()
Button("Open Main Window") {
openWindow(id: "main")
}
Button("Quit") {
NSApplication.shared.terminate(nil)
}
.keyboardShortcut("q")
}
.padding()
}
.menuBarExtraStyle(.window) // or .menu for simple dropdown
Always implement these when applicable:
| Action | Shortcut | Implementation |
|---|---|---|
| New | ⌘N | .keyboardShortcut("n") |
| Open | ⌘O | .keyboardShortcut("o") |
| Save | ⌘S | .keyboardShortcut("s") |
| Close | ⌘W | .keyboardShortcut("w") |
| Undo | ⌘Z | .keyboardShortcut("z") |
| Redo | ⇧⌘Z | .keyboardShortcut("z", modifiers: [.command, .shift]) |
| Cut | ⌘X | .keyboardShortcut("x") |
| Copy | ⌘C | .keyboardShortcut("c") |
| Paste | ⌘V | .keyboardShortcut("v") |
| Select All | ⌘A | .keyboardShortcut("a") |
| Find | ⌘F | .keyboardShortcut("f") |
| Preferences | ⌘, | .keyboardShortcut(",") |
| Hide | ⌘H | System handled |
| Quit | ⌘Q | System handled |
Button("Toggle Sidebar") {
toggleSidebar()
}
.keyboardShortcut("s", modifiers: [.command, .control])
// Function keys
Button("Refresh") { }
.keyboardShortcut(KeyEquivalent.init(Character(UnicodeScalar(NSF5FunctionKey)!)))
// Arrow keys
Button("Next") { }
.keyboardShortcut(.rightArrow)
| Size | Shape | Use Case |
|---|---|---|
| Mini | Rounded rect | Compact toolbars, dense UIs |
| Small | Rounded rect | Secondary controls, sidebars |
| Regular | Rounded rect | Primary controls (default) |
| Large | Capsule | Prominent actions |
| Extra Large | Capsule + Glass | Hero CTAs, onboarding |
// Size modifiers
Button("Action") { }
.controlSize(.mini) // Smallest
.controlSize(.small) // Compact
.controlSize(.regular) // Default
.controlSize(.large) // Prominent
.controlSize(.extraLarge) // Hero (macOS 15+)
// Primary action (prominent)
Button("Save Changes") { }
.buttonStyle(.borderedProminent)
.controlSize(.large)
// Secondary action
Button("Cancel") { }
.buttonStyle(.bordered)
// Tertiary/link style
Button("Learn More") { }
.buttonStyle(.plain)
.foregroundStyle(.link)
// Destructive
Button("Delete", role: .destructive) { }
.buttonStyle(.bordered)
// Toolbar button
Button { } label: {
Label("Add", systemImage: "plus")
}
.buttonStyle(.borderless)
// Standard text field
TextField("Search", text: $query)
.textFieldStyle(.roundedBorder)
// Search field with tokens
TextField("Search", text: $query)
.searchable(text: $query, tokens: $tokens) { token in
Label(token.name, systemImage: token.icon)
}
// Secure field
SecureField("Password", text: $password)
.textFieldStyle(.roundedBorder)
Table(items, selection: $selection) {
TableColumn("Name", value: \.name)
.width(min: 100, ideal: 150)
TableColumn("Date") { item in
Text(item.date, format: .dateTime)
}
.width(100)
TableColumn("Status") { item in
StatusBadge(status: item.status)
}
.width(80)
}
.tableStyle(.inset(alternatesRowBackgrounds: true))
.contextMenu(forSelectionType: Item.ID.self) { selection in
Button("Open") { }
Button("Delete", role: .destructive) { }
}
// Popover
Button("Info") {
showPopover = true
}
.popover(isPresented: $showPopover, arrowEdge: .bottom) {
InfoView()
.frame(width: 300, height: 200)
.padding()
}
// Sheet
.sheet(isPresented: $showSheet) {
SheetContent()
.frame(minWidth: 400, minHeight: 300)
}
// Alert
.alert("Delete Item?", isPresented: $showAlert) {
Button("Cancel", role: .cancel) { }
Button("Delete", role: .destructive) {
deleteItem()
}
} message: {
Text("This action cannot be undone.")
}
// Semantic styles (preferred)
Text("Title").font(.largeTitle) // 26pt bold
Text("Headline").font(.headline) // 13pt semibold
Text("Subheadline").font(.subheadline) // 11pt regular
Text("Body").font(.body) // 13pt regular
Text("Callout").font(.callout) // 12pt regular
Text("Caption").font(.caption) // 10pt regular
Text("Caption 2").font(.caption2) // 10pt regular
// Monospaced for code
Text("let x = 1").font(.system(.body, design: .monospaced))
// Foreground
.foregroundStyle(.primary) // Primary text
.foregroundStyle(.secondary) // Secondary text
.foregroundStyle(.tertiary) // Tertiary text
.foregroundStyle(.quaternary) // Quaternary text
// Backgrounds
.background(.background) // Window background
.background(.regularMaterial) // Translucent material
// Accent colors
.tint(.accentColor) // App accent color
.foregroundStyle(.link) // Clickable links
// Semantic colors
Color.red // System red (adapts to light/dark)
Color.blue // System blue
// Materials (adapt to background content)
.background(.ultraThinMaterial) // Most transparent
.background(.thinMaterial)
.background(.regularMaterial) // Default
.background(.thickMaterial)
.background(.ultraThickMaterial) // Least transparent
// Vibrancy in sidebars
List { }
.listStyle(.sidebar)
.scrollContentBackground(.hidden)
.background(.ultraThinMaterial)
// Standard spacing values
VStack(spacing: 8) { } // Standard
VStack(spacing: 16) { } // Section spacing
VStack(spacing: 20) { } // Group spacing
// Padding
.padding(8) // Tight
.padding(12) // Standard
.padding(16) // Comfortable
.padding(20) // Spacious
// Content margins
.contentMargins(16) // Uniform margins
.contentMargins(.horizontal, 20) // Horizontal only
// Respect toolbar safe area
.safeAreaInset(edge: .top) {
ToolbarContent()
}
// Ignore safe area for backgrounds
.ignoresSafeArea(.container, edges: .top)
// Content that should avoid toolbar
.safeAreaPadding(.top)
// Minimum 44x44 points for clickable elements
Button { } label: {
Image(systemName: "gear")
}
.frame(minWidth: 44, minHeight: 44)
// Use contentShape for larger hit areas
RoundedRectangle(cornerRadius: 8)
.frame(width: 200, height: 100)
.contentShape(Rectangle())
.onTapGesture { }
// Responsive to window size
GeometryReader { geometry in
if geometry.size.width > 600 {
HStack { content }
} else {
VStack { content }
}
}
// Grid that adapts
LazyVGrid(columns: [
GridItem(.adaptive(minimum: 150, maximum: 250))
], spacing: 16) {
ForEach(items) { ItemView(item: $0) }
}
// Labels and hints
Button { } label: {
Image(systemName: "plus")
}
.accessibilityLabel("Add item")
.accessibilityHint("Creates a new item in your library")
// Grouping related elements
VStack {
Text(item.title)
Text(item.subtitle)
}
.accessibilityElement(children: .combine)
// Custom actions
.accessibilityAction(named: "Delete") {
deleteItem()
}
// Focus management
@FocusState private var focusedField: Field?
TextField("Name", text: $name)
.focused($focusedField, equals: .name)
.onSubmit {
focusedField = .email
}
// Focusable custom views
.focusable()
.onMoveCommand { direction in
handleArrowKey(direction)
}
// Scales with user preference
Text("Content")
.dynamicTypeSize(.large ... .accessibility3)
// Fixed size when necessary (use sparingly)
Text("Fixed")
.dynamicTypeSize(.large)
@Environment(\.accessibilityReduceMotion) var reduceMotion
.animation(reduceMotion ? .none : .spring(), value: isExpanded)
// Alternative non-animated transitions
.transaction { transaction in
if reduceMotion {
transaction.animation = nil
}
}
@Environment(\.colorSchemeContrast) var contrast
// Increase contrast when needed
.foregroundStyle(contrast == .increased ? .primary : .secondary)
| Deprecated | Modern | Notes |
|---|---|---|
NavigationView | NavigationSplitView / NavigationStack | Split for macOS, Stack for simple flows |
.navigationViewStyle(.columns) | NavigationSplitView | Built-in column support |
List { }.listStyle(.sidebar) with NavigationLink | NavigationSplitView sidebar | Proper split view behavior |
.toolbar { ToolbarItem(...) } in detail | .toolbar on NavigationSplitView | Toolbar applies to correct scope |
NSWindowController | WindowGroup / Window | Pure SwiftUI window management |
NSMenu / NSMenuItem | .commands { } / CommandMenu | Declarative menus |
NSToolbar | .toolbar { } | SwiftUI toolbar API |
NSTouchBar | .touchBar { } | SwiftUI Touch Bar |
NSOpenPanel.begin() | .fileImporter() | SwiftUI file dialog |
NSSavePanel.begin() | .fileExporter() | SwiftUI save dialog |
.background(Color.clear) for materials | .background(.regularMaterial) | Proper material support |
| Custom blur effects | .glassEffect() (Tahoe) | Native Liquid Glass |
// Wrap AppKit view
struct NSViewWrapper: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
// Create and configure NSView
}
func updateNSView(_ nsView: NSView, context: Context) {
// Update when SwiftUI state changes
}
}
// Access NSWindow
.background(WindowAccessor { window in
window?.titlebarAppearsTransparent = true
})
.glassEffect() or appropriate materialNavigationSplitView used for multi-column layoutsDocumentGroup.borderedProminent.destructive role┌─────────────────────────────────────────────────────┐
│ Mini/Small/Medium │ Large/XLarge │
│ ┌──────────────────┐ │ ╭──────────────────╮ │
│ │ Rounded Rect │ │ │ Capsule │ │
│ └──────────────────┘ │ ╰──────────────────╯ │
│ │ │
│ Compact layouts │ Hero actions │
│ Toolbars, sidebars │ Onboarding, CTAs │
└─────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────┐
│ .automatic Standard window with titlebar │
│ .hiddenTitleBar Full content, titlebar hidden │
│ .plain No chrome, utility panels │
│ .unified Toolbar merges with titlebar │
│ .unifiedCompact Compact unified toolbar │
└─────────────────────────────────────────────────────┘
┌─────────────┬───────────────┬─────────────────────┐
│ Sidebar │ Content │ Detail │
│ │ │ │
│ Source │ List or │ Selected item │
│ List │ Grid │ properties │
│ │ │ │
│ Collections│ Items │ Inspector panel │
│ Folders │ Browse │ Edit view │
│ │ │ │
│ Min: 180 │ Flexible │ Min: 300 │
│ Max: 300 │ │ Ideal: 400+ │
└─────────────┴───────────────┴─────────────────────┘
NavigationSplitView (three-column)