AgentStack
SKILL verified MIT Self-run

Swiftui Craft

skill-dndungu-agent-skills-swiftui-craft · by dndungu

Production SwiftUI craft and native iOS/HIG compliance — make an app feel native and match Apple Human Interface Guidelines: spacing grid, typography and Dynamic Type, semantic colors and dark mode, safe areas and Dynamic Island, tab bars/sheets/modals, haptics, iOS accessibility (VoiceOver), SF Symbols, WidgetKit visual rules, and iPhone/iPad layout adaptation. Use when reviewing or improving Sw…

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-dndungu-agent-skills-swiftui-craft

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Are you the author of Swiftui Craft? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

swiftui-craft — production SwiftUI craft rules

Consolidates the retired standalone skills swiftui-design-principles (v1.1.1, arjitj2, MIT), swiftui-design-skill (v1.0.0, wholiver, MIT), and ios-hig-design (v1.5.0, wondelai, MIT). Load when REVIEWING existing SwiftUI UI quality, when an approved design system is being implemented in a real app, or when auditing native-idiom / Apple HIG compliance. These are implementation-time rules: what separates an app that feels "right" and native from one where margins, spacing, text sizes, or platform conventions look "off". The HIG native-idiom framework (safe areas, Dynamic Type, Dark Mode, gestures/haptics, accessibility, SF Symbols, the 10/10 scoring rubric) lives in references/hig-overview.md; the topic router below points into it.

Does not do: greenfield design exploration, mockups, or design systems — that is /ios-design (direction → tokens → component cards → rendered screens). Widget plumbing (timelines, intents, entitlements, push reloads) → /widgetkit. Liquid Glass API work → /liquid-glass. Design-to-production validation pipelines → /design-fidelity.

Reconciliation with the mockup lane. Two rules below (semantic system colors, NavigationStack) are correct in a real app but wrong in the headless mockup lane (RENDERER.md fidelity limits). Resolution: mockups use Theme tokens and custom chrome; at implementation time each Theme token becomes an asset-catalog color (light+dark variants) or maps onto the closest semantic color, and custom mockup chrome becomes real NavigationStack / TabView chrome styled by the system. Apps WITHOUT a design system default to semantic colors outright.

Core philosophy: restraint over decoration — fewer colors, fewer font sizes, fewer spacing values, fewer words, used consistently. Attention is scarce — one clear headline and one compact supporting block beat repeated explanation scattered across title, subtitle, body, and footer.

1. Spacing: one grid, no arbitrary values

Allowed: 4 8 12 16 20 24 32 40 48. Values like 14, 18, 26, 34 create visual dissonance the eye registers even when the reader can't name it.

  • Outer content padding: 16–20pt horizontal.
  • Between major sections: 24–32pt vertical.
  • Within grouped components: 4–12pt.
  • Card/row internal padding: 12–16pt vertical, 16pt horizontal (never 4pt vertical).

2. Typography: hierarchy through weight, not just size

  • ≤ 5 distinct font sizes per app, each with a named purpose. Lighter

weights at large sizes (elegant), regular/medium at small sizes.

  • Example scale for a data app: hero 36–42 .light, secondary stat 20–24

.light, body 15 .regular, section header 11 .medium uppercase with tracking, caption 11–13 .regular.

  • ONE font design everywhere — app AND widgets. Never .monospaced in the

app but .rounded on the lock screen.

  • Tracking: at most 2 values, only on uppercase labels (e.g. 1.5 for section

labels, 3 for toolbar titles). Never 3+ near-identical kerning values.

  • Identifiers (years, IDs) must not locale-group: Text(String(year)) or

.number.grouping(.never) — never Text("\(year)") rendering "2,026".

  • No minimumScaleFactor hacks — fix the layout instead.
  • At most 2 weights per family per screen; one hierarchy channel — size OR

weight — per screen. Any runtime-updating number uses monospaced/tabular digits (no reflow jitter). Identity test: the app should be recognizable in a desaturated screenshot — typography carries the brand.

  • Content text (body, labels, captions) uses semantic styles — .font(.body),

.title, .caption — so Dynamic Type scales it; reserve the custom scale above for hero/display/stat text only. Test every layout at the largest Dynamic Type size (references/hig-typography.md for the color mapping).

3. Color: semantic first, tokens when a system exists

  • No design system → semantic colors: Color(.systemBackground),

