### Install Skill with pi package manager Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/README.md Install the skill using the 'pi' package manager. This command fetches and installs the skill, making it available automatically in pi sessions. ```bash pi install https://github.com/AvdLee/SwiftUI-Agent-Skill ``` -------------------------------- ### Install Skill with skills.sh Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/README.md Use this command to install the skill via the skills.sh platform. This is a quick way to add the skill to your environment. ```bash npx skills add https://github.com/avdlee/swiftui-agent-skill --skill swiftui-expert-skill ``` -------------------------------- ### Example Agent Prompts for Trace Analysis and Recording Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/README.md These are example prompts the agent can use to trigger trace analysis or recording. They demonstrate how to specify trace files, focus analysis, and initiate recording sessions. ```text Analyse ~/Desktop/MyApp.trace and tell me what's wrong. Focus analysis on what happens right after the 'feed loaded' log. Which of my SwiftUI views is responsible for the hang around 6s? Record a new trace: attach to MyApp on my iPhone — I'll tell you when I'm done. ``` -------------------------------- ### SwiftUI Text Initialization Examples Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/text-patterns.md Demonstrates the three primary ways to initialize a SwiftUI Text view: for localization, with a string variable, and as a non-localized literal. ```swift // Localized literal - "Save" is used as the localization key and looked up in Localizable.strings (only if one exists in the project) Text("Save") ``` ```swift // String variable - bypasses localization automatically; no verbatim needed let filename: String = model.exportFilename Text(filename) ``` ```swift // Non-localized literal - use verbatim only when the literal must not be localized Text(verbatim: "pencil") ``` -------------------------------- ### Chaining Trace Recording and Analysis Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md This example demonstrates how to capture the output trace path from the recording script and immediately pipe it into the analysis script for further processing. ```bash TRACE=$(python3 "${SKILL_DIR}/scripts/record_trace.py" \ --attach Helm --stop-file /tmp/stop-trace --output ~/Desktop/session.trace \ 2>&1 | awk '/trace written:/ {print $NF}') python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace "$TRACE" --json-only ``` -------------------------------- ### Install Claude Code Plugin Skill Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/README.md Install the specific swiftui-expert skill from the previously added marketplace in Claude Code. Ensure you use the correct version identifier. ```bash /plugin install swiftui-expert@swiftui-expert-skill ``` -------------------------------- ### Record SwiftUI Trace in Background Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/SKILL.md Starts a SwiftUI trace recording in the background for agent-driven sessions. The recording stops when the specified stop-file is touched. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" \ --device "" --attach "" \ --stop-file /tmp/stop-trace --output ~/Desktop/session.trace ``` -------------------------------- ### Chart Framework Initialization Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/charts.md Essential setup for using SwiftUI Charts, including importing the framework and defining the root Chart container. ```swift import SwiftUI import Charts Chart(sales) { item in BarMark( x: .value("Month", item.month), y: .value("Revenue", item.revenue) ) } ``` -------------------------------- ### Guide Focus Movement with .focusSection Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/focus-patterns.md Apply `.focusSection()` to a group of focusable descendants to guide directional and sequential focus movement. This is beneficial when focusable elements are spatially separated and standard navigation might skip them. ```swift HStack { VStack { Button("1") {}; Button("2") {}; Spacer() } Spacer() VStack { Spacer(); Button("A") {}; Button("B") {} } .focusSection() } ``` -------------------------------- ### Configure Default Window Size and Resizability Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/macos-window-styling.md Sets the initial size and resizability behavior for a window. `.defaultSize` defines the initial dimensions, `.defaultPosition` sets the starting location, and `.windowResizability(.contentMinSize)` allows resizing based on content minimums. ```swift WindowGroup { ContentView() .frame(minWidth: 600, minHeight: 400) } .defaultSize(width: 900, height: 600) .defaultPosition(.center) .windowResizability(.contentMinSize) ``` -------------------------------- ### Complex View with Multiple State Sources Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md This example shows a large SwiftUI view that depends on multiple independent state sources, potentially leading to unnecessary re-evaluations of the entire view body on any state change. ```swift struct BigAndComplicatedView: View { @State private var counter = 0 @State private var isToggled = false @StateObject private var viewModel = SomeViewModel() let title = "Big and Complicated View" var body: some View { VStack { Text(title) .font(.largeTitle) Text("Counter: \(counter)") .font(.title) Toggle("Enable Feature", isOn: $isToggled) .padding() Button("Increment Counter") { counter += 1 } Text("ViewModel Data: \(viewModel.data)") .padding() Button("Fetch Data") { viewModel.fetchData() } } } } ``` -------------------------------- ### Use @ViewBuilder for Container View Content Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md This example shows the recommended approach using @ViewBuilder for content in container views. This allows SwiftUI to compare the content and skip updates when it hasn't changed, improving performance. Use this pattern for efficient view updates. ```swift // GOOD - view can be compared struct MyContainer: View { @ViewBuilder let content: Content var body: some View { VStack { Text("Header") content // SwiftUI can compare and skip if unchanged } } } // Usage - SwiftUI can diff ExpensiveView MyContainer { ExpensiveView() } ``` -------------------------------- ### SwiftUI: DocumentGroup for Document-Based Apps Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/macos-scenes.md Demonstrates the setup for a document-based application using DocumentGroup. This includes defining a custom document type conforming to FileDocument and integrating it into the app's scene structure. ```swift DocumentGroup(newDocument: TextFile()) { ContentView(document: config.$document) } struct TextFile: FileDocument { static var readableContentTypes: [UTType] { [.plainText] } var text: String = "" init() {} init(configuration: ReadConfiguration) throws { text = String(data: configuration.file.regularFileContents ?? Data(), encoding: .utf8) ?? "" } func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper { FileWrapper(regularFileWithContents: Data(text.utf8)) } } ``` -------------------------------- ### Launch App and Record Trace Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md Launch an application and record a trace from its initial frame. This is useful for diagnosing cold-start performance issues. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" \ --device "" \ --launch "/path/to/App.app" \ --output ~/Desktop/launch.trace ``` -------------------------------- ### Create Composite Scrollable Bar Charts Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/charts-accessibility.md An example of a complex chart using iOS 17+ APIs, including horizontal scrolling, selection ranges, and custom axis formatting. ```swift @State private var selectedRange: ClosedRange? Chart(weeklyRevenue) { week in BarMark(x: .value("Week", week.index), y: .value("Revenue", week.revenue)) .foregroundStyle(by: .value("Region", week.region)) } .chartScrollableAxes(.horizontal) .chartXVisibleDomain(length: 8) .chartXSelection(range: $selectedRange) .chartXAxis { AxisMarks(values: .stride(by: 1)) { AxisGridLine() AxisValueLabel { Text("W\($0.as(Int.self) ?? 0)") } } } ``` -------------------------------- ### #Preview Macro with Traits Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Configure the preview environment using traits without altering the view's code. This allows for testing different layouts, sizes, and orientations. ```swift // Fixed size #Preview(traits: .fixedLayout(width: 300, height: 100)) { CompactBanner(message: "Welcome") } // Size that fits content #Preview(traits: .sizeThatFitsLayout) { BadgeView(count: 5) } // Landscape orientation #Preview(traits: .landscapeLeft) { DashboardView() } ``` -------------------------------- ### Narrow State Scope in SwiftUI Views Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/performance-patterns.md Pass only necessary data to child views instead of the entire model to reduce update fan-out. The 'Good' example demonstrates passing specific values as `let` properties, while the 'Bad' example shows a broad dependency on the entire `@Environment` model. ```swift // Bad - broad dependency on entire model struct ItemRow: View { @Environment(AppModel.self) private var model let item: Item var body: some View { Text(item.name).foregroundStyle(model.theme.primaryColor) } } // Good - narrow dependency struct ItemRow: View { let item: Item let themeColor: Color var body: some View { Text(item.name).foregroundStyle(themeColor) } } ``` -------------------------------- ### List Connected Devices Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/SKILL.md Lists available devices and simulators for trace recording. Use this to identify the correct device name or UDID. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices ``` -------------------------------- ### Disable Animations in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-basics.md Provides methods for disabling animations in SwiftUI. The 'GOOD' examples show disabling animations using the `.transaction` modifier, either directly or from a parent context. The 'BAD' example illustrates a less ideal approach using a zero-duration linear animation. ```swift // GOOD - disable with transaction Text("Count: \(count)") .transaction { $0.animation = nil } // GOOD - disable from parent context DataView() .transaction { $0.disablesAnimations = true } // BAD - hacky zero duration Text("Count: \(count)") .animation(.linear(duration: 0), value: count) // Hacky ``` -------------------------------- ### Avoid Animation in Hot Paths (SwiftUI) Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-basics.md Demonstrates how to avoid unnecessary animations in performance-sensitive areas like scroll views. The 'GOOD' example gates animation by a threshold, ensuring it only triggers when needed, while the 'BAD' example animates on every scroll change, potentially impacting performance. ```swift // GOOD - gate by threshold .onPreferenceChange(ScrollOffsetKey.self) { offset in let shouldShow = offset.y < -50 if shouldShow != showTitle { // Only when crossing threshold withAnimation(.easeOut(duration: 0.2)) { showTitle = shouldShow } } } // BAD - animating every scroll change .onPreferenceChange(ScrollOffsetKey.self) { offset in withAnimation { // Fires constantly! self.offset = offset.y } } ``` -------------------------------- ### List Instruments Templates Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md Obtain a JSON list of all available Instruments templates. This is useful for selecting the correct template for specific recording needs. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" --list-templates ``` -------------------------------- ### Static Sample Data for Models Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Expose sample data as static properties on your model types. This makes it easy for previews to reuse self-contained data without needing to construct it inline. ```swift struct Item: Identifiable { let id: UUID var name: String var price: Double } extension Item { static let sample = Item(id: UUID(), name: "Widget", price: 9.99) static let samples: [Item] = [ Item(id: UUID(), name: "Widget", price: 9.99), Item(id: UUID(), name: "Gadget", price: 19.99), Item(id: UUID(), name: "Doohickey", price: 4.99), ] } #Preview { ItemListView(items: Item.samples) } ``` -------------------------------- ### Configure Project for Cursor Plugin Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/README.md Configure your project's .claude/settings.json to automatically enable the swiftui-expert skill for all team members. This ensures consistent skill availability. ```json { "enabledPlugins": { "swiftui-expert@swiftui-expert-skill": true }, "extraKnownMarketplaces": { "swiftui-expert-skill": { "source": { "source": "github", "repo": "AvdLee/SwiftUI-Agent-Skill" } } } } ``` -------------------------------- ### Manual AnimatableData for Wedge Shape Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Before the `@Animatable` macro, `animatableData` had to be manually synthesized for custom shapes. This example shows manual conformance for a `Wedge` shape. ```swift struct Wedge: Shape { var startAngle: Angle var endAngle: Angle var drawClockwise: Bool var animatableData: AnimatablePair { get { AnimatablePair(startAngle.radians, endAngle.radians) } set { startAngle = .radians(newValue.first) endAngle = .radians(newValue.second) } } func path(in rect: CGRect) -> Path { /* ... */ } ``` -------------------------------- ### Animation Precedence Example Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Demonstrates how implicit animations (defined later in the view hierarchy) override explicit animations. In this case, `.bouncy` wins over `.linear`. ```swift Button("Tap") { withAnimation(.linear) { flag.toggle() } } .animation(.bouncy, value: flag) // .bouncy wins! ``` -------------------------------- ### SwiftUI View with Ordered Properties Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Demonstrates a recommended ordering for properties within a SwiftUI View struct for improved readability. Includes environment, state, bindings, private properties, initializers, body, and computed subviews. ```swift struct ContentView: View { // MARK: - Environment Properties @Environment(\Core.colorScheme) var colorScheme // MARK: - State Properties @Binding var isToggled: Bool @State private var viewModel: SomeViewModel // MARK: - Private Properties private let title: String = "SwiftUI Guide" // MARK: - Initializer (if needed) init(isToggled: Binding) { self._isToggled = isToggled } // MARK: - Body var body: some View { VStack { header content } } // MARK: - Computed Subviews private var header: some View { Text(title).font(.largeTitle).padding() } private var content: some View { VStack { Text("Counter: \(counter)") } } } ``` -------------------------------- ### List Connected Devices Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md Retrieve a JSON list of all connected devices, simulators, and the host machine. This helps in identifying available targets for recording. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" --list-devices ``` -------------------------------- ### Basic #Preview Macro Usage Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Use the #Preview macro for modern SwiftUI previews. It is less verbose than the legacy `PreviewProvider` protocol and supports inline traits. ```swift // Modern: #Preview macro #Preview { ContentView() } // Named preview #Preview("Dark Mode") { ContentView() .preferredColorScheme(.dark) } // Legacy: PreviewProvider — still valid, but verbose for new code struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } ``` -------------------------------- ### List Logs in Trace Analysis Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/SKILL.md Find a log that marks the start or end of a region of interest within a trace file. This can be filtered by log message content and a limit. ```bash python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace \ --list-logs --log-message-contains "loaded feed" --log-limit 5 ``` -------------------------------- ### Use Different Glass Styles Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/liquid-glass.md Choose from `.regular`, `.clear`, or `.identity` glass styles. For a more prominent appearance, adjust tint opacity rather than seeking a `.prominent` style. ```swift .glassEffect(.regular) .glassEffect(.clear) .glassEffect(.identity) ``` -------------------------------- ### SwiftUI Background Shape Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Use the background modifier with a shape to create a decorative background that naturally adopts the parent's size. This example applies a blue bordered capsule to an HStack. ```swift HStack(spacing: 12) { Text("Inbox"); Text("Next") } \ .background { Capsule().strokeBorder(.blue, lineWidth: 2) } ``` -------------------------------- ### Basic AsyncImage with Phase Handling in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/image-optimization.md Demonstrates the basic usage of AsyncImage in SwiftUI, including handling loading, success, and error states. This approach ensures a responsive UI by showing a progress view during loading and a placeholder image on failure. ```swift AsyncImage(url: imageURL) { phase in switch phase { case .empty: ProgressView() case .success(let image): image .resizable() .aspectRatio(contentMode: .fit) case .failure: Image(systemName: "photo") .foregroundStyle(.secondary) @unknown default: EmptyView() } } .frame(width: 200, height: 200) ``` -------------------------------- ### Prepare Data Outside View Body Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Prepare data, such as filtering or sorting, outside the view's body. This is achieved by performing the operation once, for example in an initializer, and storing the result in a property. ```swift struct FilteredListView: View { private let filteredValues: [Int] init(values: [Int]) { self.filteredValues = values.filter { $0 > 0 } // Perform filtering once } var body: some View { List { content } } private var content: some View { ForEach(filteredValues, id: \.self) { Text(String($0)) .padding() } } } ``` -------------------------------- ### Create POD Views for Fast Diffing in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/performance-patterns.md Illustrates Plain Old Data (POD) views that use `memcmp` for efficient diffing, contrasting them with non-POD views that may use property wrappers. ```swift // POD view - fastest diffing struct FastView: View { let title: String let count: Int var body: some View { Text("\(title): \(count)") } } // Non-POD view - uses reflection or custom equality struct SlowerView: View { let title: String @State private var isExpanded = false // Property wrapper makes it non-POD var body: some View { Text(title) } } ``` -------------------------------- ### Standard Chart Marks Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/charts.md Implementation examples for various chart marks including Bar, Line, Area, Point, Rectangle, Rule, and Sector marks. ```swift // BarMark BarMark(x: .value("Product", product.name), y: .value("Units", product.units)) // LineMark LineMark(x: .value("Day", day.date), y: .value("Steps", day.count)).interpolationMethod(.monotone) // AreaMark AreaMark(x: .value("Day", sample.day), yStart: .value("Low", sample.low), yEnd: .value("High", sample.high)) // SectorMark (iOS 17+) SectorMark(angle: .value("Amount", expense.amount), innerRadius: .ratio(0.6), angularInset: 2) .foregroundStyle(by: .value("Category", expense.category)) ``` -------------------------------- ### SwiftUI Layering with ZStack Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Avoid using ZStack for simple decoration when overlay suffices, as ZStack can disrupt the layout anchoring of the primary view. This example shows an incorrect use of ZStack for a decorative icon. ```swift ZStack(alignment: .trailing) { \ Button("Continue") { } \ Image(systemName: "lock.fill").padding(.trailing, 8) \ } ``` -------------------------------- ### SwiftUI: Creating Main and Supplementary Windows Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/macos-scenes.md Demonstrates how to define the main application scene using WindowGroup and supplementary singleton windows using Window. The supplementary window can be opened programmatically via an environment action. ```swift @main struct Mail: App { var body: some Scene { WindowGroup { MailViewer() } // Supplementary singleton window Window("Connection Doctor", id: "connection-doctor") { ConnectionDoctor() } } } // Open programmatically — brings to front if already open struct OpenDoctorButton: View { @Environment(\.openWindow) private var openWindow var body: some View { Button("Connection Doctor") { openWindow(id: "connection-doctor") } } } ``` -------------------------------- ### SwiftUI Decoration with Overlay Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Use overlay to add decorative elements to a primary view, ensuring the primary view remains the layout anchor. This example adds a lock icon to the trailing edge of a Button. ```swift Button("Continue") { } \ .overlay(alignment: .trailing) { \ Image(systemName: "lock.fill").padding(.trailing, 8) \ } ``` -------------------------------- ### Interactive FocusState with @Previewable Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Manage focus states within previews using `@Previewable @FocusState` and `.defaultFocus` for initial seeding. This approach is preferred over using `.onAppear` to avoid potential race conditions with initial rendering. ```swift #Preview { @Previewable @FocusState var isFocused: Bool TextField("Search", text: .constant("")) .focused($isFocused) .defaultFocus($isFocused, true) } ``` -------------------------------- ### Basic Phase Animator Usage Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Use phaseAnimator to cycle through discrete animation phases automatically or with a trigger. The first example shows a triggered animation, while the second demonstrates an infinite loop without a trigger. ```swift // GOOD - triggered phase animation Button("Shake") { trigger += 1 } .phaseAnimator( [0.0, -10.0, 10.0, -5.0, 5.0, 0.0], trigger: trigger ) { content, offset in content.offset(x: offset) } // Infinite loop (no trigger) Circle() .phaseAnimator([1.0, 1.2, 1.0]) { content, scale in content.scaleEffect(scale) } ``` -------------------------------- ### Run Main Trace Analysis Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/SKILL.md Perform the main analysis on a trace file, optionally specifying a time window. This command outputs results in JSON format and can be limited to the top N items. ```bash python3 "${SKILL_DIR}/scripts/analyze_trace.py" --trace \ --json-only --top 10 [--window START_MS:END_MS] ``` -------------------------------- ### Querying Keyframe Animation Values with KeyframeTimeline Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Use KeyframeTimeline to get specific animation values at a given time, useful for testing or non-SwiftUI contexts. It requires an initial value struct and defines KeyframeTracks. ```swift let timeline = KeyframeTimeline(initialValue: AnimationValues()) { KeyframeTrack(\.scale) { CubicKeyframe(1.2, duration: 0.25) CubicKeyframe(1.0, duration: 0.25) } } let midpoint = timeline.value(time: 0.25) print(midpoint.scale) // Value at 0.25 seconds ``` -------------------------------- ### Adaptive SwiftUI Table for Compact Layouts Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/list-patterns.md Create a table that adapts to compact size classes by customizing the content of the first column to display combined information. Subsequent columns are hidden on compact devices. ```swift struct AdaptiveTable: View { @Environment(\.horizontalSizeClass) private var horizontalSizeClass private var isCompact: Bool { horizontalSizeClass == .compact } @State private var people: [Person] = [ /* ... */ ] @State private var sortOrder = [KeyPathComparator(\.givenName)] var body: some View { Table(people, sortOrder: $sortOrder) { TableColumn("Given Name", value: \.givenName) { person in VStack(alignment: .leading) { Text(isCompact ? person.fullName : person.givenName) if isCompact { Text(person.emailAddress) .foregroundStyle(.secondary) } } } TableColumn("Family Name", value: \.familyName) TableColumn("E-Mail Address", value: \.emailAddress) } .onChange(of: sortOrder) { _, newOrder in people.sort(using: newOrder) } } } ``` -------------------------------- ### Define Meaningful Labels for Swift Charts Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/charts-accessibility.md Demonstrates the importance of using descriptive labels in Mark initializers. These labels are critical for VoiceOver accessibility and audio graph interpretation. ```swift // Good — descriptive labels LineMark( x: .value("Date", entry.date), y: .value("Daily Steps", entry.count) ) // Bad — generic labels LineMark( x: .value("X", entry.date), y: .value("Y", entry.count) ) ``` -------------------------------- ### Phase Animator vs. Manual DispatchQueue Sequencing Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Illustrates the 'GOOD' practice of using phaseAnimator for multi-step sequences compared to the 'BAD' practice of manual DispatchQueue sequencing for animations. ```swift // GOOD - use phaseAnimator for multi-step sequences .phaseAnimator([0, -10, 10, 0], trigger: trigger) { content, offset in content.offset(x: offset) } // BAD - manual DispatchQueue sequencing Button("Animate") { withAnimation(.easeOut(duration: 0.1)) { offset = -10 } DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { withAnimation { offset = 10 } } DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { withAnimation { offset = 0 } } } ``` -------------------------------- ### Implement Custom Audio Graphs with AXChartDescriptorRepresentable Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/charts-accessibility.md Shows how to conform a view to AXChartDescriptorRepresentable to provide custom accessibility data. This allows VoiceOver to generate an audio representation of the chart data. ```swift struct StepsChart: View, AXChartDescriptorRepresentable { let steps: [DailySteps] var body: some View { Chart(steps) { day in LineMark(x: .value("Date", day.date), y: .value("Steps", day.count)) } .accessibilityChartDescriptor(self) } func makeChartDescriptor() -> AXChartDescriptor { guard let first = steps.first, let last = steps.last else { return AXChartDescriptor(title: "Daily Step Count", summary: nil, xAxis: AXNumericDataAxisDescriptor(title: "Date", range: 0...1, gridlinePositions: []) { "\($0)" }, yAxis: AXNumericDataAxisDescriptor(title: "Steps", range: 0...1, gridlinePositions: []) { "\($0)" }, additionalAxes: [], series: []) } let xAxis = AXDateDataAxisDescriptor( title: "Date", range: first.date...last.date, gridlinePositions: []) let yAxis = AXNumericDataAxisDescriptor( title: "Steps", range: 0...Double(steps.map(\.count).max() ?? 0), gridlinePositions: []) { "\(Int($0)) steps" } let series = AXDataSeriesDescriptor( name: "Daily Steps", isContinuous: true, dataPoints: steps.map { .init(x: $0.date, y: Double($0.count)) }) return AXChartDescriptor(title: "Daily Step Count", summary: nil, xAxis: xAxis, yAxis: yAxis, additionalAxes: [], series: [series]) } } ``` -------------------------------- ### Environment Action to Open Settings Window Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/macos-scenes.md Demonstrates how to programmatically open or bring the Settings window to the front using the @Environment(\.openSettings) property wrapper in SwiftUI. This is useful for creating buttons or actions that trigger the display of application preferences. ```swift struct OpenSettingsButton: View { @Environment(\.openSettings) private var openSettings var body: some View { Button("Open Settings") { openSettings() } } } ``` -------------------------------- ### Full Trace Analysis Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-analysis.md Perform a comprehensive analysis of a trace file, outputting results in JSON format. Use --window to focus on a specific time slice and --run to select a specific recording session if the trace contains multiple. ```bash python3 "${SKILL_DIR}/scripts/analyze_trace.py" \ --trace "/path/to/file.trace" \ --top 10 --top-hitches 5 \ [--window START_MS:END_MS] \ --json-only ``` -------------------------------- ### Conditional View Rendering with Concrete Types Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Prefer conditional branches with concrete view types or `@ViewBuilder` over `AnyView` to allow SwiftUI to optimize view updates. This example shows a conditional `TextField` or `Text` based on an `isEditable` state. ```swift private var nameView: some View { if isEditable { TextField("Your name", text: $name) } else { Text(name) } } ``` -------------------------------- ### Avoid Closure-Based Content in Container Views Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md This example demonstrates a common pitfall where using a closure for content in a container view prevents SwiftUI from optimizing updates, leading to unnecessary re-renders. Use this pattern when you want to force re-renders. ```swift // BAD - closure prevents SwiftUI from skipping updates struct MyContainer: View { let content: () -> Content var body: some View { VStack { Text("Header") content() // Always called, can't compare closures } } } // Usage forces re-render on every parent update MyContainer { ExpensiveView() } ``` -------------------------------- ### Agent-Driven Recording with Stop File Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md Initiate a trace recording in the background and use a stop-file to signal its clean termination. The script polls for the stop-file and sends SIGINT to xctrace. ```bash # Start recording (background) python3 "${SKILL_DIR}/scripts/record_trace.py" \ --attach Helm --stop-file /tmp/stop-trace \ --output ~/Desktop/session.trace # ...user does their thing... # Stop cleanly (from another shell or tool call) touch /tmp/stop-trace ``` -------------------------------- ### Manual animatableData with Custom Logic (iOS 26+) Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Implement `animatableData` manually when interpolation requires custom logic like normalization or clamping. For iOS 26+, use `AnimatableValues`. This example shows clamping amplitude and normalizing phase for a `WaveShape`. ```swift // iOS 26+: keep phase in 0..<2π and clamp amplitude during interpolation struct WaveShape: Shape { var amplitude: CGFloat var phase: CGFloat var maxAmplitude: CGFloat var animatableData: AnimatableValues { get { AnimatableValues(amplitude, phase) } set { amplitude = min(max(newValue.value.0, 0), maxAmplitude) phase = newValue.value.1.truncatingRemainder(dividingBy: 2 * .pi) } } func path(in rect: CGRect) -> Path { /* ... */ } ``` -------------------------------- ### Mocking Async Data with Protocols Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Inject a synchronous mock data fetcher into a view for previews by defining a protocol abstraction for the data service. This allows previews to display sample data immediately without making actual network requests. ```swift protocol DataFetching { func fetchItems() async throws -> [Item] } struct LiveDataFetcher: DataFetching { let url: URL func fetchItems() async throws -> [Item] { let (data, _) = try await URLSession.shared.data(from: url) return try JSONDecoder().decode([Item].self, from: data) } } struct MockDataFetcher: DataFetching { var result: Result<[Item], Error> = .success(Item.samples) func fetchItems() async throws -> [Item] { try result.get() } } #Preview { ItemListView(fetcher: MockDataFetcher()) } #Preview("Error State") { ItemListView(fetcher: MockDataFetcher(result: .failure(URLError(.notConnectedToInternet)))) } ``` -------------------------------- ### Avoid Computed Properties for Complex Views in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md Using @ViewBuilder functions or computed properties for complex views causes the entire function to re-execute on every parent state change, leading to unnecessary re-renders. This example demonstrates the inefficient approach. ```swift // BAD - re-executes complexSection() on every tap struct ParentView: View { @State private var count = 0 var body: some View { VStack { Button("Tap: \(count)") { count += 1 } complexSection() // Re-executes every tap! } } @ViewBuilder func complexSection() -> some View { // Complex views that re-execute unnecessarily ForEach(0..<100) { i in HStack { Image(systemName: "star") Text("Item \(i)") Spacer() Text("Detail") } } } } ``` -------------------------------- ### Mock Observable Models for Previews Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md For views using observable models, expose pre-configured instances as static properties on the model itself. This allows previews to easily inject different states like 'with items', 'empty', or 'loading'. ```swift @Observable @MainActor final class CartModel { var items: [Item] = [] var isLoading = false static var preview: CartModel { let model = CartModel() model.items = Item.samples return model } static var emptyPreview: CartModel { CartModel() } static var loadingPreview: CartModel { let model = CartModel() model.isLoading = true return model } } #Preview("With Items") { CartView() .environment(CartModel.preview) } #Preview("Empty") { CartView() .environment(CartModel.emptyPreview) } #Preview("Loading") { CartView() .environment(CartModel.loadingPreview) } ``` -------------------------------- ### Coarsen Environment Values with @Observable Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/performance-patterns.md Hold frequently changing values in an `@Observable` model and expose a coarsened value (e.g., a boolean threshold) to prevent invalidation storms. This example shows a `ViewportModel` where `isWide` only updates when the `width` crosses a specific threshold. ```swift @MainActor @Observable final class ViewportModel { var width: CGFloat = 0 { didSet { isWide = width > 600 } } private(set) var isWide = false // readers invalidate only when this flips } ``` -------------------------------- ### Implement NavigationSplitView Layouts in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/sheet-navigation-patterns.md Provides examples for creating two-column and three-column navigation interfaces. These layouts adapt automatically to different device sizes and platforms, supporting selection-based state management. ```swift struct ContentView: View { @State private var selectedItem: Item.ID? var body: some View { NavigationSplitView { List(items, selection: $selectedItem) { item in Text(item.name) } .navigationTitle("Items") } detail: { if let selectedItem, let item = items.first(where: { $0.id == selectedItem }) { ItemDetailView(item: item) } else { ContentUnavailableView("Select an Item", systemImage: "doc") } } } } ``` ```swift struct ContentView: View { @State private var departmentId: Department.ID? @State private var employeeIds = Set() var body: some View { NavigationSplitView { List(model.departments, selection: $departmentId) { dept in Text(dept.name) } } content: { if let department = model.department(id: departmentId) { List(department.employees, selection: $employeeIds) { emp in Text(emp.name) } } else { Text("Select a department") } } detail: { EmployeeDetails(for: employeeIds) } } } ``` -------------------------------- ### Implement Relative Layouts in SwiftUI Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/layout-best-practices.md Demonstrates how to use GeometryReader for dynamic sizing instead of hard-coded magic numbers. This ensures UI elements adapt correctly to varying screen sizes and orientations. ```swift // Good - relative to actual layout GeometryReader { geometry in VStack { HeaderView() .frame(height: geometry.size.height * 0.2) ContentView() } } // Avoid - magic numbers that don't adapt VStack { HeaderView() .frame(height: 150) // Doesn't adapt to different screens ContentView() } ``` -------------------------------- ### Attach to Running App Trace Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/trace-recording.md Use this command to attach the trace recording to an already running application on a connected device. Stop the recording manually with Ctrl+C. ```bash python3 "${SKILL_DIR}/scripts/record_trace.py" \ --device "Pol's iPhone" \ --attach "Helm" \ --output ~/Desktop/helm-session.trace ``` -------------------------------- ### Utilize LazyVStack for Large Data Sets Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/view-structure.md This example demonstrates how to use LazyVStack within a ScrollView to efficiently render a large number of items. Lazy containers only load views when they are about to appear on screen, optimizing memory usage and performance. Prefer this for rendering collections. ```swift struct ContentView: View { let items = Array(0..<1000) var body: some View { ScrollView { LazyVStack { ForEach(items, id: \.self) { item in Text("Item \(item)") } } } } } ``` -------------------------------- ### SwiftUI Basic Transitions and Animation Context Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-transitions.md Demonstrates how to apply basic built-in SwiftUI transitions like .slide and .scale. It emphasizes the critical requirement of providing an animation context (using .animation or withAnimation) outside the conditional block where the view is inserted or removed. ```swift import SwiftUI struct BasicTransitionsView: View { @State private var showDetail = false var body: some View { VStack { Button("Toggle") { showDetail.toggle() } if showDetail { Text("Hello, World!") .padding() .background(Color.green) .transition(.slide.combined(with: .opacity)) // Combined transition } } .animation(.spring, value: showDetail) // Animation context for the transition } } struct BasicTransitionsView_Previews: PreviewProvider { static var previews: some View { BasicTransitionsView() } } ``` -------------------------------- ### Preview with Environment Dependencies Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/previews.md Inject environment values like locale or dynamic type size into the preview using the `.environment()` modifier. This ensures the preview accurately reflects how the view behaves in different runtime contexts. ```swift #Preview { OrderDetailView(order: .sample) .environment(CartModel.preview) .environment(\.locale, Locale(identifier: "ja_JP")) .environment(\.dynamicTypeSize, .xxxLarge) } ``` -------------------------------- ### Per-Item @Observable State for List Performance Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/performance-patterns.md Use per-item `@Observable` state holders for list items to narrow update scope. This prevents all list items from re-evaluating their bodies when only one item's state changes, as demonstrated by the 'Good' example using `LandmarkViewModel`. ```swift // BAD - all item views depend on the full favorites array @Observable class ModelData { var favorites: [Landmark] = [] func isFavorite(_ landmark: Landmark) -> Bool { favorites.contains(landmark) } } struct LandmarkRow: View { let landmark: Landmark @Environment(ModelData.self) private var model var body: some View { HStack { Text(landmark.name) if model.isFavorite(landmark) { Image(systemName: "heart.fill") } } } } // GOOD - each item has its own observable view model @Observable class LandmarkViewModel { var isFavorite: Bool = false } struct LandmarkRow: View { let landmark: Landmark let viewModel: LandmarkViewModel var body: some View { HStack { Text(landmark.name) if viewModel.isFavorite { Image(systemName: "heart.fill") } } } } ``` -------------------------------- ### Basic Transaction Usage Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/animation-advanced.md Use `withAnimation` for shorthand or `withTransaction` for explicit control over animation properties. ```swift // withAnimation is shorthand for withTransaction withAnimation(.default) { flag.toggle() } // Equivalent explicit transaction var transaction = Transaction(animation: .default) withTransaction(transaction) { flag.toggle() } ``` -------------------------------- ### Add Toolbar Items and Searchable Modifier Source: https://github.com/avdlee/swiftui-agent-skill/blob/main/swiftui-expert-skill/references/macos-window-styling.md Shows how to add content to the toolbar using `ToolbarItem` and implement a searchable interface using the `.searchable` modifier. This example places a 'plus' button in the toolbar and enables search within the sidebar. ```swift struct ContentView: View { @State private var searchText = "" var body: some View { NavigationSplitView { SidebarView() } detail: { DetailView() } .toolbar { ToolbarItem(placement: .automatic) { Button(action: addItem) { Label("Add", systemImage: "plus") } } } .searchable(text: $searchText, placement: .sidebar) } } ```