Claude Cursor GitHub Copilot Skill

ios-hig-design

Design native iOS interfaces following Apple Human Interface Guidelines. Use when the user mentions "iPhone app", "iPad layout", "SwiftUI", "UIKit", "Dynamic Island", "safe areas", "HIG compliance", "SF Symbols", "haptic feedback", "iOS accessibility", "make my app feel native",

LLM Mart · 0 points · 2 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download wondelai-skills-plugins_wondelai-skills_skills_ios-hig-design-c172996.zip · 31 KB
Part of wondelai/skills — 183 skills

Install

skills CLI npx skills add https://github.com/wondelai/skills/tree/main/plugins/wondelai-skills/skills/ios-hig-design
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install wondelai-skills@llmmart
Git git clone https://github.com/wondelai/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole wondelai/skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

iOS Human Interface Guidelines Design Skill

Framework for designing native iOS interfaces that feel intuitive, consistent, and aligned with Apple's design philosophy. Based on Apple's Human Interface Guidelines, the definitive resource for apps that integrate seamlessly with iPhone, iPad, and the Apple ecosystem.

Core Principle

Apple's iOS design philosophy rests on three pillars: clarity (every element legible and purposeful), deference (the interface never overshadows the content it presents), and depth (layering, transitions, and realistic motion convey hierarchy and spatial relationships).

The foundation: The best iOS apps internalize this philosophy rather than following HIG rules mechanically. Native components, system conventions, and platform consistency aren't constraints---they're the reason iOS users trust and enjoy apps that feel like they belong.

Scoring

Goal: 10/10. Score 1 point per satisfied row of the Quick Diagnostic (6 rows), plus up to 4 points for native idiom: +1 semantic colors/text styles throughout (no hardcoded values), +1 system controls over custom reimplementations, +1 standard gestures and meaningful haptics, +1 SF Symbols and correct app-icon shape. Bands: 9-10 = native, accessible, adapts to Dark Mode and Dynamic Type, zero foreign patterns; 5-6 = works but leaks Android idioms or hardcodes color/size; <=3 = fails safe areas, touch targets, or VoiceOver. Always state the score and the specific improvements needed to reach 10/10.

iOS Design Framework

1. Layout & Safe Areas

Core concept: iOS devices have specific screen dimensions, safe area insets, and hardware intrusions (notch, Dynamic Island, home indicator) that every layout must respect.

Key insights:

  • Design for the smallest screen first (375pt width, iPhone SE)
  • Safe areas protect content from the notch, Dynamic Island, and home indicator---never place interactive elements under them
  • Standard content margins: 16-20pt from screen edges; spacing increments: 8 / 16 / 24pt
  • Minimum touch target and list row height: 44pt

Product applications:

Context Layout Pattern Example
Status bar 20pt classic, 44-54pt on Dynamic Island devices Time, signal, battery area
Navigation bar 44pt standard row + ~52pt large title (~96pt total) Back button, title, actions
Content area Flexible, scrollable, respects safe area Main app content
Tab bar 49pt height, translucent with blur 2-5 primary destinations
Home indicator 34pt inset at bottom System gesture area

Copy patterns:

  • Use VStack { }, which respects safe areas by default
  • Use .ignoresSafeArea() only for backgrounds and decoration, never interactive content
  • Test on multiple sizes, including iPhone SE and Pro Max

See references/navigation.md when laying out chrome---exact nav bar and tab bar dimensions, large-title behavior, and split-view rules.

2. Typography & Dynamic Type

Core concept: iOS uses the San Francisco (SF Pro) typeface with semantic text styles that automatically scale for accessibility via Dynamic Type. Semantic styles give consistent platform hierarchy; Dynamic Type lets users read at their preferred size without breaking layouts.

Key insights:

  • Large Title: 34pt Bold; Title: 17pt Medium; Body: 17pt Regular; Caption: 12-13pt; secondary text: 15pt at 60% opacity
  • Minimum text size 11pt (captions/secondary only)
  • Line height at least 1.3x font size; optimal line length 35-50 characters on mobile
  • Always left-aligned, non-justified text

Product applications:

Context Typography Pattern Example
Screen titles .largeTitle or .title style Large title collapses on scroll
Body content .body style, 17pt List items, descriptions
Secondary info .subheadline or .footnote Timestamps, metadata
Tab labels 10pt SF text Tab bar item labels
Buttons .body weight semibold Primary action text

Copy patterns:

  • Use .font(.title), .font(.body), .font(.caption) instead of hardcoded sizes; @ScaledMetric for custom spacing that scales
  • Prefer weight and color variation over extreme size differences for hierarchy
  • Test all layouts at the largest Dynamic Type size

See references/typography.md when matching a design to exact specs---per-style hex values and the Dark Mode text-color mapping.

3. Color & Dark Mode

Core concept: iOS provides semantic system colors that automatically adapt between light and dark appearances while preserving contrast and hierarchy.

Key insights:

  • Use Color(.label), Color(.secondaryLabel), Color(.systemBackground) instead of hardcoded colors
  • Color(.systemBlue) is the default tint; .systemRed for destructive actions; .systemGreen for success
  • Dark Mode inverts text colors and shifts backgrounds darker while keeping relative hierarchy; accent colors need lower brightness and higher saturation to pop
  • Maintain 4.5:1 contrast in both modes; preview both during development

Product applications:

Context Color Pattern Example
Primary text Color(.label) Adapts white/black per mode
Secondary text Color(.secondaryLabel) 60% opacity in both modes
Backgrounds Color(.systemBackground) / .secondarySystemBackground Layered depth
Destructive actions Color(.systemRed) Delete buttons, warnings
Interactive tint App accent color or .systemBlue Links, toggle states

Copy patterns:

  • Use .preferredColorScheme(.light) and .dark in previews to test both modes side by side
  • Define custom colors in the Asset Catalog with light/dark variants, not in code
  • Never assume a background is white or black; test with Increase Contrast enabled

See references/colors-depth.md when checking contrast---the full WCAG ratio table (normal text, large text, UI components) and the tertiary/grouped-background tokens.

4. Navigation Patterns

Core concept: iOS uses a layered navigation model: tab bars for primary destinations, navigation stacks for hierarchical drilling, and modals for focused tasks. Users rely on these patterns to know where they are and how to get back; reinventing them makes the app feel foreign.

Key insights:

  • Tab bar: 2-5 primary destinations, always visible, remembers state per tab
  • Navigation bar: back button (top-left), title (center or large), actions (top-right); large title collapses on scroll
  • Modals for focused tasks; dismiss via swipe-down or explicit close button
  • Never use hamburger menus---iOS users expect tab bars
  • Search bar can sit below the nav bar, hidden until pulled down

Product applications:

Context Navigation Pattern Example
App structure Tab bar with 3-5 tabs Home, Search, Profile
Content hierarchy Push navigation (drill-down) List > Detail > Edit
Focused tasks Modal presentation Compose, settings, filters
Search Pull-down search bar Spotlight-style search
Split view iPad sidebar + detail Mail, Notes on iPad

Copy patterns:

  • Back button text should be the previous screen's title, not "Back"
  • Tab labels are single words ("Home", "Search"); modal titles describe the task ("New Message", "Edit Profile")
  • Use NavigationStack (not deprecated NavigationView) in SwiftUI

5. Controls & Inputs

Core concept: iOS provides a rich library of native controls (buttons, lists, toggles, pickers, menus, text fields) that users already understand and expect.

Why it works: Native controls ship with built-in accessibility, haptics, and learned interaction patterns; custom controls create friction and miss edge cases Apple already solved.

Key insights:

  • Page-level actions go in the nav bar (top) or action bar (bottom)
  • Primary buttons are filled with the theme color; secondary are outlined or text-only
  • Destructive actions use red and require confirmation when irreversible
  • Lists (table views) are the fundamental iOS content pattern
  • Match keyboard type to input (.emailAddress, .phonePad, .URL); use .textContentType for autofill

Product applications:

Context Control Pattern Example
Forms Native text fields with proper keyboard types Email field with @ keyboard
Settings Grouped list with toggles, disclosure iOS Settings style
Selection Picker, segmented control, or action sheet Date picker, sort options
Destructive actions Red button + confirmation alert "Delete Account" flow
Context actions Long press menu or swipe actions Edit, share, delete on row

Copy patterns:

  • Pair .keyboardType(.emailAddress) with .textContentType(.emailAddress)
  • Prefer system confirmations: .alert() or .confirmationDialog(); use .swipeActions on list rows
  • Place primary action buttons at the bottom of the screen within thumb reach

Ethical boundary: Never disguise ads as native controls or make destructive actions easy to trigger accidentally.

See references/components.md when building a specific control---button styles, list/section variants, picker vs segmented-control choice, and confirmation-dialog wiring. See references/keyboard-input.md when building forms---keyboard-type table, input accessory views, and hardware-keyboard shortcuts.

6. Accessibility

Core concept: iOS has world-class accessibility features (VoiceOver, Dynamic Type, Switch Control, Voice Control), and every app must support them as a first-class concern. App Store review can reject apps that are unusable with assistive technologies.

Key insights:

  • Every interactive element needs an .accessibilityLabel; use .accessibilityValue for state and .accessibilityHint for effect
  • Group related elements with .accessibilityElement(children: .combine)
  • Support Dynamic Type at all sizes; test at the largest setting
  • Honor the 44 x 44pt touch target (section 1) and 4.5:1 contrast minimum (section 3) as accessibility requirements, not just visual defaults
  • Never convey meaning through color alone

Product applications:

Context Accessibility Pattern Example
Icons .accessibilityLabel("Favorite") Heart icon with label
Sliders .accessibilityValue("\(Int(volume * 100))%") Volume control
Buttons .accessibilityHint("Shares this item") Share button
Groups .accessibilityElement(children: .combine) Avatar + name row
Images Decorative: .accessibilityHidden(true) Background patterns

Copy patterns:

  • Write labels as nouns ("Favorite", "Settings"); write hints as actions ("Shares this item with others")
  • Test the complete app flow using only VoiceOver
  • Use Xcode's Accessibility Inspector to audit contrast and labels

See references/accessibility.md before sign-off---the full VoiceOver-implementation patterns and a pre-ship accessibility checklist to run the app against.

7. Icons & Images

Core concept: iOS uses SF Symbols as the standard icon system and requires app icons in specific sizes with the signature superellipse ("squircle") mask applied automatically. SF Symbols align optically with San Francisco text and scale with Dynamic Type, so they stay aligned and crisp at every weight and size.

Key insights:

  • Use SF Symbols (Image(systemName:)) for all standard icons---they scale with text
  • App icons: export 1024x1024px square; iOS applies the squircle mask (corner radius = side x 0.222 with 61% smoothing)
  • iOS 18+ supports light, dark, and tinted icon variants
  • Avoid text in app icons; keep designs simple with recognizable silhouettes

Product applications:

Context Icon Pattern Example
Tab bar SF Symbols, filled variant for selected house.fill, magnifyingglass
Navigation bar SF Symbols at regular weight gear, plus, ellipsis
List accessories SF Symbols, secondary color chevron.right, checkmark
App icon 1024px square, simple bold design Single recognizable glyph

Copy patterns:

  • Use Image(systemName: "heart.fill"); apply .symbolRenderingMode(.hierarchical) for multi-color depth
  • Size symbols relative to text with .imageScale(.large) or .font()
  • Browse symbols in the free SF Symbols app from Apple

Ethical boundary: Never use icons that suggest functionality that doesn't exist or contradict iOS conventions (trash = delete, not archive).

See references/app-icons.md when exporting the app icon---per-context size table, exact squircle math, and the iOS 18 light/dark/tinted variant requirements.

8. Gestures & Haptics

Core concept: iOS defines standard gestures (swipe back, pull to refresh, long press for context menu) and haptic feedback patterns that must be respected and never overridden. Gestures are muscle memory---repurposing swipe-back or pull-to-refresh disorients users; haptics give invisible confirmation that an action registered.

Key insights:

  • Never override: swipe-right-from-edge (back), swipe-down on modal (dismiss), pull-down on list (refresh)
  • Swipe-left on rows reveals actions; long press shows context menus; pinch zooms images and maps
  • Three haptic types: impact (physical actions), notification (outcomes), selection (UI changes)
  • Haptics should be subtle and meaningful---never constant or annoying

Product applications:

Context Gesture/Haptic Pattern Example
Navigation Swipe right from left edge System back gesture
Modals Swipe down to dismiss Sheet dismissal
Lists Pull to refresh, swipe for actions Refresh content, delete row
Confirmation .success haptic on completion Payment confirmed
Selection Selection haptic on toggle/pick Picker wheel scroll

Copy patterns:

  • UIImpactFeedbackGenerator(style: .medium) for physical interactions; UISelectionFeedbackGenerator() for UI state changes
  • UINotificationFeedbackGenerator() with .success, .warning, .error for outcomes
  • Call .prepare() before triggering haptics to minimize latency

See references/gestures.md when wiring gestures or animation---the full reserved-gesture table, haptic-generator recipes, and standard animation timing/curves.

Common Mistakes

Mistake Why It Fails Fix
Overriding standard gestures Breaks muscle memory for swipe-back, pull-refresh Use system gestures as intended; custom gestures only for supplementary actions
Touch targets under 44pt Mis-taps, frustration, accessibility failures Make all interactive elements at least 44 x 44pt
Ignoring safe areas Content hidden behind notch, Dynamic Island, home indicator Respect safe area insets; .ignoresSafeArea() only for backgrounds
Using Android patterns on iOS Hamburger menus, top tabs, FABs feel foreign Use tab bars, bottom sheets, native iOS components
Skipping Dark Mode Broken layouts, unreadable text for Dark Mode users Use semantic colors; test both appearances
Hardcoding font sizes Breaks Dynamic Type, excludes low-vision users Use semantic text styles (.title, .body, .caption) throughout
Low contrast text Fails WCAG AA; unreadable in sunlight Maintain 4.5:1 minimum; test with Increase Contrast
Not testing on real devices Simulator misses performance, haptics, safe area edge cases Test on physical devices at smallest and largest sizes

Quick Diagnostic

Audit any iOS interface design:

Question If No Action
Does the layout respect safe areas on all device sizes? Content hidden behind hardware Audit on iPhone SE and Pro Max; fix insets
Are all touch targets at least 44 x 44pt? Mis-taps and accessibility failures Increase tap areas; .frame(minWidth: 44, minHeight: 44)
Does the app work fully in Dark Mode? Broken/unreadable UI for Dark Mode users Replace hardcoded colors with semantic system colors
Does text scale properly with Dynamic Type? Excludes low-vision users Use semantic text styles; test at largest setting
Can a VoiceOver user complete every task? App inaccessible to blind users Add labels, values, hints to all interactive elements
Are navigation patterns native iOS? App feels foreign Replace hamburger menus with tab bars; standard push/modal navigation

Beyond Core UI

The eight framework sections above each link their deep-dive reference inline at the point of need. Three further references cover system surfaces that sit outside the on-screen UI:

  • See references/privacy-permissions.md when the app requests camera, location, contacts, or any protected resource---request timing, pre-permission priming screens, usage-string wording, and the denied-permission recovery path.
  • See references/widgets-extensions.md when building a Home Screen widget, App Clip, Live Activity, or share/action extension---supported sizes and per-surface design constraints.
  • See references/system-integration.md when wiring the app into the OS---Siri/Shortcuts intents, Handoff, drag-and-drop, universal links, and Spotlight indexing.

Further Reading

For the complete guidelines, platform-specific guidance, and latest updates:

About the Author

The Apple Human Interface Guidelines are written and maintained by Apple's Human Interface Design team, one of the most influential design organizations in technology. First published in 1984 alongside the original Macintosh, the HIG established principles---direct manipulation, consistency, user control---that defined graphical interface design and have evolved through iPhone, iPad, Apple Watch, and Vision Pro. It remains freely available at developer.apple.com as the essential reference for Apple platforms.