.secondarySystemBackground, .separator, .primary, .secondary, .tertiary. They handle light/dark and accessibility for free.

  • Design system → Theme tokens with explicit light+dark values (the

mockup lane already enforces this); wire them through the asset catalog.

  • Never a ladder of hardcoded Color.white.opacity(0.08 … 0.94) values.

If you need opacity at all, limit to 2–3 values with clear purposes (≈0.15 subtle strokes, ≈0.3 separators).

  • Default blue tint nowhere — define an accent.
  • Dark mode is designed, not inverted; semantic/adaptive colors tested in

both appearances. Dark carries measurable hue — no pure #000 background or #FFF text in either scheme; light/dark are one hue at two lightnesses.

  • Hue budget: at most 4 saturated hues per screen, each with exactly one

documented meaning; ~70% of visible surface stays neutral — saturation lives in content and state, never chrome.

4. Component sizing: proportional, consistent strokes

  • Progress rings: ~200pt in a main view, ~90pt in a small widget, thin

strokes (≈3pt). Never a 260pt ring with 8–9pt strokes dominating the screen.

  • Background and foreground strokes of the same element use the SAME

lineWidth — 9 behind 8 reads as misalignment.

  • Toggle rows: natural height from 12pt vertical padding, 15pt label, and

Toggle's built-in label — never .labelsHidden() plus a manual HStack, never .frame(height: 70).

  • Tap targets ≥ 44×44pt, always.

5. Cards & grouped content: system patterns

  • Corner radius 10pt for cards/groups (iOS system style); never 22pt+.

Radii nest concentrically (inner ~ half of outer) and vary by role — "everything 16pt-rounded on a gray field" is the canonical AI-slop tell.

  • Background Color(.secondarySystemBackground) (or the system's surface

token) — no decorative gradients or overlay borders on standard cards.

  • Dividers: system Divider().padding(.leading, 16) — never custom divider

structs.

6. Navigation & layout structure

  • NavigationStack with a real toolbar — not a bare ZStack with a

manually placed title Text.

  • Layout: VStack/HStack/LazyVGrid; paged content via ScrollView +

.scrollTargetBehavior(.paging). Prefer containerRelativeFrame (iOS 17+) over GeometryReader; never UIScreen.main.bounds. Color, not UIColor/NSColor.

  • Not one giant VStack — break into semantic sections with clear hierarchy.
  • Native navigation model: tab bar for 2–5 primary destinations (never a

hamburger menu), push NavigationStack for drill-down, modal sheets for focused tasks (dismiss by swipe-down or explicit close). Back-button text is the previous screen's title, not "Back". Full model in references/hig-navigation.md.

  • Respect safe areas: interactive content never under the notch, Dynamic

Island, or home indicator; .ignoresSafeArea() for backgrounds only. Design smallest-screen-first (375pt) and verify on iPhone SE through Pro Max.

7. WidgetKit

  • Lock-screen circular/linear indicators: Gauge with .accessoryCircular

/ .linearCapacity — never manual circle drawing.

  • Background: .containerBackground(.fill.tertiary, for: .widget) — never a

hardcoded color.

  • Support all relevant families (accessoryCircular/Rectangular/Inline,

systemSmall/Medium/Large); medium and large share the same structural hierarchy (header / progress / footer) unless a hard size constraint forces otherwise.

  • Explicit internal padding (≈12pt) on home-screen widgets to avoid clipping

at rounded edges.

  • Memory budget ~30 MB: dense visualizations (365-dot grids) draw in one

Canvas pass, never hundreds of nested ZStacks in a LazyVGrid.

  • Timeline refresh matches data granularity: .after(midnight) for daily

data, ~15-min periodic for time-of-day fills — never minute-level for static daily data.

8. Interactive elements

  • Toggle(isOn:){label} with a single accent .tint — built-in label, not

hidden.

  • Mutually exclusive options = ONE selected enum value rendered as a

checklist/picker, never N independent toggles that allow contradictory state.

  • Changing numbers animate: .contentTransition(.numericText()).
  • Motion carries state: no animation without a state/data trigger (the

remove-it test — if meaning survives removal, remove it). One signature animation per workflow; everything else ≤0.35s sharing at most two curves; no idle shimmer or bounce garnish.

  • Density bimodality: a screen is either dense (≥3:1 type contrast, one

oversized anchor) or calm (few elements, generous margins) — medium density with medium contrast is the slop zone.

9. Interactive editors (crops, collages, canvases)

  • Present from payload state: .sheet(item: $activeRequest) — never

Bool + separately managed optional data that can race.

  • ONE shared geometry model for live preview and export — preview and

