@mmerterden/multi-agent-pipeline 20.17.1 → 20.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/docs/facts.json +6 -6
  3. package/install/_mcp-register.mjs +1 -1
  4. package/install/_xcode-skills.mjs +263 -0
  5. package/install/catalog-history.json +1 -1
  6. package/install/claude.mjs +23 -0
  7. package/install/codex.mjs +11 -0
  8. package/install/copilot.mjs +9 -0
  9. package/manifest.json +85 -45
  10. package/package.json +1 -1
  11. package/pipeline/commands/multi-agent/stack/SKILL.md +2 -0
  12. package/pipeline/lib/xcode-plugin.mjs +131 -0
  13. package/pipeline/multi-agent-refs/features/doctor.md +10 -0
  14. package/pipeline/scripts/doctor.mjs +38 -0
  15. package/pipeline/scripts/uninstall.mjs +57 -1
  16. package/pipeline/skills/.skill-manifest.json +33 -13
  17. package/pipeline/skills/.skills-index.json +66 -11
  18. package/pipeline/skills/shared/README.md +18 -13
  19. package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +3 -1
  20. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +2 -1
  21. package/pipeline/skills/shared/external/hig-app-icons/SKILL.md +159 -0
  22. package/pipeline/skills/shared/external/hig-app-icons/evals/evals.json +48 -0
  23. package/pipeline/skills/shared/external/hig-app-icons/evals/trigger-eval.json +22 -0
  24. package/pipeline/skills/shared/external/hig-app-icons/references/icon-workflow.md +115 -0
  25. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +32 -4
  26. package/pipeline/skills/shared/external/hig-components-layout/evals/evals.json +47 -0
  27. package/pipeline/skills/shared/external/hig-components-layout/evals/trigger-eval.json +22 -0
  28. package/pipeline/skills/shared/external/hig-components-layout/references/bars-and-tabs.md +231 -0
  29. package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +5 -30
  30. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +1 -1
  31. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +23 -4
  32. package/pipeline/skills/shared/external/hig-foundations/evals/evals.json +47 -0
  33. package/pipeline/skills/shared/external/hig-foundations/evals/trigger-eval.json +21 -0
  34. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +34 -26
  35. package/pipeline/skills/shared/external/hig-foundations/references/type-color-spacing.md +219 -0
  36. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +5 -4
  37. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +19 -3
  38. package/pipeline/skills/shared/external/hig-patterns/references/onboarding-and-states.md +188 -0
  39. package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +5 -11
  40. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +17 -5
  41. package/pipeline/skills/shared/external/hig-platforms/references/ipad-layout.md +218 -0
  42. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +4 -1
  43. package/pipeline/skills/shared/external/ios-accessibility/references/large-content-and-appearance.md +135 -0
  44. package/pipeline/skills/shared/external/ios-design-review/SKILL.md +146 -0
  45. package/pipeline/skills/shared/external/ios-design-review/evals/evals.json +48 -0
  46. package/pipeline/skills/shared/external/ios-design-review/evals/trigger-eval.json +22 -0
  47. package/pipeline/skills/shared/external/ios-design-review/references/appearance-matrix.md +135 -0
  48. package/pipeline/skills/shared/external/ios-design-review/references/checklist.md +193 -0
  49. package/pipeline/skills/shared/external/ios-haptics/SKILL.md +191 -0
  50. package/pipeline/skills/shared/external/ios-haptics/evals/evals.json +49 -0
  51. package/pipeline/skills/shared/external/ios-haptics/evals/trigger-eval.json +22 -0
  52. package/pipeline/skills/shared/external/ios-haptics/references/core-haptics.md +215 -0
  53. package/pipeline/skills/shared/external/ios-iphone-duo/NOTICE.md +53 -0
  54. package/pipeline/skills/shared/external/ios-iphone-duo/SKILL.md +179 -0
  55. package/pipeline/skills/shared/external/ios-iphone-duo/evals/evals.json +65 -0
  56. package/pipeline/skills/shared/external/ios-iphone-duo/evals/trigger-eval.json +22 -0
  57. package/pipeline/skills/shared/external/ios-iphone-duo/references/api-map.md +212 -0
  58. package/pipeline/skills/shared/external/ios-iphone-duo/references/fixed-assumptions.md +202 -0
  59. package/pipeline/skills/shared/external/ios-iphone-duo/references/poses-and-panes.md +122 -0
  60. package/pipeline/skills/shared/external/ios-sf-symbols/SKILL.md +177 -0
  61. package/pipeline/skills/shared/external/ios-sf-symbols/evals/evals.json +49 -0
  62. package/pipeline/skills/shared/external/ios-sf-symbols/evals/trigger-eval.json +22 -0
  63. package/pipeline/skills/shared/external/ios-sf-symbols/references/effects-and-custom-symbols.md +135 -0
  64. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +38 -50
  65. package/pipeline/skills/shared/external/swiftui-animation/evals/evals.json +47 -0
  66. package/pipeline/skills/shared/external/swiftui-animation/evals/trigger-eval.json +22 -0
  67. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +7 -73
  68. package/pipeline/skills/shared/external/swiftui-animation/references/scroll-effects.md +185 -0
  69. package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +6 -6
  70. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +3 -253
  71. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +4 -47
  72. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +3 -111
  73. package/pipeline/skills/shared/external/swiftui-expert-skill/references/liquid-glass.md +11 -381
  74. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +184 -224
  75. package/pipeline/skills/shared/external/swiftui-liquid-glass/evals/evals.json +47 -0
  76. package/pipeline/skills/shared/external/swiftui-liquid-glass/evals/trigger-eval.json +22 -0
  77. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +246 -33
  78. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/uikit-glass.md +227 -0
  79. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +15 -18
  80. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/components-index.md +1 -1
  81. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/haptics.md +6 -68
  82. package/pipeline/skills/skills-index.md +16 -11
  83. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +0 -786
