Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate SwiftUI views with proper state management (@State, @Binding, @ObservedObject, @StateObject) and macOS-specific patterns
.claude/skills/a5c-ai-swiftui-view-generator/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 2534% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -16% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 82% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 102% | 0% |
| case-03 | ✓→✗ | ▼ Worse | 116% | 0% |
Generate SwiftUI views with proper state management for macOS applications. This skill creates well-structured SwiftUI components using @State, @Binding, @ObservedObject, @StateObject, and @EnvironmentObject property wrappers.
json{ "type": "object", "properties": { "projectPath": { "type": "string", "description": "Path to the Swift project" }, "viewName": { "type": "string", "description": "Name of the view to generate" }, "viewType": { "enum": ["screen", "component", "list", "form", "settings", "sheet"], "default": "screen" }, "stateProperties": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "wrapper": { "enum": ["State", "Binding", "ObservedObject", "StateObject", "EnvironmentObject"] } } } }, "includeViewModel": { "type": "boolean", "default": true }, "macOSSpecific": { "type": "boolean", "default": true } }, "required": ["projectPath", "viewName"] }
json{ "type": "object", "properties": { "success": { "type": "boolean" }, "files": { "type": "array", "items": { "type": "object", "properties": { "path": { "type": "string" }, "type": { "enum": ["view", "viewmodel", "model"] } } } } }, "required": ["success"] }
swift// ContentView.swift import SwiftUI struct ContentView: View { @StateObject private var viewModel = ContentViewModel() @State private var searchText = "" @State private var isShowingSettings = false var body: some View { NavigationSplitView { // Sidebar SidebarView(selection: $viewModel.selectedCategory) } detail: { // Detail view if let category = viewModel.selectedCategory { CategoryDetailView(category: category) } else { Text("Select a category") .foregroundStyle(.secondary) } } .searchable(text: $searchText, prompt: "Search items...") .onChange(of: searchText) { _, newValue in viewModel.search(query: newValue) } .toolbar { ToolbarItemGroup { Button(action: viewModel.refresh) { Label("Refresh", systemImage: "arrow.clockwise") } Button(action: { isShowingSettings = true }) { Label("Settings", systemImage: "gear") } } } .sheet(isPresented: $isShowingSettings) { SettingsView() } .task { await viewModel.loadData() } } } // MARK: - Preview #Preview { ContentView() } #Preview("With Data") { ContentView() .environmentObject(PreviewData.sampleViewModel) }
swift// ContentViewModel.swift import SwiftUI import Combine @MainActor class ContentViewModel: ObservableObject { @Published var items: [Item] = [] @Published var selectedCategory: Category? @Published var isLoading = false @Published var errorMessage: String? private let dataService: DataService private var cancellables = Set<AnyCancellable>() init(dataService: DataService = .shared) { self.dataService = dataService } func loadData() async { isLoading = true errorMessage = nil do { items = try await dataService.fetchItems() } catch { errorMessage = error.localizedDescription } isLoading = false } func search(query: String) { // Debounced search implementation Task { try? await Task.sleep(nanoseconds: 300_000_000) // Perform search } } func refresh() { Task { await loadData() } } }
swift// ItemRowView.swift import SwiftUI struct ItemRowView: View { let item: Item @Binding var isSelected: Bool var onDelete: (() -> Void)? var body: some View { HStack { Image(systemName: item.icon) .foregroundStyle(item.color) .frame(width: 24, height: 24) VStack(alignment: .leading, spacing: 4) { Text(item.title) .font(.headline) Text(item.subtitle) .font(.subheadline) .foregroundStyle(.secondary) } Spacer() if isSelected { Image(systemName: "checkmark") .foregroundStyle(.blue) } } .padding(.vertical, 4) .contentShape(Rectangle()) .onTapGesture { isSelected.toggle() } .contextMenu { Button("Edit") { } Button("Duplicate") { } Divider() Button("Delete", role: .destructive) { onDelete?() } } } }
swift// SettingsView.swift import SwiftUI struct SettingsView: View { var body: some View { TabView { GeneralSettingsView() .tabItem { Label("General", systemImage: "gear") } AppearanceSettingsView() .tabItem { Label("Appearance", systemImage: "paintpalette") } AdvancedSettingsView() .tabItem { Label("Advanced", systemImage: "slider.horizontal.3") } } .frame(width: 500, height: 400) } } struct GeneralSettingsView: View { @AppStorage("launchAtLogin") private var launchAtLogin = false @AppStorage("checkForUpdates") private var checkForUpdates = true var body: some View { Form { Toggle("Launch at Login", isOn: $launchAtLogin) Toggle("Check for Updates Automatically", isOn: $checkForUpdates) } .formStyle(.grouped) .padding() } }
swift// ItemListView.swift import SwiftUI struct ItemListView: View { @ObservedObject var viewModel: ItemListViewModel @State private var selection: Set<Item.ID> = [] @State private var sortOrder = [KeyPathComparator(\Item.name)] var body: some View { Table(viewModel.items, selection: $selection, sortOrder: $sortOrder) { TableColumn("Name", value: \.name) TableColumn("Type", value: \.type) TableColumn("Modified", value: \.modifiedDate) { item in Text(item.modifiedDate, style: .date) } TableColumn("Size") { item in Text(ByteCountFormatter.string(fromByteCount: item.size, countStyle: .file)) } .width(80) } .onChange(of: sortOrder) { _, newOrder in viewModel.sort(by: newOrder) } .contextMenu(forSelectionType: Item.ID.self) { items in Button("Open") { viewModel.open(items) } Button("Delete", role: .destructive) { viewModel.delete(items) } } primaryAction: { items in viewModel.open(items) } } }
swift@State private var isExpanded = false @State private var selectedTab = 0
swift@Binding var isPresented: Bool @Binding var selectedItem: Item?
swift@StateObject private var viewModel = MyViewModel()
swift@ObservedObject var viewModel: MyViewModel
swift@EnvironmentObject var settings: AppSettings
swift@AppStorage("username") private var username = ""
macos-entitlements-generator - App capabilitiesmacos-notarization-workflow - Distributionxctest-ui-test-generator - UI testingswiftui-macos-expert - SwiftUI expertisedesktop-ux-analyst - UX patterns| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 4,691 | 17,898 | +282% | 1 | 1 | 0% | 248 | 6,533 | +2534% | 0 | 0 | — |
case-02 | fail→pass | 15,417 | 3,807 | -75% | 1 | 1 | 0% | 3,620 | 3,036 | -16% | 0 | 0 | — |
case-03 | pass→fail | 15,381 | 19,299 | +25% | 1 | 1 | 0% | 3,188 | 6,889 | +116% | 0 | 0 | — |
case-04 | fail→pass | 12,197 | 9,688 | -21% | 1 | 1 | 0% | 2,419 | 4,412 | +82% | 0 | 0 | — |
case-05 | pass→pass | 12,485 | 15,173 | +22% | 1 | 1 | 0% | 2,645 | 5,755 | +118% | 0 | 0 | — |
case-06 | fail→pass | 14,904 | 12,287 | -18% | 1 | 1 | 0% | 2,462 | 4,965 | +102% | 0 | 0 | — |
case-07 | pass→pass | 9,029 | 8,778 | -3% | 1 | 1 | 0% | 1,676 | 3,787 | +126% | 0 | 0 | — |
case-08 | pass→pass | 7,778 | 8,798 | +13% | 1 | 1 | 0% | 1,583 | 4,053 | +156% | 0 | 0 | — |
case-09 | pass→pass | 6,786 | 5,310 | -22% | 1 | 1 | 0% | 1,305 | 3,284 | +152% | 0 | 0 | — |
case-10 | pass→pass | 7,387 | 9,242 | +25% | 1 | 1 | 0% | 1,390 | 4,323 | +211% | 0 | 0 | — |
case-11 | pass→pass | 6,753 | 4,435 | -34% | 1 | 1 | 0% | 1,218 | 3,166 | +160% | 0 | 0 | — |
case-12 | pass→pass | 7,637 | 6,160 | -19% | 1 | 1 | 0% | 1,430 | 3,489 | +144% | 0 | 0 | — |
case-13 | pass→pass | 5,942 | 5,373 | -10% | 1 | 1 | 0% | 1,054 | 3,254 | +209% | 0 | 0 | — |
case-14 | pass→pass | 6,623 | 3,231 | -51% | 1 | 1 | 0% | 1,217 | 2,916 | +140% | 0 | 0 | — |
case-15 | pass→pass | 4,163 | 4,798 | +15% | 1 | 1 | 0% | 770 | 3,163 | +311% | 0 | 0 | — |
case-16 | pass→pass | 9,078 | 9,756 | +7% | 1 | 1 | 0% | 1,491 | 4,042 | +171% | 0 | 0 | — |
case-17 | pass→pass | 3,331 | 4,740 | +42% | 1 | 1 | 0% | 579 | 3,224 | +457% | 0 | 0 | — |
case-18 | pass→pass | 9,586 | 8,905 | -7% | 1 | 1 | 0% | 1,818 | 4,011 | +121% | 0 | 0 | — |
case-19 | pass→pass | 7,006 | 5,259 | -25% | 1 | 1 | 0% | 1,187 | 3,211 | +171% | 0 | 0 | — |
case-20 | fail→fail | 6,032 | 6,645 | +10% | 1 | 1 | 0% | 1,247 | 3,704 | +197% | 0 | 0 | — |
case-21 | fail→fail | 6,462 | 7,078 | +10% | 1 | 1 | 0% | 1,358 | 3,764 | +177% | 0 | 0 | — |
case-22 | fail→fail | 6,291 | 7,881 | +25% | 1 | 1 | 0% | 1,288 | 3,964 | +208% | 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. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +14 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.