render must not each invent their own pan/zoom/crop math. Revealed background on zoom-out is part of that model or it doesn't happen.

  • Gestures (tap / long-press-drag / pinch) share one interaction state

machine with explicit priority — not scattered booleans.

  • No-scroll editor screens budget height top-down through named regions

(header / canvas stage / settings / toolbar) with the math in one place.

  • Custom headers: know whether the parent already respects the safe area —

never add safeAreaInsets.top reflexively (double-counting = dead space). Keep them compact: chrome, not a content section.

  • Multi-mode editors show ONE active settings surface at a time; the canvas

stays visually dominant.

10. Shared data model (app + widgets)

One model, one calculation, used by both the app views and the widget TimelineProvider — never duplicated snapshot structs with re-derived date math. If the UI implies live progress, include time-of-day in the shared fraction.

11. Assets & placeholders

  • SF Symbols or a real icon set — never emoji as functional icons, never

AI-drawn SVG clipart or CSS-silhouette illustrations.

  • Can't source a real asset? Clean, labeled gray placeholder and ask the

user for materials. A rough honest layout beats a polished generic one.

12. Native iOS idiom (HIG) — accessibility, gestures, haptics

  • Every interactive element carries an .accessibilityLabel (noun: "Favorite");

.accessibilityValue for state, .accessibilityHint for effect (action: "Shares this item"); group with .accessibilityElement(children: .combine); hide decorative images with .accessibilityHidden(true). A VoiceOver user must be able to complete every task. Never convey meaning by color alone.

  • Never override system gestures: swipe-from-edge (back), swipe-down (dismiss

modal), pull-down (refresh). Row swipe reveals actions; long-press shows context menus.

  • Haptics are subtle and meaningful, never constant: impact for physical

actions, notification (.success/.warning/.error) for outcomes, selection for UI changes; .prepare() before triggering.

  • Native controls over custom reimplementations (they carry accessibility and

haptics for free); system confirmations (.alert() / .confirmationDialog()), .swipeActions on rows, keyboard type paired with .textContentType.

Full HIG framework, scoring rubric (10/10), and per-topic depth in references/hig-overview.md.

Topic → reference router

| Topic | Reference file | |-------|----------------| | HIG framework, three pillars, 10/10 scoring, common mistakes, quick diagnostic | references/hig-overview.md | | Nav/tab bar dimensions, large-title behavior, split view | references/hig-navigation.md | | Semantic text hex values, Dark Mode text mapping | references/hig-typography.md | | Extra color-layering tokens, full WCAG contrast table | references/hig-colors-depth.md | | Button/list/section/picker/confirmation-dialog specifics | references/hig-components.md | | Keyboard types, input accessory views, hardware shortcuts | references/hig-keyboard-input.md | | VoiceOver patterns, pre-ship accessibility checklist | references/hig-accessibility.md | | App-icon sizes, squircle math, iOS 18 light/dark/tinted variants | references/hig-app-icons.md | | Reserved gestures, haptic recipes, animation timing/curves | references/hig-gestures.md | | Permission timing, priming screens, usage strings, denied recovery | references/hig-privacy-permissions.md | | Widget/App Clip/Live Activity/extension sizes + constraints | references/hig-widgets-extensions.md | | Siri/Shortcuts, Handoff, drag-and-drop, universal links, Spotlight | references/hig-system-integration.md |

13. Review checklist (run for review mode; score honestly)

Spacing on the grid · ≤5 font sizes, one design incl. widgets · semantic or token colors, no opacity ladders · equal stroke widths · 10pt card radius + system Divider · Toggle built-in labels · exclusive choices are one value · NavigationStack present · Gauge in lock-screen widgets · .containerBackground(.fill.tertiary) · widget families consistent + padded · Canvas for dense widget visuals · timeline matches granularity · no locale-grouped identifiers · tracking ≤2 values · no minimumScaleFactor · editors present from payload state · one geometry model preview+export · no double-counted safe areas · height budgeted centrally on fixed screens · one settings surface at a time · 44pt targets · dark mode designed · content text scales with Dynamic Type · interactive elements have accessibility labels and a VoiceOver-completable flow · native navigation (tab bar not hamburger, NavigationStack, modal sheets) · safe areas respected on SE→Pro Max · system gestures not overridden, haptics subtle · SF Symbols + correct app-icon shape · no banned slop patterns (~/.claude/skills/ios-design/DIRECTION.md §4) · one signature detail per screen.

Report review findings as file:line + rule + minimal fix, most severe first.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.