@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.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 (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,793 +1,691 @@
1
- # MapKit Patterns Reference
1
+ # MapKit Patterns for SwiftUI
2
2
 
3
- Extended patterns for MapKit on iOS 17+ with SwiftUI. Import `MapKit` and
4
- `SwiftUI` in every file that uses these APIs.
5
-
6
- ```swift
7
- import MapKit
8
- import SwiftUI
9
- ```
10
-
11
- ---
3
+ Everything here targets iOS 17 and SwiftUI unless a heading names a later
4
+ release. Each file that uses these types imports both `MapKit` and `SwiftUI`.
12
5
 
13
6
  ## Contents
14
7
 
15
- - [Complete Map View Setup](#complete-map-view-setup)
16
- - [Custom Annotation Views](#custom-annotation-views)
17
- - [Camera Control (MapCameraPosition)](#camera-control-mapcameraposition)
18
- - [Map Selection Handling](#map-selection-handling)
19
- - [Search with Autocomplete](#search-with-autocomplete)
8
+ - [A Full Map Screen](#a-full-map-screen)
9
+ - [Custom Annotations](#custom-annotations)
10
+ - [Camera Control](#camera-control)
11
+ - [Selection](#selection)
12
+ - [Autocomplete Search](#autocomplete-search)
20
13
  - [Route Display](#route-display)
21
- - [Look Around Preview](#look-around-preview)
22
- - [Map Snapshots (MKMapSnapshotter)](#map-snapshots-mkmapsnapshotter)
23
- - [Clustering Annotations](#clustering-annotations)
24
- - [MapKit with MKMapItem Utilities](#mapkit-with-mkmapitem-utilities)
25
- - [iOS 26 New APIs](#ios-26-new-apis)
26
- - [User Location Display](#user-location-display)
27
- - [Map in a List or ScrollView](#map-in-a-list-or-scrollview)
28
- - [Coordinate Utilities](#coordinate-utilities)
14
+ - [Cycling Directions (iOS 14+)](#cycling-directions-ios-14)
15
+ - [Street-Level Look Around](#street-level-look-around)
16
+ - [Still Images with MKMapSnapshotter](#still-images-with-mkmapsnapshotter)
17
+ - [Dense Annotations and Clustering](#dense-annotations-and-clustering)
18
+ - [MKMapItem Helpers](#mkmapitem-helpers)
19
+ - [Geocoding and Places on iOS 26](#geocoding-and-places-on-ios-26)
20
+ - [Showing the User](#showing-the-user)
21
+ - [Maps Inside Scrolling Content](#maps-inside-scrolling-content)
22
+ - [Coordinate Math](#coordinate-math)
29
23
  - [Accessibility](#accessibility)
30
- - [References](#references)
24
+ - [Apple Documentation](#apple-documentation)
31
25
 
32
- ## Complete Map View Setup
26
+ ## A Full Map Screen
33
27
 
34
- A production-ready map view with markers, user location, and controls.
28
+ A bike-dock finder: user location, one marker per dock coloured by
29
+ availability, built-in points of interest hidden, a detail card for the
30
+ selected dock.
35
31
 
36
32
  ```swift
37
- struct StoreLocatorMap: View {
38
- let stores: [Store]
39
- @State private var position: MapCameraPosition = .automatic
40
- @State private var selectedStore: Store?
33
+ import SwiftUI
34
+ import MapKit
35
+
36
+ struct BikeDock: Identifiable, Hashable {
37
+ let id: UUID
38
+ let name: String
39
+ let latitude: Double
40
+ let longitude: Double
41
+ let freeBikes: Int
42
+
43
+ var coordinate: CLLocationCoordinate2D {
44
+ CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
45
+ }
46
+ }
47
+
48
+ struct DockFinderView: View {
49
+ let docks: [BikeDock]
50
+ @State private var camera: MapCameraPosition = .userLocation(fallback: .automatic)
51
+ @State private var picked: BikeDock?
41
52
 
42
53
  var body: some View {
43
- Map(position: $position, selection: $selectedStore) {
54
+ Map(position: $camera, selection: $picked) {
44
55
  UserAnnotation()
45
-
46
- ForEach(stores) { store in
47
- Marker(store.name, systemImage: "storefront",
48
- coordinate: store.coordinate)
49
- .tint(store.isOpen ? .green : .gray)
50
- .tag(store)
56
+ ForEach(docks) { dock in
57
+ Marker(dock.name, systemImage: "bicycle", coordinate: dock.coordinate)
58
+ .tint(dock.freeBikes > 0 ? .green : .gray)
59
+ .tag(dock)
51
60
  }
52
61
  }
53
- .mapStyle(.standard(pointsOfInterest: .excludingAll))
54
62
  .mapControls {
55
- MapUserLocationButton()
56
63
  MapCompass()
57
- MapScaleView()
58
64
  MapPitchToggle()
65
+ MapScaleView()
66
+ MapUserLocationButton()
59
67
  }
68
+ .mapStyle(.standard(pointsOfInterest: .excludingAll))
60
69
  .safeAreaInset(edge: .bottom) {
61
- if let store = selectedStore {
62
- StoreDetailCard(store: store)
70
+ if let picked {
71
+ Text("\(picked.name): \(picked.freeBikes) bikes")
63
72
  .padding()
73
+ .frame(maxWidth: .infinity)
74
+ .background(.regularMaterial)
64
75
  }
65
76
  }
66
77
  }
67
78
  }
68
79
  ```
69
80
 
70
- Conform the data model to `Hashable` for use with map selection:
71
-
72
- ```swift
73
- struct Store: Identifiable, Hashable {
74
- let id: UUID
75
- let name: String
76
- let coordinate: CLLocationCoordinate2D
77
- let isOpen: Bool
78
-
79
- static func == (lhs: Store, rhs: Store) -> Bool { lhs.id == rhs.id }
80
- func hash(into hasher: inout Hasher) { hasher.combine(id) }
81
- }
82
- ```
83
-
84
- ---
81
+ Whatever you tag and select must be `Hashable`. `CLLocationCoordinate2D` is
82
+ neither `Hashable` nor `Equatable`, so a model that stores one cannot get the
83
+ synthesised conformance. Either keep plain `Double` latitude and longitude, as
84
+ above, and build the coordinate on demand, or write `==` and `hash(into:)`
85
+ yourself using only `id`.
85
86
 
86
- ## Custom Annotation Views
87
+ ## Custom Annotations
87
88
 
88
- Use `Annotation` for fully custom SwiftUI content at a coordinate. Prefer
89
- `Marker` for standard pins because it provides the platform marker appearance
90
- and a title that VoiceOver can announce.
89
+ `Annotation` takes arbitrary SwiftUI content. For an ordinary pin, prefer
90
+ `Marker`: it looks like the platform marker and VoiceOver reads its title
91
+ without extra work.
91
92
 
92
93
  ```swift
93
- Map {
94
- ForEach(friends) { friend in
95
- Annotation(friend.name, coordinate: friend.coordinate, anchor: .bottom) {
94
+ struct FriendPin: MapContent {
95
+ let name: String
96
+ let photo: URL
97
+ let spot: CLLocationCoordinate2D
98
+
99
+ var body: some MapContent {
100
+ Annotation(name, coordinate: spot, anchor: .bottom) {
96
101
  VStack(spacing: 0) {
97
- AsyncImage(url: friend.avatarURL) { image in
98
- image.resizable().scaledToFill()
102
+ AsyncImage(url: photo) { loaded in
103
+ loaded.resizable().aspectRatio(contentMode: .fill)
99
104
  } placeholder: {
100
- Color.gray
105
+ ProgressView()
101
106
  }
102
107
  .frame(width: 40, height: 40)
103
- .clipShape(.circle)
104
- .overlay(Circle().stroke(.white, lineWidth: 2))
108
+ .clipShape(Circle())
109
+ .overlay { Circle().strokeBorder(.white, lineWidth: 2) }
105
110
 
106
- Image(systemName: "triangle.fill")
107
- .font(.caption2)
111
+ Image(systemName: "arrowtriangle.down.fill")
112
+ .imageScale(.small)
108
113
  .foregroundStyle(.white)
109
- .rotationEffect(.degrees(180))
110
- .offset(y: -3)
111
114
  }
112
115
  }
113
116
  }
114
117
  }
115
118
  ```
116
119
 
117
- ### Annotation with anchorOffset for callout-style layout
120
+ ### Callout-style annotation anchored at the bottom
121
+
122
+ SwiftUI's `Annotation` positions content with `anchor`, a `UnitPoint`; it has
123
+ no point-offset parameter. For a label floating above a pin, stack the label
124
+ over the symbol and anchor at `.bottom`, so the tip of the symbol sits on the
125
+ coordinate.
118
126
 
119
127
  ```swift
120
- Annotation(place.name, coordinate: place.coordinate, anchor: .bottom) {
121
- VStack(spacing: 2) {
122
- Text(place.name)
123
- .font(.caption)
124
- .fontWeight(.semibold)
125
- .padding(.horizontal)
126
- .padding(.vertical)
127
- .background(.ultraThinMaterial, in: .capsule)
128
-
129
- Image(systemName: "mappin.circle.fill")
130
- .font(.title)
131
- .foregroundStyle(.red)
128
+ struct LabeledPin: MapContent {
129
+ let title: String
130
+ let spot: CLLocationCoordinate2D
131
+
132
+ var body: some MapContent {
133
+ Annotation(title, coordinate: spot, anchor: .bottom) {
134
+ VStack(spacing: 3) {
135
+ Text(title)
136
+ .font(.caption.weight(.semibold))
137
+ .padding(.horizontal, 8)
138
+ .padding(.vertical, 4)
139
+ .background(.ultraThinMaterial, in: Capsule())
140
+ Image(systemName: "mappin.circle.fill")
141
+ .font(.title2)
142
+ .foregroundStyle(.white, .pink)
143
+ }
144
+ }
132
145
  }
133
146
  }
134
147
  ```
135
148
 
136
- ---
137
-
138
- ## Camera Control (MapCameraPosition)
149
+ ## Camera Control
139
150
 
140
151
  ### Setting an initial position
141
152
 
142
- `MapCameraPosition` controls what the map displays. Bind it to let the user
143
- interact and to move the camera programmatically.
144
-
145
- ```swift
146
- // Center on a region
147
- @State private var position: MapCameraPosition = .region(
148
- MKCoordinateRegion(
149
- center: CLLocationCoordinate2D(latitude: 37.334, longitude: -122.009),
150
- span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
151
- )
152
- )
153
-
154
- // Follow user location
155
- @State private var position: MapCameraPosition = .userLocation(fallback: .automatic)
156
-
157
- // Specific camera angle (3D perspective)
158
- @State private var position: MapCameraPosition = .camera(
159
- MapCamera(centerCoordinate: applePark, distance: 1000, heading: 90, pitch: 60)
160
- )
161
-
162
- // Frame specific items
163
- position = .item(MKMapItem.forCurrentLocation())
164
- position = .rect(MKMapRect(...))
165
- ```
153
+ | Position | Shows |
154
+ |----------|-------|
155
+ | `.region(MKCoordinateRegion(center: c, span: nearbySpan))` | a region around a centre (`nearbySpan` here is about 0.05 degrees each way) |
156
+ | `.userLocation(fallback: .automatic)` | follows the user |
157
+ | `.camera(MapCamera(centerCoordinate: c, distance: 1200, heading: 120, pitch: 55))` | a tilted 3D viewpoint, 1.2 km out, facing south-east |
158
+ | `.item(MKMapItem.forCurrentLocation())` | frames a map item |
159
+ | `.rect(someMapRect)` | frames an `MKMapRect` |
166
160
 
167
161
  ### Animate camera changes
168
162
 
169
- Wrap position updates in `withAnimation` for smooth transitions:
163
+ Assign inside `withAnimation` (any curve, for example `.easeInOut`) for a fly-to:
170
164
 
171
165
  ```swift
172
- func flyTo(_ coordinate: CLLocationCoordinate2D) {
173
- withAnimation(.easeInOut(duration: 1.0)) {
174
- position = .camera(
175
- MapCamera(centerCoordinate: coordinate, distance: 2000,
176
- heading: 0, pitch: 45)
177
- )
166
+ func fly(to target: CLLocationCoordinate2D) {
167
+ withAnimation(.smooth(duration: 1)) {
168
+ let overhead = MapCamera(centerCoordinate: target, distance: 1800, heading: 30, pitch: 50)
169
+ camera = .camera(overhead)
178
170
  }
179
171
  }
180
172
  ```
181
173
 
182
174
  ### Frame multiple annotations
183
175
 
184
- ```swift
185
- func frameAllStores() {
186
- withAnimation {
187
- position = .automatic // Frames all map content
188
- }
189
- }
190
-
191
- // Or frame a specific rect
192
- func frameRegion(_ region: MKCoordinateRegion) {
193
- withAnimation {
194
- position = .region(region)
195
- }
196
- }
197
- ```
176
+ `camera = .automatic` (inside `withAnimation`) frames all map content.
177
+ `camera = .region(someRegion)` frames a region you computed, for example with
178
+ the helper in [Coordinate Math](#coordinate-math).
198
179
 
199
180
  ### Read current camera position
200
181
 
201
- Use `onMapCameraChange` to observe what the user is looking at:
202
-
203
182
  ```swift
204
- @State private var visibleRegion: MKCoordinateRegion?
205
-
206
- Map(position: $position) { ... }
207
- .onMapCameraChange(frequency: .onEnd) { context in
208
- visibleRegion = context.region
183
+ Map(position: $camera) { /* content */ }
184
+ .onMapCameraChange(frequency: .onEnd) { ctx in
185
+ visibleRegion = ctx.region
209
186
  }
210
187
  ```
211
188
 
212
- `frequency: .onEnd` fires after the user finishes scrolling. Use
213
- `.continuous` only when you need live tracking (costs more CPU).
214
-
215
- ---
189
+ `.onEnd` fires once the user stops moving the map. `.continuous` fires during
190
+ the gesture and costs more CPU; use it only for live tracking.
216
191
 
217
- ## Map Selection Handling
192
+ ## Selection
218
193
 
219
- ### Select markers by MKMapItem
194
+ ### Selecting an MKMapItem
220
195
 
221
- Use `MKMapItem` as the selection type when you want to look up place details:
196
+ Bind selection to `MKMapItem?` when a pick should lead to place details.
222
197
 
223
198
  ```swift
224
- @State private var selectedItem: MKMapItem?
199
+ struct MuseumMap: View {
200
+ let museums: [MKMapItem]
201
+ @State private var chosen: MKMapItem?
202
+ @State private var streetScene: MKLookAroundScene?
225
203
 
226
- Map(selection: $selectedItem) {
227
- ForEach(searchResults) { result in
228
- Marker(item: result)
204
+ var body: some View {
205
+ Map(selection: $chosen) {
206
+ ForEach(museums, id: \.self) { museum in
207
+ Marker(item: museum)
208
+ }
209
+ }
210
+ .onChange(of: chosen) { _, museum in
211
+ guard let museum else { return }
212
+ Task { streetScene = try? await MKLookAroundSceneRequest(mapItem: museum).scene }
213
+ }
229
214
  }
230
215
  }
231
- .onChange(of: selectedItem) { _, newItem in
232
- guard let item = newItem else { return }
233
- Task { await fetchLookAround(for: item) }
234
- }
235
216
  ```
236
217
 
237
- ### Select by custom Identifiable tag
238
-
239
- ```swift
240
- @State private var selectedPlaceID: Place.ID?
241
-
242
- Map(selection: $selectedPlaceID) {
243
- ForEach(places) { place in
244
- Marker(place.name, coordinate: place.coordinate)
245
- .tag(place.id)
246
- }
247
- }
248
- ```
218
+ ### Selecting by your own ID
249
219
 
250
- ---
220
+ Bind to `Place.ID?` and tag each marker with `.tag(place.id)`. The tag type and
221
+ the binding type must match.
251
222
 
252
- ## Search with Autocomplete
223
+ ## Autocomplete Search
253
224
 
254
- Full pattern: completer feeds suggestions, selecting a suggestion triggers a
255
- full search that returns `MKMapItem` results.
225
+ Suggestions come from `MKLocalSearchCompleter`; picking one runs a full
226
+ `MKLocalSearch` that returns `MKMapItem`s.
256
227
 
257
228
  ```swift
258
- @Observable
259
- final class MapSearchService: NSObject, MKLocalSearchCompleterDelegate {
260
- var completions: [MKLocalSearchCompletion] = []
261
- var searchResults: [MKMapItem] = []
262
- var queryFragment: String = "" {
263
- didSet { completer.queryFragment = queryFragment }
264
- }
229
+ import MapKit
230
+ import Observation
265
231
 
232
+ @MainActor
233
+ @Observable
234
+ final class PlaceFinder: NSObject, MKLocalSearchCompleterDelegate {
235
+ private(set) var suggestions: [MKLocalSearchCompletion] = []
236
+ private(set) var matches: [MKMapItem] = []
266
237
  private let completer: MKLocalSearchCompleter
267
238
 
239
+ var fragment = "" {
240
+ didSet { completer.queryFragment = fragment }
241
+ }
242
+
268
243
  override init() {
269
- completer = MKLocalSearchCompleter()
244
+ let engine = MKLocalSearchCompleter()
245
+ engine.resultTypes = [.address, .pointOfInterest]
246
+ completer = engine
270
247
  super.init()
271
248
  completer.delegate = self
272
- completer.resultTypes = [.address, .pointOfInterest]
273
249
  }
274
250
 
275
- // Restrict suggestions to the visible map region
276
- func updateRegion(_ region: MKCoordinateRegion) {
251
+ func focus(on region: MKCoordinateRegion) {
277
252
  completer.region = region
278
253
  }
279
254
 
280
- func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
281
- completions = completer.results
255
+ nonisolated func completerDidUpdateResults(_ source: MKLocalSearchCompleter) {
256
+ MainActor.assumeIsolated { suggestions = completer.results }
282
257
  }
283
258
 
284
- func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
285
- completions = []
259
+ nonisolated func completer(_ source: MKLocalSearchCompleter, didFailWithError failure: any Error) {
260
+ MainActor.assumeIsolated { suggestions = [] }
286
261
  }
287
262
 
288
- func select(_ completion: MKLocalSearchCompletion) async {
289
- let request = MKLocalSearch.Request(completion: completion)
263
+ func choose(_ suggestion: MKLocalSearchCompletion) async {
264
+ let request = MKLocalSearch.Request(completion: suggestion)
290
265
  request.resultTypes = [.pointOfInterest, .address]
266
+ let search = MKLocalSearch(request: request)
291
267
  do {
292
- let response = try await MKLocalSearch(request: request).start()
293
- searchResults = response.mapItems
268
+ let reply = try await search.start()
269
+ matches = reply.mapItems
294
270
  } catch {
295
- searchResults = []
271
+ matches = []
296
272
  }
297
273
  }
298
274
  }
299
275
  ```
300
276
 
301
- ### Search View Integration
277
+ `focus(on:)` narrows suggestions to the visible region. The delegate copies
278
+ `results` on update and clears the list on failure. It reads the model's own
279
+ `completer` inside `assumeIsolated`, not the callback parameter: the parameter
280
+ is a non-`Sendable` value from a nonisolated context, and Swift 6 will not
281
+ send it into the main-actor closure.
282
+
283
+ ### Wiring it into a screen
302
284
 
303
285
  ```swift
304
- struct MapSearchView: View {
305
- @State private var searchService = MapSearchService()
306
- @State private var searchText = ""
307
- @State private var position: MapCameraPosition = .automatic
286
+ struct PlaceSearchScreen: View {
287
+ @State private var finder = PlaceFinder()
288
+ @State private var typed = ""
289
+ @State private var camera: MapCameraPosition = .automatic
308
290
 
309
291
  var body: some View {
310
- Map(position: $position) {
311
- ForEach(searchService.searchResults, id: \.self) { item in
312
- Marker(item: item)
313
- }
292
+ Map(position: $camera) {
293
+ ForEach(finder.matches, id: \.self) { Marker(item: $0) }
314
294
  }
315
- .searchable(text: $searchText, prompt: "Search places")
295
+ .searchable(text: $typed, prompt: "Search places")
316
296
  .searchSuggestions {
317
- ForEach(searchService.completions, id: \.self) { completion in
297
+ ForEach(finder.suggestions, id: \.self) { suggestion in
318
298
  Button {
319
- Task { await searchService.select(completion) }
299
+ Task { await finder.choose(suggestion) }
320
300
  } label: {
321
301
  VStack(alignment: .leading) {
322
- Text(completion.title)
323
- Text(completion.subtitle)
324
- .font(.caption)
325
- .foregroundStyle(.secondary)
302
+ Text(suggestion.title)
303
+ Text(suggestion.subtitle).font(.caption).foregroundStyle(.secondary)
326
304
  }
327
305
  }
328
306
  }
329
307
  }
330
- .task(id: searchText) {
331
- try? await Task.sleep(for: .milliseconds(300))
308
+ .task(id: typed) {
309
+ let quietPeriod = Duration.milliseconds(300)
310
+ try? await Task.sleep(for: quietPeriod)
332
311
  guard !Task.isCancelled else { return }
333
- searchService.queryFragment = searchText
312
+ finder.fragment = typed
334
313
  }
335
314
  .onMapCameraChange(frequency: .onEnd) { context in
336
- searchService.updateRegion(context.region)
315
+ finder.focus(on: context.region)
337
316
  }
338
317
  }
339
318
  }
340
319
  ```
341
320
 
342
- ---
321
+ `.task(id:)` restarts on each keystroke and cancels the previous sleep, which
322
+ is the debounce.
343
323
 
344
324
  ## Route Display
345
325
 
346
- Calculate directions and draw the route polyline on the map.
347
-
348
326
  ```swift
349
- struct DirectionsMapView: View {
350
- let source: MKMapItem
351
- let destination: MKMapItem
327
+ struct CommuteView: View {
328
+ let home: MKMapItem
329
+ let office: MKMapItem
352
330
  @State private var route: MKRoute?
353
- @State private var position: MapCameraPosition = .automatic
354
- @State private var travelTime: String = ""
331
+ @State private var camera: MapCameraPosition = .automatic
332
+ @State private var failed = false
355
333
 
356
334
  var body: some View {
357
- Map(position: $position) {
335
+ Map(position: $camera) {
358
336
  if let route {
359
- MapPolyline(route.polyline)
360
- .stroke(.blue, lineWidth: 6)
337
+ MapPolyline(route.polyline).stroke(.indigo, lineWidth: 6)
361
338
  }
362
- Marker(item: source)
363
- .tint(.green)
364
- Marker(item: destination)
365
- .tint(.red)
339
+ Marker(item: home).tint(.green)
340
+ Marker(item: office).tint(.red)
366
341
  }
367
342
  .overlay(alignment: .top) {
368
- if !travelTime.isEmpty {
369
- Text(travelTime)
370
- .font(.caption)
371
- .padding()
372
- .background(.ultraThinMaterial, in: .capsule)
373
- .padding(.top)
343
+ if let route {
344
+ Text(Duration.seconds(route.expectedTravelTime)
345
+ .formatted(.units(allowed: [.hours, .minutes], width: .abbreviated)))
346
+ .padding(8)
347
+ .background(.ultraThinMaterial, in: Capsule())
348
+ } else if failed {
349
+ Text("No route found").padding(8).background(.ultraThinMaterial, in: Capsule())
374
350
  }
375
351
  }
376
- .task { await calculateRoute() }
352
+ .task { await load() }
377
353
  }
378
354
 
379
- private func calculateRoute() async {
355
+ private func load() async {
380
356
  let request = MKDirections.Request()
381
- request.source = source
382
- request.destination = destination
357
+ request.source = home
358
+ request.destination = office
383
359
  request.transportType = .automobile
384
-
360
+ let directions = MKDirections(request: request)
385
361
  do {
386
- let response = try await MKDirections(request: request).calculate()
387
- route = response.routes.first
388
- if let route {
389
- let formatter = DateComponentsFormatter()
390
- formatter.unitsStyle = .abbreviated
391
- formatter.allowedUnits = [.hour, .minute]
392
- travelTime = formatter.string(from: route.expectedTravelTime) ?? ""
393
-
394
- withAnimation {
395
- position = .rect(route.polyline.boundingMapRect)
396
- }
362
+ let reply = try await directions.calculate()
363
+ guard let best = reply.routes.first else {
364
+ failed = true
365
+ return
397
366
  }
367
+ route = best
368
+ withAnimation { camera = .rect(best.polyline.boundingMapRect) }
398
369
  } catch {
399
- print("Directions error: \(error.localizedDescription)")
370
+ failed = true
400
371
  }
401
372
  }
402
373
  }
403
374
  ```
404
375
 
405
- ### Multiple Route Options
376
+ The travel time is formatted as hours and minutes in abbreviated units
377
+ (`DateComponentsFormatter` with `.abbreviated` and `[.hour, .minute]` does
378
+ the same on older code). After the route arrives the camera animates to the
379
+ polyline's `boundingMapRect`. Failures set visible state rather than being swallowed.
380
+
381
+ ### Alternate routes
382
+
383
+ Set `request.requestsAlternateRoutes = true` and `response.routes` holds
384
+ several. Emphasise the first, mute the rest:
406
385
 
407
386
  ```swift
408
- request.requestsAlternateRoutes = true
409
- let response = try await MKDirections(request: request).calculate()
410
-
411
- // response.routes contains multiple route options
412
- // Display all routes, highlight the selected one:
413
- ForEach(Array(response.routes.enumerated()), id: \.offset) { index, route in
414
- MapPolyline(route.polyline)
415
- .stroke(index == 0 ? .blue : .gray.opacity(0.5), lineWidth: index == 0 ? 6 : 3)
387
+ ForEach(Array(routes.enumerated()), id: \.offset) { position, option in
388
+ let isBest = position == 0
389
+ MapPolyline(option.polyline)
390
+ .stroke(isBest ? Color.blue : Color.secondary.opacity(0.5), lineWidth: isBest ? 6 : 3)
416
391
  }
417
392
  ```
418
393
 
419
394
  ### ETA Calculation
420
395
 
421
- Use `calculateETA()` when you only need travel time, not the full route geometry.
396
+ When only the duration matters, skip the geometry:
422
397
 
423
398
  ```swift
424
- func getETA(from source: MKMapItem, to destination: MKMapItem) async throws -> TimeInterval {
399
+ func minutesAway(_ request: MKDirections.Request) async throws -> TimeInterval {
400
+ try await MKDirections(request: request).calculateETA().expectedTravelTime
401
+ }
402
+ ```
403
+
404
+ ## Cycling Directions (iOS 14+)
405
+
406
+ `MKDirectionsTransportType.cycling` has existed since iOS 14; it is not an
407
+ iOS 26 addition.
408
+
409
+ ```swift
410
+ func bikeRoute(toward stop: MKMapItem) async throws -> MKRoute? {
425
411
  let request = MKDirections.Request()
426
- request.source = source
427
- request.destination = destination
412
+ request.source = .forCurrentLocation()
413
+ request.destination = stop
414
+ request.transportType = .cycling
428
415
  let directions = MKDirections(request: request)
429
- let response = try await directions.calculateETA()
430
- return response.expectedTravelTime
416
+ let reply = try await directions.calculate()
417
+ return reply.routes.first
431
418
  }
432
419
  ```
433
420
 
434
- ---
421
+ ## Street-Level Look Around
435
422
 
436
- ## Look Around Preview
437
-
438
- Show Apple's street-level imagery for a selected location. Availability
439
- depends on region coverage.
423
+ Look Around is Apple's street-level imagery. Coverage is regional, so always
424
+ plan for "no scene".
440
425
 
441
426
  ```swift
442
- struct LookAroundView: View {
443
- let mapItem: MKMapItem
427
+ struct StreetPreview: View {
428
+ let place: MKMapItem
444
429
  @State private var scene: MKLookAroundScene?
445
430
 
446
431
  var body: some View {
447
- Group {
432
+ ZStack {
448
433
  if let scene {
449
434
  LookAroundPreview(scene: .constant(scene))
450
- .frame(height: 200)
451
- .clipShape(.rect(cornerRadius: 12))
452
435
  } else {
453
- ContentUnavailableView("No Look Around",
454
- systemImage: "eye.slash",
455
- description: Text("Look Around is not available here."))
436
+ ContentUnavailableView("No street view here", systemImage: "eye.slash")
456
437
  }
457
438
  }
458
- .task(id: mapItem) {
439
+ .frame(height: 200)
440
+ .clipShape(RoundedRectangle(cornerRadius: 12))
441
+ .task(id: place) {
459
442
  scene = nil
460
- let request = MKLookAroundSceneRequest(mapItem: mapItem)
461
- scene = try? await request.scene
443
+ scene = try? await MKLookAroundSceneRequest(mapItem: place).scene
462
444
  }
463
445
  }
464
446
  }
465
447
  ```
466
448
 
467
- ### Look Around overlay on a Map
449
+ ### Street view floating over the map
468
450
 
469
451
  ```swift
470
- Map(selection: $selectedItem) { ... }
452
+ Map(selection: $chosen) { /* markers */ }
471
453
  .overlay(alignment: .bottomTrailing) {
472
- if lookAroundScene != nil {
473
- LookAroundPreview(scene: $lookAroundScene)
474
- .frame(width: 200, height: 130)
475
- .clipShape(.rect(cornerRadius: 10))
454
+ if streetScene != nil {
455
+ LookAroundPreview(scene: $streetScene)
456
+ .frame(width: 200, height: 130, alignment: .center)
457
+ .clipShape(RoundedRectangle(cornerRadius: 10))
476
458
  .padding()
477
459
  }
478
460
  }
479
- .onChange(of: selectedItem) { _, newItem in
480
- guard let item = newItem else {
481
- lookAroundScene = nil
482
- return
483
- }
484
- Task {
485
- let request = MKLookAroundSceneRequest(mapItem: item)
486
- lookAroundScene = try? await request.scene
487
- }
461
+ .onChange(of: chosen) { _, item in
462
+ guard let item else { streetScene = nil; return }
463
+ Task { streetScene = try? await MKLookAroundSceneRequest(mapItem: item).scene }
488
464
  }
489
465
  ```
490
466
 
491
- ---
492
-
493
- ## Map Snapshots (MKMapSnapshotter)
467
+ ## Still Images with MKMapSnapshotter
494
468
 
495
- Generate a static image of a map region. Useful for share sheets, widgets,
496
- notifications, or thumbnails.
469
+ A snapshot is a still image of a map: share sheets, widgets, notification
470
+ attachments, list thumbnails.
497
471
 
498
472
  ```swift
499
- func generateMapSnapshot(center: CLLocationCoordinate2D,
500
- size: CGSize = CGSize(width: 300, height: 200)) async throws -> UIImage {
473
+ import MapKit
474
+ import UIKit
475
+
476
+ let cardSize = CGSize(width: 300, height: 200)
477
+
478
+ func thumbnail(of spot: CLLocationCoordinate2D, fitting frame: CGSize = cardSize) async throws -> UIImage {
479
+ let size = frame
501
480
  let options = MKMapSnapshotter.Options()
502
- options.region = MKCoordinateRegion(
503
- center: center,
504
- span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
505
- )
506
- options.size = size
507
481
  options.mapType = .standard
508
482
  options.showsBuildings = true
483
+ options.size = size
484
+ options.region = MKCoordinateRegion(center: spot, latitudinalMeters: 1100, longitudinalMeters: 1100)
485
+
486
+ let shot = try await MKMapSnapshotter(options: options).start()
487
+ let pinPoint = shot.point(for: spot)
488
+ let symbol = UIImage(systemName: "mappin.circle.fill")
489
+ let pin = symbol?.withTintColor(.systemRed)
509
490
 
510
- let snapshotter = MKMapSnapshotter(options: options)
511
- let snapshot = try await snapshotter.start()
512
-
513
- // Draw a pin at the center
514
- let image = UIGraphicsImageRenderer(size: size).image { context in
515
- snapshot.image.draw(at: .zero)
516
- let point = snapshot.point(for: center)
517
- let pin = UIImage(systemName: "mappin.circle.fill")?
518
- .withTintColor(.red, renderingMode: .alwaysOriginal)
519
- pin?.draw(at: CGPoint(x: point.x - 15, y: point.y - 30),
520
- blendMode: .normal, alpha: 1.0)
491
+ return UIGraphicsImageRenderer(size: size).image { _ in
492
+ shot.image.draw(at: .zero)
493
+ pin?.draw(at: CGPoint(x: pinPoint.x - 12, y: pinPoint.y - 24))
521
494
  }
522
- return image
523
495
  }
524
496
  ```
525
497
 
526
- ---
498
+ A square of 1100 m is roughly 0.01 degrees of latitude: street level.
499
+ `point(for:)` converts a coordinate into the image's coordinate space.
527
500
 
528
501
  ## Dense Annotations and Clustering
529
502
 
530
- For dense SwiftUI maps, hide titles at low zoom or reduce visible items based
531
- on the current camera region. Use `MKMapView` when you need explicit cluster
532
- configuration.
533
-
534
- ```swift
535
- Map {
536
- ForEach(allStores) { store in
537
- Marker(store.name, systemImage: "cart", coordinate: store.coordinate)
538
- .annotationTitles(.hidden) // Hide titles at low zoom
539
- }
540
- }
541
- .mapStyle(.standard(pointsOfInterest: .excludingAll))
542
- ```
503
+ SwiftUI `Map` has no cluster configuration. With many markers:
543
504
 
544
- For custom clustering behavior with `MKMapView` (UIKit interop), set
545
- `clusteringIdentifier` on `MKMarkerAnnotationView`.
505
+ - hide titles at low zoom with `.annotationTitles(.hidden)` on each `Marker`;
506
+ - show only what falls inside the current camera region;
507
+ - drop built-in points of interest with
508
+ `.mapStyle(.standard(pointsOfInterest: .excludingAll))`.
546
509
 
547
- ---
510
+ Real clustering needs `MKMapView` through UIKit interop: give each
511
+ `MKMarkerAnnotationView` the same `clusteringIdentifier`.
548
512
 
549
- ## MapKit with MKMapItem Utilities
513
+ ## MKMapItem Helpers
550
514
 
551
515
  ### Open in Apple Maps
552
516
 
517
+ On iOS 26 build the item from a location; `MKMapItem(placemark:)` is
518
+ deprecated there.
519
+
553
520
  ```swift
554
- let item = MKMapItem(placemark: MKPlacemark(coordinate: coordinate))
555
- item.name = "Destination"
556
- item.openInMaps(launchOptions: [
557
- MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving
558
- ])
521
+ @available(iOS 26, *)
522
+ func openDrivingDirections(to spot: CLLocationCoordinate2D, name: String) {
523
+ let item = MKMapItem(location: CLLocation(latitude: spot.latitude, longitude: spot.longitude),
524
+ address: nil)
525
+ item.name = name
526
+ item.openInMaps(launchOptions: [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving])
527
+ }
559
528
  ```
560
529
 
561
- ### Distance Calculation
530
+ Below iOS 26 the same call starts from
531
+ `MKMapItem(placemark: MKPlacemark(coordinate: spot))`.
532
+
533
+ ### Distance
562
534
 
563
535
  ```swift
564
- func distanceBetween(_ a: CLLocationCoordinate2D,
565
- _ b: CLLocationCoordinate2D) -> CLLocationDistance {
566
- let locA = CLLocation(latitude: a.latitude, longitude: a.longitude)
567
- let locB = CLLocation(latitude: b.latitude, longitude: b.longitude)
568
- return locA.distance(from: locB) // meters
536
+ func metres(from origin: CLLocationCoordinate2D, to target: CLLocationCoordinate2D) -> CLLocationDistance {
537
+ let here = CLLocation(latitude: origin.latitude, longitude: origin.longitude)
538
+ let there = CLLocation(latitude: target.latitude, longitude: target.longitude)
539
+ return here.distance(from: there)
569
540
  }
570
541
  ```
571
542
 
572
- ### Format Distance for Display
543
+ ### Formatting distance
544
+
545
+ `MKDistanceFormatter` respects the user's locale and units:
573
546
 
574
547
  ```swift
575
- let formatter = MKDistanceFormatter()
576
- formatter.unitStyle = .abbreviated
577
- let text = formatter.string(fromDistance: 1500) // "0.9 mi" or "1.5 km"
548
+ let distanceText = MKDistanceFormatter()
549
+ distanceText.unitStyle = .abbreviated
550
+ let shown = distanceText.string(fromDistance: 1500)
578
551
  ```
579
552
 
580
- ---
553
+ `shown` is "0.9 mi" for a US-English user and "1.5 km" for most others.
581
554
 
582
- ## iOS 26 New APIs
555
+ ## Geocoding and Places on iOS 26
583
556
 
584
557
  ### MKGeocodingRequest
585
558
 
586
- Convert an address string to map items with richer data than `CLGeocoder`:
559
+ Address text in, `MKMapItem`s out, with more detail than `CLGeocoder` gave.
560
+ The initializer is failable.
587
561
 
588
562
  ```swift
589
563
  @available(iOS 26, *)
590
- func geocodeAddresses(_ addresses: [String]) async -> [MKMapItem] {
591
- var items: [MKMapItem] = []
592
- for address in addresses {
593
- guard let request = MKGeocodingRequest(addressString: address) else { continue }
594
- if let mapItems = try? await request.mapItems {
595
- items.append(contentsOf: mapItems)
564
+ func resolveAll(_ lines: [String]) async -> [MKMapItem] {
565
+ var found: [MKMapItem] = []
566
+ for line in lines {
567
+ guard let request = MKGeocodingRequest(addressString: line) else { continue }
568
+ if let items = try? await request.mapItems {
569
+ found.append(contentsOf: items)
596
570
  }
597
571
  }
598
- return items
572
+ return found
599
573
  }
600
574
  ```
601
575
 
602
576
  ### MKReverseGeocodingRequest
603
577
 
604
- Convert coordinates to map items with `MKAddress`:
605
-
606
578
  ```swift
607
579
  @available(iOS 26, *)
608
- func reverseGeocode(_ coordinate: CLLocationCoordinate2D) async -> MKAddress? {
609
- let location = CLLocation(latitude: coordinate.latitude,
610
- longitude: coordinate.longitude)
611
- guard let request = MKReverseGeocodingRequest(location: location) else {
612
- return nil
613
- }
614
- let mapItems = try? await request.mapItems
615
- return mapItems?.first?.address
580
+ func address(at spot: CLLocation) async throws -> MKAddress? {
581
+ guard let request = MKReverseGeocodingRequest(location: spot) else { return nil }
582
+ return try await request.mapItems.first?.address
616
583
  }
617
584
  ```
618
585
 
619
586
  ### MKAddress and MKAddressRepresentations
620
587
 
621
- `MKAddress` provides full and short address strings. Use an `MKMapItem`'s
622
- `MKAddressRepresentations` to format addresses for different contexts:
623
-
624
- ```swift
625
- @available(iOS 26, *)
626
- func formatAddress(for item: MKMapItem) -> String {
627
- // Use address representations for locale-aware formatting
628
- item.addressRepresentations?.fullAddress(includingRegion: true, singleLine: true)
629
- ?? item.address?.fullAddress
630
- ?? ""
631
- }
632
- ```
633
-
634
- ### PlaceDescriptor (via GeoToolbox)
635
-
636
- Create place references from coordinates when you do not have a Place ID:
588
+ `MKAddress` has `fullAddress` and an optional `shortAddress`.
589
+ `MKMapItem.addressRepresentations` formats for a context:
637
590
 
638
591
  ```swift
639
- import GeoToolbox
640
-
641
592
  @available(iOS 26, *)
642
- func mapItem(for myCoordinate: CLLocationCoordinate2D) async throws -> MKMapItem {
643
- let descriptor = PlaceDescriptor(
644
- representations: [.coordinate(myCoordinate)],
645
- commonName: "My Favorite Cafe"
646
- )
647
-
648
- let request = MKMapItemRequest(placeDescriptor: descriptor)
649
- return try await request.mapItem
593
+ func oneLine(_ item: MKMapItem) -> String {
594
+ let formats = item.addressRepresentations
595
+ if let line = formats?.fullAddress(includingRegion: true, singleLine: true) { return line }
596
+ return item.address?.fullAddress ?? ""
650
597
  }
651
-
652
- // Use mapItem with any MapKit API: Marker(item:), directions, place cards
653
598
  ```
654
599
 
655
- ### Cycling Directions (iOS 14+)
656
-
657
- ```swift
658
- func cyclingRoute(to destination: MKMapItem) async throws -> MKRoute? {
659
- let request = MKDirections.Request()
660
- request.source = .forCurrentLocation()
661
- request.destination = destination
662
- request.transportType = .cycling
663
- let response = try await MKDirections(request: request).calculate()
664
- return response.routes.first
665
- }
666
- ```
667
-
668
- ---
669
-
670
- ## User Location Display
600
+ `addressRepresentations` also offers `cityName`, `cityWithContext` and
601
+ `regionName`.
671
602
 
672
- Show the user's position with the built-in blue dot:
603
+ ### PlaceDescriptor (via GeoToolbox)
673
604
 
674
- ```swift
675
- Map(position: $position) {
676
- UserAnnotation() // Blue dot with accuracy ring
677
- // ... other content
678
- }
679
- .mapControls {
680
- MapUserLocationButton() // Button to re-center on user
681
- }
682
- ```
605
+ `import GeoToolbox`. A `PlaceDescriptor` names a place by coordinate or
606
+ address when no place ID exists; resolve it with
607
+ `MKMapItemRequest(placeDescriptor:)` and `try await request.mapItem`. The
608
+ result is an ordinary `MKMapItem`, usable with `Marker(item:)`, directions and
609
+ place cards. Example in [SKILL.md](../SKILL.md#placedescriptor-ios-26).
683
610
 
684
- `UserAnnotation()` requires location authorization. If authorization is
685
- denied, the annotation does not appear and no error is thrown.
611
+ ## Showing the User
686
612
 
687
- ---
613
+ - `UserAnnotation()` in the map content draws the blue dot and accuracy ring.
614
+ - `MapUserLocationButton()` in `.mapControls` recentres on the user.
615
+ - Without authorization the dot simply is not drawn and no error is raised,
616
+ so a missing dot is a permission question, not a rendering bug.
688
617
 
689
- ## Map in a List or ScrollView
618
+ ## Maps Inside Scrolling Content
690
619
 
691
- When embedding a `Map` inside a `ScrollView`, disable map gestures that
692
- conflict with scrolling:
620
+ Map gestures fight with scrolling. Turn them off for a thumbnail, or allow
621
+ only pinch zoom:
693
622
 
694
623
  ```swift
695
- ScrollView {
696
- Map(position: $position, interactionModes: []) {
697
- Marker("Location", coordinate: coord)
698
- }
699
- .frame(height: 200)
700
- .clipShape(.rect(cornerRadius: 12))
701
-
702
- Text("Details below the map...")
624
+ Map(position: $camera, interactionModes: []) {
625
+ Marker("Venue", coordinate: venue)
703
626
  }
627
+ .frame(height: 200)
628
+ .clipShape(RoundedRectangle(cornerRadius: 12))
704
629
  ```
705
630
 
706
- Use `interactionModes: []` for a fully static map thumbnail or
707
- `interactionModes: [.zoom]` to allow pinch-to-zoom without pan conflicts.
708
-
709
- ---
631
+ `interactionModes: [.zoom]` keeps pinch without competing with the scroll.
710
632
 
711
- ## Coordinate Utilities
633
+ ## Coordinate Math
712
634
 
713
- ### Region from an array of coordinates
635
+ ### Bounding region for a set of points
714
636
 
715
637
  ```swift
716
- func regionForCoordinates(_ coords: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
717
- guard !coords.isEmpty else {
718
- return MKCoordinateRegion()
719
- }
720
- var minLat = coords[0].latitude
721
- var maxLat = coords[0].latitude
722
- var minLon = coords[0].longitude
723
- var maxLon = coords[0].longitude
724
-
725
- for coord in coords {
726
- minLat = min(minLat, coord.latitude)
727
- maxLat = max(maxLat, coord.latitude)
728
- minLon = min(minLon, coord.longitude)
729
- maxLon = max(maxLon, coord.longitude)
730
- }
731
-
732
- let center = CLLocationCoordinate2D(
733
- latitude: (minLat + maxLat) / 2,
734
- longitude: (minLon + maxLon) / 2
735
- )
736
- let span = MKCoordinateSpan(
737
- latitudeDelta: (maxLat - minLat) * 1.3, // 30% padding
738
- longitudeDelta: (maxLon - minLon) * 1.3
638
+ func enclosingRegion(_ points: [CLLocationCoordinate2D]) -> MKCoordinateRegion {
639
+ let lats = points.map(\.latitude)
640
+ let lons = points.map(\.longitude)
641
+ guard let south = lats.min(), let north = lats.max(),
642
+ let west = lons.min(), let east = lons.max() else { return MKCoordinateRegion() }
643
+ return MKCoordinateRegion(
644
+ center: CLLocationCoordinate2D(latitude: (south + north) / 2, longitude: (west + east) / 2),
645
+ span: MKCoordinateSpan(latitudeDelta: (north - south) * 1.3,
646
+ longitudeDelta: (east - west) * 1.3)
739
647
  )
740
- return MKCoordinateRegion(center: center, span: span)
741
648
  }
742
649
  ```
743
650
 
651
+ The factor 1.3 leaves 30 percent padding around the points.
652
+
744
653
  ### CLLocationCoordinate2D Equatable conformance
745
654
 
746
- `CLLocationCoordinate2D` does not conform to `Equatable` by default.
747
- Extend it when needed for comparisons:
655
+ The type is not `Equatable`. Add it with `@retroactive`, which (Swift 5.10
656
+ and later) acknowledges conforming another module's type to another module's
657
+ protocol and silences the warning:
748
658
 
749
659
  ```swift
750
660
  extension CLLocationCoordinate2D: @retroactive Equatable {
751
- public static func == (lhs: Self, rhs: Self) -> Bool {
752
- lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude
661
+ public static func == (a: CLLocationCoordinate2D, b: CLLocationCoordinate2D) -> Bool {
662
+ a.latitude == b.latitude && a.longitude == b.longitude
753
663
  }
754
664
  }
755
665
  ```
756
666
 
757
- Note: Use `@retroactive` (Swift 5.10+) to silence the warning about
758
- conforming types from other modules.
759
-
760
- ---
761
-
762
667
  ## Accessibility
763
668
 
764
669
  ### Marker accessibility
765
670
 
766
- `Marker` views include built-in VoiceOver support using the title string.
767
- Add `.accessibilityLabel` for richer descriptions:
768
-
769
- ```swift
770
- Marker(store.name, coordinate: store.coordinate)
771
- .accessibilityLabel("\(store.name), \(store.distanceText) away")
772
- ```
671
+ VoiceOver reads a `Marker`'s title. Add detail when it helps:
672
+ `.accessibilityLabel("\(dock.name), \(distanceText) away")`.
773
673
 
774
674
  ### Map accessibility
775
675
 
776
- Add a concise description of the map purpose:
676
+ Summarise the map itself:
777
677
 
778
678
  ```swift
779
- Map { ... }
679
+ Map(position: $camera) { /* markers */ }
780
680
  .accessibilityElement()
781
- .accessibilityLabel("Store locations map showing \(stores.count) stores")
681
+ .accessibilityLabel("Map of \(docks.count) bike docks nearby")
782
682
  ```
783
683
 
784
- ---
785
-
786
- ## References
684
+ ## Apple Documentation
787
685
 
788
- - Apple docs: [MapKit for SwiftUI](https://sosumi.ai/documentation/MapKit/MapKit-for-SwiftUI)
789
- - Apple docs: [Map](https://sosumi.ai/documentation/MapKit/Map)
790
- - Apple docs: [MapCameraPosition](https://sosumi.ai/documentation/MapKit/MapCameraPosition)
791
- - Apple docs: [MKLocalSearch](https://sosumi.ai/documentation/MapKit/MKLocalSearch)
792
- - Apple docs: [MKDirections](https://sosumi.ai/documentation/MapKit/MKDirections)
793
- - Apple docs: [MKLookAroundScene](https://sosumi.ai/documentation/MapKit/MKLookAroundScene)
686
+ - [MapKit for SwiftUI](https://developer.apple.com/documentation/mapkit/mapkit-for-swiftui)
687
+ - [Map](https://developer.apple.com/documentation/mapkit/map)
688
+ - [MapCameraPosition](https://developer.apple.com/documentation/mapkit/mapcameraposition)
689
+ - [MKLocalSearch](https://developer.apple.com/documentation/mapkit/mklocalsearch)
690
+ - [MKDirections](https://developer.apple.com/documentation/mapkit/mkdirections)
691
+ - [MKLookAroundScene](https://developer.apple.com/documentation/mapkit/mklookaroundscene)