@mmerterden/multi-agent-pipeline 20.17.0 → 20.17.2

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 +23 -0
  2. package/docs/facts.json +6 -6
  3. package/docs/features.md +1 -1
  4. package/install/catalog-history.json +1 -1
  5. package/manifest.json +85 -47
  6. package/package.json +1 -1
  7. package/pipeline/commands/multi-agent/setup/SKILL.md +2 -2
  8. package/pipeline/commands/multi-agent/update/SKILL.md +2 -2
  9. package/pipeline/multi-agent-refs/features/usage-reporting.md +106 -67
  10. package/pipeline/schemas/prefs.schema.json +23 -2
  11. package/pipeline/scripts/usage-identity.mjs +312 -53
  12. package/pipeline/scripts/usage-register.mjs +204 -85
  13. package/pipeline/scripts/usage-report.mjs +7 -5
  14. package/pipeline/skills/.skill-manifest.json +35 -15
  15. package/pipeline/skills/.skills-index.json +66 -11
  16. package/pipeline/skills/shared/README.md +18 -13
  17. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +2 -2
  18. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -2
  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 +170 -0
  55. package/pipeline/skills/shared/external/ios-iphone-duo/evals/evals.json +50 -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 +145 -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
@@ -1,7 +1,29 @@
1
1
  # Liquid Glass API Reference
2
2
 
3
3
  Signatures and behaviour behind the `swiftui-liquid-glass` skill. Read its
