From ios-dev-toolkit
Final quality pass for iOS/SwiftUI views — fixes spacing, typography, color, animation, accessibility, and HIG compliance to make interfaces feel crafted, not coded. Use this skill whenever the user mentions polish, finishing touches, pre-launch review, "something looks off", visual QA, design pass, or wants to elevate an iOS view from functional to beautiful. Also use when reviewing SwiftUI code for design quality, even if the user doesn't say "polish" explicitly — any request to make an iOS screen look better, feel more native, or match Apple-quality apps should trigger this skill.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ios-dev-toolkit:ios-polishThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are performing a final design quality pass on SwiftUI views. Your job is not just to check for
You are performing a final design quality pass on SwiftUI views. Your job is not just to check for correctness — it's to make the interface feel crafted. Every Apple-quality app shares certain traits: generous spacing, purposeful typography, restrained color, fluid motion, and invisible accessibility. This skill teaches you to see what's missing and fix it.
Before changing anything, read every file in scope and answer:
State your findings briefly, then proceed to the systematic pass.
Work through each dimension in order. For each one, note what you'd change and why, then make the change. Skip dimensions that are already solid — don't touch what works.
Great spacing is the single biggest difference between "designed" and "default."
Principles:
.safeAreaInset(edge:) for floating elements, never manual padding that guesses notch/indicator heights.List with .listRowInsets() over manual VStack + ForEach + Divider — the system handles separators, swipe actions, and dynamic type scaling.Red flags: Hard-coded padding like .padding(10), missing spacing between sections, elements touching safe area edges, ScrollView content hidden behind navigation bars.
iOS typography should feel effortless. San Francisco does the heavy lifting — you direct it.
Principles:
.font(.body), .font(.headline), .font(.caption) — never .font(.system(size: 14)). Text styles scale with Dynamic Type automatically..semibold or .bold headline per section. Everything else stays .regular. Too many weights creates noise..lineSpacing(4) on body text. Multiline labels need room..caption or .footnote should answer: "Would the user miss this if it were gone?" If no, remove it.Red flags: Hard-coded font sizes, more than 2 font weights on screen, .font(.caption2) used for important info, missing lineLimit() on user-generated content.
See references/typography.md for the full text style hierarchy and Dynamic Type testing guide.
Color communicates. Every color choice should answer "what does this tell the user?"
Principles:
Color(.label), Color(.secondaryLabel), Color(.tertiaryLabel), Color(.systemBackground), Color(.secondarySystemBackground). These adapt to dark mode and accessibility settings automatically.#808080 gray feels lifeless. This is a taste call that separates good from great.Color(.secondarySystemBackground)), text uses Color(.label). Test both appearances.Red flags: Hard-coded color literals (Color.gray), custom colors that don't adapt to dark mode, more than 3 non-neutral colors on one screen, decorative color that doesn't communicate meaning.
See references/color-system.md for the semantic color palette and dark mode design guide.
The user's eye should flow naturally from what matters most to what matters least.
Principles:
DisclosureGroup, NavigationLink, or .sheet to reveal detail on demand..toolbarBackground(.hidden) when the screen benefits from it.Red flags: Multiple elements competing for attention, uniform text size across different content types, section headers that feel disconnected from their content.
Motion should feel like physics, not CSS transitions.
Principles:
.spring(.snappy) for quick UI feedback (toggles, taps). .spring(.smooth) for layout changes (expanding sections, sheet presentations). .spring(.bouncy) only for playful, celebratory moments (task completion).matchedGeometryEffect or navigationTransition(.zoom) to maintain spatial context.withAnimation(accessibilityReduceMotion ? .none : .spring(.snappy)) or use @Environment(\.accessibilityReduceMotion). Functional transitions (showing/hiding content) can stay, but simplify them.Red flags: .linear or .easeInOut animations (feel mechanical), animations longer than 500ms, missing Reduce Motion support, decorative animations with no purpose, .animation(_, value:) on a parent that animates everything.
See references/motion.md for the spring configurations, transition patterns, and gesture-driven animation guide.
SF Symbols are free design polish — use them well.
Principles:
.headline context, use .font(.headline) on the symbol too. Mismatched weights look sloppy..symbolRenderingMode(.hierarchical) adds subtle depth to symbols. Use it as default over .monochrome for decorative icons..fill) for selected/active states (tab bar, toggles). Outlined for inactive/unselected. This is a core iOS pattern..symbolEffect(.bounce) on tap, .symbolEffect(.pulse) for ongoing activity, .symbolEffect(.variableColor) for progress. These feel native and delightful with zero effort..font(.title2) or .imageScale(.large) — not .frame(width: 24, height: 24). This scales with Dynamic Type.Red flags: Symbols that don't match surrounding text weight, .monochrome used everywhere, custom icons where an SF Symbol exists, symbols sized with .frame().
Every touch should have a response. Silence feels broken.
Principles:
.contentShape(Rectangle()) to expand hit areas beyond visible bounds.Button for tappable elements — it provides built-in accessibility, highlight states, and keyboard support. onTapGesture loses all of this..sensoryFeedback(.selection, trigger: value) for picks/toggles. .sensoryFeedback(.impact(.medium), trigger: action) for confirmations. .sensoryFeedback(.success, trigger: completion) for achievements. Haptics are the difference between "app" and "native app.".redacted(reason: .placeholder) for skeleton screens. ProgressView() for indeterminate waits. Never leave the user staring at unchanged UI while something loads..swipeActions with .destructive role. Confirmation .alert or .confirmationDialog for irreversible actions.Red flags: Small touch targets, onTapGesture on interactive elements, no loading indicators during network calls, delete without confirmation, silent errors.
These are the states users see most during first use and poor connectivity. They set the emotional tone.
Principles:
ContentUnavailableView (iOS 17+) with a clear message and action button. "No tasks yet" is functional. "All caught up! Time to relax." is human..redacted(reason: .placeholder)) that match the final layout shape. This feels faster than a spinner..transition(.opacity.combined(with: .scale(0.95))). Abrupt state switches feel jarring.Red flags: Blank screens during loading, generic "Something went wrong", no retry mechanism, abrupt state transitions, empty lists with no explanation.
Accessibility is design quality you can't see, but millions of users feel.
Principles:
Button, toggle, and tappable element needs .accessibilityLabel() if the visual label isn't sufficient (e.g., icon-only buttons).ViewThatFits or .minimumScaleFactor() when space is tight. Never truncate critical info..accessibilityElement(children: .combine) on card views so VoiceOver reads "Task: Buy groceries, assigned to Mom, due tomorrow" as one unit, not four separate elements.withAnimation and .transition should have a reduced-motion alternative.Red flags: Icon-only buttons without labels, views that break at large text sizes, low contrast on secondary text, VoiceOver reading individual elements of a logical group.
The best polish is invisible — the app just feels like it belongs on iOS.
Principles:
NavigationStack with navigationTitle and toolbar, not custom headers. The system handles large title collapsing, safe areas, and back gestures.DatePicker, Toggle, Picker, Stepper — not custom versions unless you have a genuine UX reason. Users know how system controls work..refreshable { } on any list that shows server data. It's expected..swipeActions for quick actions on list rows. Leading for positive (complete), trailing for destructive (delete)..sheet or .fullScreenCover for creation flows. Alerts for binary decisions. Confirmation dialogs for destructive choices..searchable() on any list with more than ~10 items. Users expect it.Red flags: Custom navigation bars, custom toggles/pickers without reason, missing pull-to-refresh on server data, alerts used for complex input, no search on long lists.
Before finishing, run this quick check. "iOS Slop" is the native equivalent of "AI Slop" — it's the telltale signs of a web developer's first iOS app, or an AI that hasn't learned platform taste.
Fail if any of these are true:
.easeInOut or .linear animations instead of springsColor.gray) instead of semantic/tinted neutralsonTapGesture used where Button should beAfter making all changes, verify:
.easeInOut or .linear — always use springsColor.gray — use Color(.secondaryLabel) or tinted neutralsonTapGesture for buttons — use Buttonnpx claudepluginhub elvinouyang/claude-skill-collection --plugin ios-dev-toolkitGenerates production-grade SwiftUI code for Apple Design Award-quality iOS interfaces—screens, components, redesigns—with bold aesthetics and screenshot-driven iteration.
Generates SwiftUI and UIKit components for iOS apps following Apple's HIG. Validates designs, ensures accessibility compliance for iPhone, iPad, and Apple Watch.
Applies Apple Human Interface Guidelines for iPhone UI design, layout, safe areas, touch targets, screen sizes, and typography in SwiftUI/UIKit.