Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Master iOS Human Interface Guidelines and SwiftUI patterns for building native iOS apps. Use when designing iOS interfaces, implementing SwiftUI views, or ensuring apps follow Apple's design principles.
.claude/skills/dicklesworthstone-mobile-ios-design/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-16 | ✓→✗ | ▼ Worse | 63% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 181% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 91% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 86% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 62% | 0% |
Master iOS Human Interface Guidelines (HIG) and SwiftUI patterns to build polished, native iOS applications that feel at home on Apple platforms.
Clarity: Content is legible, icons are precise, adornments are subtle Deference: UI helps users understand content without competing with it Depth: Visual layers and motion convey hierarchy and enable navigation
Platform Considerations:
Stack-Based Layouts:
swift// Vertical stack with alignment VStack(alignment: .leading, spacing: 12) { Text("Title") .font(.headline) Text("Subtitle") .font(.subheadline) .foregroundStyle(.secondary) } // Horizontal stack with flexible spacing HStack { Image(systemName: "star.fill") Text("Featured") Spacer() Text("View All") .foregroundStyle(.blue) }
Grid Layouts:
swift// Adaptive grid that fills available width LazyVGrid(columns: [ GridItem(.adaptive(minimum: 150, maximum: 200)) ], spacing: 16) { ForEach(items) { item in ItemCard(item: item) } } // Fixed column grid LazyVGrid(columns: [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()) ], spacing: 12) { ForEach(items) { item in ItemThumbnail(item: item) } }
NavigationStack (iOS 16+):
swiftstruct ContentView: View { @State private var path = NavigationPath() var body: some View { NavigationStack(path: $path) { List(items) { item in NavigationLink(value: item) { ItemRow(item: item) } } .navigationTitle("Items") .navigationDestination(for: Item.self) { item in ItemDetailView(item: item) } } } }
TabView:
swiftstruct MainTabView: View { @State private var selectedTab = 0 var body: some View { TabView(selection: $selectedTab) { HomeView() .tabItem { Label("Home", systemImage: "house") } .tag(0) SearchView() .tabItem { Label("Search", systemImage: "magnifyingglass") } .tag(1) ProfileView() .tabItem { Label("Profile", systemImage: "person") } .tag(2) } } }
SF Symbols:
swift// Basic symbol Image(systemName: "heart.fill") .foregroundStyle(.red) // Symbol with rendering mode Image(systemName: "cloud.sun.fill") .symbolRenderingMode(.multicolor) // Variable symbol (iOS 16+) Image(systemName: "speaker.wave.3.fill", variableValue: volume) // Symbol effect (iOS 17+) Image(systemName: "bell.fill") .symbolEffect(.bounce, value: notificationCount)
Dynamic Type:
swift// Use semantic fonts Text("Headline") .font(.headline) Text("Body text that scales with user preferences") .font(.body) // Custom font that respects Dynamic Type Text("Custom") .font(.custom("Avenir", size: 17, relativeTo: .body))
Colors and Materials:
swift// Semantic colors that adapt to light/dark mode Text("Primary") .foregroundStyle(.primary) Text("Secondary") .foregroundStyle(.secondary) // System materials for blur effects Rectangle() .fill(.ultraThinMaterial) .frame(height: 100) // Vibrant materials for overlays Text("Overlay") .padding() .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 12))
Shadows and Depth:
swift// Standard card shadow RoundedRectangle(cornerRadius: 16) .fill(.background) .shadow(color: .black.opacity(0.1), radius: 8, y: 4) // Elevated appearance .shadow(radius: 2, y: 1) .shadow(radius: 8, y: 4)
swiftimport SwiftUI struct FeatureCard: View { let title: String let description: String let systemImage: String var body: some View { HStack(spacing: 16) { Image(systemName: systemImage) .font(.title) .foregroundStyle(.blue) .frame(width: 44, height: 44) .background(.blue.opacity(0.1), in: Circle()) VStack(alignment: .leading, spacing: 4) { Text(title) .font(.headline) Text(description) .font(.subheadline) .foregroundStyle(.secondary) .lineLimit(2) } Spacer() Image(systemName: "chevron.right") .foregroundStyle(.tertiary) } .padding() .background(.background, in: RoundedRectangle(cornerRadius: 12)) .shadow(color: .black.opacity(0.05), radius: 4, y: 2) } }
.primary, .secondary, .background for automatic light/dark mode support.body, .headline) instead of fixed sizes.accessibilityLabel() and .accessibilityHint() modifierssafeAreaInset and avoid hardcoded padding at screen edges@SceneStorage for preserving user state.fixedSize() sparingly; prefer flexible layoutsLazyVStack/LazyHStack for long scrolling listsNavigationLink values are Hashable| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 11,225 | 40,082 | +257% | 1 | 1 | 0% | 2,236 | 6,279 | +181% | 0 | 0 | — |
case-02 | pass→pass | 11,883 | 17,489 | +47% | 1 | 1 | 0% | 2,232 | 4,274 | +91% | 0 | 0 | — |
case-03 | pass→pass | 16,601 | 19,770 | +19% | 1 | 1 | 0% | 2,972 | 5,538 | +86% | 0 | 0 | — |
case-04 | pass→pass | 17,439 | 14,433 | -17% | 1 | 1 | 0% | 2,688 | 4,347 | +62% | 0 | 0 | — |
case-05 | fail→fail | 7,140 | 8,186 | +15% | 1 | 1 | 0% | 1,236 | 3,259 | +164% | 0 | 0 | — |
case-06 | pass→pass | 7,112 | 7,266 | +2% | 1 | 1 | 0% | 1,394 | 3,118 | +124% | 0 | 0 | — |
case-07 | pass→pass | 7,569 | 6,459 | -15% | 1 | 1 | 0% | 1,478 | 2,934 | +99% | 0 | 0 | — |
case-08 | pass→pass | 11,918 | 18,038 | +51% | 1 | 1 | 0% | 2,318 | 5,001 | +116% | 0 | 0 | — |
case-09 | pass→pass | 10,573 | 12,846 | +21% | 1 | 1 | 0% | 2,084 | 4,227 | +103% | 0 | 0 | — |
case-10 | pass→pass | 17,131 | 13,791 | -19% | 1 | 1 | 0% | 2,754 | 4,186 | +52% | 0 | 0 | — |
case-11 | pass→pass | 9,338 | 9,472 | +1% | 1 | 1 | 0% | 1,668 | 3,408 | +104% | 0 | 0 | — |
case-12 | pass→pass | 9,787 | 10,233 | +5% | 1 | 1 | 0% | 1,795 | 3,354 | +87% | 0 | 0 | — |
case-13 | pass→pass | 10,927 | 7,314 | -33% | 1 | 1 | 0% | 2,261 | 3,361 | +49% | 0 | 0 | — |
case-14 | pass→pass | 16,071 | 16,617 | +3% | 1 | 1 | 0% | 2,525 | 4,267 | +69% | 0 | 0 | — |
case-15 | pass→pass | 4,432 | 3,988 | -10% | 1 | 1 | 0% | 643 | 2,380 | +270% | 0 | 0 | — |
case-16 | pass→fail | 16,675 | 17,672 | +6% | 1 | 1 | 0% | 3,163 | 5,146 | +63% | 0 | 0 | — |
case-17 | pass→pass | 25,643 | 21,454 | -16% | 1 | 1 | 0% | 3,941 | 4,872 | +24% | 0 | 0 | — |
case-18 | pass→pass | 4,044 | 3,287 | -19% | 1 | 1 | 0% | 659 | 2,380 | +261% | 0 | 0 | — |
case-19 | pass→pass | 11,546 | 9,004 | -22% | 1 | 1 | 0% | 1,728 | 3,138 | +82% | 0 | 0 | — |
case-20 | fail→fail | 18,454 | 15,422 | -16% | 1 | 1 | 0% | 3,101 | 4,532 | +46% | 0 | 0 | — |
case-21 | pass→pass | 9,165 | 7,805 | -15% | 1 | 1 | 0% | 1,558 | 3,189 | +105% | 0 | 0 | — |
case-22 | pass→pass | 11,655 | 12,021 | +3% | 1 | 1 | 0% | 1,960 | 3,881 | +98% | 0 | 0 | — |
case-23 | pass→pass | 12,817 | 9,986 | -22% | 1 | 1 | 0% | 2,319 | 3,755 | +62% | 0 | 0 | — |
case-24 | pass→pass | 11,632 | 9,719 | -16% | 1 | 1 | 0% | 2,031 | 3,477 | +71% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of -100 percentage points is the difference between those two pass rates over the 24 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Other measured skills in the registry, with their headline benchmark lift.