@mmerterden/multi-agent-pipeline 20.6.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 (326) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +328 -329
  5. package/package.json +2 -2
  6. package/pipeline/multi-agent-refs/features/design-conformance.md +62 -64
  7. package/pipeline/scripts/_notices.mjs +12 -1
  8. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  9. package/pipeline/skills/.skill-manifest.json +106 -106
  10. package/pipeline/skills/shared/README.md +71 -71
  11. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +1 -0
  12. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  13. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  14. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  15. package/pipeline/skills/shared/external/android-architecture/SKILL.md +2 -0
  16. package/pipeline/skills/shared/external/android-performance/SKILL.md +2 -0
  17. package/pipeline/skills/shared/external/android-security/SKILL.md +2 -0
  18. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  19. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  20. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  21. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  22. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  23. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  24. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  25. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  26. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  27. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  28. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  29. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  30. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  31. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  32. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  33. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  34. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  35. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  36. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  37. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  38. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  39. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  40. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  41. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  42. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  43. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  44. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  45. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  46. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  47. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  48. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  49. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  50. package/pipeline/skills/shared/external/backlog/BACKLOG.md +1 -1
  51. package/pipeline/skills/shared/external/backlog/SKILL.md +56 -33
  52. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  53. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  54. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  55. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +1 -0
  56. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  57. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  58. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  59. package/pipeline/skills/shared/external/compose-components/SKILL.md +2 -0
  60. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +3 -2
  61. package/pipeline/skills/shared/external/compose-testing/SKILL.md +2 -0
  62. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  63. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  64. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  65. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  66. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  67. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  68. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  69. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  70. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  71. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  72. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  73. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  74. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  75. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  76. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  77. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  78. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  79. package/pipeline/skills/shared/external/council/SKILL.md +1 -0
  80. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  81. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  82. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  83. package/pipeline/skills/shared/external/css-modern/SKILL.md +1 -0
  84. package/pipeline/skills/shared/external/database-patterns/SKILL.md +1 -0
  85. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  86. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  87. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  88. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  89. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  90. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  91. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  92. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  93. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  94. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  95. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  96. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  97. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  98. package/pipeline/skills/shared/external/evidence-github/SKILL.md +2 -0
  99. package/pipeline/skills/shared/external/evidence-registry/SKILL.md +2 -0
  100. package/pipeline/skills/shared/external/gradle-kotlin-dsl/SKILL.md +2 -0
  101. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  102. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  103. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  104. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  105. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  106. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  107. package/pipeline/skills/shared/external/html-semantic/SKILL.md +1 -0
  108. package/pipeline/skills/shared/external/humanizer/SKILL.md +1 -0
  109. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  110. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  111. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  112. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  113. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +1 -0
  115. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  116. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  117. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  118. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  119. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +1 -0
  120. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  121. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  122. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  123. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  124. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  125. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  126. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  127. package/pipeline/skills/shared/external/ios-security/SKILL.md +2 -0
  128. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  129. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  130. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  131. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  132. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  133. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  134. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +91 -283
  135. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +119 -151
  136. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +60 -90
  137. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +119 -156
  138. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +726 -787
  139. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +253 -288
  140. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +243 -304
  141. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +88 -104
  142. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +181 -235
  143. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +198 -263
  144. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +461 -466
  145. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +145 -151
  146. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +123 -141
  147. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +146 -157
  148. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +22 -19
  149. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +156 -140
  150. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  151. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  152. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  153. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  154. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  155. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  156. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  157. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  158. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  159. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  160. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  161. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  162. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  163. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +1 -0
  164. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  165. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  166. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  167. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  168. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  169. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  170. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  171. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  172. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  173. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  174. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  175. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  176. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  177. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  178. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  179. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  180. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  181. package/pipeline/skills/shared/external/play-store-review/SKILL.md +2 -0
  182. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  183. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  184. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  185. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  186. package/pipeline/skills/shared/external/python-patterns/SKILL.md +1 -0
  187. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +1 -0
  188. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  189. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  190. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  191. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +1 -0
  192. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +2 -0
  193. package/pipeline/skills/shared/external/room-database/SKILL.md +2 -0
  194. package/pipeline/skills/shared/external/search-first/SKILL.md +1 -0
  195. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  196. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  197. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  198. package/pipeline/skills/shared/external/signal-community/SKILL.md +2 -0
  199. package/pipeline/skills/shared/external/skill-creator/SKILL.md +80 -41
  200. package/pipeline/skills/shared/external/skill-creator/audit.md +63 -59
  201. package/pipeline/skills/shared/external/skill-creator/checklist.md +28 -20
  202. package/pipeline/skills/shared/external/skill-creator/examples.md +40 -40
  203. package/pipeline/skills/shared/external/skill-creator/label-check.md +48 -36
  204. package/pipeline/skills/shared/external/skill-creator/scripts/audit-panel.js +91 -100
  205. package/pipeline/skills/shared/external/skill-creator/template.md +51 -39
  206. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  207. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  208. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  209. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  210. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  211. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  212. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  213. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  214. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  215. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  216. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  217. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  218. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  219. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  220. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  221. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  222. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  223. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  224. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  225. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  226. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  227. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  228. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  229. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  230. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  231. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  232. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  233. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  234. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  235. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  236. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  237. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  238. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  239. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  240. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  241. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  242. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  243. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  244. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  245. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  246. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  247. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  248. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  249. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  250. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  251. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  252. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  253. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  254. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  255. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  256. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  257. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  258. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  259. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  260. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  261. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  262. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  263. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  264. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  265. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  266. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  267. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  268. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  269. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  270. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  271. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  272. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  273. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  274. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  275. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  276. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  277. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  278. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  279. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  280. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  281. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  282. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  283. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  284. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  285. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  286. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  287. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  288. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  289. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  290. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  291. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  292. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  293. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  294. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  295. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  296. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  297. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  298. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  299. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  300. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  301. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  302. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  303. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  304. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  305. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  306. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  307. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  308. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  309. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  310. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +1 -0
  311. package/pipeline/skills/shared/external/testing-backend/SKILL.md +1 -0
  312. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  313. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  314. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +1 -0
  315. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  316. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  317. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  318. package/pipeline/skills/shared/external/vue-composition/SKILL.md +1 -0
  319. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  320. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  321. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +1 -0
  322. package/pipeline/skills/shared/external/web-performance/SKILL.md +1 -0
  323. package/pipeline/skills/shared/external/web-testing/SKILL.md +1 -0
  324. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  325. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  326. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,536 +1,358 @@