Files (skills)
  • references
    • accessibility.md 1.3 KB
      # iOS Accessibility
      
      ## VoiceOver Support
      
      Every interactive element needs accessibility labels:
      
      ```swift
      // Accessible label (what it is)
      Image(systemName: "heart.fill")
          .accessibilityLabel("Favorite")
      
      // Accessible value (current state)
      Slider(value: $volume)
          .accessibilityLabel("Volume")
          .accessibilityValue("\(Int(volume * 100))%")
      
      // Accessible hint (what it does)
      Button("Share") { share() }
          .accessibilityHint("Shares this item with others")
      
      // Group related elements
      HStack {
          Image(systemName: "person")
          Text("John Doe")
      }
      .accessibilityElement(children: .combine)
      ```
      
      ## Dynamic Type
      
      Support user font size preferences:
      
      ```swift
      // Use semantic text styles (automatically scales)
      Text("Content")
          .font(.body)
      
      // For custom fonts, scale with Dynamic Type
      @ScaledMetric var customSize: CGFloat = 16
      
      Text("Custom")
          .font(.system(size: customSize))
      ```
      
      ## High Contrast Mode
      
      ```swift
      @Environment(\.colorSchemeContrast) var contrast
      
      var textColor: Color {
          contrast == .increased ? .primary : .secondary
      }
      ```
      
      ## Accessibility Checklist
      
      - [ ] All images have accessibility labels
      - [ ] Touch targets are minimum 44×44pt
      - [ ] Text scales with Dynamic Type
      - [ ] Color contrast meets WCAG standards
      - [ ] Motion can be reduced
      - [ ] VoiceOver navigation is logical
      - [ ] Don't rely solely on color to convey meaning
      
    • app-icons.md 704 B
      # iOS App Icons
      
      ## Required Sizes
      
      | Size | Usage |
      |------|-------|
      | 1024 × 1024px | App Store |
      | 180 × 180px | iPhone home screen (@3x) |
      | 120 × 120px | iPhone home screen (@2x), Spotlight |
      | 167 × 167px | iPad Pro |
      | 152 × 152px | iPad (@2x) |
      | 87 × 87px | Settings |
      
      ## Icon Shape
      
      iOS applies a **superellipse** ("squircle") mask automatically. Export icons as squares.
      
      For custom border matching the shape:
      - Corner radius = side length × 0.222
      - Corner smoothing = 61% (iOS preset in Figma)
      
      ## Icon Guidelines
      
      - Simple, recognizable silhouette
      - Works at all sizes (remove fine details for small sizes)
      - Consider light, dark, and tinted variants (iOS 18+)
      - Avoid text in icons
      
    • colors-depth.md 1.5 KB
      # iOS Colors & Theming Reference
      
      SKILL.md section 3 covers the core semantic palette (`label`, `secondaryLabel`, `systemBackground`, `systemBlue`/`systemRed`/`systemGreen`) and the three Dark Mode adaptation rules. This file adds what it does not carry: the extra layering tokens and the full WCAG contrast table.
      
      ## Extra Semantic Tokens (beyond the core set)
      
      For multi-level hierarchy and grouped layouts, reach past the core six:
      
      ```swift
      Color(.tertiaryLabel)              // 3rd-level text (placeholders, disabled)
      Color(.quaternaryLabel)            // 4th-level (separators, faint glyphs)
      Color(.secondarySystemBackground)  // elevated cards / grouped table sections
      Color(.tertiarySystemBackground)   // a layer above secondary
      Color(.systemGroupedBackground)    // base behind grouped lists (Settings style)
      Color(.separator)                  // hairline dividers (already mode-aware)
      ```
      
      Use the grouped-background family for `.insetGrouped` lists; use the plain `systemBackground` family for full-bleed content.
      
      ## Color Contrast (full WCAG table)
      
      SKILL.md states the 4.5:1 floor for body text. The complete set of minimums:
      
      | Content | Minimum ratio |
      |---------|---------------|
      | Normal text (< 18pt, or < 14pt bold) | 4.5:1 |
      | Large text (>= 18pt, or >= 14pt bold) | 3:1 |
      | UI components and graphical objects (icons, control borders, focus rings) | 3:1 |
      
      Verify with Xcode's Accessibility Inspector color contrast check, in both light and dark modes and with Increase Contrast enabled.
      
    • components.md 5.7 KB
      # iOS UI Components
      
      ## Buttons
      
      **Page-level actions**: Appear in nav bar (top) or action bar (bottom)
      
      ```
      ┌─────────────────────────────────┐
      │ Cancel              Save  Edit  │  ← Nav bar actions
      ├─────────────────────────────────┤
      │                                 │
      │         Page Content            │
      │                                 │
      ├─────────────────────────────────┤
      │   Share    Copy    Delete       │  ← Action bar
      └─────────────────────────────────┘
      ```
      
      **On-page buttons**: Often appear on cards or sections
      
      - Primary buttons: Filled with theme color
      - Secondary buttons: Outlined or text-only
      - Destructive actions: Red text/color
      
      ## Lists (Table Views)
      
      Lists are fundamental to iOS design. Configure each row with:
      
      **Left side** (optional):
      - Icon or image
      
      **Center**:
      - Primary text (17pt regular)
      - Secondary text (15pt or 12pt, lighter color)
      - Tertiary text (if needed)
      
      **Right side** (choose one):
      - Chevron (→) — navigates to detail screen
      - Text + Chevron — shows current value, tappable to change
      - Checkmark (✓) — single selection from list
      - Switch — toggle on/off
      - Text button — action link
      
      ## Input Controls
      
      Most inputs are styled as list items:
      
      **Text Input**:
      ```
      ┌─────────────────────────────────┐
      │ Email                           │  ← Hint text disappears on typing
      └─────────────────────────────────┘
      ```
      
      **Switch**:
      ```
      ┌─────────────────────────────────┐
      │ Notifications          [====○] │
      └─────────────────────────────────┘
      ```
      
      **Date/Time Picker**:
      ```
      ┌─────────────────────────────────┐
      │ Date          [ Jan 15, 2025 ] │  ← Light gray button, expands inline
      └─────────────────────────────────┘
      ```
      
      **Picker Screen Pattern**:
      - List item shows current value + chevron
      - Tapping navigates to selection screen
      - Selected option marked with checkmark
      
      ## Pull-Down Menus
      
      For short option lists without navigation:
      
      ```swift
      Menu("Options") {
          Button("Edit", action: edit)
          Button("Share", action: share)
          Divider()
          Button("Delete", role: .destructive, action: delete)
      }
      ```
      
      ## Touch Targets & Spacing
      
      ### Minimum Touch Target
      
      **44 × 44 points** — This is non-negotiable for all interactive elements.
      
      ```swift
      Button("Tap") {
          // Action
      }
      .frame(minWidth: 44, minHeight: 44)
      ```
      
      ### Standard Spacing Values
      
      | Spacing | Usage |
      |---------|-------|
      | 8pt | Tight spacing (related elements) |
      | 16pt | Standard spacing (sections) |
      | 20pt | Screen edge margins |
      | 24pt | Loose spacing (major sections) |
      
      ```swift
      VStack(spacing: 16) {
          // Standard component spacing
      }
      ```
      
      ---
      
      ## Menu Patterns
      
      ### Context Menus
      
      Long-press to reveal contextual actions:
      
      ```swift
      Text("Item")
          .contextMenu {
              Button("Edit", action: edit)
              Button("Share", action: share)
              Divider()
              Button("Delete", role: .destructive, action: delete)
          }
      ```
      
      **Guidelines:**
      - Group related actions
      - Use dividers between groups
      - Destructive actions at bottom, marked red
      - Include icons where helpful
      
      ### Pull-Down Menus
      
      Tap to reveal options without navigation:
      
      ```swift
      Menu("Options") {
          Button("Sort by Name", action: sortByName)
          Button("Sort by Date", action: sortByDate)
          Divider()
          Menu("Filter") {
              Button("Active", action: filterActive)
              Button("Completed", action: filterCompleted)
          }
      }
      ```
      
      **When to use:**
      - 3-6 options that don't need full screen
      - Actions that don't require additional input
      - Sorting, filtering, view options
      
      ### Action Sheets
      
      For important decisions requiring attention:
      
      ```swift
      .confirmationDialog("Choose Action", isPresented: $showingSheet) {
          Button("Camera") { }
          Button("Photo Library") { }
          Button("Cancel", role: .cancel) { }
      }
      ```
      
      **Guidelines:**
      - Title is optional (use for clarity)
      - Limit to 5-6 actions
      - Cancel is always last
      - Destructive actions in red
      
      ---
      
      ## Confirmation Dialogs
      
      ### When to Confirm
      
      | Action | Needs Confirmation? |
      |--------|---------------------|
      | Delete single item | Sometimes (if permanent) |
      | Delete multiple items | Yes |
      | Discard unsaved changes | Yes |
      | Log out | Usually not |
      | Send message | No |
      | Purchase | Yes (final step) |
      
      ### Alert Structure
      
      ```swift
      .alert("Delete Item?", isPresented: $showingAlert) {
          Button("Delete", role: .destructive, action: deleteItem)
          Button("Cancel", role: .cancel) { }
      } message: {
          Text("This action cannot be undone.")
      }
      ```
      
      **Guidelines:**
      - Title: Clear action question
      - Message: Explain consequences (brief)
      - Buttons: Specific verbs, not just "OK"
      - Destructive button on left (less expected position)
      - Cancel on right (easy to tap)
      
      ### Undo vs. Confirm
      
      **Prefer undo when:**
      - Action is recoverable
      - Speed matters
      - Confirmations would be annoying
      
      **Require confirmation when:**
      - Action is irreversible
      - Data/money loss possible
      - Action affects others
      
      ```swift
      // Undo pattern
      .toolbar {
          Button("Undo") { undoManager.undo() }
      }
      
      // Swipe to delete with undo toast
      .swipeActions(edge: .trailing) {
          Button("Delete", role: .destructive) {
              withAnimation {
                  deleteWithUndo(item)
              }
          }
      }
      ```
      
    • gestures.md 1.2 KB
      # iOS Gestures & Interactions
      
      ## Standard Gestures (Never Override)
      
      | Gesture | Standard Action |
      |---------|-----------------|
      | Swipe right from left edge | Navigate back |
      | Swipe down on modal | Dismiss modal |
      | Pull down on list | Refresh content |
      | Swipe left on row | Reveal actions (delete, etc.) |
      | Pinch | Zoom in/out |
      | Long press | Context menu |
      
      ## Haptic Feedback
      
      Provide tactile feedback for meaningful interactions:
      
      ```swift
      // Impact feedback (physical actions)
      let impact = UIImpactFeedbackGenerator(style: .medium)
      impact.impactOccurred()
      
      // Notification feedback (outcomes)
      let notification = UINotificationFeedbackGenerator()
      notification.notificationOccurred(.success)  // or .warning, .error
      
      // Selection feedback (UI changes)
      let selection = UISelectionFeedbackGenerator()
      selection.selectionChanged()
      ```
      
      ## Animation Guidelines
      
      - Use spring animations for natural, bouncy feel
      - Respect `reduceMotion` accessibility setting
      - Keep animations brief and purposeful
      
      ```swift
      @Environment(\.accessibilityReduceMotion) var reduceMotion
      
      var animation: Animation {
          reduceMotion ? .none : .spring()
      }
      
      withAnimation(animation) {
          // Animate property changes
      }
      ```
      
    • keyboard-input.md 11.5 KB
      # iOS Keyboard & Input Patterns
      
      Comprehensive guide to keyboard handling, text input, and hardware keyboard support.
      
      
      ## Table of Contents
      1. [Software Keyboard Types](#software-keyboard-types)
      2. [Text Content Types](#text-content-types)
      3. [Input Accessory Views](#input-accessory-views)
      4. [Keyboard Avoidance](#keyboard-avoidance)
      5. [Hardware Keyboard Support](#hardware-keyboard-support)
      6. [Text Editing](#text-editing)
      7. [Secure Text Entry](#secure-text-entry)
      8. [Search Input](#search-input)
      9. [Common Patterns](#common-patterns)
      
      ---
      
      ## Software Keyboard Types
      
      ### Choosing the Right Keyboard
      
      Match the keyboard to the expected input:
      
      | Input Type | Keyboard | UIKeyboardType |
      |------------|----------|----------------|
      | General text | Default | `.default` |
      | Email | Email-optimized (@ and . prominent) | `.emailAddress` |
      | URL | URL-optimized (/, .com) | `.URL` |
      | Phone number | Number pad | `.phonePad` |
      | Numeric (with punctuation) | Numbers + punctuation | `.numbersAndPunctuation` |
      | Numeric only | Decimal pad | `.decimalPad` |
      | Twitter handle | Twitter keyboard | `.twitter` |
      | Web search | Search keyboard | `.webSearch` |
      | ASCII only | ASCII-capable | `.asciiCapable` |
      
      ### SwiftUI Implementation
      
      ```swift
      TextField("Email", text: $email)
          .keyboardType(.emailAddress)
          .textContentType(.emailAddress)
          .autocapitalization(.none)
          .disableAutocorrection(true)
      ```
      
      ### UIKit Implementation
      
      ```swift
      textField.keyboardType = .emailAddress
      textField.textContentType = .emailAddress
      textField.autocapitalizationType = .none
      textField.autocorrectionType = .no
      ```
      
      ---
      
      ## Text Content Types
      
      Enable autofill by specifying content types:
      
      | Content | textContentType | Enables |
      |---------|-----------------|---------|
      | Name | `.name` | Contact autofill |
      | Given name | `.givenName` | |
      | Family name | `.familyName` | |
      | Email | `.emailAddress` | Email autofill |
      | Phone | `.telephoneNumber` | Phone autofill |
      | Address | `.streetAddressLine1` | Address autofill |
      | City | `.addressCity` | |
      | State | `.addressState` | |
      | ZIP | `.postalCode` | |
      | Country | `.countryName` | |
      | Credit card | `.creditCardNumber` | Camera card scanning |
      | Username | `.username` | Keychain autofill |
      | Password | `.password` | Keychain autofill |
      | New password | `.newPassword` | Password generation |
      | One-time code | `.oneTimeCode` | SMS autofill |
      
      ### Password and Login Fields
      
      ```swift
      // Login form
      TextField("Email", text: $email)
          .textContentType(.username)
          .keyboardType(.emailAddress)
      
      SecureField("Password", text: $password)
          .textContentType(.password)
      
      // Registration form
      SecureField("Create Password", text: $newPassword)
          .textContentType(.newPassword)
      ```
      
      ### One-Time Code (2FA)
      
      ```swift
      TextField("Verification Code", text: $code)
          .textContentType(.oneTimeCode)
          .keyboardType(.numberPad)
      ```
      
      iOS automatically suggests codes from SMS messages when this content type is set.
      
      ---
      
      ## Input Accessory Views
      
      ### When to Use
      
      Input accessory views appear above the keyboard for:
      - Navigation between fields (Previous/Next)
      - Custom actions (Done, formatting buttons)
      - Context-specific tools
      
      ### Standard Toolbar Pattern
      
      ```swift
      struct FormTextField: View {
          @Binding var text: String
          @FocusState private var isFocused: Bool
      
          var body: some View {
              TextField("Value", text: $text)
                  .focused($isFocused)
                  .toolbar {
                      ToolbarItemGroup(placement: .keyboard) {
                          Spacer()
                          Button("Done") {
                              isFocused = false
                          }
                      }
                  }
          }
      }
      ```
      
      ### Multi-Field Navigation
      
      ```swift
      struct FormView: View {
          @FocusState private var focusedField: Field?
      
          enum Field {
              case firstName, lastName, email
          }
      
          var body: some View {
              Form {
                  TextField("First Name", text: $firstName)
                      .focused($focusedField, equals: .firstName)
      
                  TextField("Last Name", text: $lastName)
                      .focused($focusedField, equals: .lastName)
      
                  TextField("Email", text: $email)
                      .focused($focusedField, equals: .email)
              }
              .toolbar {
                  ToolbarItemGroup(placement: .keyboard) {
                      Button(action: focusPrevious) {
                          Image(systemName: "chevron.up")
                      }
                      .disabled(!canFocusPrevious)
      
                      Button(action: focusNext) {
                          Image(systemName: "chevron.down")
                      }
                      .disabled(!canFocusNext)
      
                      Spacer()
      
                      Button("Done") {
                          focusedField = nil
                      }
                  }
              }
          }
      }
      ```
      
      ---
      
      ## Keyboard Avoidance
      
      ### Automatic Behavior (SwiftUI)
      
      SwiftUI automatically adjusts for keyboard in most cases:
      - ScrollViews scroll to keep focused field visible
      - Safe area adjusts for keyboard height
      
      ### Manual Keyboard Handling
      
      ```swift
      struct KeyboardAdaptive: ViewModifier {
          @State private var keyboardHeight: CGFloat = 0
      
          func body(content: Content) -> some View {
              content
                  .padding(.bottom, keyboardHeight)
                  .onReceive(Publishers.keyboardHeight) { height in
                      withAnimation(.easeOut(duration: 0.25)) {
                          keyboardHeight = height
                      }
                  }
          }
      }
      ```
      
      ### Best Practices
      
      1. **Scroll to show field** - Focused field should be visible
      2. **Don't cover important actions** - Submit buttons should remain accessible
      3. **Animate adjustments** - Match keyboard animation (0.25s ease-out)
      4. **Test on different devices** - Keyboard heights vary
      
      ---
      
      ## Hardware Keyboard Support
      
      ### Why It Matters
      
      iPads commonly use hardware keyboards. Apps should:
      - Support standard keyboard shortcuts
      - Provide discoverability
      - Not break when hardware keyboard is attached
      
      ### Standard Shortcuts to Support
      
      | Shortcut | Action | Notes |
      |----------|--------|-------|
      | ⌘N | New item | Standard creation |
      | ⌘S | Save | |
      | ⌘⌫ | Delete | With confirmation |
      | ⌘F | Find/Search | |
      | ⌘Z | Undo | |
      | ⌘⇧Z | Redo | |
      | ⌘C/⌘V/⌘X | Copy/Paste/Cut | |
      | ⌘, | Settings/Preferences | |
      | ⌘W | Close window/modal | |
      | Escape | Cancel/dismiss | |
      | Tab | Next field | |
      | ⇧Tab | Previous field | |
      | Return | Submit form | When appropriate |
      
      ### SwiftUI Keyboard Shortcuts
      
      ```swift
      struct ContentView: View {
          var body: some View {
              NavigationStack {
                  ItemList()
                      .toolbar {
                          Button("New Item", action: createItem)
                              .keyboardShortcut("n", modifiers: .command)
                      }
              }
          }
      }
      
      // For custom shortcuts in list items
      List {
          ForEach(items) { item in
              ItemRow(item: item)
          }
      }
      .onDeleteCommand(perform: deleteSelected)  // ⌘⌫
      ```
      
      ### Keyboard Shortcut Discoverability
      
      Hold ⌘ to show available shortcuts. Ensure your shortcuts appear:
      
      ```swift
      Button("Save", action: save)
          .keyboardShortcut("s", modifiers: .command)
          // Appears in keyboard shortcut overlay
      ```
      
      ---
      
      ## Text Editing
      
      ### Autocapitalization
      
      | Style | Use For |
      |-------|---------|
      | `.sentences` | General text, messages |
      | `.words` | Names, titles |
      | `.allCharacters` | Codes, abbreviations |
      | `.none` | Email, usernames, URLs |
      
      ### Autocorrection
      
      | Setting | Use For |
      |---------|---------|
      | Enabled (default) | Prose, messages |
      | Disabled | Code, usernames, specific values |
      
      ```swift
      TextField("Username", text: $username)
          .autocapitalization(.none)
          .disableAutocorrection(true)
      ```
      
      ### Text Input Traits Summary
      
      ```swift
      TextField("Email", text: $email)
          .keyboardType(.emailAddress)      // Keyboard layout
          .textContentType(.emailAddress)   // Autofill hint
          .autocapitalization(.none)        // No auto-caps
          .disableAutocorrection(true)      // No autocorrect
          .textInputAutocapitalization(.never) // iOS 15+
      ```
      
      ---
      
      ## Secure Text Entry
      
      ### Password Fields
      
      ```swift
      SecureField("Password", text: $password)
          .textContentType(.password)
      ```
      
      ### Show/Hide Toggle Pattern
      
      ```swift
      struct PasswordField: View {
          @Binding var password: String
          @State private var isSecure = true
      
          var body: some View {
              HStack {
                  if isSecure {
                      SecureField("Password", text: $password)
                  } else {
                      TextField("Password", text: $password)
                  }
      
                  Button(action: { isSecure.toggle() }) {
                      Image(systemName: isSecure ? "eye.slash" : "eye")
                          .foregroundColor(.secondary)
                  }
              }
              .textContentType(.password)
          }
      }
      ```
      
      ---
      
      ## Search Input
      
      ### Search Field Behavior
      
      ```swift
      struct SearchView: View {
          @State private var searchText = ""
      
          var body: some View {
              NavigationStack {
                  List(filteredItems) { item in
                      ItemRow(item: item)
                  }
                  .searchable(
                      text: $searchText,
                      placement: .navigationBarDrawer(displayMode: .always),
                      prompt: "Search items"
                  )
              }
          }
      }
      ```
      
      ### Search Suggestions
      
      ```swift
      .searchable(text: $searchText) {
          ForEach(suggestions) { suggestion in
              Text(suggestion.name)
                  .searchCompletion(suggestion.name)
          }
      }
      ```
      
      ---
      
      ## Common Patterns
      
      ### Form with All Best Practices
      
      ```swift
      struct RegistrationForm: View {
          @State private var email = ""
          @State private var password = ""
          @State private var confirmPassword = ""
          @FocusState private var focusedField: Field?
      
          enum Field: Hashable {
              case email, password, confirmPassword
          }
      
          var body: some View {
              Form {
                  Section("Account") {
                      TextField("Email", text: $email)
                          .keyboardType(.emailAddress)
                          .textContentType(.username)
                          .autocapitalization(.none)
                          .disableAutocorrection(true)
                          .focused($focusedField, equals: .email)
                          .submitLabel(.next)
                          .onSubmit { focusedField = .password }
      
                      SecureField("Password", text: $password)
                          .textContentType(.newPassword)
                          .focused($focusedField, equals: .password)
                          .submitLabel(.next)
                          .onSubmit { focusedField = .confirmPassword }
      
                      SecureField("Confirm Password", text: $confirmPassword)
                          .textContentType(.newPassword)
                          .focused($focusedField, equals: .confirmPassword)
                          .submitLabel(.done)
                          .onSubmit(register)
                  }
      
                  Section {
                      Button("Create Account", action: register)
                  }
              }
              .toolbar {
                  ToolbarItemGroup(placement: .keyboard) {
                      Button("Previous") { moveFocus(-.previous) }
                      Button("Next") { moveFocus(.next) }
                      Spacer()
                      Button("Done") { focusedField = nil }
                  }
              }
          }
      }
      ```
      
      ### Submit Label Options
      
      | Label | Use For |
      |-------|---------|
      | `.done` | Final field, closes keyboard |
      | `.go` | Triggers action (search, navigate) |
      | `.next` | Moves to next field |
      | `.return` | Inserts newline (text areas) |
      | `.search` | Search field |
      | `.send` | Message composition |
      | `.continue` | Multi-step forms |
      | `.join` | Joining/connecting |
      | `.route` | Navigation apps |
      
      ```swift
      TextField("Search", text: $query)
          .submitLabel(.search)
          .onSubmit { performSearch() }
      ```
      
    • navigation.md 4.5 KB
      # iOS Navigation Patterns
      
      ## Tab Bar (Primary Navigation)
      
      The tab bar provides access to main app destinations.
      
      - **Position**: Bottom of screen, always visible (except modals/keyboards)
      - **Items**: 2-5 tabs maximum
      - **Overflow**: Use "More" tab if >5 destinations needed
      - **Selected state**: Fill color indicates active tab
      - **Labels**: 10pt SF text
      - **Background**: Slightly translucent with background blur ("frosted glass")
      
      **Behavior**:
      - Each tab remembers its navigation state
      - Tapping active tab returns to root screen of that tab
      - Tab bar hidden during modals and keyboard display
      
      ## Navigation Bar (Contextual Navigation)
      
      - **Back button**: Top-left, allows return to previous screen
      - **Actions**: Top-right, context-specific actions
      - **Title**: Center (scrolled state) or left-aligned large title (unscrolled)
      
      **Scroll Behavior**:
      - Large title collapses to compact centered title on scroll
      - Search bar can move or hide on scroll
      - Smooth animated transitions between states
      
      ## Navigating Back
      
      | Method | Context |
      |--------|---------|
      | "Back" button (top-left) | Standard navigation |
      | Swipe right from left edge | Standard navigation |
      | "Cancel" / "Done" button | Modal views |
      | Swipe down on content | Modals, fullscreen media |
      
      ## Modal Sheets
      
      Use modals for focused tasks that shouldn't interrupt context completely.
      
      - Slides up from bottom
      - Previous screen visible (recessed) in background
      - Dismiss via: close button, swipe down, or completing task
      
      ---
      
      ## Search UI Patterns
      
      ### Search Bar Placement
      
      | Context | Placement |
      |---------|-----------|
      | Primary search (core feature) | Navigation bar, persistent |
      | Secondary search | Below nav, hidden on scroll |
      | List filtering | Above list, inline |
      
      ### Search Behavior
      
      **States:**
      1. **Inactive:** Placeholder text, magnifying glass icon
      2. **Active/Focused:** Keyboard appears, cancel button shows
      3. **Typing:** Results update (instant or debounced)
      4. **Results:** Displayed in list below
      
      **SwiftUI implementation:**
      ```swift
      .searchable(
          text: $searchText,
          placement: .navigationBarDrawer(displayMode: .always),
          prompt: "Search items"
      )
      ```
      
      ### Search Suggestions
      
      - Recent searches
      - Trending/popular searches
      - Autocomplete suggestions
      - Scoped suggestions (filter by category)
      
      ```swift
      .searchable(text: $searchText) {
          ForEach(suggestions) { suggestion in
              Text(suggestion.name)
                  .searchCompletion(suggestion.name)
          }
      }
      ```
      
      ---
      
      ## Split View Navigation (iPad)
      
      ### Two-Column Layout
      
      ```
      ┌──────────────────┬────────────────────────────────┐
      │                  │                                │
      │  Primary List    │     Detail View                │
      │  (Sidebar)       │                                │
      │                  │                                │
      │  Item 1          │     Selected item details      │
      │  Item 2 ←        │                                │
      │  Item 3          │                                │
      │                  │                                │
      └──────────────────┴────────────────────────────────┘
      ```
      
      **Behavior:**
      - Primary column: 320pt default width
      - Detail column: Fills remaining space
      - Collapse to single column on compact width
      
      ### Three-Column Layout
      
      ```
      ┌────────────┬────────────┬──────────────────────────┐
      │  Sidebar   │ Content    │    Detail                │
      │            │            │                          │
      │  Section 1 │  Item A    │    Item details here     │
      │  Section 2 │  Item B ←  │                          │
      │  Section 3 │  Item C    │                          │
      └────────────┴────────────┴──────────────────────────┘
      ```
      
      **SwiftUI:**
      ```swift
      NavigationSplitView {
          Sidebar()
      } content: {
          ContentList()
      } detail: {
          DetailView()
      }
      ```
      
      ### Responsive Behavior
      
      | Width | Behavior |
      |-------|----------|
      | Compact (iPhone) | Stack navigation |
      | Regular (iPad portrait) | Two-column or overlay |
      | Regular (iPad landscape) | Three-column available |
      
      **Best practices:**
      - Show placeholder in detail when nothing selected
      - Remember selection across rotation
      - Support column resizing (where appropriate)
      
    • privacy-permissions.md 13.5 KB
      # iOS Privacy & Permissions
      
      Best practices for permission requests, privacy UI, and building user trust.
      
      
      ## Table of Contents
      1. [Permission Request Philosophy](#permission-request-philosophy)
      2. [Permission Request Timing](#permission-request-timing)
      3. [Permission Types & Best Practices](#permission-types-best-practices)
      4. [Handling Denied Permissions](#handling-denied-permissions)
      5. [Privacy UI Patterns](#privacy-ui-patterns)
      6. [App Privacy Labels](#app-privacy-labels)
      7. [Usage String Best Practices](#usage-string-best-practices)
      8. [Testing Permissions](#testing-permissions)
      
      ---
      
      ## Permission Request Philosophy
      
      **Core principle:** Request permissions only when needed, explain why, and respect "no."
      
      Users are increasingly permission-fatigued. Every unnecessary or poorly-timed request damages trust and increases denial rates.
      
      ---
      
      ## Permission Request Timing
      
      ### Just-In-Time Requests
      
      Request permissions when the user takes an action that requires them, not at app launch.
      
      **Bad:** Request camera permission on first launch
      **Good:** Request camera permission when user taps "Take Photo"
      
      ### The Pre-Permission Pattern
      
      Before the system dialog, show a custom screen explaining the value.
      
      ```
      ┌─────────────────────────────────────────┐
      │                                         │
      │         [Camera icon]                   │
      │                                         │
      │    Take photos of your receipts         │
      │                                         │
      │    We use your camera to quickly        │
      │    scan and organize your expenses.     │
      │    Photos are stored only on your       │
      │    device.                              │
      │                                         │
      │    ┌─────────────────────────────────┐  │
      │    │        Allow Camera             │  │
      │    └─────────────────────────────────┘  │
      │                                         │
      │            Maybe Later                  │
      │                                         │
      └─────────────────────────────────────────┘
      ```
      
      **Benefits:**
      - Explains value before system dialog
      - "Maybe Later" doesn't trigger system denial
      - Higher acceptance rates
      - Better user understanding
      
      ### System Permission Dialog
      
      ```swift
      // Camera
      AVCaptureDevice.requestAccess(for: .video) { granted in
          // Handle response
      }
      
      // Photos
      PHPhotoLibrary.requestAuthorization(for: .readWrite) { status in
          // Handle status
      }
      
      // Location
      locationManager.requestWhenInUseAuthorization()
      // or
      locationManager.requestAlwaysAuthorization()
      
      // Notifications
      UNUserNotificationCenter.current().requestAuthorization(
          options: [.alert, .badge, .sound]
      ) { granted, error in
          // Handle response
      }
      ```
      
      ---
      
      ## Permission Types & Best Practices
      
      ### Camera
      
      **When to request:** When user initiates camera action
      
      **Usage string example:**
      "[App] needs camera access to scan documents and take photos for your projects."
      
      **Best practices:**
      - Only request when camera feature is used
      - Offer photo library as alternative
      - Handle denial gracefully (show library option)
      
      ### Photo Library
      
      **Access levels (iOS 14+):**
      - `.addOnly` - Can add photos, can't read (for saving)
      - `.readWrite` - Full access
      - Limited selection - User picks specific photos
      
      **When to request:** When user wants to access photos
      
      **Usage string example:**
      "[App] accesses your photos to let you add images to your posts."
      
      **Best practices:**
      - Request `.addOnly` if you only need to save
      - Support limited photo selection (don't require full access)
      - Use PHPicker for one-time selection (no permission needed)
      
      ```swift
      // PHPicker - no permission required
      var config = PHPickerConfiguration()
      config.selectionLimit = 1
      config.filter = .images
      
      let picker = PHPickerViewController(configuration: config)
      ```
      
      ### Location
      
      **Authorization levels:**
      - `.whenInUse` - Only while app is active
      - `.always` - Background location access
      
      **When to request:** When location feature is needed
      
      **Usage strings needed:**
      - `NSLocationWhenInUseUsageDescription`
      - `NSLocationAlwaysAndWhenInUseUsageDescription` (for always)
      
      **Best practices:**
      - Start with "When In Use" before requesting "Always"
      - Explain why background location is needed
      - Provide value even without location
      - Use significant location changes if precise tracking unnecessary
      
      ```swift
      // Request when in use first
      locationManager.requestWhenInUseAuthorization()
      
      // Later, if needed, escalate to always
      // (triggers new system prompt explaining upgrade)
      locationManager.requestAlwaysAuthorization()
      ```
      
      ### Notifications
      
      **When to request:** After user has experienced app value
      
      **Usage string example:**
      "[App] sends notifications for messages from your team and important updates."
      
      **Best practices:**
      - Don't request on first launch
      - Wait until user has seen value
      - Explain what notifications they'll receive
      - Provide in-app notification preferences
      - Respect system settings
      
      **Provisional notifications (iOS 12+):**
      ```swift
      // Quietly delivered to Notification Center
      // User can choose to keep or turn off
      UNUserNotificationCenter.current().requestAuthorization(
          options: [.provisional, .alert, .sound]
      ) { granted, error in }
      ```
      
      ### Contacts
      
      **When to request:** When user initiates contact-related feature
      
      **Usage string example:**
      "[App] accesses your contacts to help you invite friends and find people you know."
      
      **Best practices:**
      - Use CNContactPickerViewController when possible (no permission)
      - Only request full access when truly needed
      - Never sync contacts without explicit permission
      
      ### Microphone
      
      **When to request:** When user initiates audio recording
      
      **Usage string example:**
      "[App] uses your microphone to record voice messages and audio notes."
      
      **Best practices:**
      - Clear indicator when recording
      - Option to preview before sending
      - Explain storage/transmission of audio
      
      ### Health Data
      
      **When to request:** When user enables health features
      
      **Best practices:**
      - Request only specific data types needed
      - Explain how data will be used
      - Provide value without health access
      - Handle partial authorization
      
      ### Tracking (ATT)
      
      **When to request:** Before tracking user across apps
      
      **Required prompt:**
      ```swift
      ATTrackingManager.requestTrackingAuthorization { status in
          switch status {
          case .authorized:
              // Enable tracking
          case .denied, .restricted:
              // Disable tracking
          case .notDetermined:
              // Request hasn't been shown yet
          }
      }
      ```
      
      **Best practices:**
      - Explain value of personalized ads first
      - Don't punish users who decline
      - App must function without tracking
      
      ---
      
      ## Handling Denied Permissions
      
      ### Graceful Degradation
      
      Always provide alternative paths when permission is denied.
      
      | Permission Denied | Alternative |
      |-------------------|-------------|
      | Camera | Photo library option |
      | Location | Manual address entry |
      | Notifications | In-app message center |
      | Contacts | Manual contact entry |
      | Photos | Camera-only option |
      
      ### Re-Requesting After Denial
      
      Once denied, system won't show prompt again. Guide users to Settings.
      
      ```swift
      func openAppSettings() {
          guard let settingsUrl = URL(string: UIApplication.openSettingsURLString),
                UIApplication.shared.canOpenURL(settingsUrl) else {
              return
          }
          UIApplication.shared.open(settingsUrl)
      }
      ```
      
      **UI pattern:**
      ```
      ┌─────────────────────────────────────────┐
      │                                         │
      │         Camera Access Needed            │
      │                                         │
      │    To scan documents, allow camera      │
      │    access in Settings.                  │
      │                                         │
      │    ┌─────────────────────────────────┐  │
      │    │       Open Settings             │  │
      │    └─────────────────────────────────┘  │
      │                                         │
      │           Not Now                       │
      │                                         │
      └─────────────────────────────────────────┘
      ```
      
      ### Don't Ask Again (Within Session)
      
      If user taps "Maybe Later" on pre-permission screen, don't immediately ask again.
      
      ```swift
      // Track dismissal
      UserDefaults.standard.set(Date(), forKey: "camera_prompt_dismissed")
      
      // Wait before showing again
      func shouldShowCameraPrompt() -> Bool {
          guard let lastDismissed = UserDefaults.standard.object(
              forKey: "camera_prompt_dismissed"
          ) as? Date else {
              return true
          }
          // Wait at least 3 days
          return Date().timeIntervalSince(lastDismissed) > 3 * 24 * 60 * 60
      }
      ```
      
      ---
      
      ## Privacy UI Patterns
      
      ### Permission Status Indicators
      
      Show current permission state in settings:
      
      ```
      ┌─────────────────────────────────────────┐
      │ Permissions                             │
      ├─────────────────────────────────────────┤
      │ 📷 Camera                  Allowed    ▶ │
      │ 📍 Location                While Using▶ │
      │ 🔔 Notifications           Off        ▶ │
      │ 📱 Contacts                Not Asked  ▶ │
      └─────────────────────────────────────────┘
      ```
      
      ### Data Usage Transparency
      
      Explain what data is collected and why:
      
      ```
      ┌─────────────────────────────────────────┐
      │ Privacy                                 │
      ├─────────────────────────────────────────┤
      │                                         │
      │ Data We Collect                         │
      │                                         │
      │ • Usage analytics                       │
      │   To improve app performance            │
      │                                         │
      │ • Crash reports                         │
      │   To fix bugs and issues                │
      │                                         │
      │ • Photos you upload                     │
      │   Stored securely on our servers        │
      │                                         │
      │ [View Privacy Policy]                   │
      │                                         │
      └─────────────────────────────────────────┘
      ```
      
      ### Data Deletion Options
      
      Provide clear data management:
      
      ```
      ┌─────────────────────────────────────────┐
      │ Your Data                               │
      ├─────────────────────────────────────────┤
      │ Download My Data                      ▶ │
      │ Delete My Account                     ▶ │
      └─────────────────────────────────────────┘
      ```
      
      ---
      
      ## App Privacy Labels
      
      ### Required Categories
      
      Your App Store listing must declare:
      
      **Data Used to Track You**
      - Data used for advertising across apps
      
      **Data Linked to You**
      - Identifiable data (name, email, etc.)
      
      **Data Not Linked to You**
      - Anonymous analytics, crash data
      
      ### Best Practices
      
      - Be accurate—Apple verifies
      - Minimize collection to reduce label size
      - Simpler labels build trust
      - Update when collection changes
      
      ---
      
      ## Usage String Best Practices
      
      ### Structure
      
      ```
      "[App name] [action] to [user benefit]."
      ```
      
      ### Examples by Permission
      
      | Permission | Good Example |
      |------------|--------------|
      | Camera | "MyApp uses the camera to scan barcodes for quick product lookup." |
      | Photos | "MyApp saves photos you create to your photo library." |
      | Location | "MyApp uses your location to show nearby restaurants and estimated delivery times." |
      | Microphone | "MyApp uses the microphone to record voice notes for your journal entries." |
      | Contacts | "MyApp accesses contacts to help you split bills with friends." |
      
      ### What to Avoid
      
      - Generic explanations ("to improve your experience")
      - Technical jargon
      - Mentioning advertising without explaining value
      - Being vague about data use
      
      ---
      
      ## Testing Permissions
      
      ### Reset Permissions
      
      ```bash
      # Reset all permissions for specific app
      xcrun simctl privacy booted reset all com.yourapp.bundleid
      
      # Reset specific permission
      xcrun simctl privacy booted reset camera com.yourapp.bundleid
      ```
      
      ### Test All States
      
      For each permission:
      1. Never requested (first launch)
      2. Authorized
      3. Denied
      4. Restricted (parental controls)
      5. Limited (Photos)
      6. Provisional (Notifications)
      
      ### Automated Testing
      
      ```swift
      func testCameraPermissionDenied() {
          // Set up mock authorization status
          mockCameraAuthorization = .denied
      
          // Trigger camera feature
          app.buttons["Take Photo"].tap()
      
          // Verify fallback UI appears
          XCTAssertTrue(app.staticTexts["Camera access needed"].exists)
          XCTAssertTrue(app.buttons["Open Settings"].exists)
      }
      ```
      
    • system-integration.md 9.3 KB
      # iOS System Integration
      
      Siri, Shortcuts, Handoff, drag and drop, and other system-level integrations.
      
      
      ## Table of Contents
      1. [Siri Integration](#siri-integration)
      2. [Shortcuts App Integration](#shortcuts-app-integration)
      3. [Handoff](#handoff)
      4. [Drag and Drop](#drag-and-drop)
      5. [Universal Links](#universal-links)
      6. [Spotlight Search](#spotlight-search)
      7. [Focus & Notifications](#focus-notifications)
      8. [Quick Note Integration](#quick-note-integration)
      9. [SharePlay](#shareplay)
      10. [System Appearance](#system-appearance)
      11. [Best Practices Summary](#best-practices-summary)
      
      ---
      
      ## Siri Integration
      
      ### SiriKit Domains
      
      Your app can integrate with Siri through predefined domains:
      
      | Domain | Example Intents |
      |--------|-----------------|
      | Messaging | Send message, search messages |
      | Lists & Notes | Create note, add to list |
      | Payments | Send payment, request payment |
      | Workouts | Start workout, end workout |
      | Media | Play media, add to library |
      | Ride booking | Request ride, get ride status |
      | Car commands | Lock car, get car status |
      | Visual codes | Look up barcode, QR code |
      
      ### Designing for Voice
      
      **Confirmation dialogs:**
      ```
      Siri: "Send $50 to Sarah for dinner?"
      User: "Yes" / "Change amount" / "Cancel"
      ```
      
      **Guidelines:**
      - Confirm significant actions
      - Allow easy correction
      - Provide visual feedback alongside voice
      - Handle ambiguity gracefully
      
      ### Custom Intents
      
      For actions not in predefined domains:
      
      ```swift
      // Define in Intents.intentdefinition
      Intent: OrderCoffee
      Parameters: coffeeType, size, location
      ```
      
      **Best practices:**
      - Use descriptive parameter names
      - Provide good examples
      - Support synonyms
      - Test with various phrasings
      
      ### Siri Shortcuts
      
      Allow users to create custom voice triggers:
      
      ```swift
      // Donate shortcut when user completes action
      let activity = NSUserActivity(activityType: "com.app.order-favorite")
      activity.title = "Order my usual coffee"
      activity.isEligibleForSearch = true
      activity.isEligibleForPrediction = true
      activity.suggestedInvocationPhrase = "Order my usual"
      
      view.userActivity = activity
      ```
      
      **Guidelines:**
      - Donate shortcuts for repeated actions
      - Suggest clear invocation phrases
      - Provide relevant parameters
      - Test in Shortcuts app
      
      ---
      
      ## Shortcuts App Integration
      
      ### App Shortcuts (iOS 16+)
      
      Pre-built shortcuts that appear automatically:
      
      ```swift
      struct MyAppShortcuts: AppShortcutsProvider {
          static var appShortcuts: [AppShortcut] {
              AppShortcut(
                  intent: OrderCoffeeIntent(),
                  phrases: [
                      "Order coffee with \(.applicationName)",
                      "Get my usual from \(.applicationName)"
                  ],
                  shortTitle: "Order Coffee",
                  systemImageName: "cup.and.saucer.fill"
              )
          }
      }
      ```
      
      ### Shortcut Actions
      
      Expose app functionality as Shortcuts actions:
      
      **Good candidates:**
      - Actions users repeat frequently
      - Actions that can run without UI
      - Data that can be passed to other apps
      - Automatable workflows
      
      **Design considerations:**
      - Clear action names (verb + object)
      - Meaningful parameters with defaults
      - Useful outputs for chaining
      - Error messages that explain what went wrong
      
      ---
      
      ## Handoff
      
      ### Enabling Handoff
      
      Allow users to continue activities across Apple devices:
      
      ```swift
      let activity = NSUserActivity(activityType: "com.app.viewing-item")
      activity.title = "Viewing Product: \(product.name)"
      activity.userInfo = ["productID": product.id]
      activity.isEligibleForHandoff = true
      activity.webpageURL = URL(string: "https://myapp.com/product/\(product.id)")
      
      userActivity = activity
      ```
      
      ### Handoff Guidelines
      
      **Do:**
      - Continue at exactly where user left off
      - Restore scroll position, form state, etc.
      - Support universal links as fallback
      - Update activity as context changes
      
      **Don't:**
      - Require re-authentication
      - Lose user's work
      - Show significantly different content
      
      ### Web Fallback
      
      If app isn't installed on receiving device:
      ```swift
      activity.webpageURL = URL(string: "https://myapp.com/activity/\(id)")
      ```
      
      ---
      
      ## Drag and Drop
      
      ### Supporting Drag
      
      ```swift
      .draggable(item) {
          // Drag preview
          ItemPreview(item: item)
      }
      ```
      
      ### Supporting Drop
      
      ```swift
      .dropDestination(for: ItemType.self) { items, location in
          // Handle dropped items
          return true
      }
      ```
      
      ### Drag and Drop Guidelines
      
      **Visual feedback:**
      - Show clear drag preview
      - Indicate valid drop targets
      - Animate transitions smoothly
      
      **Multi-item:**
      - Support selecting multiple items
      - Stack preview for multiple items
      - Handle batch operations
      
      **Cross-app:**
      - Export standard data types (images, text, URLs)
      - Accept common formats
      - Maintain quality during transfer
      
      ### Platform Considerations
      
      | Platform | Drag Initiation |
      |----------|-----------------|
      | iPhone | Long press + drag (within app) |
      | iPad | Long press or tap + drag |
      | Mac (Catalyst) | Click + drag |
      
      ---
      
      ## Universal Links
      
      ### Setting Up
      
      1. Configure `apple-app-site-association` on your server:
      ```json
      {
        "applinks": {
          "apps": [],
          "details": [{
            "appID": "TEAMID.com.example.app",
            "paths": ["/product/*", "/user/*"]
          }]
        }
      }
      ```
      
      2. Add Associated Domains capability:
      ```
      applinks:example.com
      ```
      
      ### Handling Links
      
      ```swift
      func application(_ application: UIApplication,
                       continue userActivity: NSUserActivity,
                       restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
          guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
                let url = userActivity.webpageURL else {
              return false
          }
          return handleUniversalLink(url)
      }
      ```
      
      ### Best Practices
      
      - Parse URLs robustly (handle malformed links)
      - Navigate to appropriate screen
      - Show content immediately (don't require login first)
      - Fall back gracefully if content unavailable
      
      ---
      
      ## Spotlight Search
      
      ### Indexing Content
      
      ```swift
      let attributeSet = CSSearchableItemAttributeSet(contentType: .text)
      attributeSet.title = item.title
      attributeSet.contentDescription = item.description
      attributeSet.thumbnailData = item.thumbnailData
      
      let searchableItem = CSSearchableItem(
          uniqueIdentifier: item.id,
          domainIdentifier: "com.app.items",
          attributeSet: attributeSet
      )
      
      CSSearchableIndex.default().indexSearchableItems([searchableItem])
      ```
      
      ### What to Index
      
      **Good candidates:**
      - User content (notes, documents)
      - Saved items (favorites, history)
      - Frequently accessed items
      
      **Avoid:**
      - Sensitive data
      - Transient content
      - Every possible item (be selective)
      
      ### Search Result Design
      
      Results appear in Spotlight:
      ```
      ┌─────────────────────────────────────────┐
      │ 🔲 My Note Title                        │
      │    Preview of note content...           │
      │    MyApp                                │
      └─────────────────────────────────────────┘
      ```
      
      **Include:**
      - Clear title
      - Helpful description
      - Thumbnail if visual
      - Accurate metadata
      
      ---
      
      ## Focus & Notifications
      
      ### Focus Awareness
      
      Respect user's Focus mode:
      
      ```swift
      UNUserNotificationCenter.current().getNotificationSettings { settings in
          if settings.notificationCenterSetting == .disabled {
              // User has notifications silenced
          }
      }
      ```
      
      ### Time Sensitive Notifications
      
      For truly urgent notifications:
      
      ```swift
      let content = UNMutableNotificationContent()
      content.title = "Your ride is here"
      content.interruptionLevel = .timeSensitive
      ```
      
      **Use only when:**
      - Immediate action required
      - User explicitly opted in
      - Content is genuinely time-sensitive
      
      ---
      
      ## Quick Note Integration
      
      ### Adding Quick Note Capability
      
      Allow highlighting content for Quick Note:
      
      ```swift
      Text(content)
          .contextMenu {
              Button("Add to Quick Note") {
                  // System handles this
              }
          }
      ```
      
      ---
      
      ## SharePlay
      
      ### When to Use SharePlay
      
      - Watching content together
      - Collaborative activities
      - Shared experiences
      
      ### SharePlay Guidelines
      
      **Sync state:**
      - Keep all participants in sync
      - Handle network latency gracefully
      - Provide individual controls where appropriate
      
      **Visual design:**
      - Show who's in the session
      - Indicate when others interact
      - Provide easy leave option
      
      ---
      
      ## System Appearance
      
      ### Supporting Dark Mode
      
      ```swift
      // Adaptive colors
      Color.primary      // Auto light/dark
      Color.secondary    // Auto light/dark
      
      // Custom adaptive colors
      extension Color {
          static let background = Color("Background") // From asset catalog
      }
      ```
      
      ### Supporting Dynamic Type
      
      ```swift
      Text("Title")
          .font(.title)      // Scales with Dynamic Type
      
      // Custom scalable fonts
      .font(.custom("MyFont", size: 17, relativeTo: .body))
      ```
      
      ### Supporting Accessibility
      
      ```swift
      Text("Content")
          .accessibilityLabel("Detailed description")
          .accessibilityHint("Tap to view details")
      ```
      
      ---
      
      ## Best Practices Summary
      
      | Integration | Key Consideration |
      |-------------|-------------------|
      | Siri | Clear confirmation, handle ambiguity |
      | Shortcuts | Expose repeatable, automatable actions |
      | Handoff | Preserve exact state across devices |
      | Drag & Drop | Clear previews, multi-item support |
      | Universal Links | Deep link to specific content |
      | Spotlight | Index valuable, non-sensitive content |
      | Focus | Respect user's notification preferences |
      
      **Universal principle:** System integrations should feel seamless—users shouldn't think about which device or app they're using.
      
    • typography.md 1.7 KB
      # iOS Typography Reference
      
      SKILL.md section 2 covers the sizes, weights, and the six type rules (min 11pt, 1.3x line height, 35-50 chars, left-aligned, weight-over-size, 4.5:1). This file adds what it does not carry: exact light-mode color values and the Dark Mode color mapping.
      
      ## System Font: San Francisco
      
      iOS uses San Francisco (SF Pro) as the default typeface. Always reach the styles through semantic APIs (`.font(.title)`, `.font(.body)`, `.font(.caption)`) so Dynamic Type scaling and these colors apply automatically — never hardcode the point sizes or hex values below.
      
      ## Light-Mode Color Values
      
      The point sizes live in SKILL.md; these are the hex values iOS resolves each semantic style to in light mode.
      
      | Element | Semantic style | Color (light) |
      |---------|----------------|---------------|
      | Large Title / Title / Body | `.largeTitle` `.title` `.body` | `#000000` (label) |
      | Secondary text | `.subheadline` + `.secondary` | `#3C3C43` @ 60% (secondaryLabel) |
      | Caption / Tertiary | `.caption` + `.secondary` | `#3C3C43` @ 60% |
      | Tab bar labels (unselected) | 10pt | `#8A8A8E` (tertiaryLabel) |
      
      ```swift
      Text("Caption")
          .font(.caption)
          .foregroundColor(.secondary)   // resolves to secondaryLabel in both modes
      ```
      
      ## Dark Mode Color Mapping
      
      Semantic styles flip automatically; this is the mapping they apply so you can verify a custom color matches it:
      
      - Primary text `#000000` -> `#FFFFFF` (label)
      - Secondary/tertiary gray -> lighter gray at the same opacity (secondaryLabel/tertiaryLabel)
      - Backgrounds shift darker while preserving the relative hierarchy between layers
      
      If you define a custom text color, put light/dark variants in the Asset Catalog so it follows this mapping instead of staying fixed.
      
    • widgets-extensions.md 13.5 KB
      # iOS Widgets & App Extensions
      
      Design guidelines for widgets, App Clips, and system extensions.
      
      
      ## Table of Contents
      1. [Widget Design](#widget-design)
      2. [Widget Configuration](#widget-configuration)
      3. [App Clips](#app-clips)
      4. [Share Extensions](#share-extensions)
      5. [Action Extensions](#action-extensions)
      6. [Live Activities](#live-activities)
      7. [Widget Development Tips](#widget-development-tips)
      
      ---
      
      ## Widget Design
      
      ### Widget Philosophy
      
      Widgets provide **glanceable information** on the Home Screen, Lock Screen, and StandBy mode. They are not mini-apps—they're windows into your app's most useful content.
      
      **Key principles:**
      - Show immediately useful information
      - Update content thoughtfully (not constantly)
      - Respect the user's Home Screen aesthetic
      - Drive users to the app for deeper engagement
      
      ### Widget Sizes
      
      **Home Screen widgets:**
      
      | Size | Name | Grid Units | Use Case |
      |------|------|------------|----------|
      | Small | `systemSmall` | 2×2 | Single piece of information |
      | Medium | `systemMedium` | 4×2 | Key content + one interaction |
      | Large | `systemLarge` | 4×4 | Rich content, multiple items |
      | Extra Large | `systemExtraLarge` | 8×4 | iPad only, dashboard view |
      
      **Lock Screen widgets (iOS 16+):**
      
      | Size | Name | Characteristics |
      |------|------|-----------------|
      | Circular | `accessoryCircular` | Small icon or gauge |
      | Rectangular | `accessoryRectangular` | Text + small visual |
      | Inline | `accessoryInline` | Text only, above time |
      
      ### Widget Content Guidelines
      
      **Do:**
      - Show the most important information
      - Update content at meaningful intervals
      - Use the app's visual style
      - Support multiple sizes (let users choose)
      - Provide multiple widget types if you have different use cases
      
      **Don't:**
      - Cram too much information
      - Show stale data
      - Use widgets for advertising
      - Require interaction to see content
      - Update too frequently (drains battery)
      
      ### Small Widget Design
      
      ```
      ┌─────────────────────┐
      │                     │
      │    [Icon/Image]     │
      │                     │
      │    Primary Info     │
      │    Secondary        │
      │                     │
      └─────────────────────┘
      ```
      
      **Guidelines:**
      - One tap target (entire widget)
      - Essential info only
      - Clear visual hierarchy
      - No buttons or complex interactions
      
      ### Medium Widget Design
      
      ```
      ┌─────────────────────────────────────────┐
      │  [Icon]                                 │
      │  Title               ┌─────────────┐    │
      │  Subtitle            │   Action    │    │
      │                      └─────────────┘    │
      │  Additional context                     │
      └─────────────────────────────────────────┘
      ```
      
      **Guidelines:**
      - Can have multiple tap targets
      - Show 2-4 pieces of information
      - Actions should be quick (open to specific view)
      
      ### Large Widget Design
      
      ```
      ┌─────────────────────────────────────────┐
      │  Header                          Edit   │
      ├─────────────────────────────────────────┤
      │  ┌─────────┐ ┌─────────┐ ┌─────────┐   │
      │  │ Item 1  │ │ Item 2  │ │ Item 3  │   │
      │  └─────────┘ └─────────┘ └─────────┘   │
      │                                         │
      │  ┌─────────┐ ┌─────────┐ ┌─────────┐   │
      │  │ Item 4  │ │ Item 5  │ │ Item 6  │   │
      │  └─────────┘ └─────────┘ └─────────┘   │
      └─────────────────────────────────────────┘
      ```
      
      **Guidelines:**
      - Multiple tap targets allowed
      - Show a collection or dashboard
      - Include clear visual grouping
      - Optional: Edit configuration
      
      ### Lock Screen Widget Design
      
      Lock Screen widgets have limited space and no color.
      
      **Circular:**
      ```
      ┌─────┐
      │ 73° │  Temperature
      │ ☀️  │  Weather icon
      └─────┘
      ```
      
      **Rectangular:**
      ```
      ┌─────────────────────┐
      │ Next Event          │
      │ Team Meeting @ 2pm  │
      └─────────────────────┘
      ```
      
      **Best practices:**
      - Design for small size
      - Use SF Symbols (render well)
      - Test in Light and Dark modes
      - Consider StandBy mode (larger display)
      
      ---
      
      ## Widget Configuration
      
      ### User-Configurable Widgets
      
      Allow users to customize what the widget shows:
      
      ```swift
      struct ConfigurationIntent: WidgetConfigurationIntent {
          static var title: LocalizedStringResource = "Configuration"
      
          @Parameter(title: "City")
          var city: City?
      
          @Parameter(title: "Units")
          var units: TemperatureUnit
      }
      ```
      
      **Configuration UI:**
      - Keep options simple (few parameters)
      - Provide sensible defaults
      - Preview changes before confirming
      
      ### Widget Families
      
      Support multiple sizes:
      
      ```swift
      struct MyWidget: Widget {
          var body: some WidgetConfiguration {
              StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
                  MyWidgetView(entry: entry)
              }
              .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
          }
      }
      ```
      
      ---
      
      ## App Clips
      
      ### What App Clips Are
      
      App Clips are lightweight versions of your app (<10MB) for quick, focused tasks without full installation.
      
      **Invocation points:**
      - NFC tags
      - QR codes
      - App Clip codes
      - Safari Smart App Banner
      - Maps
      - Messages
      
      ### App Clip Design Principles
      
      **1. Focus on one task**
      - Rent a bike
      - Order food
      - Pay for parking
      
      **2. Minimize required information**
      - Only ask for what's essential
      - Use Sign in with Apple
      - Use Apple Pay
      
      **3. Fast experience**
      - User expects to finish in under a minute
      - No lengthy onboarding
      - Minimal UI, maximum function
      
      **4. Encourage full app download**
      - Show value of full app
      - Make download easy (banner)
      - Don't block functionality to force download
      
      ### App Clip UI Guidelines
      
      ```
      ┌─────────────────────────────────────────┐
      │  [Header: What you can do]              │
      ├─────────────────────────────────────────┤
      │                                         │
      │  [Primary action UI]                    │
      │                                         │
      │  ┌─────────────────────────────────┐    │
      │  │        [Apple Pay]              │    │
      │  └─────────────────────────────────┘    │
      │                                         │
      ├─────────────────────────────────────────┤
      │  Get the full app for more features     │
      │  ┌─────────────────────────────────┐    │
      │  │        Download App             │    │
      │  └─────────────────────────────────┘    │
      └─────────────────────────────────────────┘
      ```
      
      ### App Clip Code Design
      
      App Clip Codes are scannable codes that launch App Clips:
      
      ```
             ┌─────────────────┐
            ╱                   ╲
           │   [App Clip Code]   │
           │   Circular pattern  │
           │   with NFC chip     │
            ╲                   ╱
             └─────────────────┘
               Scan or tap to
               rent a scooter
      ```
      
      **Placement guidelines:**
      - Clear call to action below code
      - Explain what will happen
      - Accessible height (3.5-5 feet)
      - Well-lit, clean surface
      
      ---
      
      ## Share Extensions
      
      ### Share Extension Design
      
      ```
      ┌─────────────────────────────────────────┐
      │  Post to [App Name]                 ✕   │
      ├─────────────────────────────────────────┤
      │  ┌─────────────────────────────────┐    │
      │  │ [Preview of content]            │    │
      │  └─────────────────────────────────┘    │
      │                                         │
      │  Add a comment...                       │
      │                                         │
      │  ┌─────────────────────────────────┐    │
      │  │           Share               │    │
      │  └─────────────────────────────────┘    │
      └─────────────────────────────────────────┘
      ```
      
      **Guidelines:**
      - Show preview of shared content
      - Minimal configuration options
      - Quick completion (< 10 seconds ideal)
      - Clear success/error feedback
      
      ---
      
      ## Action Extensions
      
      ### Action Extension Design
      
      Action extensions process content in place:
      
      ```
      ┌─────────────────────────────────────────┐
      │  Markup                             Done │
      ├─────────────────────────────────────────┤
      │                                         │
      │  [Modified content preview]             │
      │                                         │
      ├─────────────────────────────────────────┤
      │  [Tools for modification]               │
      └─────────────────────────────────────────┘
      ```
      
      **Guidelines:**
      - Focus on specific task
      - Return modified content to host app
      - Match system UI conventions
      - Support undo/cancel
      
      ---
      
      ## Live Activities
      
      ### What Live Activities Are
      
      Real-time updates on Lock Screen and Dynamic Island for ongoing events:
      - Sports scores
      - Delivery tracking
      - Timers
      - Ride sharing
      
      ### Live Activity Design
      
      **Lock Screen (expanded):**
      ```
      ┌─────────────────────────────────────────┐
      │  [Leading]     [Center]      [Trailing] │
      │  Team A           vs           Team B   │
      │    24            Q3             21      │
      └─────────────────────────────────────────┘
      ```
      
      **Dynamic Island (compact):**
      ```
      ┌──────────────────────────────────────┐
      │  🏀  24 - 21  Q3                     │
      └──────────────────────────────────────┘
      ```
      
      **Dynamic Island (expanded):**
      ```
      ┌────────────────────────────────────────┐
      │  Lakers          vs          Celtics   │
      │    24                          21      │
      │  ────────────────────────────────────  │
      │       Q3  •  4:32 remaining            │
      └────────────────────────────────────────┘
      ```
      
      ### Live Activity Guidelines
      
      **Do:**
      - Update only when meaningful changes occur
      - Design for all Dynamic Island states
      - Provide clear end states
      - Respect 8-hour maximum duration
      
      **Don't:**
      - Update every second (unless timer)
      - Show static content
      - Use for notifications
      - Require interaction to see status
      
      ---
      
      ## Widget Development Tips
      
      ### Timeline Updates
      
      ```swift
      func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
          let entries = [
              SimpleEntry(date: Date(), data: currentData),
              SimpleEntry(date: Date().addingTimeInterval(60*15), data: futureData)
          ]
      
          let timeline = Timeline(entries: entries, policy: .atEnd)
          completion(timeline)
      }
      ```
      
      **Update policies:**
      - `.atEnd` - Update when all entries displayed
      - `.after(date)` - Update at specific time
      - `.never` - Only update on user action
      
      ### Deep Links
      
      Widgets should link to specific content:
      
      ```swift
      Link(destination: URL(string: "myapp://item/\(item.id)")!) {
          ItemView(item: item)
      }
      ```
      
      ### Placeholder Design
      
      Show meaningful placeholder while loading:
      
      ```swift
      struct PlaceholderView: View {
          var body: some View {
              VStack {
                  RoundedRectangle(cornerRadius: 8)
                      .fill(Color.gray.opacity(0.3))
                  RoundedRectangle(cornerRadius: 4)
                      .fill(Color.gray.opacity(0.2))
              }
          }
      }
      ```
      
  • SKILL.md 19.9 KB
    ---
    name: ios-hig-design
    description: 'Design native iOS interfaces following Apple Human Interface Guidelines. Use when the user mentions "iPhone app", "iPad layout", "SwiftUI", "UIKit", "Dynamic Island", "safe areas", "HIG compliance", "SF Symbols", "haptic feedback", "iOS accessibility", "make my app feel native", or "follow Apple design guidelines". Also trigger when building tab bars, navigation stacks, sheets, or modals for iOS, implementing dark mode, or adapting layouts across screen sizes. Covers navigation patterns, accessibility, SF Symbols, and platform conventions. For general UI polish, see refactoring-ui. For affordance design, see design-everyday-things.'
    license: MIT
    metadata:
      author: wondelai
      version: "1.5.1"
    ---
    
    # iOS Human Interface Guidelines Design Skill
    
    Framework for designing native iOS interfaces that feel intuitive, consistent, and aligned with Apple's design philosophy. Based on Apple's Human Interface Guidelines, the definitive resource for apps that integrate seamlessly with iPhone, iPad, and the Apple ecosystem.
    
    ## Core Principle
    
    Apple's iOS design philosophy rests on three pillars: **clarity** (every element legible and purposeful), **deference** (the interface never overshadows the content it presents), and **depth** (layering, transitions, and realistic motion convey hierarchy and spatial relationships).
    
    **The foundation:** The best iOS apps internalize this philosophy rather than following HIG rules mechanically. Native components, system conventions, and platform consistency aren't constraints---they're the reason iOS users trust and enjoy apps that feel like they belong.
    
    ## Scoring
    
    **Goal: 10/10.** Score 1 point per satisfied row of the Quick Diagnostic (6 rows), plus up to 4 points for native idiom: +1 semantic colors/text styles throughout (no hardcoded values), +1 system controls over custom reimplementations, +1 standard gestures and meaningful haptics, +1 SF Symbols and correct app-icon shape. Bands: **9-10** = native, accessible, adapts to Dark Mode and Dynamic Type, zero foreign patterns; **5-6** = works but leaks Android idioms or hardcodes color/size; **<=3** = fails safe areas, touch targets, or VoiceOver. Always state the score and the specific improvements needed to reach 10/10.
    
    ## iOS Design Framework
    
    ### 1. Layout & Safe Areas
    
    **Core concept:** iOS devices have specific screen dimensions, safe area insets, and hardware intrusions (notch, Dynamic Island, home indicator) that every layout must respect.
    
    **Key insights:**
    - Design for the smallest screen first (375pt width, iPhone SE)
    - Safe areas protect content from the notch, Dynamic Island, and home indicator---never place interactive elements under them
    - Standard content margins: 16-20pt from screen edges; spacing increments: 8 / 16 / 24pt
    - Minimum touch target and list row height: 44pt
    
    **Product applications:**
    
    | Context | Layout Pattern | Example |
    |---------|---------------|---------|
    | **Status bar** | 20pt classic, 44-54pt on Dynamic Island devices | Time, signal, battery area |
    | **Navigation bar** | 44pt standard row + ~52pt large title (~96pt total) | Back button, title, actions |
    | **Content area** | Flexible, scrollable, respects safe area | Main app content |
    | **Tab bar** | 49pt height, translucent with blur | 2-5 primary destinations |
    | **Home indicator** | 34pt inset at bottom | System gesture area |
    
    **Copy patterns:**
    - Use `VStack { }`, which respects safe areas by default
    - Use `.ignoresSafeArea()` only for backgrounds and decoration, never interactive content
    - Test on multiple sizes, including iPhone SE and Pro Max
    
    See [references/navigation.md](references/navigation.md) when laying out chrome---exact nav bar and tab bar dimensions, large-title behavior, and split-view rules.
    
    ### 2. Typography & Dynamic Type
    
    **Core concept:** iOS uses the San Francisco (SF Pro) typeface with semantic text styles that automatically scale for accessibility via Dynamic Type. Semantic styles give consistent platform hierarchy; Dynamic Type lets users read at their preferred size without breaking layouts.
    
    **Key insights:**
    - Large Title: 34pt Bold; Title: 17pt Medium; Body: 17pt Regular; Caption: 12-13pt; secondary text: 15pt at 60% opacity
    - Minimum text size 11pt (captions/secondary only)
    - Line height at least 1.3x font size; optimal line length 35-50 characters on mobile
    - Always left-aligned, non-justified text
    
    **Product applications:**
    
    | Context | Typography Pattern | Example |
    |---------|-------------------|---------|
    | **Screen titles** | `.largeTitle` or `.title` style | Large title collapses on scroll |
    | **Body content** | `.body` style, 17pt | List items, descriptions |
    | **Secondary info** | `.subheadline` or `.footnote` | Timestamps, metadata |
    | **Tab labels** | 10pt SF text | Tab bar item labels |
    | **Buttons** | `.body` weight semibold | Primary action text |
    
    **Copy patterns:**
    - Use `.font(.title)`, `.font(.body)`, `.font(.caption)` instead of hardcoded sizes; `@ScaledMetric` for custom spacing that scales
    - Prefer weight and color variation over extreme size differences for hierarchy
    - Test all layouts at the largest Dynamic Type size
    
    See [references/typography.md](references/typography.md) when matching a design to exact specs---per-style hex values and the Dark Mode text-color mapping.
    
    ### 3. Color & Dark Mode
    
    **Core concept:** iOS provides semantic system colors that automatically adapt between light and dark appearances while preserving contrast and hierarchy.
    
    **Key insights:**
    - Use `Color(.label)`, `Color(.secondaryLabel)`, `Color(.systemBackground)` instead of hardcoded colors
    - `Color(.systemBlue)` is the default tint; `.systemRed` for destructive actions; `.systemGreen` for success
    - Dark Mode inverts text colors and shifts backgrounds darker while keeping relative hierarchy; accent colors need lower brightness and higher saturation to pop
    - Maintain 4.5:1 contrast in both modes; preview both during development
    
    **Product applications:**
    
    | Context | Color Pattern | Example |
    |---------|--------------|---------|
    | **Primary text** | `Color(.label)` | Adapts white/black per mode |
    | **Secondary text** | `Color(.secondaryLabel)` | 60% opacity in both modes |
    | **Backgrounds** | `Color(.systemBackground)` / `.secondarySystemBackground` | Layered depth |
    | **Destructive actions** | `Color(.systemRed)` | Delete buttons, warnings |
    | **Interactive tint** | App accent color or `.systemBlue` | Links, toggle states |
    
    **Copy patterns:**
    - Use `.preferredColorScheme(.light)` and `.dark` in previews to test both modes side by side
    - Define custom colors in the Asset Catalog with light/dark variants, not in code
    - Never assume a background is white or black; test with Increase Contrast enabled
    
    See [references/colors-depth.md](references/colors-depth.md) when checking contrast---the full WCAG ratio table (normal text, large text, UI components) and the tertiary/grouped-background tokens.
    
    ### 4. Navigation Patterns
    
    **Core concept:** iOS uses a layered navigation model: tab bars for primary destinations, navigation stacks for hierarchical drilling, and modals for focused tasks. Users rely on these patterns to know where they are and how to get back; reinventing them makes the app feel foreign.
    
    **Key insights:**
    - Tab bar: 2-5 primary destinations, always visible, remembers state per tab
    - Navigation bar: back button (top-left), title (center or large), actions (top-right); large title collapses on scroll
    - Modals for focused tasks; dismiss via swipe-down or explicit close button
    - Never use hamburger menus---iOS users expect tab bars
    - Search bar can sit below the nav bar, hidden until pulled down
    
    **Product applications:**
    
    | Context | Navigation Pattern | Example |
    |---------|-------------------|---------|
    | **App structure** | Tab bar with 3-5 tabs | Home, Search, Profile |
    | **Content hierarchy** | Push navigation (drill-down) | List > Detail > Edit |
    | **Focused tasks** | Modal presentation | Compose, settings, filters |
    | **Search** | Pull-down search bar | Spotlight-style search |
    | **Split view** | iPad sidebar + detail | Mail, Notes on iPad |
    
    **Copy patterns:**
    - Back button text should be the previous screen's title, not "Back"
    - Tab labels are single words ("Home", "Search"); modal titles describe the task ("New Message", "Edit Profile")
    - Use `NavigationStack` (not deprecated `NavigationView`) in SwiftUI
    
    ### 5. Controls & Inputs
    
    **Core concept:** iOS provides a rich library of native controls (buttons, lists, toggles, pickers, menus, text fields) that users already understand and expect.
    
    **Why it works:** Native controls ship with built-in accessibility, haptics, and learned interaction patterns; custom controls create friction and miss edge cases Apple already solved.
    
    **Key insights:**
    - Page-level actions go in the nav bar (top) or action bar (bottom)
    - Primary buttons are filled with the theme color; secondary are outlined or text-only
    - Destructive actions use red and require confirmation when irreversible
    - Lists (table views) are the fundamental iOS content pattern
    - Match keyboard type to input (`.emailAddress`, `.phonePad`, `.URL`); use `.textContentType` for autofill
    
    **Product applications:**
    
    | Context | Control Pattern | Example |
    |---------|----------------|---------|
    | **Forms** | Native text fields with proper keyboard types | Email field with @ keyboard |
    | **Settings** | Grouped list with toggles, disclosure | iOS Settings style |
    | **Selection** | Picker, segmented control, or action sheet | Date picker, sort options |
    | **Destructive actions** | Red button + confirmation alert | "Delete Account" flow |
    | **Context actions** | Long press menu or swipe actions | Edit, share, delete on row |
    
    **Copy patterns:**
    - Pair `.keyboardType(.emailAddress)` with `.textContentType(.emailAddress)`
    - Prefer system confirmations: `.alert()` or `.confirmationDialog()`; use `.swipeActions` on list rows
    - Place primary action buttons at the bottom of the screen within thumb reach
    
    **Ethical boundary:** Never disguise ads as native controls or make destructive actions easy to trigger accidentally.
    
    See [references/components.md](references/components.md) when building a specific control---button styles, list/section variants, picker vs segmented-control choice, and confirmation-dialog wiring. See [references/keyboard-input.md](references/keyboard-input.md) when building forms---keyboard-type table, input accessory views, and hardware-keyboard shortcuts.
    
    ### 6. Accessibility
    
    **Core concept:** iOS has world-class accessibility features (VoiceOver, Dynamic Type, Switch Control, Voice Control), and every app must support them as a first-class concern. App Store review can reject apps that are unusable with assistive technologies.
    
    **Key insights:**
    - Every interactive element needs an `.accessibilityLabel`; use `.accessibilityValue` for state and `.accessibilityHint` for effect
    - Group related elements with `.accessibilityElement(children: .combine)`
    - Support Dynamic Type at all sizes; test at the largest setting
    - Honor the 44 x 44pt touch target (section 1) and 4.5:1 contrast minimum (section 3) as accessibility requirements, not just visual defaults
    - Never convey meaning through color alone
    
    **Product applications:**
    
    | Context | Accessibility Pattern | Example |
    |---------|----------------------|---------|
    | **Icons** | `.accessibilityLabel("Favorite")` | Heart icon with label |
    | **Sliders** | `.accessibilityValue("\(Int(volume * 100))%")` | Volume control |
    | **Buttons** | `.accessibilityHint("Shares this item")` | Share button |
    | **Groups** | `.accessibilityElement(children: .combine)` | Avatar + name row |
    | **Images** | Decorative: `.accessibilityHidden(true)` | Background patterns |
    
    **Copy patterns:**
    - Write labels as nouns ("Favorite", "Settings"); write hints as actions ("Shares this item with others")
    - Test the complete app flow using only VoiceOver
    - Use Xcode's Accessibility Inspector to audit contrast and labels
    
    See [references/accessibility.md](references/accessibility.md) before sign-off---the full VoiceOver-implementation patterns and a pre-ship accessibility checklist to run the app against.
    
    ### 7. Icons & Images
    
    **Core concept:** iOS uses SF Symbols as the standard icon system and requires app icons in specific sizes with the signature superellipse ("squircle") mask applied automatically. SF Symbols align optically with San Francisco text and scale with Dynamic Type, so they stay aligned and crisp at every weight and size.
    
    **Key insights:**
    - Use SF Symbols (`Image(systemName:)`) for all standard icons---they scale with text
    - App icons: export 1024x1024px square; iOS applies the squircle mask (corner radius = side x 0.222 with 61% smoothing)
    - iOS 18+ supports light, dark, and tinted icon variants
    - Avoid text in app icons; keep designs simple with recognizable silhouettes
    
    **Product applications:**
    
    | Context | Icon Pattern | Example |
    |---------|-------------|---------|
    | **Tab bar** | SF Symbols, filled variant for selected | `house.fill`, `magnifyingglass` |
    | **Navigation bar** | SF Symbols at regular weight | `gear`, `plus`, `ellipsis` |
    | **List accessories** | SF Symbols, secondary color | `chevron.right`, `checkmark` |
    | **App icon** | 1024px square, simple bold design | Single recognizable glyph |
    
    **Copy patterns:**
    - Use `Image(systemName: "heart.fill")`; apply `.symbolRenderingMode(.hierarchical)` for multi-color depth
    - Size symbols relative to text with `.imageScale(.large)` or `.font()`
    - Browse symbols in the free SF Symbols app from Apple
    
    **Ethical boundary:** Never use icons that suggest functionality that doesn't exist or contradict iOS conventions (trash = delete, not archive).
    
    See [references/app-icons.md](references/app-icons.md) when exporting the app icon---per-context size table, exact squircle math, and the iOS 18 light/dark/tinted variant requirements.
    
    ### 8. Gestures & Haptics
    
    **Core concept:** iOS defines standard gestures (swipe back, pull to refresh, long press for context menu) and haptic feedback patterns that must be respected and never overridden. Gestures are muscle memory---repurposing swipe-back or pull-to-refresh disorients users; haptics give invisible confirmation that an action registered.
    
    **Key insights:**
    - Never override: swipe-right-from-edge (back), swipe-down on modal (dismiss), pull-down on list (refresh)
    - Swipe-left on rows reveals actions; long press shows context menus; pinch zooms images and maps
    - Three haptic types: impact (physical actions), notification (outcomes), selection (UI changes)
    - Haptics should be subtle and meaningful---never constant or annoying
    
    **Product applications:**
    
    | Context | Gesture/Haptic Pattern | Example |
    |---------|----------------------|---------|
    | **Navigation** | Swipe right from left edge | System back gesture |
    | **Modals** | Swipe down to dismiss | Sheet dismissal |
    | **Lists** | Pull to refresh, swipe for actions | Refresh content, delete row |
    | **Confirmation** | `.success` haptic on completion | Payment confirmed |
    | **Selection** | Selection haptic on toggle/pick | Picker wheel scroll |
    
    **Copy patterns:**
    - `UIImpactFeedbackGenerator(style: .medium)` for physical interactions; `UISelectionFeedbackGenerator()` for UI state changes
    - `UINotificationFeedbackGenerator()` with `.success`, `.warning`, `.error` for outcomes
    - Call `.prepare()` before triggering haptics to minimize latency
    
    See [references/gestures.md](references/gestures.md) when wiring gestures or animation---the full reserved-gesture table, haptic-generator recipes, and standard animation timing/curves.
    
    ## Common Mistakes
    
    | Mistake | Why It Fails | Fix |
    |---------|-------------|-----|
    | **Overriding standard gestures** | Breaks muscle memory for swipe-back, pull-refresh | Use system gestures as intended; custom gestures only for supplementary actions |
    | **Touch targets under 44pt** | Mis-taps, frustration, accessibility failures | Make all interactive elements at least 44 x 44pt |
    | **Ignoring safe areas** | Content hidden behind notch, Dynamic Island, home indicator | Respect safe area insets; `.ignoresSafeArea()` only for backgrounds |
    | **Using Android patterns on iOS** | Hamburger menus, top tabs, FABs feel foreign | Use tab bars, bottom sheets, native iOS components |
    | **Skipping Dark Mode** | Broken layouts, unreadable text for Dark Mode users | Use semantic colors; test both appearances |
    | **Hardcoding font sizes** | Breaks Dynamic Type, excludes low-vision users | Use semantic text styles (`.title`, `.body`, `.caption`) throughout |
    | **Low contrast text** | Fails WCAG AA; unreadable in sunlight | Maintain 4.5:1 minimum; test with Increase Contrast |
    | **Not testing on real devices** | Simulator misses performance, haptics, safe area edge cases | Test on physical devices at smallest and largest sizes |
    
    ## Quick Diagnostic
    
    Audit any iOS interface design:
    
    | Question | If No | Action |
    |----------|-------|--------|
    | Does the layout respect safe areas on all device sizes? | Content hidden behind hardware | Audit on iPhone SE and Pro Max; fix insets |
    | Are all touch targets at least 44 x 44pt? | Mis-taps and accessibility failures | Increase tap areas; `.frame(minWidth: 44, minHeight: 44)` |
    | Does the app work fully in Dark Mode? | Broken/unreadable UI for Dark Mode users | Replace hardcoded colors with semantic system colors |
    | Does text scale properly with Dynamic Type? | Excludes low-vision users | Use semantic text styles; test at largest setting |
    | Can a VoiceOver user complete every task? | App inaccessible to blind users | Add labels, values, hints to all interactive elements |
    | Are navigation patterns native iOS? | App feels foreign | Replace hamburger menus with tab bars; standard push/modal navigation |
    
    ## Beyond Core UI
    
    The eight framework sections above each link their deep-dive reference inline at the point of need. Three further references cover system surfaces that sit outside the on-screen UI:
    
    - See [references/privacy-permissions.md](references/privacy-permissions.md) when the app requests camera, location, contacts, or any protected resource---request timing, pre-permission priming screens, usage-string wording, and the denied-permission recovery path.
    - See [references/widgets-extensions.md](references/widgets-extensions.md) when building a Home Screen widget, App Clip, Live Activity, or share/action extension---supported sizes and per-surface design constraints.
    - See [references/system-integration.md](references/system-integration.md) when wiring the app into the OS---Siri/Shortcuts intents, Handoff, drag-and-drop, universal links, and Spotlight indexing.
    
    ## Further Reading
    
    For the complete guidelines, platform-specific guidance, and latest updates:
    
    - [Apple Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/) --- the definitive reference for all Apple platforms
    - [SF Symbols](https://developer.apple.com/sf-symbols/) --- Apple's icon system, 5,000+ configurable symbols
    - [Apple Design Resources](https://developer.apple.com/design/resources/) --- official Figma/Sketch templates and UI kits
    - [WWDC Design Sessions](https://developer.apple.com/videos/design/) --- videos on design principles and new features
    - *"Designed by Apple in California"* --- photo book of Apple's design process (out of print; Apple no longer sells it)
    - [*"The Design of Everyday Things"*](https://www.amazon.com/Design-Everyday-Things-Revised-Expanded/dp/0465050654?tag=wondelai00-20) by Don Norman --- the human-centered design text that influenced Apple
    - [*"Universal Principles of Design"*](https://www.amazon.com/Universal-Principles-Design-Revised-Updated/dp/1592535879?tag=wondelai00-20) by William Lidwell, Kritina Holden, and Jill Butler --- 125 principles applicable to iOS
    
    ## About the Author
    
    The **Apple Human Interface Guidelines** are written and maintained by Apple's Human Interface Design team, one of the most influential design organizations in technology. First published in 1984 alongside the original Macintosh, the HIG established principles---direct manipulation, consistency, user control---that defined graphical interface design and have evolved through iPhone, iPad, Apple Watch, and Vision Pro. It remains freely available at developer.apple.com as the essential reference for Apple platforms.
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related