@@ -0,0 +1,218 @@
1
+ # iPad layout and windowing
2
+
3
+ Companion to `../SKILL.md` for the `hig-platforms` skill: how one SwiftUI
4
+ layout adapts from a narrow iPad window to a full external display. Hinged
5
+ iPhone hardware (iPhone Duo) has its own skill, `ios-iphone-duo`.
6
+
7
+ ## Contents
8
+
9
+ 1. [Windows on iPadOS 26](#1-windows-on-ipados-26)
10
+ 2. [Size classes, not devices](#2-size-classes-not-devices)
11
+ 3. [Choosing a layout tool](#3-choosing-a-layout-tool)
12
+ 4. [ViewThatFits](#4-viewthatfits)
13
+ 5. [AnyLayout](#5-anylayout)
14
+ 6. [A custom Layout](#6-a-custom-layout)
15
+ 7. [Scenes, multiple windows and the menu bar](#7-scenes-multiple-windows-and-the-menu-bar)
16
+ 8. [Test matrix](#8-test-matrix)
17
+
18
+ ## 1. Windows on iPadOS 26
19
+
20
+ People choose one of two presentations in Multitasking settings:
21
+
22
+ - **Full screen**: app windows fill the screen; people switch with the app
23
+ switcher.
24
+ - **Windowed**: people resize windows freely, keep several on screen,
25
+ reposition them and bring them to front. The system remembers size and
26
+ placement.
27
+
28
+ What this means for layout:
29
+
30
+ - Support arbitrary sizes. Windows resize fluidly down to a minimum rather
31
+ than snapping between preset sizes, so a layout cannot assume a short list of
32
+ widths. Stage Manager (iPadOS 16 and later on supported iPads) already
33
+ required this.
34
+ - `UIRequiresFullScreen` is deprecated in iPadOS 26. In windowed mode it no
35
+ longer gives a full-screen app; the system keeps a fixed scene size and
36
+ scales the app when people resize. Apple asks iPad apps to support
37
+ multitasking and dynamic resizing instead.
38
+ - Keep leading toolbar items clear of the window controls that appear at the
39
+ leading edge of the toolbar in windowed mode; move such buttons inward.
40
+ - Set a sensible minimum (and, where useful, maximum) size so the layout never
41
+ overlaps: `UISceneSizeRestrictions.minimumSize` in UIKit,
42
+ `.windowResizability(_:)` and `.defaultSize(_:)` on scenes in SwiftUI
43
+ (iOS 17).
44
+ - Use standard split views: `NavigationSplitView` reflows its columns for every
45
+ width with system transitions.
46
+
47
+ ## 2. Size classes, not devices
48
+
49
+ | Context | Horizontal | Vertical |
50
+ |---|---|---|
51
+ | iPad full screen, either orientation | regular | regular |
52
+ | iPad window narrowed to a phone-like width | compact | regular |
53
+ | iPhone portrait | compact | regular |
54
+ | iPhone landscape (most models) | compact | compact |
55
+
56
+ Read `@Environment(\.horizontalSizeClass)` and `verticalSizeClass`; never
57
+ branch on the device model or on `UIDevice.current.userInterfaceIdiom` for
58
+ layout. A size class says whether there is room for more columns; the
59
+ container's actual size decides the details.
60
+
61
+ ```swift
62
+ @Environment(\.horizontalSizeClass) private var widthClass
63
+
64
+ var body: some View {
65
+ if widthClass == .compact {
66
+ JobList(jobs: jobs)
67
+ } else {
68
+ NavigationSplitView {
69
+ JobList(jobs: jobs)
70
+ } detail: {
71
+ JobDetailPlaceholder()
72
+ }
73
+ }
74
+ }
75
+ ```
76
+
77
+ `NavigationSplitView` already collapses to a stack in compact width, so the
78
+ branch above is only needed when the compact design differs.
79
+
80
+ ## 3. Choosing a layout tool
81
+
82
+ | Question | Tool (since) |
83
+ |---|---|
84
+ | Does a list-detail hierarchy need columns? | `NavigationSplitView` (iOS 16) |
85
+ | Which of a few fixed arrangements fits the space? | `ViewThatFits` (iOS 16) |
86
+ | Switch between stack axes while keeping state and animating? | `AnyLayout` (iOS 16) |
87
+ | Size a view relative to its container? | `containerRelativeFrame(_:alignment:)` (iOS 17) |
88
+ | A layout no stack or grid expresses? | A type conforming to `Layout` (iOS 16) |
89
+ | Readable width for long text in a wide window? | `.contentMargins` (iOS 17) or a max width |
90
+
91
+ Reach for `GeometryReader` last; it takes all offered space and couples the
92
+ view to raw sizes.
93
+
94
+ ## 4. ViewThatFits
95
+
96
+ Picks the first child that fits the proposed size along the given axes.
97
+
98
+ ```swift
99
+ ViewThatFits(in: .horizontal) {
100
+ HStack(spacing: 12) {
101
+ JobSummary(job: job)
102
+ Spacer()
103
+ JobActions(job: job)
104
+ }
105
+ VStack(alignment: .leading, spacing: 8) {
106
+ JobSummary(job: job)
107
+ JobActions(job: job)
108
+ }
109
+ }
110
+ ```
111
+
112
+ Each candidate is a separate subtree: state inside one is lost when the other
113
+ wins. Keep state above `ViewThatFits`.
114
+
115
+ ## 5. AnyLayout
116
+
117
+ Wraps a layout type so the arrangement can change while view identity, and so
118
+ state, survives, and the change can animate.
119
+
120
+ ```swift
121
+ @Environment(\.horizontalSizeClass) private var widthClass
122
+ @Environment(\.dynamicTypeSize) private var typeSize
123
+
124
+ var body: some View {
125
+ let isNarrow = widthClass == .compact || typeSize.isAccessibilitySize
126
+ let layout = isNarrow
127
+ ? AnyLayout(VStackLayout(alignment: .leading, spacing: 12))
128
+ : AnyLayout(HStackLayout(alignment: .top, spacing: 20))
129
+
130
+ layout {
131
+ PartsList(parts: job.parts)
132
+ PhotoStrip(photos: job.photos)
133
+ }
134
+ .animation(.smooth, value: isNarrow)
135
+ }
136
+ ```
137
+
138
+ `HStackLayout`, `VStackLayout`, `ZStackLayout` and `GridLayout` are the
139
+ built-in layout types to swap between.
140
+
141
+ ## 6. A custom Layout
142
+
143
+ Conform to `Layout` and implement `sizeThatFits(proposal:subviews:cache:)` and
144
+ `placeSubviews(in:proposal:subviews:cache:)`. A flow layout that wraps chips
145
+ onto new lines is the usual case:
146
+
147
+ ```swift
148
+ struct FlowLayout: Layout {
149
+ var spacing: CGFloat = 8
150
+
151
+ func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize {
152
+ let maxWidth = proposal.width ?? .infinity
153
+ var origin = CGPoint.zero
154
+ var lineHeight: CGFloat = 0
155
+ var usedWidth: CGFloat = 0
156
+ for subview in subviews {
157
+ let size = subview.sizeThatFits(.unspecified)
158
+ if origin.x > 0, origin.x + size.width > maxWidth {
159
+ origin.x = 0
160
+ origin.y += lineHeight + spacing
161
+ lineHeight = 0
162
+ }
163
+ origin.x += size.width + spacing
164
+ usedWidth = max(usedWidth, origin.x - spacing)
165
+ lineHeight = max(lineHeight, size.height)
166
+ }
167
+ return CGSize(width: usedWidth, height: origin.y + lineHeight)
168
+ }
169
+
170
+ func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) {
171
+ var origin = bounds.origin
172
+ var lineHeight: CGFloat = 0
173
+ for subview in subviews {
174
+ let size = subview.sizeThatFits(.unspecified)
175
+ if origin.x > bounds.minX, origin.x + size.width > bounds.maxX {
176
+ origin.x = bounds.minX
177
+ origin.y += lineHeight + spacing
178
+ lineHeight = 0
179
+ }
180
+ subview.place(at: origin, proposal: ProposedViewSize(size))
181
+ origin.x += size.width + spacing
182
+ lineHeight = max(lineHeight, size.height)
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ A custom layout works with `AnyLayout` too, so it can be swapped in for wide
189
+ windows only.
190
+
191
+ ## 7. Scenes, multiple windows and the menu bar
192
+
193
+ - Support multiple windows when people might compare two records
194
+ (`UIApplicationSupportsMultipleScenes`, `WindowGroup(for:)` with a value,
195
+ `openWindow(value:)`). Offer "Open in New Window" in a context menu rather
196
+ than opening windows by default.
197
+ - iPadOS 26 adds a menu bar; populate it with `.commands` on the scene, as on
198
+ the Mac, and give frequent commands keyboard shortcuts.
199
+ - Use the word "window" in user-facing text, never "scene".
200
+ - Do not build custom window frames or controls.
201
+
202
+ ## 8. Test matrix
203
+
204
+ 1. Full screen, portrait and landscape.
205
+ 2. Windowed at the minimum size, a phone-like width and a wide width; resize
206
+ slowly and watch for jumps.
207
+ 3. External display.
208
+ 4. Largest Dynamic Type size in a narrow window.
209
+ 5. Right-to-left: sidebars, swipe edges and back gestures mirror.
210
+
211
+ Sources:
212
+ [HIG: Windows](https://developer.apple.com/design/human-interface-guidelines/windows),
213
+ [HIG: Layout](https://developer.apple.com/design/human-interface-guidelines/layout),
214
+ [Adopting Liquid Glass: windows and modals](https://developer.apple.com/documentation/technologyoverviews/adopting-liquid-glass),
215
+ [UIRequiresFullScreen](https://developer.apple.com/documentation/bundleresources/information-property-list/uirequiresfullscreen),
216
+ [ViewThatFits](https://developer.apple.com/documentation/swiftui/viewthatfits),
217
+ [AnyLayout](https://developer.apple.com/documentation/swiftui/anylayout),
218
+ [Layout](https://developer.apple.com/documentation/swiftui/layout).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ios-accessibility
3
- description: "VoiceOver, Voice Control, Switch Control and Full Keyboard Access in SwiftUI, UIKit and AppKit on iOS, iPadOS and macOS: labels, hints, values, traits, accessibilityInputLabels, NSAccessibility, grouping and reading order, @AccessibilityFocusState focus restore, Dynamic Type and @ScaledMetric, rotors, custom actions, XCTest accessibility checks, system accessibility preferences, Accessibility Nutrition Labels and App Store Connect answers. Use when implementing, reviewing or auditing accessibility (a11y). Not for keyboard or directional focus mechanics (Tab order, FocusState, UIFocusGuide): use hig-inputs."
3
+ description: "VoiceOver, Voice Control, Switch Control and Full Keyboard Access in SwiftUI, UIKit and AppKit: labels, traits, grouping, focus restore, Dynamic Type, Large Content Viewer, rotors, custom actions, accessibility checks and Nutrition Labels. Use when implementing, reviewing or auditing accessibility (a11y). Not for keyboard or directional focus mechanics: use hig-inputs."
4
4
  metadata:
5
5
  source: multi-agent-pipeline
6
6
  ---
@@ -23,6 +23,9 @@ References:
23
23
  label categories and what passes or fails each one.
24
24
  - [Media](references/media-accessibility.md): captions, SDH, audio
25
25
  descriptions and `AVMediaCharacteristic`.
26
+ - [Large content and appearance](references/large-content-and-appearance.md):
27
+ the Large Content Viewer for controls that cannot grow, and how Liquid
28
+ Glass reacts to Reduce Transparency, Increase Contrast and Reduce Motion.
26
29
 
27
30
  ## Ground rules
28
31
 
@@ -0,0 +1,135 @@
1
+ # Large Content Viewer, and Liquid Glass with appearance settings
2
+
3
+ Companion to `../SKILL.md` for the `ios-accessibility` skill.
4
+
5
+ ## Contents
6
+
7
+ 1. [Large Content Viewer](#1-large-content-viewer)
8
+ 2. [SwiftUI](#2-swiftui)
9
+ 3. [UIKit](#3-uikit)
10
+ 4. [Liquid Glass and appearance settings](#4-liquid-glass-and-appearance-settings)
11
+ 5. [Checks](#5-checks)
12
+
13
+ ## 1. Large Content Viewer
14
+
15
+ When text is set to one of the large accessibility sizes, some controls cannot
16
+ grow without breaking the screen: tab bar items, toolbar buttons, segmented
17
+ controls, a compact player bar. For those, the Large Content Viewer shows an
18
+ enlarged label and image in the middle of the screen while the person presses
19
+ and holds the control. System tab bars and toolbars do this already.
20
+
21
+ Rules from Apple's documentation:
22
+
23
+ - It is not a replacement for Dynamic Type. Lists, rows and body text must
24
+ grow; use the viewer only where an element must stay small for a real
25
+ design reason.
26
+ - Views whose Dynamic Type size is capped with `dynamicTypeSize(_:)` are the
27
+ typical candidates.
28
+ - If the control also has a long-press action, lengthen that press when the
29
+ viewer is enabled so people can read the enlarged content first.
30
+
31
+ ## 2. SwiftUI
32
+
33
+ | API | Since | Use |
34
+ |---|---|---|
35
+ | `accessibilityShowsLargeContentViewer()` | iOS 15 | Default large content built from the view's label and image |
36
+ | `accessibilityShowsLargeContentViewer(_:)` | iOS 15 | Custom large content, for example a `Label` for an icon-only button |
37
+ | `@Environment(\.accessibilityLargeContentViewerEnabled)` | iOS 15 | Whether the viewer is on, to adjust coexisting gestures |
38
+
39
+ ```swift
40
+ struct PlayerBar: View {
41
+ @Environment(\.accessibilityLargeContentViewerEnabled) private var largeContentViewer
42
+
43
+ var body: some View {
44
+ HStack(spacing: 24) {
45
+ Button(action: skipBack) {
46
+ Image(systemName: "gobackward.15")
47
+ }
48
+ .accessibilityLabel("Skip back 15 seconds")
49
+ .accessibilityShowsLargeContentViewer {
50
+ Label("Skip back 15 seconds", systemImage: "gobackward.15")
51
+ }
52
+
53
+ Button("Play", systemImage: "play.fill", action: play)
54
+ .labelStyle(.iconOnly)
55
+ .accessibilityShowsLargeContentViewer()
56
+ }
57
+ .dynamicTypeSize(...DynamicTypeSize.xxxLarge)
58
+ .onLongPressGesture(minimumDuration: largeContentViewer ? 1.2 : 0.5) {
59
+ showQueue()
60
+ }
61
+ }
62
+ }
63
+ ```
64
+
65
+ The cap keeps the bar's layout fixed; the viewer gives the enlarged reading
66
+ back.
67
+
68
+ ## 3. UIKit
69
+
70
+ | API | Since | Use |
71
+ |---|---|---|
72
+ | `UILargeContentViewerInteraction` | iOS 13 | Adds the press-and-hold gesture to a container view |
73
+ | `UIView.showsLargeContentViewer` | iOS 13 | Opts a view in |
74
+ | `UIView.largeContentTitle`, `largeContentImage` | iOS 13 | What the viewer shows |
75
+ | `UIView.scalesLargeContentImage` | iOS 13 | Scale the image up (useful for template symbols) |
76
+ | `UILargeContentViewerInteraction.isEnabled` | iOS 13 | Whether the viewer is on |
77
+
78
+ Bar items in system bars are covered by the system. For custom controls, set
79
+ the properties on the view and add the interaction to its container:
80
+
81
+ ```swift
82
+ final class CompactPlayerBar: UIView {
83
+ private let skipBackButton = UIButton(type: .system)
84
+
85
+ override init(frame: CGRect) {
86
+ super.init(frame: frame)
87
+ skipBackButton.setImage(UIImage(systemName: "gobackward.15"), for: .normal)
88
+ skipBackButton.accessibilityLabel = String(localized: "Skip back 15 seconds")
89
+ skipBackButton.showsLargeContentViewer = true
90
+ skipBackButton.largeContentTitle = String(localized: "Skip back 15 seconds")
91
+ skipBackButton.largeContentImage = UIImage(systemName: "gobackward.15")
92
+ skipBackButton.scalesLargeContentImage = true
93
+ addSubview(skipBackButton)
94
+ addInteraction(UILargeContentViewerInteraction())
95
+ }
96
+
97
+ required init?(coder: NSCoder) {
98
+ fatalError("init(coder:) is not supported")
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## 4. Liquid Glass and appearance settings
104
+
105
+ On Apple's 26 releases, people can pick a preferred look for Liquid Glass in
106
+ Settings and can turn on Reduce Transparency, Increase Contrast or Reduce
107
+ Motion. Each can remove or modify glass effects. System bars, sheets and
108
+ controls adapt by themselves; custom glass and custom colors do not always.
109
+
110
+ | Setting | SwiftUI | UIKit | What custom UI must do |
111
+ |---|---|---|---|
112
+ | Reduce Transparency | `accessibilityReduceTransparency` | `UIAccessibility.isReduceTransparencyEnabled` | Text over custom glass or blur stays readable; switch to an opaque fill where it does not |
113
+ | Increase Contrast | `colorSchemeContrast == .increased` | `UIAccessibility.isDarkerSystemColorsEnabled` | Custom colors provide increased-contrast variants; contrast minimums hold |
114
+ | Reduce Motion | `accessibilityReduceMotion` | `UIAccessibility.isReduceMotionEnabled` | Glass morphing and custom transitions become simple fades or instant changes |
115
+ | Bold Text | `legibilityWeight == .bold` | `UIAccessibility.isBoldTextEnabled` | Custom-drawn text follows the heavier weight |
116
+
117
+ Glass-specific checks (clear glass and its dimming layer, tint contrast, no
118
+ opaque fills behind system bars) and the material rules (where glass belongs,
119
+ regular versus clear, fallbacks) are in `swiftui-liquid-glass`.
120
+
121
+ ## 5. Checks
122
+
123
+ - Set an accessibility text size, then press and hold every small fixed
124
+ control (tab items, toolbar buttons, player controls): the viewer appears
125
+ with a meaningful title and image.
126
+ - Rows and body text grow instead of relying on the viewer.
127
+ - Turn on Reduce Transparency, Increase Contrast and Reduce Motion one at a
128
+ time and walk every screen with custom glass.
129
+ - The screenshot matrix for a design review lives in `ios-design-review`.
130
+
131
+ Sources:
132
+ [accessibilityShowsLargeContentViewer()](https://developer.apple.com/documentation/swiftui/view/accessibilityshowslargecontentviewer()),
133
+ [UILargeContentViewerInteraction](https://developer.apple.com/documentation/uikit/uilargecontentviewerinteraction),
134
+ [HIG: Materials](https://developer.apple.com/design/human-interface-guidelines/materials),
135
+ [Adopting Liquid Glass](https://developer.apple.com/documentation/technologyoverviews/adopting-liquid-glass).
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: ios-design-review
3
+ description: "Design critique and screenshot-based visual QA of iOS screens against the HIG, checked across light and dark, Dynamic Type, RTL, contrast and transparency settings with simulator tools. Use when asking whether a screen looks right, wanting a design pass on screenshots or a build, or visual QA before release, not a Swift code review."
4
+ metadata:
5
+ source: multi-agent-pipeline
6
+ date_added: "2026-10-08"
7
+ not-for: swiftui-pro, ios-accessibility
8
+ ---
9
+
10
+ # iOS design review
11
+
12
+ A design review looks at what people see and touch: the rendered screen, in
13
+ every appearance it can take. It answers "does this screen meet the platform's
14
+ design bar, and where does it fall short", with evidence a designer or
15
+ developer can act on. It is not a code review; reading Swift for API misuse is
16
+ `swiftui-pro`'s job, and building accessibility support is `ios-accessibility`'s.
17
+
18
+ The reason to keep the two apart: code that looks correct can still render
19
+ badly (a fixed frame that clips at the largest text size, a tint that fails
20
+ contrast in dark mode), and odd-looking code can render well. Only the screen
21
+ settles a design question.
22
+
23
+ ## Where this sits
24
+
25
+ | Need | Go to |
26
+ |---|---|
27
+ | Critique a screen against HIG, any appearance | this skill |
28
+ | Pixel and spacing conformance to a Figma frame, every state, mock mode | `/multi-agent:design-check` |
29
+ | One-axis sweep of a whole app | `/multi-agent:test-dark-mode`, `/multi-agent:test-dynamic-type`, `/multi-agent:test-accessibility` |
30
+ | Store screenshot set | `/multi-agent:test-screenshots` |
31
+ | Review the SwiftUI code | `swiftui-pro` |
32
+ | Implement VoiceOver, traits, focus | `ios-accessibility` |
33
+ | Implement or fix Liquid Glass | `swiftui-liquid-glass` |
34
+ | Icons, symbols, haptics, foldable layout | `hig-app-icons`, `ios-sf-symbols`, `ios-haptics`, `ios-iphone-duo` |
35
+
36
+ Use the commands for breadth (every screen, one axis) and this skill for depth
37
+ (one flow, every axis, judged against the guidelines). When a command already
38
+ produced captures, review those instead of recapturing.
39
+
40
+ ## Inputs and honesty
41
+
42
+ Accept whatever exists: screenshots, a running simulator, a design render on
43
+ disk, or the source. Say up front which you have, because it bounds what can be
44
+ proven:
45
+
46
+ - Screenshots only: layout, hierarchy, copy and visible contrast can be judged;
47
+ touch target sizes, accessibility labels and behaviour cannot.
48
+ - A running simulator: add the accessibility tree (`ios_get_ui_tree`) and
49
+ element geometry (`design_ui_geometry`) to measure targets and spacing.
50
+ - Source as well: findings can be pinned to `file:line`.
51
+ - A design render: `design_visual_compare` measures insets, gaps and colour
52
+ against it. Without one, judge against HIG alone and say so.
53
+
54
+ ## The review
55
+
56
+ Walk the layers in `references/checklist.md`, in order. Each layer has the
57
+ questions to ask and the HIG page that backs them. In short:
58
+
59
+ 1. **Layout**: content inside safe areas, backgrounds may extend past them;
60
+ consistent margins; alignment; nothing tappable under bars; adapts to width
61
+ instead of assuming a device size.
62
+ 2. **Typography**: text styles rather than fixed sizes, iOS default 17 pt and
63
+ minimum 11 pt, hierarchy through weight and size, no truncation that hides
64
+ meaning at large sizes.
65
+ 3. **Colour and contrast**: semantic colours, at least 4.5:1 for text up to
66
+ 17 pt and 3:1 for 18 pt or bold, meaning never carried by colour alone.
67
+ 4. **Materials and Liquid Glass**: glass on the navigation and control layer,
68
+ standard materials in the content layer, clear glass only over rich media
69
+ with a dimming layer when the media is bright.
70
+ 5. **Iconography**: SF Symbols weight and scale matched to adjacent text,
71
+ consistent variants, labels on icon-only controls.
72
+ 6. **Navigation and bars**: system bars and tab bars, standard placements,
73
+ back and close where people expect them.
74
+ 7. **Controls and touch**: 44x44 pt default target, 28x28 pt minimum, spacing
75
+ between adjacent targets, standard controls where they exist.
76
+ 8. **Feedback and motion**: every action acknowledged, motion that explains
77
+ rather than decorates, a reduced alternative under Reduce Motion.
78
+ 9. **States**: empty, loading, error, offline, permission denied, long content.
79
+ 10. **Content and copy**: short, specific, consistent terms, localized.
80
+
81
+ ## The appearance matrix
82
+
83
+ A screen is reviewed in each appearance it can take, because each one breaks
84
+ different things. `references/appearance-matrix.md` has, for every row, how to
85
+ set it (toolkit tool or manual setting) and what typically goes wrong.
86
+
87
+ | Appearance | Set with | Typical failures |
88
+ |---|---|---|
89
+ | Light, dark | `ios_set_appearance` | hard-coded colours, invisible separators, images without a dark variant |
90
+ | Dynamic Type, default to AX5 | `ios_set_content_size` | clipping, truncation, overlapping, fixed-height rows, layouts that never switch to vertical |
91
+ | Right-to-left | `ios_set_locale` with `ar` or `he` (relaunch) | unflipped back chevrons and progress, mirrored artwork, left-aligned text |
92
+ | Increase Contrast | `ios_set_increase_contrast` | custom colours with no high-contrast variant |
93
+ | Reduce Transparency | Settings app, set by hand | glass or blur that does not fall back to an opaque surface |
94
+ | Reduce Motion | Settings app, set by hand | parallax, zooms and repeating symbol effects still playing |
95
+ | Liquid Glass look (Clear or Tinted) | Settings > Display & Brightness, by hand | custom glass that ignores the setting, legibility on Clear |
96
+
97
+ Not every screen needs every cell. Pick the cells the screen can break (a
98
+ text-heavy form needs every Dynamic Type step; a media player needs Reduce
99
+ Motion and Clear glass), list the ones you skipped and why, and record which
100
+ were set by hand.
101
+
102
+ ## Procedure on a simulator
103
+
104
+ 1. Clean the status bar: `ios_status_bar` with preset `clean`, so captures
105
+ compare across runs.
106
+ 2. Reach the screen with `ui_locate` and `ios_tap_element` rather than
107
+ coordinates. A locator that resolves to exactly one element survives layout
108
+ changes; a coordinate does not.
109
+ 3. Baseline capture: `ios_screenshot`, `ios_get_ui_tree`, `design_ui_geometry`.
110
+ 4. For each chosen matrix cell: set it, wait for the UI to settle, capture
111
+ again. Batch the sweep with `agent_run_steps` and add `expect_text` or
112
+ `expect_element` steps so a navigation slip fails the batch instead of
113
+ producing captures of the wrong screen.
114
+ 5. Measure: target sizes and gaps from geometry, contrast from the capture,
115
+ insets and spacing against the design with `design_visual_compare` when a
116
+ render exists.
117
+ 6. Reset what you changed (appearance, content size, contrast, locale) so the
118
+ next run starts clean.
119
+
120
+ The full step list with arguments is in `references/appearance-matrix.md`.
121
+
122
+ ## Reporting
123
+
124
+ One finding per problem, each with:
125
+
126
+ - **Layer** from the checklist and **severity**: blocking (unusable, illegible,
127
+ inaccessible, or a guideline the store enforces), important (clearly below
128
+ the HIG bar), suggestion (polish).
129
+ - **Where**: `file:line` when the source is known, otherwise screen, element
130
+ and the matrix cell it appears in.
131
+ - **Evidence**: capture path, UI tree node, measured value against the
132
+ threshold (for example "close button 32x32 pt, minimum 44x44 pt").
133
+ - **Why it matters** in one sentence, and the **fix direction**.
134
+
135
+ End with a **Not proven** section: what could not be checked and why (no
136
+ device, setting not available, screenshot-only input, behaviour that needs a
137
+ real device such as haptics). A short honest list is worth more than a long
138
+ confident one. `references/checklist.md` has a report template.
139
+
140
+ ## References
141
+
142
+ - `references/checklist.md`: the layer-by-layer checklist, thresholds, report template.
143
+ - `references/appearance-matrix.md`: setting each appearance, toolkit procedure, failure catalogue.
144
+ - HIG: https://developer.apple.com/design/human-interface-guidelines/
145
+ - Accessibility thresholds: https://developer.apple.com/design/human-interface-guidelines/accessibility
146
+ - Materials: https://developer.apple.com/design/human-interface-guidelines/materials
@@ -0,0 +1,48 @@
1
+ {
2
+ "skill_name": "ios-design-review",
3
+ "evals": [
4
+ {
5
+ "id": 0,
6
+ "name": "settings-screen-matrix-review",
7
+ "prompt": "Our redesigned Settings screen ships next week. I have the app running on an iPhone 17 simulator with the multi-agent-toolkit MCP connected. Give it a proper design pass, not a code review: tell me what to check, how you would capture it, and what the report should look like.",
8
+ "expected_output": "Treats the task as a visual design review rather than code review. Chooses relevant appearance-matrix cells (light and dark, Dynamic Type including an accessibility size such as AX5, right-to-left, Increase Contrast, Reduce Transparency, Reduce Motion, Liquid Glass look) and says which can be set with toolkit tools (ios_set_appearance, ios_set_content_size, ios_set_increase_contrast, ios_set_locale) and which must be set by hand in Settings. Navigates with ui_locate and ios_tap_element, captures with ios_screenshot, ios_get_ui_tree and design_ui_geometry, and guards a batch with expect_element or expect_text. Applies HIG thresholds (44x44 pt targets, 4.5:1 text contrast, 17 pt default text). Reports findings with layer, severity, location, evidence and fix, and ends with a Not proven section.",
9
+ "files": [],
10
+ "expectations": [
11
+ "Frames the work as a rendered-screen design review, not a Swift code review",
12
+ "Covers dark mode and at least one accessibility Dynamic Type size",
13
+ "Names toolkit tools for setting appearances (ios_set_appearance, ios_set_content_size or ios_set_increase_contrast)",
14
+ "States that Reduce Transparency, Reduce Motion or the Liquid Glass look have no toolkit switch and are set by hand",
15
+ "Uses at least one concrete HIG threshold such as 44x44 pt or 4.5:1",
16
+ "Report format includes evidence per finding and a section for what could not be proven"
17
+ ]
18
+ },
19
+ {
20
+ "id": 1,
21
+ "name": "screenshot-only-critique",
22
+ "prompt": "Here are three screenshots of our checkout flow (light mode only, default text size). The designer says it is ready. Can you critique it against Apple's guidelines and tell me if it is shippable?",
23
+ "expected_output": "Reviews what screenshots can show (layout, hierarchy, contrast, copy, glass use, symbol consistency) and explicitly states the limits: touch target hit areas, accessibility labels, dark mode, large text, right-to-left and behaviour cannot be judged from three light-mode captures. Does not declare it shippable; lists the missing matrix cells as Not proven and recommends capturing them or running the test-dark-mode and test-dynamic-type commands.",
24
+ "files": [],
25
+ "expectations": [
26
+ "States what cannot be proven from light-mode, default-size screenshots",
27
+ "Does not declare the flow shippable without the missing appearances",
28
+ "Mentions dark mode and large Dynamic Type as unchecked",
29
+ "Points to the dark-mode or dynamic-type test commands, or to capturing those cells",
30
+ "Keeps findings tied to visible evidence rather than speculation about the code"
31
+ ]
32
+ },
33
+ {
34
+ "id": 2,
35
+ "name": "glass-and-contrast-judgement",
36
+ "prompt": "Design review question: our photo viewer puts a toolbar with clear Liquid Glass over full-screen photos, and the product cards on the home feed also use glassEffect as their background. Text on the toolbar is sometimes hard to read on bright photos. What does Apple's guidance say, and how should the review report it?",
37
+ "expected_output": "Says Liquid Glass belongs to the navigation and control layer and that content-layer cards should use standard materials, so the card backgrounds are a finding. Accepts clear glass over rich media for the photo toolbar but recommends a dark dimming layer of about 35% when the photo is bright. Suggests checking with the Liquid Glass look set to Clear and Tinted and with Reduce Transparency, and routes the implementation fix to swiftui-liquid-glass. Reports with layer, severity, evidence and fix direction.",
38
+ "files": [],
39
+ "expectations": [
40
+ "Flags glass on content cards as a content-layer misuse",
41
+ "Recommends standard materials for the content layer",
42
+ "Recommends a dimming layer of about 35% behind clear glass over bright media",
43
+ "Mentions checking under Reduce Transparency or the Clear and Tinted look setting",
44
+ "Routes implementation to swiftui-liquid-glass rather than writing the fix as the review"
45
+ ]
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,22 @@
1
+ [
2
+ { "query": "Can you do a design review of these screenshots of our onboarding?", "should_trigger": true },
3
+ { "query": "Check whether the profile screen looks right in dark mode and at the largest text size on the simulator", "should_trigger": true },
4
+ { "query": "Visual QA pass on the checkout flow before release, against the HIG", "should_trigger": true },
5
+ { "query": "Is this settings screen up to Apple's design bar? Tell me what looks off", "should_trigger": true },
6
+ { "query": "Critique the spacing, typography and contrast of this iOS screen", "should_trigger": true },
7
+ { "query": "Run through the appearance matrix for the home screen: RTL, Increase Contrast, Reduce Transparency", "should_trigger": true },
8
+ { "query": "Does our use of Liquid Glass on the feed look right, design-wise?", "should_trigger": true },
9
+ { "query": "Take screenshots of the order screen in light and dark and tell me what fails the guidelines", "should_trigger": true },
10
+ { "query": "Our designer wants a second opinion on the new tab bar layout, here is a capture", "should_trigger": true },
11
+ { "query": "Review the rendered login screen for touch target sizes and text contrast", "should_trigger": true },
12
+ { "query": "Review this SwiftUI view's code for deprecated APIs and performance issues", "should_trigger": false },
13
+ { "query": "Add VoiceOver labels and accessibility traits to our custom slider", "should_trigger": false },
14
+ { "query": "Compare every state of the payment module against the Figma frames in mock mode and export the report", "should_trigger": false },
15
+ { "query": "Generate the App Store screenshot set in German", "should_trigger": false },
16
+ { "query": "Implement glassEffect on our floating action button", "should_trigger": false },
17
+ { "query": "Which SF Symbol rendering mode should I use for a battery indicator?", "should_trigger": false },
18
+ { "query": "Design our app icon's dark and tinted variants in Icon Composer", "should_trigger": false },
19
+ { "query": "Review my pull request diff for bugs", "should_trigger": false },
20
+ { "query": "Walk every screen of the app at accessibility-extra-large and list truncation bugs", "should_trigger": false },
21
+ { "query": "Make our app ready for the foldable iPhone's hinge and reserved regions", "should_trigger": false }
22
+ ]