1
- # VisionKit Scanner Patterns
1
+ # VisionKit scanners
2
2
 
3
- Complete implementation patterns for DataScannerViewController and
4
- VNDocumentCameraViewController covering availability checking, configuration,
5
- SwiftUI integration, delegate handling, custom overlays, and camera permissions.
6
- All patterns target iOS 26+ with Swift 6.3 unless noted.
3
+ Camera UI that VisionKit provides on top of Vision: the live
4
+ `DataScannerViewController` and the paper-oriented
5
+ `VNDocumentCameraViewController`. Summary in `../SKILL.md`.
7
6
 
8
7
  ## Contents
9
- - Camera Permission Setup
10
- - DataScannerViewController
11
- - Delegate Methods
12
- - SwiftUI Integration
13
- - Custom Overlay UI
14
- - VNDocumentCameraViewController
15
8
 
16
- ## Camera Permission Setup
9
+ - [Camera permission](#camera-permission)
10
+ - [DataScannerViewController](#datascannerviewcontroller)
11
+ - [Delegate callbacks](#delegate-callbacks)
12
+ - [SwiftUI](#swiftui)
13
+ - [Custom overlay](#custom-overlay)
14
+ - [VNDocumentCameraViewController](#vndocumentcameraviewcontroller)
15
+ - [Performance](#performance)
17
16
 
18
- Add the camera usage description to Info.plist before using any scanner:
17
+ ## Camera permission
19
18
 
20
- ```xml
21
- <key>NSCameraUsageDescription</key>
22
- <string>Camera access is needed to scan text and barcodes.</string>
23
- ```
24
-
25
- Request permission before presenting the scanner:
19
+ Both scanners use the camera, so Info.plist needs `NSCameraUsageDescription`
20
+ before either is shown. Ask for access explicitly when you want to control the
21
+ moment of the prompt:
26
22
 
27
23
  ```swift
28
24
  import AVFoundation
29
25
 
30
- func requestCameraAccess() async -> Bool {
26
+ func cameraAllowed() async -> Bool {
31
27
  let status = AVCaptureDevice.authorizationStatus(for: .video)
32
- switch status {
33
- case .authorized:
28
+ if status == .authorized {
34
29
  return true
35
- case .notDetermined:
36
- return await AVCaptureDevice.requestAccess(for: .video)
37
- case .denied, .restricted:
38
- return false
39
- @unknown default:
40
- return false
41
30
  }
31
+ if status == .notDetermined {
32
+ let granted = await AVCaptureDevice.requestAccess(for: .video)
33
+ return granted
34
+ }
35
+ return false
42
36
  }
43
37
  ```
44
38
 
45
- ## DataScannerViewController
39
+ `.denied`, `.restricted` and any status added in a future release all fall
40
+ through to `false`.
46
41
 
47
- `DataScannerViewController` provides a full-screen live camera scanner for text
48
- and barcodes with built-in highlighting and interaction. Available on devices
49
- with an A12 chip or later (iOS 16+).
42
+ ## DataScannerViewController
50
43
 
51
- ### Availability Checking
44
+ A full-screen live scanner with built-in highlighting and tap handling.
45
+ Available from iOS 16 on devices with an A12 Bionic chip or newer.
52
46
 
53
- Always check both hardware support and runtime availability before presenting.
47
+ Two class properties gate it, and both must be true before presenting:
54
48
 
55
- ```swift
56
- import VisionKit
49
+ - `isSupported`: the hardware can run it.
50
+ - `isAvailable`: supported, plus camera access is granted and not blocked by
51
+ restrictions such as device management.
57
52
 
58
- func canUseDataScanner() -> Bool {
59
- // Hardware check: requires A12 Bionic or later
60
- guard DataScannerViewController.isSupported else {
61
- return false
62
- }
63
- // Runtime check: camera authorized and not restricted
64
- guard DataScannerViewController.isAvailable else {
65
- return false
66
- }
67
- return true
68
- }
69
- ```
53
+ ### Initializer options
70
54
 
71
- `isSupported` checks hardware capability (A12+). `isAvailable` checks that the
72
- camera is authorized and not restricted by device management. Both must be true.
55
+ | Parameter | Default | Meaning |
56
+ |---|---|---|
57
+ | `recognizedDataTypes` | required | Set of text and barcode types to find |
58
+ | `qualityLevel` | `.balanced` | Speed versus detail |
59
+ | `recognizesMultipleItems` | `false` | Track many items or only the most prominent |
60
+ | `isHighFrameRateTrackingEnabled` | `true` | Smoother highlight tracking, more power |
61
+ | `isPinchToZoomEnabled` | `true` | Pinch gesture zooms the camera |
62
+ | `isGuidanceEnabled` | `true` | On-screen hints such as "slow down" |
63
+ | `isHighlightingEnabled` | `false` | System highlight boxes around found items |
73
64
 
74
- ### Configuration and Initialization
65
+ Three configurations for different jobs:
75
66
 
76
67
  ```swift
77
68
  import VisionKit
78
69
 
79
- func createTextScanner() -> DataScannerViewController {
80
- DataScannerViewController(
81
- recognizedDataTypes: [
82
- .text(languages: ["en"]),
83
- ],
84
- qualityLevel: .balanced,
85
- recognizesMultipleItems: true,
86
- isHighFrameRateTrackingEnabled: true,
87
- isPinchToZoomEnabled: true,
88
- isGuidanceEnabled: true,
89
- isHighlightingEnabled: true
90
- )
91
- }
70
+ @MainActor
71
+ enum ScannerPresets {
72
+ static func signReader() -> DataScannerViewController {
73
+ DataScannerViewController(
74
+ recognizedDataTypes: [.text()],
75
+ qualityLevel: .accurate,
76
+ recognizesMultipleItems: true,
77
+ isHighFrameRateTrackingEnabled: false,
78
+ isPinchToZoomEnabled: true,
79
+ isGuidanceEnabled: false,
80
+ isHighlightingEnabled: true
81
+ )
82
+ }
92
83
 
93
- func createBarcodeScanner() -> DataScannerViewController {
94
- DataScannerViewController(
95
- recognizedDataTypes: [
96
- .barcode(symbologies: [.qr, .ean13, .code128]),
97
- ],
98
- qualityLevel: .fast,
99
- recognizesMultipleItems: false,
100
- isHighFrameRateTrackingEnabled: false,
101
- isPinchToZoomEnabled: false,
102
- isGuidanceEnabled: true,
103
- isHighlightingEnabled: true
104
- )
105
- }
84
+ static func boardingPassReader() -> DataScannerViewController {
85
+ DataScannerViewController(
86
+ recognizedDataTypes: [.barcode(symbologies: [.pdf417, .aztec, .qr])],
87
+ qualityLevel: .fast,
88
+ isHighFrameRateTrackingEnabled: false,
89
+ isPinchToZoomEnabled: false
90
+ )
91
+ }
106
92
 
107
- func createMixedScanner() -> DataScannerViewController {
108
- DataScannerViewController(
109
- recognizedDataTypes: [
110
- .text(languages: ["en"]),
111
- .barcode(symbologies: [.qr, .ean13]),
112
- ],
113
- qualityLevel: .balanced,
114
- recognizesMultipleItems: true,
115
- isHighFrameRateTrackingEnabled: true,
116
- isPinchToZoomEnabled: true,
117
- isGuidanceEnabled: true,
118
- isHighlightingEnabled: true
119
- )
93
+ static func parcelReader() -> DataScannerViewController {
94
+ DataScannerViewController(
95
+ recognizedDataTypes: [
96
+ .text(textContentType: .shipmentTrackingNumber),
97
+ .barcode(symbologies: [.code128, .qr])
98
+ ],
99
+ qualityLevel: .balanced,
100
+ isHighlightingEnabled: true
101
+ )
102
+ }
120
103
  }
121
104
  ```
122
105
 
123
- ### Recognized Data Types
106
+ ### Data types
124
107
 
125
- ```swift
126
- // Text with language hints
127
- let textType: DataScannerViewController.RecognizedDataType =
128
- .text(languages: ["en", "fr", "de"])
129
-
130
- // Text filtered by content type
131
- let emailType: DataScannerViewController.RecognizedDataType =
132
- .text(textContentType: .emailAddress)
133
- let urlType: DataScannerViewController.RecognizedDataType =
134
- .text(textContentType: .URL)
135
- let phoneType: DataScannerViewController.RecognizedDataType =
136
- .text(textContentType: .telephoneNumber)
137
- let addressType: DataScannerViewController.RecognizedDataType =
138
- .text(textContentType: .fullAddress)
139
- let flightType: DataScannerViewController.RecognizedDataType =
140
- .text(textContentType: .flightNumber)
141
- let trackingType: DataScannerViewController.RecognizedDataType =
142
- .text(textContentType: .shipmentTrackingNumber)
143
-
144
- // Barcode with specific symbologies
145
- let qrOnly: DataScannerViewController.RecognizedDataType =
146
- .barcode(symbologies: [.qr])
147
- let retailBarcodes: DataScannerViewController.RecognizedDataType =
148
- .barcode(symbologies: [.ean8, .ean13, .upce, .code128])
149
- ```
108
+ `DataScannerViewController.RecognizedDataType` values:
150
109
 
151
- ### Quality Levels
110
+ - `.text(languages:textContentType:)`: both arguments are optional, so
111
+ `.text()`, `.text(languages: ["fr"])` and
112
+ `.text(textContentType: .flightNumber)` all work.
113
+ - `.barcode(symbologies:)`: takes `VNBarcodeSymbology` values.
152
114
 
153
- | Level | Use Case | Notes |
154
- |---|---|---|
155
- | `.fast` | Barcode scanning, quick text grab | Lowest latency |
156
- | `.balanced` | General purpose text + barcode | Default choice |
157
- | `.accurate` | Detailed OCR, small text | Higher latency |
115
+ Text content types narrow recognition to one kind of string: `.URL`,
116
+ `.emailAddress`, `.telephoneNumber`, `.fullStreetAddress`, `.flightNumber`,
117
+ `.shipmentTrackingNumber`, `.dateTimeDuration`, and `.currency` (iOS 17).
158
118
 
159
- ### Starting and Stopping
119
+ A retail product scanner usually needs `.ean13`, `.ean8`, `.upce` and
120
+ `.code128`.
160
121
 
161
- ```swift
162
- func presentScanner(_ scanner: DataScannerViewController,
163
- from presenter: UIViewController) {
164
- scanner.delegate = presenter as? DataScannerViewControllerDelegate
165
- presenter.present(scanner, animated: true) {
166
- try? scanner.startScanning()
167
- }
168
- }
122
+ ### Quality levels
169
123
 
170
- func dismissScanner(_ scanner: DataScannerViewController) {
171
- scanner.stopScanning()
172
- scanner.dismiss(animated: true)
173
- }
174
- ```
124
+ - `.fast`: lowest latency; barcodes and large, quick text.
125
+ - `.balanced`: the sensible default for most scanners.
126
+ - `.accurate`: small or dense text; slower to respond.
175
127
 
176
- ## Delegate Methods
128
+ ### Start and stop
177
129
 
178
- Implement `DataScannerViewControllerDelegate` to handle recognized items and
179
- scanner lifecycle events.
130
+ Scanning can only start once the controller is on screen. Set the delegate,
131
+ present, and start in the presentation completion. To finish, call
132
+ `stopScanning()` and then dismiss.
180
133
 
181
134
  ```swift
135
+ import UIKit
182
136
  import VisionKit
183
137
 
184
- final class ScannerCoordinator: NSObject, DataScannerViewControllerDelegate {
185
-
186
- var onTextRecognized: ((String) -> Void)?
187
- var onBarcodeRecognized: ((String, VNBarcodeSymbology) -> Void)?
188
-
189
- // Called when the user taps on a recognized item
190
- func dataScanner(
191
- _ scanner: DataScannerViewController,
192
- didTapOn item: RecognizedItem
193
- ) {
194
- switch item {
195
- case .text(let text):
196
- onTextRecognized?(text.transcript)
197
- case .barcode(let barcode):
198
- if let payload = barcode.payloadStringValue {
199
- onBarcodeRecognized?(payload, barcode.observation.symbology)
200
- }
201
- @unknown default:
202
- break
203
- }
204
- }
205
-
206
- // Called when new items appear in the camera view
207
- func dataScanner(
208
- _ scanner: DataScannerViewController,
209
- didAdd addedItems: [RecognizedItem],
210
- allItems: [RecognizedItem]
211
- ) {
212
- for item in addedItems {
213
- switch item {
214
- case .text(let text):
215
- print("New text: \(text.transcript)")
216
- case .barcode(let barcode):
217
- print("New barcode: \(barcode.payloadStringValue ?? "nil")")
218
- @unknown default:
219
- break
220
- }
138
+ @MainActor
139
+ final class ScanCoordinator {
140
+ private var live: DataScannerViewController?
141
+
142
+ func open(from host: UIViewController, delegate: DataScannerViewControllerDelegate) {
143
+ let passReader = ScannerPresets.boardingPassReader()
144
+ passReader.delegate = delegate
145
+ live = passReader
146
+ host.present(passReader, animated: true) {
147
+ try? passReader.startScanning()
221
148
  }
222
149
  }
223
150
 
224
- // Called when items are updated (position or content changes)
225
- func dataScanner(
226
- _ scanner: DataScannerViewController,
227
- didUpdate updatedItems: [RecognizedItem],
228
- allItems: [RecognizedItem]
229
- ) {
230
- // Handle position or content updates
231
- }
232
-
233
- // Called when items leave the camera view
234
- func dataScanner(
235
- _ scanner: DataScannerViewController,
236
- didRemove removedItems: [RecognizedItem],
237
- allItems: [RecognizedItem]
238
- ) {
239
- // Clean up UI for removed items
240
- }
241
-
242
- // Called when the scanner becomes unavailable (e.g., camera revoked)
243
- func dataScannerDidChangeUnavailabilityReasons(
244
- _ scanner: DataScannerViewController
245
- ) {
246
- // Handle unavailability -- dismiss or show fallback
151
+ func close() {
152
+ guard let live else { return }
153
+ live.stopScanning()
154
+ live.dismiss(animated: true)
155
+ self.live = nil
247
156
  }
248
157
  }
249
158
  ```
250
159
 
251
- ### Async Sequence for Recognized Items
160
+ ## Delegate callbacks
161
+
162
+ `DataScannerViewControllerDelegate` methods, all main-actor isolated:
163
+
164
+ | Method | When it fires |
165
+ |---|---|
166
+ | `dataScanner(_:didTapOn:)` | The user tapped a recognized item |
167
+ | `dataScanner(_:didAdd:allItems:)` | New items appeared |
168
+ | `dataScanner(_:didUpdate:allItems:)` | Items moved or their content changed |
169
+ | `dataScanner(_:didRemove:allItems:)` | Items left the frame |
170
+ | `dataScanner(_:becameUnavailableWithError:)` | Scanning stopped being possible, for example camera access was revoked; dismiss or fall back |
171
+ | `dataScannerDidZoom(_:)` | Zoom factor changed |
252
172
 
253
- Use `recognizedItems` for a reactive stream of all currently visible items:
173
+ `RecognizedItem` is an enum. Handle both cases and keep an `@unknown default`:
254
174
 
255
175
  ```swift
256
- func observeRecognizedItems(_ scanner: DataScannerViewController) async {
257
- for await items in scanner.recognizedItems {
258
- let texts = items.compactMap { item -> String? in
259
- guard case .text(let text) = item else { return nil }
260
- return text.transcript
261
- }
262
- let barcodes = items.compactMap { item -> String? in
263
- guard case .barcode(let barcode) = item else { return nil }
264
- return barcode.payloadStringValue
265
- }
266
- await MainActor.run {
267
- // Update UI with current texts and barcodes
268
- }
176
+ import VisionKit
177
+
178
+ func describe(_ item: RecognizedItem) -> String {
179
+ switch item {
180
+ case .text(let recognized):
181
+ return recognized.transcript
182
+ case .barcode(let code):
183
+ return "\(code.observation.symbology.rawValue): \(code.payloadStringValue ?? "?")"
184
+ @unknown default:
185
+ return ""
269
186
  }
270
187
  }
271
188
  ```
272
189
 
273
- ### Capturing a Photo
190
+ ### Async stream of items
274
191
 
275
- Capture a still image from the scanner for further processing:
192
+ `recognizedItems` is an `AsyncStream<[RecognizedItem]>`: every element is the
193
+ full set of items currently in view.
276
194
 
277
195
  ```swift
278
- func captureAndProcess(_ scanner: DataScannerViewController) async throws {
279
- let photo = try await scanner.capturePhoto()
280
- // photo is a UIImage -- process with Vision or save
196
+ import VisionKit
197
+
198
+ @MainActor
199
+ func watch(_ scanner: DataScannerViewController,
200
+ onText: ([String]) -> Void,
201
+ onCodes: ([String]) -> Void) async {
202
+ for await visible in scanner.recognizedItems {
203
+ var lines: [String] = []
204
+ var codes: [String] = []
205
+ for item in visible {
206
+ switch item {
207
+ case .text(let recognized): lines.append(recognized.transcript)
208
+ case .barcode(let code): codes.append(code.payloadStringValue ?? "")
209
+ @unknown default: break
210
+ }
211
+ }
212
+ onText(lines)
213
+ onCodes(codes)
214
+ }
281
215
  }
282
216
  ```
283
217
 
284
- ## SwiftUI Integration
218
+ ### Still photo
285
219
 
286
- Wrap `DataScannerViewController` in `UIViewControllerRepresentable` for use
287
- in SwiftUI views.
220
+ `try await scanner.capturePhoto()` returns a `UIImage` of the current camera
221
+ frame, useful for a high-resolution OCR pass or for attaching to a record.
288
222
 
289
- ### Full DataScanner Representable
223
+ ## SwiftUI
224
+
225
+ A representable that reports tapped items through bindings:
290
226
 
291
227
  ```swift
292
- import SwiftUI
293
228
  import VisionKit
229
+ import SwiftUI
294
230
 
295
- struct DataScannerRepresentable: UIViewControllerRepresentable {
296
- let recognizedDataTypes: Set<DataScannerViewController.RecognizedDataType>
297
- let qualityLevel: DataScannerViewController.QualityLevel
298
- let recognizesMultipleItems: Bool
299
- @Binding var recognizedText: [String]
300
- @Binding var recognizedBarcodes: [String]
231
+ struct LiveScanner: UIViewControllerRepresentable {
232
+ let kinds: Set<DataScannerViewController.RecognizedDataType>
233
+ var quality: DataScannerViewController.QualityLevel = .balanced
234
+ var many = false
235
+ @Binding var lines: [String]
236
+ @Binding var payloads: [String]
301
237
 
302
238
  func makeUIViewController(context: Context) -> DataScannerViewController {
303
- let scanner = DataScannerViewController(
304
- recognizedDataTypes: recognizedDataTypes,
305
- qualityLevel: qualityLevel,
306
- recognizesMultipleItems: recognizesMultipleItems,
307
- isHighFrameRateTrackingEnabled: true,
308
- isPinchToZoomEnabled: true,
309
- isGuidanceEnabled: true,
239
+ let liveView = DataScannerViewController(
240
+ recognizedDataTypes: kinds,
241
+ qualityLevel: quality,
242
+ recognizesMultipleItems: many,
310
243
  isHighlightingEnabled: true
311
244
  )
312
- scanner.delegate = context.coordinator
313
- return scanner
245
+ liveView.delegate = context.coordinator
246
+ Task { @MainActor in
247
+ try? liveView.startScanning()
248
+ }
249
+ return liveView
314
250
  }
315
251
 
316
- func updateUIViewController(
317
- _ controller: DataScannerViewController,
318
- context: Context
319
- ) {
320
- // No dynamic updates needed
321
- }
252
+ func updateUIViewController(_ scannerController: DataScannerViewController, context: Context) {}
322
253
 
323
- func makeCoordinator() -> Coordinator {
324
- Coordinator(parent: self)
254
+ func makeCoordinator() -> Tapper {
255
+ Tapper(owner: self)
325
256
  }
326
257
 
327
- static func dismantleUIViewController(
328
- _ controller: DataScannerViewController,
329
- coordinator: Coordinator
330
- ) {
331
- controller.stopScanning()
258
+ static func dismantleUIViewController(_ scannerController: DataScannerViewController, coordinator: Tapper) {
259
+ scannerController.stopScanning()
332
260
  }
333
261
 
334
262
  @MainActor
335
- final class Coordinator: NSObject, DataScannerViewControllerDelegate {
336
- let parent: DataScannerRepresentable
263
+ final class Tapper: NSObject, DataScannerViewControllerDelegate {
264
+ private let owner: LiveScanner
337
265
 
338
- init(parent: DataScannerRepresentable) {
339
- self.parent = parent
266
+ init(owner: LiveScanner) {
267
+ self.owner = owner
340
268
  }
341
269
 
342
- func dataScanner(
343
- _ scanner: DataScannerViewController,
344
- didTapOn item: RecognizedItem
345
- ) {
270
+ func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) {
346
271
  switch item {
347
- case .text(let text):
348
- parent.recognizedText.append(text.transcript)
349
- case .barcode(let barcode):
350
- if let payload = barcode.payloadStringValue {
351
- parent.recognizedBarcodes.append(payload)
272
+ case .text(let recognized):
273
+ owner.lines.append(recognized.transcript)
274
+ case .barcode(let code):
275
+ if let value = code.payloadStringValue {
276
+ owner.payloads.append(value)
352
277
  }
353
278
  @unknown default:
354
279
  break
355
280
  }
356
281
  }
357
-
358
- func dataScanner(
359
- _ scanner: DataScannerViewController,
360
- didAdd addedItems: [RecognizedItem],
361
- allItems: [RecognizedItem]
362
- ) {
363
- // Handle newly recognized items
364
- }
365
-
366
- func dataScanner(
367
- _ scanner: DataScannerViewController,
368
- didUpdate updatedItems: [RecognizedItem],
369
- allItems: [RecognizedItem]
370
- ) {
371
- // Handle item updates
372
- }
373
-
374
- func dataScanner(
375
- _ scanner: DataScannerViewController,
376
- didRemove removedItems: [RecognizedItem],
377
- allItems: [RecognizedItem]
378
- ) {
379
- // Handle removed items
380
- }
381
282
  }
382
283
  }
383
284
  ```
384
285
 
385
- ### SwiftUI Scanner View
286
+ `startScanning()` must wait until the controller is presented. The deferred
287
+ `Task` above runs after `makeUIViewController` returns; stopping belongs in
288
+ `dismantleUIViewController`.
289
+
290
+ A screen that offers the scanner only where it can run:
386
291
 
387
292
  ```swift
388
- import SwiftUI
389
293
  import VisionKit
294
+ import SwiftUI
390
295
 
391
- struct ScannerView: View {
392
- @State private var recognizedText: [String] = []
393
- @State private var recognizedBarcodes: [String] = []
394
- @State private var isShowingScanner = false
296
+ struct ShelfScanScreen: View {
297
+ @State private var scanning = false
298
+ @State private var lines: [String] = []
299
+ @State private var payloads: [String] = []
395
300
 
396
301
  var body: some View {
397
- VStack {
302
+ Form {
398
303
  if DataScannerViewController.isSupported {
399
- Button("Scan") {
400
- isShowingScanner = true
401
- }
402
- .fullScreenCover(isPresented: $isShowingScanner) {
403
- NavigationStack {
404
- DataScannerRepresentable(
405
- recognizedDataTypes: [
406
- .text(languages: ["en"]),
407
- .barcode(symbologies: [.qr]),
408
- ],
409
- qualityLevel: .balanced,
410
- recognizesMultipleItems: true,
411
- recognizedText: $recognizedText,
412
- recognizedBarcodes: $recognizedBarcodes
413
- )
414
- .ignoresSafeArea()
415
- .toolbar {
416
- ToolbarItem(placement: .cancellationAction) {
417
- Button("Done") {
418
- isShowingScanner = false
419
- }
420
- }
421
- }
422
- }
423
- }
304
+ Button("Scan labels") { scanning = true }
424
305
  } else {
425
- ContentUnavailableView(
426
- "Scanner Not Available",
427
- systemImage: "camera.fill",
428
- description: Text("This device does not support scanning.")
429
- )
306
+ ContentUnavailableView("Scanning unavailable",
307
+ systemImage: "camera.fill",
308
+ description: Text("Live scanning needs a newer iPhone or iPad."))
430
309
  }
431
-
432
- List {
433
- Section("Text") {
434
- ForEach(recognizedText, id: \.self) { text in
435
- Text(text)
436
- }
437
- }
438
- Section("Barcodes") {
439
- ForEach(recognizedBarcodes, id: \.self) { barcode in
440
- Text(barcode)
310
+ Section("Text") { ForEach(lines, id: \.self, content: Text.init) }
311
+ Section("Codes") { ForEach(payloads, id: \.self, content: Text.init) }
312
+ }
313
+ .fullScreenCover(isPresented: $scanning) {
314
+ NavigationStack {
315
+ LiveScanner(kinds: [.text(), .barcode()], lines: $lines, payloads: $payloads)
316
+ .ignoresSafeArea()
317
+ .toolbar {
318
+ ToolbarItem(placement: .cancellationAction) {
319
+ Button("Close") { scanning = false }
320
+ }
441
321
  }
442
- }
443
322
  }
444
323
  }
445
324
  }
446
325
  }
447
326
  ```
448
327
 
449
- ### Starting the Scanner After Presentation
328
+ ## Custom overlay
450
329
 
451
- The scanner must be started after the view controller is fully presented.
452
- Use `onAppear` with a coordinator flag or start in the completion handler:
330
+ Layer your own guidance on top of the scanner with a `ZStack`:
453
331
 
454
332
  ```swift
455
- struct AutoStartScannerRepresentable: UIViewControllerRepresentable {
456
- func makeUIViewController(context: Context) -> DataScannerViewController {
457
- let scanner = DataScannerViewController(
458
- recognizedDataTypes: [.text(languages: ["en"])],
459
- qualityLevel: .balanced,
460
- recognizesMultipleItems: false,
461
- isHighFrameRateTrackingEnabled: true,
462
- isHighlightingEnabled: true
463
- )
464
- scanner.delegate = context.coordinator
465
- // Start scanning after a brief delay to ensure presentation is complete
466
- Task { @MainActor in
467
- try? scanner.startScanning()
468
- }
469
- return scanner
470
- }
471
-
472
- func updateUIViewController(
473
- _ controller: DataScannerViewController,
474
- context: Context
475
- ) {}
476
-
477
- func makeCoordinator() -> ScannerCoordinator {
478
- ScannerCoordinator()
479
- }
480
-
481
- static func dismantleUIViewController(
482
- _ controller: DataScannerViewController,
483
- coordinator: ScannerCoordinator
484
- ) {
485
- controller.stopScanning()
486
- }
487
- }
488
- ```
489
-
490
- ## Custom Overlay UI
491
-
492
- Add custom views on top of the scanner for region-of-interest indicators,
493
- instructions, or result display.
494
-
495
- ### Overlay with Region of Interest
333
+ import VisionKit
334
+ import SwiftUI
496
335
 
497
- ```swift
498
- struct ScannerWithOverlay: View {
499
- @State private var isShowingScanner = false
500
- @State private var lastScannedText = ""
336
+ struct FramedScanner: View {
337
+ @State private var lines: [String] = []
338
+ @State private var payloads: [String] = []
501
339
 
502
340
  var body: some View {
503
341
  ZStack {
504
- AutoStartScannerRepresentable()
342
+ LiveScanner(kinds: [.barcode()], lines: $lines, payloads: $payloads)
505
343
  .ignoresSafeArea()
506
-
507
- VStack {
508
- // Top instruction bar
509
- Text("Point camera at text or barcode")
510
- .font(.subheadline)
511
- .padding(.horizontal)
512
- .padding(.vertical)
344
+ VStack(spacing: 24) {
345
+ Text("Fit the code inside the frame")
346
+ .padding(.horizontal, 16)
347
+ .padding(.vertical, 8)
513
348
  .background(.ultraThinMaterial, in: Capsule())
514
- .padding(.top)
515
-
516
- Spacer()
517
-
518
- // Scan region indicator
519
- RoundedRectangle(cornerRadius: 12)
520
- .strokeBorder(.white.opacity(0.6), lineWidth: 2)
521
- .frame(width: 280, height: 180)
522
-
523
- Spacer()
524
-
525
- // Result display
526
- if !lastScannedText.isEmpty {
527
- Text(lastScannedText)
528
- .font(.body)
529
- .padding()
530
- .frame(maxWidth: .infinity)
531
- .background(.ultraThinMaterial)
532
- .clipShape(.rect(cornerRadius: 12))
349
+ RoundedRectangle(cornerRadius: 16)
350
+ .stroke(.white.opacity(0.7), lineWidth: 3)
351
+ .frame(width: 260, height: 260)
352
+ if let latest = payloads.last {
353
+ Text(latest)
533
354
  .padding()
355
+ .background(.thinMaterial, in: .rect(cornerRadius: 12))
534
356
  }
535
357
  }
536
358
  }
@@ -538,201 +360,203 @@ struct ScannerWithOverlay: View {
538
360
  }
539
361
  ```
540
362
 
363
+ Sizes in these examples are placeholders; take them from the design system.
364
+
541
365
  ## VNDocumentCameraViewController
542
366
 
543
- `VNDocumentCameraViewController` provides a full-screen document camera with
544
- auto-capture, perspective correction, and multi-page scanning. Available on
545
- all devices running iOS 13+.
367
+ Presents a camera that fills the screen, snaps pages on its own, straightens
368
+ them, and collects several pages per session. It works on every device that runs iOS 13 or later.
546
369
 
547
- ### UIKit Presentation
370
+ A small helper used by both versions below:
548
371
 
549
372
  ```swift
550
373
  import VisionKit
551
374
 
552
- final class DocumentScannerPresenter: NSObject,
553
- VNDocumentCameraViewControllerDelegate
554
- {
555
- weak var presenter: UIViewController?
375
+ extension VNDocumentCameraScan {
376
+ var allPages: [UIImage] {
377
+ var collected: [UIImage] = []
378
+ for index in 0..<pageCount {
379
+ collected.append(imageOfPage(at: index))
380
+ }
381
+ return collected
382
+ }
383
+ }
384
+ ```
385
+
386
+ UIKit:
387
+
388
+ ```swift
389
+ import UIKit
390
+ import VisionKit
556
391
 
557
- func showDocumentScanner() {
558
- let scanner = VNDocumentCameraViewController()
559
- scanner.delegate = self
560
- presenter?.present(scanner, animated: true)
392
+ @MainActor
393
+ final class PaperScanFlow: NSObject, @MainActor VNDocumentCameraViewControllerDelegate {
394
+ private weak var host: UIViewController?
395
+ var onPages: ([UIImage]) -> Void = { _ in }
396
+ var onFailure: (Error) -> Void = { _ in }
397
+
398
+ func start(from host: UIViewController) {
399
+ self.host = host
400
+ let camera = VNDocumentCameraViewController()
401
+ camera.delegate = self
402
+ host.present(camera, animated: true)
561
403
  }
562
404
 
563
- func documentCameraViewController(
564
- _ controller: VNDocumentCameraViewController,
565
- didFinishWith scan: VNDocumentCameraScan
566
- ) {
567
- controller.dismiss(animated: true)
568
- for pageIndex in 0..<scan.pageCount {
569
- let pageImage = scan.imageOfPage(at: pageIndex)
570
- // Process each scanned page image
571
- }
405
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
406
+ didFinishWith scan: VNDocumentCameraScan) {
407
+ camera.dismiss(animated: true)
408
+ onPages(scan.allPages)
572
409
  }
573
410
 
574
- func documentCameraViewControllerDidCancel(
575
- _ controller: VNDocumentCameraViewController
576
- ) {
577
- controller.dismiss(animated: true)
411
+ func documentCameraViewControllerDidCancel(_ camera: VNDocumentCameraViewController) {
412
+ camera.dismiss(animated: true)
578
413
  }
579
414
 
580
- func documentCameraViewController(
581
- _ controller: VNDocumentCameraViewController,
582
- didFailWithError error: Error
583
- ) {
584
- controller.dismiss(animated: true)
585
- // Handle scanning error
415
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
416
+ didFailWithError error: Error) {
417
+ camera.dismiss(animated: true)
418
+ onFailure(error)
586
419
  }
587
420
  }
588
421
  ```
589
422
 
590
- ### SwiftUI Document Scanner
423
+ `VNDocumentCameraViewControllerDelegate` carries no actor annotation, so the
424
+ conformance is written as `@MainActor VNDocumentCameraViewControllerDelegate`
425
+ (an isolated conformance, Swift 6.2 and later). The presenter is held `weak`
426
+ so the flow object never keeps a dismissed screen alive.
427
+
428
+ SwiftUI:
591
429
 
592
430
  ```swift
593
- import SwiftUI
594
431
  import VisionKit
432
+ import SwiftUI
595
433
 
596
- struct DocumentScannerRepresentable: UIViewControllerRepresentable {
597
- @Binding var scannedImages: [UIImage]
598
- @Environment(\.dismiss) private var dismiss
434
+ struct PaperCamera: UIViewControllerRepresentable {
435
+ @Binding var pages: [UIImage]
436
+ @Environment(\.dismiss) private var close
599
437
 
600
438
  func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
601
- let scanner = VNDocumentCameraViewController()
602
- scanner.delegate = context.coordinator
603
- return scanner
439
+ let camera = VNDocumentCameraViewController()
440
+ camera.delegate = context.coordinator
441
+ return camera
604
442
  }
605
443
 
606
- func updateUIViewController(
607
- _ controller: VNDocumentCameraViewController,
608
- context: Context
609
- ) {}
444
+ func updateUIViewController(_ camera: VNDocumentCameraViewController, context: Context) {}
610
445
 
611
- func makeCoordinator() -> Coordinator {
612
- Coordinator(parent: self)
446
+ func makeCoordinator() -> Receiver {
447
+ Receiver(owner: self)
613
448
  }
614
449
 
615
450
  @MainActor
616
- final class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
617
- let parent: DocumentScannerRepresentable
451
+ final class Receiver: NSObject, @MainActor VNDocumentCameraViewControllerDelegate {
452
+ private let owner: PaperCamera
618
453
 
619
- init(parent: DocumentScannerRepresentable) {
620
- self.parent = parent
454
+ init(owner: PaperCamera) {
455
+ self.owner = owner
621
456
  }
622
457
 
623
- func documentCameraViewController(
624
- _ controller: VNDocumentCameraViewController,
625
- didFinishWith scan: VNDocumentCameraScan
626
- ) {
627
- parent.scannedImages = (0..<scan.pageCount).map { scan.imageOfPage(at: $0) }
628
- parent.dismiss()
458
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
459
+ didFinishWith scan: VNDocumentCameraScan) {
460
+ owner.pages = scan.allPages
461
+ owner.close()
629
462
  }
630
463
 
631
- func documentCameraViewControllerDidCancel(
632
- _ controller: VNDocumentCameraViewController
633
- ) {
634
- parent.dismiss()
464
+ func documentCameraViewControllerDidCancel(_ camera: VNDocumentCameraViewController) {
465
+ owner.close()
635
466
  }
636
467
 
637
- func documentCameraViewController(
638
- _ controller: VNDocumentCameraViewController,
639
- didFailWithError error: Error
640
- ) {
641
- parent.dismiss()
468
+ func documentCameraViewController(_ camera: VNDocumentCameraViewController,
469
+ didFailWithError error: Error) {
470
+ owner.close()
642
471
  }
643
472
  }
644
473
  }
645
474
  ```
646
475
 
647
- ### Document Scanner with OCR Pipeline
476
+ ### Scan then read
648
477
 
649
- Combine document scanning with Vision text recognition for a complete OCR flow:
478
+ A model that runs OCR over every captured page, and a view that drives it:
650
479
 
651
480
  ```swift
481
+ import Observation
652
482
  import SwiftUI
653
- import VisionKit
654
483
  import Vision
484
+ import VisionKit
655
485
 
656
486
  @MainActor
657
487
  @Observable
658
- final class DocumentOCRModel {
659
- var scannedPages: [UIImage] = []
660
- var extractedText: [String] = []
661
- var isProcessing = false
662
-
663
- func processScannedPages() async {
664
- isProcessing = true
665
- defer { isProcessing = false }
666
-
667
- extractedText = []
668
- for page in scannedPages {
669
- guard let cgImage = page.cgImage else { continue }
488
+ final class PaperReader {
489
+ var pages: [UIImage] = []
490
+ var transcripts: [String] = []
491
+ var busy = false
492
+
493
+ func transcribe() async {
494
+ busy = true
495
+ defer { busy = false }
496
+ var results: [String] = []
497
+ for page in pages {
498
+ guard let bitmap = page.cgImage else {
499
+ results.append("(page could not be read)")
500
+ continue
501
+ }
502
+ var request = RecognizeTextRequest()
503
+ request.usesLanguageCorrection = true
504
+ request.recognitionLanguages = [Locale.Language(identifier: "en-GB")]
505
+ request.recognitionLevel = .accurate
670
506
  do {
671
- var request = RecognizeTextRequest()
672
- request.recognitionLevel = .accurate
673
- request.recognitionLanguages = [Locale.Language(identifier: "en-US")]
674
- request.usesLanguageCorrection = true
675
-
676
- let observations = try await request.perform(on: cgImage)
677
- let pageText = observations
678
- .compactMap { $0.topCandidates(1).first?.string }
679
- .joined(separator: "\n")
680
- extractedText.append(pageText)
507
+ let found = try await request.perform(on: bitmap)
508
+ let body = found.compactMap { $0.topCandidates(1).first }.map(\.string)
509
+ results.append(body.joined(separator: "\n"))
681
510
  } catch {
682
- extractedText.append("[Recognition failed]")
511
+ results.append("(recognition failed)")
683
512
  }
684
513
  }
514
+ transcripts = results
685
515
  }
686
516
  }
687
517
 
688
- struct DocumentOCRView: View {
689
- @State private var model = DocumentOCRModel()
690
- @State private var isShowingScanner = false
518
+ struct PaperReaderScreen: View {
519
+ @State private var reader = PaperReader()
520
+ @State private var capturing = false
691
521
 
692
522
  var body: some View {
693
- NavigationStack {
694
- List {
695
- if model.isProcessing {
696
- ProgressView("Recognizing text...")
697
- }
698
- ForEach(Array(model.extractedText.enumerated()), id: \.offset) { index, text in
699
- Section("Page \(index + 1)") {
700
- Text(text)
701
- .font(.body)
702
- .textSelection(.enabled)
703
- }
704
- }
523
+ Form {
524
+ Button("Scan pages") { capturing = true }
525
+ if reader.busy {
526
+ ProgressView()
705
527
  }
706
- .navigationTitle("Document OCR")
707
- .toolbar {
708
- Button("Scan") {
709
- isShowingScanner = true
528
+ ForEach(reader.transcripts.indices, id: \.self) { page in
529
+ Section("Page \(page + 1)") {
530
+ Text(reader.transcripts[page]).textSelection(.enabled)
710
531
  }
711
532
  }
712
- .fullScreenCover(isPresented: $isShowingScanner) {
713
- DocumentScannerRepresentable(scannedImages: $model.scannedPages)
714
- }
715
- .onChange(of: model.scannedPages) {
716
- Task { await model.processScannedPages() }
717
- }
533
+ }
534
+ .sheet(isPresented: $capturing) {
535
+ PaperCamera(pages: $reader.pages)
536
+ }
537
+ .onChange(of: reader.pages) {
538
+ Task { await reader.transcribe() }
718
539
  }
719
540
  }
720
541
  }
721
542
  ```
722
543
 
723
- ## Performance Considerations
544
+ User-facing strings here are literals for brevity; ship them as localized keys.
545
+
546
+ ## Performance
724
547
 
725
- ### DataScannerViewController
548
+ Live scanner:
726
549
 
727
- - Use `.fast` quality for barcode-only scanning
728
- - Set `recognizesMultipleItems = false` when only one result is needed
729
- - Disable `isHighFrameRateTrackingEnabled` for barcode scanning to save power
730
- - Limit `recognizedDataTypes` to only what you need
731
- - Stop scanning when processing results to avoid wasted CPU cycles
550
+ - Use `.fast` when only barcodes are scanned.
551
+ - Set `recognizesMultipleItems = false` when one result is enough.
552
+ - Turn off `isHighFrameRateTrackingEnabled` for barcode-only scanners to save
553
+ power.
554
+ - Ask only for the `recognizedDataTypes` the feature needs.
555
+ - Call `stopScanning()` while you process a result, and resume afterwards.
732
556
 
733
- ### VNDocumentCameraViewController
557
+ Document camera:
734
558
 
735
- - Pages are returned as `UIImage` at full resolution -- resize before
736
- processing if memory is a concern
737
- - Process pages sequentially to avoid memory spikes
738
- - Use `autoreleasepool` when processing many pages in a loop
559
+ - Pages arrive as full-resolution `UIImage` values; downscale them if memory
560
+ is tight.
561
+ - Process pages one after another rather than all at once, and wrap
562
+ synchronous per-page loops in `autoreleasepool` when there are many.