Install
$ agentstack add skill-dev869-swift-tothemax-swiftui-max ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
SwiftUI to the Max
Write SwiftUI the way a senior Apple-platforms engineer writes it in mid-2026: Observation-first, value-typed, identity-aware, and Liquid Glass-native. Prefer deleting code to adding it; most SwiftUI bugs are self-inflicted state or identity problems.
Scope split: This skill owns UI. Swift language, strict concurrency, actors/Sendable, macros, SwiftPM, and Swift Testing belong to the sibling swift-language skill — route there instead of answering language questions here (e.g. "is this Sendable", Swift 6 migration, @concurrent). SwiftUI code that contains concurrency needs both.
Give yourself eyes (mandatory for UI work)
UI built blind is the single biggest quality gap in agent-written SwiftUI. Never declare UI work done without having rendered and looked at it. The loop:
- Build for the simulator (
xcodebuild -scheme App -destination 'platform=iOS Simulator,name=iPhone 17' build) or, for isolated components, render withImageRendererfrom a scratch target. - Screenshot:
xcrun simctl io booted screenshot /tmp/screen.png— then read the image and critique it againstapple-hig-uxstandards (spacing, hierarchy, Dynamic Type, dark mode). - Repeat across the matrix that matters: light/dark, small/large Dynamic Type, smallest + largest supported device.
- Lock in what's right with snapshot tests so regressions are caught without eyes.
Full workflow (simulator CLI, PreviewHost pattern, hot reload with Inject, snapshot testing, accessibility audits): references/visual-iteration-workflow.md.
Build vs. recipe vs. library
Before hand-rolling any common component, check references/component-recipes.md (canonical implementations of the 12 hardest-to-get-right components) and references/ecosystem-libraries.md (curated, maintenance-verified third-party catalog: effects, images, markdown, dev tooling, architecture). Default order: native API → recipe from this skill → library from the vetted list. Never re-implement what Pow/Nuke/Lottie already do well; never import a library for what native does in 20 lines. For app-wide consistency (tokens, themes, reusable components), follow references/design-system-kit.md and consume tokens instead of magic numbers.
Version landscape (July 2026)
| Release | Status | Headline UI features | |---|---|---| | iOS 17 / macOS 14 | old floor | Observation (@Observable), @Entry-era environment patterns, scrollTargetBehavior/scrollPosition, keyframe/phase animators, #Preview | | iOS 18 / macOS 15 | common floor | @Entry macro, zoom navigation transitions, scroll geometry/visibility callbacks, mesh gradients, floating tab bar/TabSection | | iOS 26 / macOS 26 "Tahoe" | current shipping (unified "26" version number across platforms) | Liquid Glass design system (glassEffect, GlassEffectContainer), @Animatable macro, rich-text TextEditor (AttributedString), WebView, scroll edge effects, tabBarMinimizeBehavior, Instruments SwiftUI template | | iOS 27 / macOS 27 "Golden Gate" (WWDC26) | beta — mark all usage as beta | @State becomes a macro (lazy class init), reorderable containers, swipeActions in any ScrollView, ToolbarOverflowMenu/visibilityPriority, WritableDocument/ReadableDocument, AsyncImage HTTP caching, ContentBuilder (build-time wins), item-binding alert/confirmationDialog, resizable iPhone apps |
Gate anything above the deployment target with #available and provide a real fallback, not a blank view.
Modern defaults (non-negotiable unless the target forces otherwise)
- Observation over Combine-era state. New model types are
@Observableclasses (or plain structs held in@State).ObservableObject/@Published/@StateObjectare legacy — use only below iOS 17. Why: Observation tracks per-property reads, so views update only when a property they actually read changes. NavigationStack/NavigationSplitView, neverNavigationView. Drive navigation with apathvalue (NavigationPathor a typed array) so deep links and state restoration are data, not view spelunking.@Entryfor environment keys. One line replaces theEnvironmentKey+ extension boilerplate:
``swift extension EnvironmentValues { @Entry var audioMixer = AudioMixer() // iOS 18+; hand-rolled key below that } ``
- Composition over
AnyView. Returnsome View, split subviews, use@ViewBuilderproperties/functions and generics.AnyViewerases identity and blocks diffing — reach for it only at true dynamic boundaries (e.g. heterogeneous routing tables). - Stable identity.
ForEachoverIdentifiabledata with ids that survive edits (neverid: \.selfon mutable strings, never array indices for reorderable data). Remember:if/elsecreates different identities (transition + state reset); modifying one view (opacity,disabled) preserves identity. - Value flows down, actions flow up. Pass the smallest thing that works:
letfor display,@Bindingfor mutation, closures for events. Don't pass a whole store into a leaf view that reads one field. bodyis pure. No side effects, no object allocation per evaluation, noDateFormatter()inline, no sorting/filtering big arrays. Compute in the model, or memoize; kick effects off with.task/.onChange.- Semantic styling. System colors/materials,
Font.TextStyle(Dynamic Type),foregroundStyleoverforegroundColor, button/label/list styles over hand-built lookalikes. Accessibility is part of "done": labels on image-only buttons,accessibilityElement(children: .combine)for composite rows.
Legacy → modern translation table
| Legacy (flag on sight) | Modern replacement | Since | |---|---|---| | NavigationView | NavigationStack(path:) / NavigationSplitView | iOS 16 | | NavigationLink(destination:) (eager) | NavigationLink(value:) + navigationDestination(for:) | iOS 16 | | ObservableObject + @Published | @Observable class | iOS 17 | | @StateObject / @ObservedObject | @State (owner) / plain let (non-owner) | iOS 17 | | @EnvironmentObject | @Environment(MyModel.self) + .environment(model) | iOS 17 | | EnvironmentKey struct + extension | @Entry | iOS 18 | | foregroundColor | foregroundStyle | iOS 15 | | .animation(.spring) (no value) | .animation(.spring, value: x) or withAnimation | iOS 15 | | onChange(of:) { newValue in } (1-param) | onChange(of:) { old, new in } / zero-param | iOS 17 | | DispatchQueue.main.async / onAppear for async work | .task { } / .task(id:) (auto-cancelling) | iOS 15 | | UIScreen.main.bounds sizing | GeometryReader (sparingly) / containerRelativeFrame | iOS 17 | | AnimatableModifier / manual animatableData | @Animatable macro | iOS 26 | | Hand-built blur "glass" (.ultraThinMaterial chrome) | glassEffect + GlassEffectContainer | iOS 26 | | cornerRadius(_:) | clipShape(.rect(cornerRadius:)) / concentric shapes | iOS 16/26 | | MasterDetailView-style bool spaghetti for alerts | alert(item:) / confirmationDialog(item:) | iOS 27 beta (sheet-style item binding) | | @State private var model = BigModel() eager init | unchanged code, now lazy — but drop default values when assigning in init | iOS 27 beta (@State macro) |
FetchRequest/Core Data ↔ SwiftData @Query: see references/state-and-data-flow.md.
Performance rules of thumb
- Measure before rewriting: Instruments 26 → SwiftUI template ("Long View Body Updates" lane), or
Self._printChanges()in body while reproducing. Guessing wastes time; the tooling names the guilty view. - Keep bodies cheap and small — extraction into child views is free and narrows invalidation scope.
- Big value types diff slowly; conform hot views to
Equatable(or restructure so inputs are small) to skip subtree updates. LazyVStack/LazyHStack/Listfor anything unbounded; but lazy containers never release built views — keep row views trivial. Stable, cheapids; no per-rowGeometryReader..task(id:)over.onChange+ manualTask— you get cancellation of the stale work for free.- Animate leaf modifiers, not layout of giant hierarchies; prefer
scrollTargetBehavior/scrollTransitionto hand-rolled offset math. - Full playbook: references/performance-and-debugging.md.
Liquid Glass (iOS 26+; refined in 27 beta)
Adopting the system design is mostly free: rebuild with Xcode 26+ and standard bars, tabs, sheets, and controls pick up Liquid Glass automatically. On the 2027-era OSes (beta), glass tint additionally follows the user's system-level Liquid Glass appearance slider with no code changes. Rules for custom surfaces:
// One floating control
Image(systemName: "plus")
.frame(width: 52, height: 52)
.glassEffect(.regular.interactive(), in: .circle)
// Multiple glass shapes that sit near each other MUST share a container,
// so they blend/morph instead of stacking blur on blur.
GlassEffectContainer(spacing: 24) {
ForEach(tools) { tool in
ToolIcon(tool)
.glassEffect()
.glassEffectID(tool.id, in: namespace) // enables morph transitions
}
}
glassEffect(_:in:)with.regular/.clear,.tint(_:),.interactive();buttonStyle(.glass)and.glassProminentfor buttons.- Glass is chrome, not content: use it for the floating control layer above scrolling content, never for list rows or whole backgrounds. One glass layer — don't nest.
- Let content flow under bars:
backgroundExtensionEffect()for hero images,scrollEdgeEffectStyle(_:for:)to manage edge legibility,tabBarMinimizeBehavior(.onScrollDown)on TabView. - Custom-styled controls: audit tinted/rounded hand-rolled buttons — replace with glass button styles rather than approximating.
- Escape hatch while migrating:
UIDesignRequiresCompatibilityInfo.plist key (temporary; Apple has said it is going away — treat as tech debt). - iOS 27 beta refinements: respect the
appearsActiveenvironment value for glass emphasis; toolbar items getvisibilityPriority,ToolbarOverflowMenu, and pinned-trailing placement — see references/platform-integration.md and layout ref.
Routing table
| Question smells like… | Go to | |---|---| | @Observable vs @State vs @Binding, environment DI, ObservableObject migration, SwiftData in views | references/state-and-data-flow.md | | Custom layout, Grid, ViewThatFits, adaptive UI, transitions, matchedGeometry, phase/keyframe animation, scroll APIs, reordering | references/layout-and-animation.md | | Slow lists, hitches, spinning bodies, Instruments traces, identity bugs, "why did this view update" | references/performance-and-debugging.md | | UIKit/AppKit interop, hosting, representables, widgets, Live Activities, App Intents, multiplatform targets | references/platform-integration.md | | Building a specific component: bottom sheet, custom tab bar, parallax header, infinite scroll, skeleton, search, forms, image grids, onboarding, charts, toasts, list state machines | references/component-recipes.md | | Should I use a library? Which one? Pow, Lottie, Nuke vs Kingfisher, markdown, TCA vs vanilla, snapshot testing, hot reload, DI | references/ecosystem-libraries.md | | Design tokens, theming, custom fonts with Dynamic Type, reusable component package, brand consistency, style protocols | references/design-system-kit.md | | Rendering/screenshotting what I built, simulator CLI, previews at scale, snapshot tests, hot reload setup, visual QA matrix | references/visual-iteration-workflow.md | | async/await, actors, Sendable, MainActor isolation, Swift 6 errors, testing | sibling skill swift-language |
When reviewing code: run the translation table first (deprecated API sweep), then identity/state checks, then performance only if there's a reported symptom.
Companions & orchestration
Part of the swift-tothemax plugin — apple-dev-conductor routes multi-facet tasks. Siblings: swift-language owns concurrency/data/performance below the view layer (route non-UI Swift there); apple-hig-ux owns design judgment — consult it BEFORE building a screen, not after. Ecosystem companions (delegate if installed): swiftui-expert-skill / swiftui-pro for deep SwiftUI code review; swiftui-performance-audit for hitch investigations with Instruments. Prefer their workflows for those sub-tasks; keep this skill's WWDC26-current API facts when they disagree on versions. After substantial UI work, run a ui-crawler-max sweep (sibling skill) to exercise every screen and harvest errors, crashes, and unlabeled controls — then fix its findings here.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Dev869
- Source: Dev869/swift-tothemax
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.