4
- SKILL.md for the workflow and examples; this file is the detail.
4
+ SKILL.md first for where glass belongs and the workflow; this file is the
5
+ SwiftUI detail. UIKit is in [uikit-glass.md](uikit-glass.md).
6
+
7
+ ## Contents
8
+
9
+ - [Overview](#overview)
10
+ - [glassEffect(_:in:)](#glasseffect_in)
11
+ - [Glass](#glass)
12
+ - [Clear glass and the dimming layer](#clear-glass-and-the-dimming-layer)
13
+ - [GlassEffectContainer](#glasseffectcontainer)
14
+ - [glassEffectID(_:in:)](#glasseffectid_in)
15
+ - [glassEffectUnion(id:namespace:)](#glasseffectunionidnamespace)
16
+ - [glassEffectTransition(_:) and GlassEffectTransition](#glasseffecttransition_-and-glasseffecttransition)
17
+ - [Button styles](#button-styles)
18
+ - [DefaultGlassEffectShape](#defaultglasseffectshape)
19
+ - [Concentric shapes](#concentric-shapes)
20
+ - [Custom bars: safeAreaBar](#custom-bars-safeareabar)
21
+ - [Scroll edge effect](#scroll-edge-effect)
22
+ - [Background extension (split views)](#background-extension-split-views)
23
+ - [Availability gating](#availability-gating)
24
+ - [Performance guidelines](#performance-guidelines)
25
+ - [Examples](#examples)
26
+ - [Apple documentation links](#apple-documentation-links)
5
27
 
6
28
  ## Overview
7
29
 
@@ -53,6 +75,33 @@ struct Glass: Equatable, Sendable {
53
75
  `interactive(_:)` hands back one that responds to fingers and pointer hover.
54
76
  Being `Sendable`, a `Glass` value can be computed anywhere and handed to a view.
55
77
 
78
+ ## Clear glass and the dimming layer
79
+
80
+ `.clear` is highly translucent and meant for components that float over
81
+ photos and video. When the media behind it is bright, put a dark dimming layer
82
+ underneath; Apple's HIG suggests 35% black. Over dark media, or with AVKit's
83
+ standard playback controls, skip it.
84
+
85
+ ```swift
86
+ @available(iOS 26, *)
87
+ struct PhotoOverlayControls: View {
88
+ var body: some View {
89
+ HStack(spacing: 16) {
90
+ Button("Share", systemImage: "square.and.arrow.up") { }
91
+ Button("Favorite", systemImage: "heart") { }
92
+ }
93
+ .labelStyle(.iconOnly)
94
+ .font(.title3)
95
+ .padding()
96
+ .glassEffect(.clear.interactive())
97
+ .background(.black.opacity(0.35), in: .capsule)
98
+ }
99
+ }
100
+ ```
101
+
102
+ Choose `.regular` instead whenever the component carries much text or sits
103
+ over content whose brightness you do not control.
104
+
56
105
  ## GlassEffectContainer
57
106
 
58
107
  A generic `View` over its `Content`, isolated to the main actor (declared
@@ -134,12 +183,78 @@ a `Button` yourself.
134
183
 
135
184
  The default `in:` argument of `glassEffect`. It resolves to a `Capsule`.
136
185
 
186
+ ## Concentric shapes
187
+
188
+ `ConcentricRectangle` (iOS 26) is a shape whose corners can be concentric with
189
+ a container's corners, fixed, or square. A corner is concentric when its radius
190
+ shares a center with the container's rounded corner, which is how sheets
191
+ follow the curve of the screen.
192
+
193
+ | Initializer or style | Result |
194
+ |---|---|
195
+ | `ConcentricRectangle()` | Every corner concentric with the container |
196
+ | `ConcentricRectangle(corners: .concentric(minimum: 12), isUniform: true)` | Concentric, never below 12 points, all corners equal |
197
+ | `ConcentricRectangle(uniformTopCorners: .fixed(12), uniformBottomCorners: .concentric)` | Fixed top, concentric bottom, like a format sheet |
198
+
199
+ The container is the device edge, a system container such as a sheet, or any
200
+ view that sets `containerShape(_:)` with a `RoundedRectangularShape`
201
+ (`RoundedRectangle`, `Capsule`, `Circle`, `Rectangle`). When a corner sits far
202
+ from the container's corner the computed radius can be zero, so use
203
+ `.concentric(minimum:)` where the corner must stay rounded.
204
+
205
+ ```swift
206
+ @available(iOS 26, *)
207
+ struct NestedPanel: View {
208
+ var body: some View {
209
+ VStack(spacing: 12) {
210
+ Text("Boarding").font(.headline)
211
+ Button("Show pass") { }
212
+ .buttonStyle(.glassProminent)
213
+ }
214
+ .padding(16)
215
+ .background(.thinMaterial, in: ConcentricRectangle(corners: .concentric(minimum: 12), isUniform: true))
216
+ .containerShape(RoundedRectangle(cornerRadius: 28))
217
+ }
218
+ }
219
+ ```
220
+
221
+ HIG asks custom components in toolbars to keep their corner radius
222
+ concentric with the bar, as standard components do.
223
+
224
+ ## Custom bars: safeAreaBar
225
+
226
+ `safeAreaBar(edge:alignment:spacing:content:)` (iOS 26) works like
227
+ `safeAreaInset`, and also extends the scroll edge effect of scroll views
228
+ under the inset, so a custom bar gets the same legibility treatment as a
229
+ system toolbar.
230
+
231
+ ```swift
232
+ @available(iOS 26, *)
233
+ struct ComposerScreen: View {
234
+ @State private var draft = ""
235
+
236
+ var body: some View {
237
+ ScrollView { MessageList() }
238
+ .safeAreaBar(edge: .bottom) {
239
+ HStack {
240
+ TextField("Message", text: $draft)
241
+ Button("Send", systemImage: "paperplane.fill") { }
242
+ .buttonStyle(.glassProminent)
243
+ }
244
+ .padding()
245
+ }
246
+ }
247
+ }
248
+ ```
249
+
137
250
  ## Scroll edge effect
138
251
 
139
- A nonisolated modifier taking an optional `ScrollEdgeEffectStyle` and, after
140
- `for:`, an `Edge.Set`. Styles are `.automatic`, `.soft` (a gradual fade) and `.hard` (a crisper cut
141
- off). System bars already apply an edge effect; set the style yourself for
142
- custom bars that float over scrolling content, or to change the look.
252
+ `scrollEdgeEffectStyle(_:for:)` takes an optional `ScrollEdgeEffectStyle` and,
253
+ after `for:`, an `Edge.Set`. Styles are `.automatic`, `.soft` (a gradual fade)
254
+ and `.hard` (a crisper cut off). `scrollEdgeEffectHidden(_:for:)` hides the
255
+ effect. System bars already apply an edge effect; adjust it for custom bars
256
+ that float over scrolling content. Remove custom darkening gradients behind
257
+ bar items, which fight the effect.
143
258
 
144
259
  ## Background extension (split views)
145
260
 
@@ -162,17 +277,6 @@ NavigationSplitView {
162
277
  }
163
278
  ```
164
279
 
165
- ## ToolbarSpacer
166
-
167
- ```swift
168
- struct ToolbarSpacer: ToolbarContent {
169
- init(_ sizing: SpacerSizing = .flexible, placement: ToolbarItemPlacement = .automatic)
170
- }
171
- ```
172
-
173
- `.fixed` inserts a fixed gap that separates glass groups; `.flexible` pushes
174
- groups apart. Available on iOS and macOS 26.
175
-
176
280
  ## Availability gating
177
281
 
178
282
  Every API above needs iOS 26. Give older systems a material background of the
@@ -198,27 +302,131 @@ extension View {
198
302
  - Prefer one container per group over many small containers.
199
303
  - Measure with Instruments (SwiftUI and Core Animation templates) before and
200
304
  after adding glass to scrolling content.
305
+ - Apple notes that combining custom glass in a `GlassEffectContainer` helps
306
+ rendering performance as well as morphing.
307
+
308
+ ## Examples
309
+
310
+ ### A gated glass card for a floating summary
201
311
 
202
- ## Accessibility considerations
312
+ ```swift
313
+ struct StatusPill: View {
314
+ let title: String
315
+
316
+ var body: some View {
317
+ let label = Text(title).font(.headline).padding(20)
203
318
 
204
- - **Reduce Transparency**: system components switch to a more opaque
205
- appearance on their own. Check that custom glass still reads well.
206
- - **Reduce Motion**: morphing and fluid animations are toned down. Make sure
207
- the interface still makes sense without them.
208
- - **Contrast**: text and icons over glass need enough contrast against
209
- whatever may scroll behind them.
319
+ if #available(iOS 26, *) {
320
+ label.glassEffect(.regular.interactive(), in: .rect(cornerRadius: 18))
321
+ } else {
322
+ label.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 18))
323
+ }
324
+ }
325
+ }
326
+ ```
210
327
 
211
- ## Best practices summary
328
+ ### A row of glass controls
212
329
 
213
- 1. Glass that shares the screen shares a `GlassEffectContainer`.
214
- 2. `.glassEffect()` goes last, once size and styling are settled.
215
- 3. The container's spacing equals the stack's spacing (or exceeds it).
216
- 4. Only controls get `.interactive()`.
217
- 5. Morphing needs `glassEffectID` plus a change inside `withAnimation`.
218
- 6. Buttons take `.glass` or `.glassProminent`.
219
- 7. Fewer glass surfaces read better than many.
220
- 8. Anything glass sits behind an iOS 26 check with a fallback.
221
- 9. Every screen is checked once with Reduce Transparency, once with Reduce Motion.
330
+ Container spacing matches the stack spacing so the circles blend only when
331
+ they move toward each other.
332
+
333
+ ```swift
334
+ @available(iOS 26, *)
335
+ struct PlaybackControls: View {
336
+ private let symbols = ["backward.fill", "play.fill", "forward.fill"]
337
+ private let gap: CGFloat = 20
338
+
339
+ var body: some View {
340
+ GlassEffectContainer(spacing: gap) {
341
+ HStack(spacing: gap) {
342
+ ForEach(symbols, id: \.self) { symbol in
343
+ Image(systemName: symbol)
344
+ .font(.title2)
345
+ .frame(width: 60, height: 60)
346
+ .glassEffect(.regular.interactive())
347
+ }
348
+ }
349
+ }
350
+ }
351
+ }
352
+ ```
353
+
354
+ ### Morphing between states
355
+
356
+ ```swift
357
+ @available(iOS 26, *)
358
+ struct ExpandingActions: View {
359
+ @Namespace private var glassSpace
360
+ @State private var expanded = false
361
+
362
+ var body: some View {
363
+ let gap: CGFloat = 36
364
+ return GlassEffectContainer(spacing: gap) {
365
+ HStack(spacing: gap) {
366
+ Button("Compose", systemImage: "square.and.pencil") {
367
+ withAnimation(.bouncy) { expanded.toggle() }
368
+ }
369
+ .buttonStyle(.glass)
370
+ .glassEffectID("compose", in: glassSpace)
371
+
372
+ if expanded {
373
+ Button("Attach", systemImage: "paperclip") { }
374
+ .buttonStyle(.glass)
375
+ .glassEffectID("attach", in: glassSpace)
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
381
+ ```
382
+
383
+ ### Merging shapes with a union
384
+
385
+ ```swift
386
+ @available(iOS 26, *)
387
+ struct FilterChips: View {
388
+ @Namespace private var chipSpace
389
+ let filters = ["Today", "Week", "Month", "Year"]
390
+
391
+ var body: some View {
392
+ let gap: CGFloat = 12
393
+ return GlassEffectContainer(spacing: gap) {
394
+ HStack(spacing: gap) {
395
+ ForEach(filters.indices, id: \.self) { index in
396
+ Text(filters[index])
397
+ .padding(.horizontal, 14)
398
+ .padding(.vertical, 8)
399
+ .glassEffect()
400
+ .glassEffectUnion(id: index < 2 ? "short" : "long", namespace: chipSpace)
401
+ }
402
+ }
403
+ }
404
+ }
405
+ }
406
+ ```
407
+
408
+ Chips 0 and 1 render as one glass shape and chips 2 and 3 as another.
409
+
410
+ ### A solid fallback under Reduce Transparency
411
+
412
+ System glass adapts on its own. A custom surface that must stay legible over
413
+ busy content can switch to a solid fill when the setting is on:
414
+
415
+ ```swift
416
+ @available(iOS 26, *)
417
+ struct MapControlStrip: View {
418
+ @Environment(\.accessibilityReduceTransparency) private var reduceTransparency
419
+
420
+ var body: some View {
421
+ let controls = HStack { LocateButton(); LayersButton() }.padding(12)
422
+ if reduceTransparency {
423
+ controls.background(Color(uiColor: .secondarySystemBackground), in: .capsule)
424
+ } else {
425
+ controls.glassEffect(.regular.interactive())
426
+ }
427
+ }
428
+ }
429
+ ```
222
430
 
223
431
  ## Apple documentation links
224
432
 
@@ -231,3 +439,8 @@ extension View {
231
439
  - [GlassEffectTransition](https://developer.apple.com/documentation/swiftui/glasseffecttransition)
232
440
  - [GlassButtonStyle](https://developer.apple.com/documentation/swiftui/glassbuttonstyle)
233
441
  - [GlassProminentButtonStyle](https://developer.apple.com/documentation/swiftui/glassprominentbuttonstyle)
442
+ - [ConcentricRectangle](https://developer.apple.com/documentation/swiftui/concentricrectangle)
443
+ - [safeAreaBar(edge:alignment:spacing:content:)](https://developer.apple.com/documentation/swiftui/view/safeareabar(edge:alignment:spacing:content:))
444
+ - [scrollEdgeEffectStyle(_:for:)](https://developer.apple.com/documentation/swiftui/view/scrolledgeeffectstyle(_:for:))
445
+ - [backgroundExtensionEffect()](https://developer.apple.com/documentation/swiftui/view/backgroundextensioneffect())
446
+ - [HIG: Materials](https://developer.apple.com/design/human-interface-guidelines/materials)
@@ -0,0 +1,227 @@
1
+ # Liquid Glass in UIKit
2
+
3
+ UIKit side of the `swiftui-liquid-glass` skill. Where glass belongs, regular
4
+ versus clear, and the accessibility rules are in `../SKILL.md` and apply
5
+ unchanged here. Every API in this file is iOS, iPadOS, Mac Catalyst and tvOS
6
+ 26.0 unless noted.
7
+
8
+ ## Contents
9
+
10
+ - [Standard components first](#standard-components-first)
11
+ - [UIGlassEffect](#uiglasseffect)
12
+ - [UIGlassContainerEffect](#uiglasscontainereffect)
13
+ - [Glass buttons](#glass-buttons)
14
+ - [Corners: UICornerConfiguration](#corners-uicornerconfiguration)
15
+ - [Scroll edge effects](#scroll-edge-effects)
16
+ - [UIBackgroundExtensionView](#uibackgroundextensionview)
17
+ - [Fallback and accessibility](#fallback-and-accessibility)
18
+ - [Opting out for one release](#opting-out-for-one-release)
19
+ - [Links](#links)
20
+
21
+ ## Standard components first
22
+
23
+ `UINavigationBar`, `UITabBar`, `UIToolbar`, sheets, popovers and standard
24
+ controls adopt the material when built with the 26 SDK. Remove custom bar
25
+ background images and appearance colors that sat behind items: they overlay
26
+ the glass and the scroll edge effect. Popovers that add their own
27
+ `UIVisualEffectView` background should drop it.
28
+
29
+ ## UIGlassEffect
30
+
31
+ A `UIVisualEffect` subclass rendering the glass material, hosted in a
32
+ `UIVisualEffectView`. Content goes in the effect view's `contentView`.
33
+
34
+ | Member | Meaning |
35
+ |---|---|
36
+ | `init(style:)` | `UIGlassEffect.Style.regular` or `.clear` |
37
+ | `isInteractive` | Reacts to touch like system glass controls |
38
+ | `tintColor` | Colors the glass for prominence; keep for one primary action or a status |
39
+
40
+ ```swift
41
+ @available(iOS 26, *)
42
+ @MainActor
43
+ func makeGlassBadge(text: String) -> UIVisualEffectView {
44
+ let glass = UIGlassEffect(style: .regular)
45
+ glass.isInteractive = true
46
+
47
+ let glassView = UIVisualEffectView(effect: glass)
48
+ glassView.cornerConfiguration = .capsule()
49
+
50
+ let label = UILabel()
51
+ label.text = text
52
+ label.font = .preferredFont(forTextStyle: .headline)
53
+ label.adjustsFontForContentSizeCategory = true
54
+ label.translatesAutoresizingMaskIntoConstraints = false
55
+ glassView.contentView.addSubview(label)
56
+
57
+ NSLayoutConstraint.activate([
58
+ label.leadingAnchor.constraint(equalTo: glassView.contentView.leadingAnchor, constant: 16),
59
+ label.trailingAnchor.constraint(equalTo: glassView.contentView.trailingAnchor, constant: -16),
60
+ label.topAnchor.constraint(equalTo: glassView.contentView.topAnchor, constant: 8),
61
+ label.bottomAnchor.constraint(equalTo: glassView.contentView.bottomAnchor, constant: -8),
62
+ ])
63
+ return glassView
64
+ }
65
+ ```
66
+
67
+ The same placement rule applies as in SwiftUI: navigation and controls only.
68
+
69
+ ## UIGlassContainerEffect
70
+
71
+ Renders several glass elements as one combined effect, so they blend and merge
72
+ when close, the UIKit counterpart of `GlassEffectContainer`. Put a
73
+ `UIVisualEffectView` with a `UIGlassContainerEffect` around nested
74
+ `UIVisualEffectView`s that each use a `UIGlassEffect`, added to the
75
+ container's `contentView`. `spacing` sets the distance at which neighbours
76
+ start to merge.
77
+
78
+ ```swift
79
+ @available(iOS 26, *)
80
+ @MainActor
81
+ func makeControlCluster(_ buttons: [UIView]) -> UIVisualEffectView {
82
+ let containerEffect = UIGlassContainerEffect()
83
+ containerEffect.spacing = 12
84
+ let container = UIVisualEffectView(effect: containerEffect)
85
+
86
+ let stack = UIStackView()
87
+ stack.axis = .horizontal
88
+ stack.spacing = 12
89
+ stack.translatesAutoresizingMaskIntoConstraints = false
90
+
91
+ for button in buttons {
92
+ let glassView = UIVisualEffectView(effect: UIGlassEffect(style: .regular))
93
+ glassView.cornerConfiguration = .capsule()
94
+ button.translatesAutoresizingMaskIntoConstraints = false
95
+ glassView.contentView.addSubview(button)
96
+ NSLayoutConstraint.activate([
97
+ button.centerXAnchor.constraint(equalTo: glassView.contentView.centerXAnchor),
98
+ button.centerYAnchor.constraint(equalTo: glassView.contentView.centerYAnchor),
99
+ glassView.widthAnchor.constraint(equalToConstant: 48),
100
+ glassView.heightAnchor.constraint(equalToConstant: 48),
101
+ ])
102
+ stack.addArrangedSubview(glassView)
103
+ }
104
+
105
+ container.contentView.addSubview(stack)
106
+ NSLayoutConstraint.activate([
107
+ stack.leadingAnchor.constraint(equalTo: container.contentView.leadingAnchor),
108
+ stack.trailingAnchor.constraint(equalTo: container.contentView.trailingAnchor),
109
+ stack.topAnchor.constraint(equalTo: container.contentView.topAnchor),
110
+ stack.bottomAnchor.constraint(equalTo: container.contentView.bottomAnchor),
111
+ ])
112
+ return container
113
+ }
114
+ ```
115
+
116
+ ## Glass buttons
117
+
118
+ Prefer a configuration to building glass around a `UIButton` by hand.
119
+
120
+ | Configuration | Use |
121
+ |---|---|
122
+ | `UIButton.Configuration.glass()` | Regular glass button |
123
+ | `.prominentGlass()` | The primary action |
124
+ | `.clearGlass()` | Over rich media |
125
+ | `.prominentClearGlass()` | Primary action over rich media |
126
+
127
+ ```swift
128
+ @available(iOS 26, *)
129
+ @MainActor
130
+ func makeDoneButton(action: UIAction) -> UIButton {
131
+ var configuration = UIButton.Configuration.prominentGlass()
132
+ configuration.title = String(localized: "Done")
133
+ return UIButton(configuration: configuration, primaryAction: action)
134
+ }
135
+ ```
136
+
137
+ ## Corners: UICornerConfiguration
138
+
139
+ `UIView.cornerConfiguration` (iOS 26, also visionOS 26) takes a
140
+ `UICornerConfiguration` built from `UICornerRadius` values.
141
+
142
+ | Expression | Result |
143
+ |---|---|
144
+ | `.corners(radius: 12)` | Fixed radius on every corner |
145
+ | `.corners(radius: .containerConcentric())` | Concentric with the containing view |
146
+ | `.corners(radius: .containerConcentric(minimum: 10))` | Concentric, never below 10 points |
147
+ | `.capsule()` | Capsule; `maximumRadius:` lets tall views break the capsule |
148
+ | `.uniformTopRadius(_:bottomLeftRadius:bottomRightRadius:)` and siblings | Mixed uniform and independent corners |
149
+
150
+ Squared corners are the default.
151
+
152
+ ## Scroll edge effects
153
+
154
+ Each `UIScrollView` has `topEdgeEffect`, `bottomEdgeEffect`, `leftEdgeEffect`
155
+ and `rightEdgeEffect`, each a `UIScrollEdgeEffect` (also visionOS 26) with:
156
+
157
+ - `style`: `UIScrollEdgeEffect.Style.automatic`, `.soft` or `.hard`
158
+ - `isHidden`: turns the effect off for that edge
159
+
160
+ ```swift
161
+ scrollView.topEdgeEffect.style = .hard
162
+ scrollView.bottomEdgeEffect.isHidden = false
163
+ ```
164
+
165
+ A custom bar that floats over the edge of a scroll view registers with
166
+ `UIScrollEdgeElementContainerInteraction`, so its labels, images, glass views
167
+ and controls shape the edge effect:
168
+
169
+ ```swift
170
+ let interaction = UIScrollEdgeElementContainerInteraction()
171
+ interaction.scrollView = scrollView
172
+ interaction.edge = .bottom
173
+ buttonContainer.addInteraction(interaction)
174
+ ```
175
+
176
+ ## UIBackgroundExtensionView
177
+
178
+ A view that can be laid out past the safe area, for example under a sidebar or
179
+ inspector, while keeping its `contentView` inside the safe area and filling the
180
+ rest with modified copies of the content's edges. It is the UIKit counterpart
181
+ of `backgroundExtensionEffect()`. `automaticallyPlacesContentView` defaults to
182
+ `true`; set it to `false` to position the content view yourself.
183
+
184
+ ```swift
185
+ @available(iOS 26, *)
186
+ @MainActor
187
+ func makeHeroBackground(image: UIImage) -> UIBackgroundExtensionView {
188
+ let extensionView = UIBackgroundExtensionView()
189
+ let imageView = UIImageView(image: image)
190
+ imageView.contentMode = .scaleAspectFill
191
+ extensionView.contentView = imageView
192
+ return extensionView
193
+ }
194
+ ```
195
+
196
+ Use it for the backdrop of a split view's secondary column, not for every
197
+ view.
198
+
199
+ ## Fallback and accessibility
200
+
201
+ - Before iOS 26, use `UIVisualEffectView(effect: UIBlurEffect(style: .systemThinMaterial))`
202
+ (or another system material) with the same shape. Gate with
203
+ `if #available(iOS 26, *)`.
204
+ - `UIAccessibility.isReduceTransparencyEnabled` and
205
+ `reduceTransparencyStatusDidChangeNotification` tell a custom surface when to
206
+ swap to an opaque background. `UIAccessibility.isDarkerSystemColorsEnabled`
207
+ reports Increase Contrast.
208
+ - Text inside glass uses Dynamic Type (`preferredFont(forTextStyle:)` with
209
+ `adjustsFontForContentSizeCategory`) and semantic label colors.
210
+
211
+ ## Opting out for one release
212
+
213
+ `UIDesignRequiresCompatibility` set to `YES` in Info.plist keeps the
214
+ previous-SDK look while building with the 26 SDK. Apple describes it as
215
+ temporary, and the system ignores it for apps built for the 27 SDKs. See
216
+ `../SKILL.md`.
217
+
218
+ ## Links
219
+
220
+ - [UIGlassEffect](https://developer.apple.com/documentation/uikit/uiglasseffect)
221
+ - [UIGlassContainerEffect](https://developer.apple.com/documentation/uikit/uiglasscontainereffect)
222
+ - [UIScrollEdgeEffect](https://developer.apple.com/documentation/uikit/uiscrolledgeeffect)
223
+ - [UIScrollEdgeElementContainerInteraction](https://developer.apple.com/documentation/uikit/uiscrolledgeelementcontainerinteraction)
224
+ - [UIBackgroundExtensionView](https://developer.apple.com/documentation/uikit/uibackgroundextensionview)
225
+ - [UICornerConfiguration](https://developer.apple.com/documentation/uikit/uicornerconfiguration-swift.struct)
226
+ - [UIButton.Configuration.glass()](https://developer.apple.com/documentation/uikit/uibutton/configuration-swift.struct/glass())
227
+ - [UIDesignRequiresCompatibility](https://developer.apple.com/documentation/bundleresources/information-property-list/uidesignrequirescompatibility)
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: swiftui-patterns
3
- description: "SwiftUI Model-View structure: @Observable ownership, @State, @Bindable, @Environment, view decomposition, custom ViewModifiers, .task loading, iOS 26 APIs, Writing Tools. Use when structuring a SwiftUI app, managing state, composing or splitting views, or adopting iOS 26 APIs. Not for file-by-file review (swiftui-pro) or single-screen wiring (swiftui-ui-patterns)."
3
+ description: "SwiftUI architecture, state: @Observable, @State, @Bindable, @Environment, view splitting, ViewModifiers, .task, API migration, Writing Tools, Transferable, sharing. Use when structuring an app or owning state. Not for review (swiftui-pro) or visual design (hig-foundations)."
4
4
  metadata:
5
5
  source: multi-agent-pipeline
6
6
  ---
@@ -332,8 +332,7 @@ struct ForecastView: View {
332
332
 
333
333
  | API | What it does |
334
334
  |---|---|
335
- | `.scrollEdgeEffectStyle(.soft, for: .top)` | Soft fade where content meets a scroll edge |
336
- | `.backgroundExtensionEffect()` | Extends a mirrored, blurred copy of the view under the safe areas |
335
+ | `.scrollEdgeEffectStyle(.soft, for: .top)`, `.backgroundExtensionEffect()` | Liquid Glass companions; see `swiftui-liquid-glass` |
337
336
  | `@Animatable` macro | Synthesises `animatableData` for a type; see `swiftui-animation` |
338
337
  | `TextEditor(text:)` with an `AttributedString` binding | Rich text editing |
339
338
 
@@ -350,19 +349,20 @@ struct ForecastView: View {
350
349
 
351
350
  ## 9. Following the HIG
352
351
 
353
- - Semantic colors (`Color.primary`, `.secondary`,
354
- `Color(uiColor: .systemBackground)`) adapt to light and dark mode.
355
- - Text styles (`.title`, `.headline`, `.body`, `.caption`) scale with Dynamic
356
- Type.
357
- - Empty and error states use `ContentUnavailableView`.
358
- - Leave `spacing:` off stacks. The default `nil` picks platform spacing; pass a
359
- number only for a deliberate choice.
360
- - Adapt layout to `horizontalSizeClass`.
361
- - Give controls an `.accessibilityLabel`, and switch stack axis when
362
- `dynamicTypeSize.isAccessibilitySize` is true.
352
+ This skill stops at structure and state. Visual rules live elsewhere:
363
353
 
364
- Details, token scales and examples:
365
- [references/design-polish.md](references/design-polish.md).
354
+ - Type, color, contrast, spacing and safe areas: `hig-foundations`.
355
+ - Bars, tabs and toolbars: `hig-components-layout`.
356
+ - Empty, error and loading states, onboarding, permission screens:
357
+ `hig-patterns`.
358
+ - Haptics and Core Haptics: `ios-haptics`.
359
+ - Liquid Glass: `swiftui-liquid-glass`.
360
+ - Theming, matched transitions, placeholders and form focus as screen
361
+ recipes: `swiftui-ui-patterns`.
362
+
363
+ Two structural habits still belong here: leave `spacing:` off stacks unless a
364
+ value is deliberate, and keep text sizes and colors semantic so the view code
365
+ does not fight Dynamic Type or dark mode.
366
366
 
367
367
  ## 10. Writing Tools (iOS 18+)
368
368
 
@@ -453,9 +453,6 @@ final class ReaderPreferences {
453
453
  the case for MV, when a view model is justified, environment versus init
454
454
  injection, testing, app shell wiring, dependency modifier, `ModelContainer`,
455
455
  enum sheets, deep links, closure-based clients.
456
- - [references/design-polish.md](references/design-polish.md): HIG layout,
457
- typography and color, theming, haptics and Core Haptics, matched transitions,
458
- loading placeholders, form focus.
459
456
  - [references/deprecated-migration.md](references/deprecated-migration.md):
460
457
  old API to current API, with the release each replacement needs.
461
458
  - [references/platform-and-sharing.md](references/platform-and-sharing.md):
@@ -22,7 +22,7 @@ Use this file to find component and cross-cutting guidance. Each entry lists whe
22
22
  - Focus handling: `references/focus.md` - Use for chaining fields and keyboard focus management.
23
23
  - Searchable: `references/searchable.md` - Use for native search UI with scopes and async results.
24
24
  - Async images and media: `references/media.md` - Use for remote media, previews, and media viewers.
25
- - Haptics: `references/haptics.md` - Use for tactile feedback tied to key actions.
25
+ - Haptics: the `ios-haptics` skill - Use for tactile feedback tied to key actions.
26
26
  - Matched transitions: `references/matched-transitions.md` - Use for smooth source-to-destination animations.
27
27
  - Deep links and URL routing: `references/deeplinks.md` - Use for in-app navigation from URLs.
28
28
  - Title menus: `references/title-menus.md` - Use for filter or context menus in the navigation title.