@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
@@ -3,41 +3,45 @@
3
3
  "evals": [
4
4
  {
5
5
  "id": 0,
6
- "prompt": "I'm building a SwiftUI drawing screen for iPad with Apple Pencil and optional finger drawing. Sketch the PencilKit wrapper, tool picker setup, save/load path, and the lifecycle details that prevent stale tools or update loops.",
7
- "expected_output": "A SwiftUI PencilKit implementation plan that wraps PKCanvasView, retains and observes PKToolPicker, chooses an appropriate drawingPolicy, serializes PKDrawing with dataRepresentation()/PKDrawing(data:), and avoids binding update loops.",
6
+ "name": "swiftui-sketch-pad",
7
+ "prompt": "I need a SwiftUI sketch pad for our iPad note app: a PencilKit canvas bound to a PKDrawing in our model, the tool palette toggled from a toolbar button, and the drawing saved to disk and restored on launch. Which input policy should we use, and how do we avoid update loops?",
8
+ "expected_output": "Builds a UIViewRepresentable with a Coordinator acting as PKCanvasViewDelegate that writes changes back to the binding. Keeps one PKToolPicker retained in the coordinator, adds the canvas as observer before showing it and makes the canvas first responder. Explains .default, .anyInput and .pencilOnly and picks one with a reason. Persists with dataRepresentation() and PKDrawing(data:), and only assigns the drawing in updateUIView when it differs.",
8
9
  "files": [],
9
10
  "expectations": [
10
- "Wraps PKCanvasView with UIViewRepresentable and uses a Coordinator as PKCanvasViewDelegate.",
11
- "Retains PKToolPicker outside a local scope and adds the canvas as an observer before showing the picker or becoming first responder.",
12
- "Explains the difference between .default, .anyInput, and .pencilOnly enough to choose one for Pencil-primary versus finger-drawing modes.",
13
- "Persists drawings using PKDrawing.dataRepresentation() and reloads with PKDrawing(data:).",
14
- "Avoids SwiftUI update loops by checking whether the canvas drawing already matches the binding before assigning."
11
+ "Uses UIViewRepresentable with a Coordinator that implements canvasViewDrawingDidChange(_:)",
12
+ "Retains a single PKToolPicker and adds the canvas as observer before setVisible and becomeFirstResponder",
13
+ "Explains all three drawing policies, describing .default as following the system Pencil setting while the picker is visible",
14
+ "Saves with dataRepresentation() and loads with PKDrawing(data:)",
15
+ "Guards updateUIView with an inequality check to stop update loops"
15
16
  ]
16
17
  },
17
18
  {
18
19
  "id": 1,
19
- "prompt": "Review this PencilKit compatibility plan: let users pick watercolor, crayon, and reed, save the PKDrawing bytes to CloudKit, and set canvasView.maximumSupportedContentVersion = .version2 so iPadOS 16 clients can open every drawing. What should change?",
20
- "expected_output": "A correction-focused review that explains PencilKit content versions, unsupported-ink load failures, the need to set maximumSupportedContentVersion on both canvas and tool picker, and the version boundary for iPadOS 17 and iOS 26 inks.",
20
+ "name": "older-ipad-sync",
21
+ "prompt": "Teachers annotate worksheets on new iPads and students open them on iPads still running iPadOS 16. Students report that some worksheets fail to open. Our plan is to set maximumSupportedContentVersion to .version2 on the canvas. Review the plan.",
22
+ "expected_output": "Explains that inks newer than the recipient supports make loading fail, gives the full content version map (version1 pen/pencil/marker, version2 the iPadOS 17 inks, version3 barrel-roll data, version4 reed pen), and says .version2 does not help iPadOS 16, which needs .version1 or a verified fallback drawing. The cap must be set on both canvas and tool picker. Notes .reed needs 26 and curated picker items need iOS 18 or visionOS 2.",
21
23
  "files": [],
22
24
  "expectations": [
23
- "States that unsupported newer inks cause older systems to fail when loading PKDrawing data rather than guaranteeing compatibility.",
24
- "Correctly maps version1 to marker/pen/pencil-era compatibility, version2 to iPadOS 17 inks, version3 to barrel-roll angle data, and version4 to reed.",
25
- "Explains that .version2 does not make drawings loadable by iPadOS 16 clients; use .version1 or a fallback for pre-iPadOS 17 compatibility.",
26
- "Sets maximumSupportedContentVersion on both PKCanvasView and PKToolPicker when restricting new content.",
27
- "Calls out .reed as iOS/iPadOS/macOS/visionOS 26+ and custom tool picker items as iOS/iPadOS 18+ or visionOS 2+."
25
+ "States that unsupported inks make older systems fail to load the drawing",
26
+ "Lists the four content versions with what each adds",
27
+ "Rejects .version2 for iPadOS 16 recipients and asks for .version1 or a checked fallback",
28
+ "Requires the cap on both PKCanvasView and PKToolPicker",
29
+ "Mentions .reed at 26 and PKToolPicker(toolItems:) at iOS 18 or visionOS 2"
28
30
  ]
29
31
  },
30
32
  {
31
33
  "id": 2,
32
- "prompt": "I need an annotation experience with freehand Apple Pencil signatures, movable text boxes, arrows, image stickers, and a standard markup toolbar. Which parts should stay in PencilKit and when should I switch to PaperKit?",
33
- "expected_output": "A boundary-aware answer that keeps freeform drawing, tool picker, stroke inspection, image export, and PKDrawing serialization in PencilKit while routing structured markup and toolbar needs to PaperKit.",
34
+ "name": "pencilkit-paperkit-split",
35
+ "prompt": "Product wants our inspection app to gain arrows, text callouts, photo stickers and a magnifier on top of the existing PencilKit signature and sketch features. What stays in PencilKit, what moves to PaperKit, and how do they connect?",
36
+ "expected_output": "PencilKit keeps the canvas, tool picker, PKDrawing persistence and export, stroke inspection and signatures. PaperKit takes shapes and arrows, text boxes, images and stickers, loupes and the markup toolbar. Connects them through PaperMarkupViewController.drawingTool accepting a PKTool and PaperMarkup appending a PKDrawing. Gives a step-by-step handoff plan without claiming PencilKit does structured markup.",
34
37
  "files": [],
35
38
  "expectations": [
36
- "Keeps PencilKit scope to PKCanvasView, PKToolPicker, PKDrawing serialization/export, stroke inspection, and signature/freehand drawing.",
37
- "Routes shapes, arrows, text boxes, images/stickers, loupes, and system-standard markup toolbar work to PaperKit.",
38
- "Mentions the verified bridge points: PaperMarkupViewController.drawingTool accepts a PKTool and PaperMarkup can append PKDrawing.",
39
- "Does not claim PencilKit directly owns structured markup elements such as movable text boxes or stickers.",
40
- "Preserves a practical handoff plan between saved PKDrawing content and a PaperKit markup workflow."
39
+ "Keeps canvas, picker, serialization, export, stroke inspection and signatures in PencilKit",
40
+ "Moves arrows, text boxes, images or stickers, loupes and the markup toolbar to PaperKit",
41
+ "Mentions PaperMarkupViewController.drawingTool taking a PKTool",
42
+ "Mentions PaperMarkup accepting an appended PKDrawing",
43
+ "Does not claim PencilKit provides structured markup",
44
+ "Gives a concrete handoff plan"
41
45
  ]
42
46
  }
43
47
  ]
@@ -1,333 +1,268 @@
1
- # PencilKit Extended Patterns
1
+ # PencilKit patterns
2
2
 
3
- Overflow reference for the `pencilkit` skill. Contains advanced patterns
4
- that exceed the main skill file's scope.
3
+ Longer recipes for the `pencilkit-drawing` skill ([../SKILL.md](../SKILL.md)).
5
4
 
6
- ## Contents
5
+ ## Listening to the tool picker
7
6
 
8
- - [Tool Picker Observer Pattern](#tool-picker-observer-pattern)
9
- - [Custom Tool Picker Items](#custom-tool-picker-items)
10
- - [Canvas View Delegate Lifecycle](#canvas-view-delegate-lifecycle)
11
- - [Undo/Redo Support](#undoredo-support)
12
- - [Thumbnail Generation](#thumbnail-generation)
13
- - [Drawing Comparison and Scoring](#drawing-comparison-and-scoring)
14
- - [Content Version Management](#content-version-management)
15
- - [Advanced SwiftUI Wrapper](#advanced-swiftui-wrapper)
16
-
17
- ## Tool Picker Observer Pattern
18
-
19
- Observe tool picker changes to update custom UI or track tool usage.
7
+ Register your controller next to the canvas so both hear about changes.
20
8
 
21
9
  ```swift
22
10
  import PencilKit
23
-
24
- class DrawingController: UIViewController, PKToolPickerObserver {
25
- let canvasView = PKCanvasView()
26
- let toolPicker = PKToolPicker()
27
-
28
- override func viewDidLoad() {
29
- super.viewDidLoad()
30
- toolPicker.addObserver(self)
31
- toolPicker.addObserver(canvasView)
11
+ import UIKit
12
+
13
+ final class StudioViewController: UIViewController, PKToolPickerObserver {
14
+ private let board = PKCanvasView()
15
+ private let palette = PKToolPicker()
16
+
17
+ override func viewDidAppear(_ isAnimated: Bool) {
18
+ super.viewDidAppear(isAnimated)
19
+ palette.addObserver(board)
20
+ palette.addObserver(self)
21
+ palette.setVisible(true, forFirstResponder: board)
22
+ board.becomeFirstResponder()
32
23
  }
33
24
 
34
25
  func toolPickerSelectedToolItemDidChange(_ toolPicker: PKToolPicker) {
35
- let item = toolPicker.selectedToolItem
36
- print("Selected tool: \(item.identifier)")
26
+ let chosen = toolPicker.selectedToolItem.identifier
27
+ title = "Tool: \(chosen)"
37
28
  }
38
29
 
39
30
  func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
40
- print("Picker visible: \(toolPicker.isVisible)")
31
+ navigationController?.setToolbarHidden(toolPicker.isVisible, animated: true)
41
32
  }
42
33
 
43
34
  func toolPickerFramesObscuredDidChange(_ toolPicker: PKToolPicker) {
44
- let obscured = toolPicker.frameObscured(in: view)
45
- // Adjust content insets to avoid overlap
46
- canvasView.contentInset.bottom = obscured.height
35
+ let covered = toolPicker.frameObscured(in: view)
36
+ board.contentInset.bottom = covered.isNull ? 0 : view.bounds.maxY - covered.minY
47
37
  }
48
38
  }
49
39
  ```
50
40
 
51
- ## Custom Tool Picker Items
41
+ The last callback keeps the bottom of the drawing reachable when the docked
42
+ palette covers part of the screen.
52
43
 
53
- Create custom tools with unique behaviors and icons. Custom tool picker items
54
- require iOS/iPadOS 18+, Mac Catalyst 18+, or visionOS 2+.
44
+ ## A custom picker item
55
45
 
56
- ```swift
57
- var customConfig = PKToolPickerCustomItem.Configuration(
58
- identifier: "com.app.highlighter",
59
- name: "Highlighter"
60
- )
61
- customConfig.defaultColor = .yellow
62
- customConfig.allowsColorSelection = true
63
- customConfig.defaultWidth = 20
64
- customConfig.widthVariants = [
65
- 10: UIImage(systemName: "line.diagonal")!,
66
- 20: UIImage(systemName: "line.3.horizontal")!,
67
- 40: UIImage(systemName: "rectangle.fill")!
68
- ]
69
- customConfig.imageProvider = { item in
70
- // Return a custom image based on current color/width
71
- let config = UIImage.SymbolConfiguration(pointSize: 24)
72
- return UIImage(systemName: "highlighter", withConfiguration: config)!
73
- }
46
+ Requires iOS or iPadOS 18, visionOS 2, or Mac Catalyst 18.
74
47
 
75
- let customItem = PKToolPickerCustomItem(configuration: customConfig)
48
+ ```swift
49
+ @available(iOS 18.0, visionOS 2.0, *)
50
+ func makeStampPicker() -> PKToolPicker {
51
+ var setup = PKToolPickerCustomItem.Configuration(identifier: "com.example.stamp",
52
+ name: "Stamp")
53
+ setup.defaultColor = .systemOrange
54
+ setup.allowsColorSelection = true
55
+ setup.defaultWidth = 24
56
+ setup.widthVariants = [
57
+ 16: UIImage(systemName: "circle.fill") ?? UIImage(),
58
+ 24: UIImage(systemName: "circle.circle.fill") ?? UIImage()
59
+ ]
60
+ setup.imageProvider = { item in
61
+ (UIImage(systemName: "seal.fill") ?? UIImage()).withTintColor(item.color)
62
+ }
76
63
 
77
- let toolPicker = PKToolPicker(toolItems: [
78
- PKToolPickerInkingItem(type: .pen, color: .black, width: 5),
79
- customItem,
80
- PKToolPickerEraserItem(type: .vector)
81
- ])
64
+ let stamp = PKToolPickerCustomItem(configuration: setup)
65
+ return PKToolPicker(toolItems: [
66
+ PKToolPickerInkingItem(type: .pen),
67
+ stamp,
68
+ PKToolPickerEraserItem(type: .bitmap)
69
+ ])
70
+ }
82
71
  ```
83
72
 
84
- ## Canvas View Delegate Lifecycle
85
-
86
- Track the complete drawing lifecycle.
73
+ ## Delegate lifecycle
87
74
 
88
75
  ```swift
89
- class DrawingManager: NSObject, PKCanvasViewDelegate {
90
- var hasUnsavedChanges = false
91
- var isCurrentlyDrawing = false
92
-
76
+ extension StudioViewController: PKCanvasViewDelegate {
93
77
  func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {
94
- isCurrentlyDrawing = true
78
+ autosaveTimer?.invalidate() // user is mid-stroke
95
79
  }
96
80
 
97
81
  func canvasViewDidEndUsingTool(_ canvasView: PKCanvasView) {
98
- isCurrentlyDrawing = false
82
+ scheduleAutosave()
99
83
  }
100
84
 
101
85
  func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
102
- hasUnsavedChanges = true
86
+ hasPendingChanges = true
103
87
  }
104
88
 
105
89
  func canvasViewDidFinishRendering(_ canvasView: PKCanvasView) {
106
- // Safe to capture a snapshot for thumbnails
90
+ refreshPreviewTile() // rendering has settled; safe to snapshot
107
91
  }
108
92
  }
109
93
  ```
110
94
 
111
- ## Undo/Redo Support
95
+ `autosaveTimer`, `hasPendingChanges`, `scheduleAutosave()` and
96
+ `refreshPreviewTile()` stand for the app's own state.
112
97
 
113
- `PKCanvasView` automatically integrates with `UndoManager`.
98
+ ## Undo and redo
99
+
100
+ The canvas registers its edits with the responder chain's `UndoManager`, so
101
+ buttons only need to forward (for example from `viewDidLoad()`):
114
102
 
115
103
  ```swift
116
- class DrawingViewController: UIViewController {
117
- let canvasView = PKCanvasView()
118
-
119
- override func viewDidLoad() {
120
- super.viewDidLoad()
121
- view.addSubview(canvasView)
122
-
123
- navigationItem.leftBarButtonItem = UIBarButtonItem(
124
- systemItem: .undo,
125
- primaryAction: UIAction { [weak self] _ in
126
- self?.canvasView.undoManager?.undo()
127
- }
128
- )
129
- navigationItem.rightBarButtonItem = UIBarButtonItem(
130
- systemItem: .redo,
131
- primaryAction: UIAction { [weak self] _ in
132
- self?.canvasView.undoManager?.redo()
133
- }
134
- )
135
- }
104
+ let stepBack = UIAction(title: "Undo", image: UIImage(systemName: "arrow.uturn.backward")) { [weak self] _ in
105
+ self?.board.undoManager?.undo()
106
+ }
107
+ let stepForward = UIAction(title: "Redo", image: UIImage(systemName: "arrow.uturn.forward")) { [weak self] _ in
108
+ self?.board.undoManager?.redo()
136
109
  }
110
+ navigationItem.rightBarButtonItems = [
111
+ UIBarButtonItem(primaryAction: stepForward),
112
+ UIBarButtonItem(primaryAction: stepBack)
113
+ ]
137
114
  ```
138
115
 
139
- ## Thumbnail Generation
140
-
141
- Generate thumbnails for document browsers or galleries.
116
+ ## Thumbnails with a fixed aspect ratio
142
117
 
143
118
  ```swift
144
- func generateThumbnail(
145
- for drawing: PKDrawing,
146
- size: CGSize,
147
- scale: CGFloat = 2.0
148
- ) -> UIImage? {
149
- let bounds = drawing.bounds
150
- guard !bounds.isEmpty else { return nil }
151
-
152
- let aspectRatio = bounds.width / bounds.height
153
- let targetAspect = size.width / size.height
154
- var renderRect = bounds
155
-
156
- if aspectRatio > targetAspect {
157
- let scaleFactor = size.width / bounds.width
158
- renderRect = CGRect(
159
- x: bounds.minX,
160
- y: bounds.midY - (size.height / scaleFactor) / 2,
161
- width: bounds.width,
162
- height: size.height / scaleFactor
163
- )
119
+ func tile(for sketch: PKDrawing, size: CGSize, scale: CGFloat) -> UIImage? {
120
+ let content = sketch.bounds
121
+ guard !content.isEmpty else { return nil }
122
+
123
+ let wanted = size.width / size.height
124
+ var frame = content
125
+ if content.width / content.height > wanted {
126
+ let width = content.height * wanted
127
+ frame = CGRect(x: content.midX - width / 2, y: content.minY,
128
+ width: width, height: content.height)
164
129
  } else {
165
- let scaleFactor = size.height / bounds.height
166
- renderRect = CGRect(
167
- x: bounds.midX - (size.width / scaleFactor) / 2,
168
- y: bounds.minY,
169
- width: size.width / scaleFactor,
170
- height: bounds.height
171
- )
130
+ let height = content.width / wanted
131
+ frame = CGRect(x: content.minX, y: content.midY - height / 2,
132
+ width: content.width, height: height)
172
133
  }
173
-
174
- return drawing.image(from: renderRect, scale: scale)
134
+ return sketch.image(from: frame, scale: scale)
175
135
  }
176
136
  ```
177
137
 
178
- ## Drawing Comparison and Scoring
138
+ ## Scoring a tracing exercise
179
139
 
180
- Compare two drawings by analyzing their strokes and points.
140
+ A simple similarity score: sample both drawings evenly, then count how many
141
+ reference samples have an attempt sample nearby.
181
142
 
182
143
  ```swift
183
- func strokeSimilarity(
184
- reference: PKDrawing,
185
- candidate: PKDrawing,
186
- tolerance: CGFloat = 20
187
- ) -> Double {
188
- let refPoints = reference.strokes.flatMap { stroke in
189
- stroke.path.interpolatedPoints(by: .distance(5)).map(\.location)
190
- }
191
-
192
- let candPoints = candidate.strokes.flatMap { stroke in
193
- stroke.path.interpolatedPoints(by: .distance(5)).map(\.location)
194
- }
195
-
196
- guard !refPoints.isEmpty else { return 0 }
197
-
198
- var matchCount = 0
199
- for refPoint in refPoints {
200
- let minDist = candPoints.map { point in
201
- hypot(refPoint.x - point.x, refPoint.y - point.y)
202
- }.min() ?? .infinity
203
-
204
- if minDist <= tolerance { matchCount += 1 }
144
+ func tracingScore(target: PKDrawing, attempt: PKDrawing, radius: CGFloat = 20) -> Double {
145
+ func samples(_ drawing: PKDrawing) -> [CGPoint] {
146
+ drawing.strokes.flatMap { stroke in
147
+ let evenly = stroke.path.interpolatedPoints(by: .distance(5))
148
+ return evenly.map { $0.location.applying(stroke.transform) }
149
+ }
205
150
  }
206
-
207
- return Double(matchCount) / Double(refPoints.count)
151
+ let wanted = samples(target)
152
+ let drawn = samples(attempt)
153
+ guard !wanted.isEmpty else { return 0 }
154
+
155
+ let hits = wanted.filter { goal in
156
+ drawn.contains { hypot($0.x - goal.x, $0.y - goal.y) <= radius }
157
+ }.count
158
+ return Double(hits) / Double(wanted.count)
208
159
  }
209
160
  ```
210
161
 
211
- ## Content Version Management
162
+ ## Managing content versions
212
163
 
213
- Handle backward compatibility when sharing drawings across OS versions.
164
+ The version map and the cap from the main skill, in one place:
214
165
 
215
166
  ```swift
216
- // Check if a drawing uses features beyond a version
217
- let drawing = canvasView.drawing
218
- let version = drawing.requiredContentVersion
219
-
220
- switch version {
221
- case .version1:
222
- // iPadOS 14-era inks: marker, pen, pencil
223
- break
224
- case .version2:
225
- // iPadOS 17 inks: monoline, fountain pen, watercolor, crayon
226
- break
227
- case .version3:
228
- // Barrel-roll angle data
229
- break
230
- case .version4:
231
- // Reed pen
232
- break
233
- @unknown default:
234
- break
167
+ func describe(_ sketch: PKDrawing) -> String {
168
+ switch sketch.requiredContentVersion {
169
+ case .version1: "pen, pencil, marker"
170
+ case .version2: "adds monoline, fountain pen, watercolor, crayon"
171
+ case .version3: "adds barrel-roll angles"
172
+ case .version4: "adds reed pen"
173
+ @unknown default: "unknown future content"
174
+ }
235
175
  }
236
176
 
237
- // Limit both canvas and picker to a specific version.
238
- // Use .version1 when saved drawings must load on pre-iPadOS 17 systems.
239
- if #available(iOS 17.0, *) {
240
- canvasView.maximumSupportedContentVersion = .version1
241
- toolPicker.maximumSupportedContentVersion = .version1
177
+ @MainActor
178
+ func limitToOldestClients(_ board: PKCanvasView, _ palette: PKToolPicker) {
179
+ if #available(iOS 17.0, *) { // drawings must open before iPadOS 17
180
+ board.maximumSupportedContentVersion = .version1
181
+ palette.maximumSupportedContentVersion = .version1
182
+ }
242
183
  }
243
184
  ```
244
185
 
245
- When you allow newer inks, branch before CloudKit or cross-device sync and
246
- upload either the original drawing or a verified fallback drawing.
186
+ ### Deciding what to upload
187
+
188
+ Before sending a drawing through CloudKit or any cross-device channel, decide
189
+ what the oldest device will receive.
247
190
 
248
191
  ```swift
249
- func drawingForPreiPadOS17Sync(_ drawing: PKDrawing) -> PKDrawing? {
250
- switch drawing.requiredContentVersion {
192
+ func payloadForOldestDevice(_ sketch: PKDrawing) -> PKDrawing? {
193
+ switch sketch.requiredContentVersion {
251
194
  case .version1:
252
- return drawing
195
+ return sketch
253
196
  case .version2, .version3, .version4:
254
- let fallback = version1Fallback(from: drawing)
255
- guard fallback.requiredContentVersion == .version1 else {
256
- // Reusing paths can preserve newer metadata, such as barrel-roll data.
257
- // Sync a thumbnail/message instead of incompatible drawing data.
258
- return nil
197
+ let simplified = downgradedCopy(of: sketch)
198
+ guard simplified.requiredContentVersion == .version1 else {
199
+ return nil // send a thumbnail or an explanation instead
259
200
  }
260
- return fallback
201
+ return simplified
261
202
  @unknown default:
262
203
  return nil
263
204
  }
264
205
  }
265
206
 
266
- func version1Fallback(from drawing: PKDrawing) -> PKDrawing {
267
- let strokes = drawing.strokes.map { stroke -> PKStroke in
268
- var fallback = stroke
269
- fallback.ink = PKInkingTool(.pen, color: .black, width: 2).ink
270
- return fallback
207
+ func downgradedCopy(of sketch: PKDrawing) -> PKDrawing {
208
+ let basicInk = PKInkingTool(.pen, color: .black, width: 4).ink
209
+ let strokes = sketch.strokes.map { original -> PKStroke in
210
+ var copy = original
211
+ copy.ink = PKInk(basicInk.inkType, color: original.ink.color)
212
+ return copy
271
213
  }
272
214
  return PKDrawing(strokes: strokes)
273
215
  }
274
216
  ```
275
217
 
276
- ## Advanced SwiftUI Wrapper
218
+ Swapping the ink is not always enough. The copied paths can still carry newer
219
+ data such as barrel-roll angles, which is why the result is checked again
220
+ before upload.
277
221
 
278
- A full-featured SwiftUI wrapper with tool picker, undo, and save support.
222
+ ## A configurable SwiftUI wrapper
279
223
 
280
224
  ```swift
281
- import SwiftUI
282
225
  import PencilKit
226
+ import SwiftUI
283
227
 
284
- struct DrawingCanvas: UIViewRepresentable {
228
+ struct SketchSurface: UIViewRepresentable {
285
229
  @Binding var drawing: PKDrawing
286
- var drawingPolicy: PKCanvasViewDrawingPolicy = .anyInput
287
- var showToolPicker: Bool = true
230
+ var policy: PKCanvasViewDrawingPolicy = .anyInput
231
+ var showsPalette = true
232
+
233
+ func makeCoordinator() -> Coordinator { Coordinator(drawing: $drawing) }
288
234
 
289
235
  func makeUIView(context: Context) -> PKCanvasView {
290
236
  let canvas = PKCanvasView()
291
- canvas.delegate = context.coordinator
292
- canvas.drawingPolicy = drawingPolicy
293
- canvas.drawing = drawing
294
237
  canvas.backgroundColor = .clear
295
238
  canvas.isOpaque = false
296
-
297
- let coordinator = context.coordinator
298
- coordinator.toolPicker.addObserver(canvas)
299
-
239
+ canvas.drawingPolicy = policy
240
+ canvas.drawing = drawing
241
+ canvas.delegate = context.coordinator
242
+ context.coordinator.palette.addObserver(canvas)
300
243
  return canvas
301
244
  }
302
245
 
303
- func updateUIView(_ canvas: PKCanvasView, context: Context) {
304
- let coordinator = context.coordinator
305
-
306
- if canvas.drawing != drawing {
307
- canvas.drawing = drawing
308
- }
309
-
310
- coordinator.toolPicker.setVisible(showToolPicker, forFirstResponder: canvas)
311
- if showToolPicker {
312
- canvas.becomeFirstResponder()
313
- }
246
+ func updateUIView(_ uiView: PKCanvasView, context: Context) {
247
+ uiView.drawingPolicy = policy
248
+ if uiView.drawing != drawing { uiView.drawing = drawing }
249
+ let palette = context.coordinator.palette
250
+ palette.setVisible(showsPalette, forFirstResponder: uiView)
251
+ if showsPalette { uiView.becomeFirstResponder() }
314
252
  }
315
253
 
316
- func makeCoordinator() -> Coordinator {
317
- Coordinator(parent: self)
318
- }
254
+ final class Coordinator: NSObject, PKCanvasViewDelegate {
255
+ let palette = PKToolPicker()
256
+ private let drawing: Binding<PKDrawing>
319
257
 
320
- class Coordinator: NSObject, PKCanvasViewDelegate {
321
- let parent: DrawingCanvas
322
- let toolPicker = PKToolPicker()
323
-
324
- init(parent: DrawingCanvas) {
325
- self.parent = parent
326
- }
258
+ init(drawing: Binding<PKDrawing>) { self.drawing = drawing }
327
259
 
328
260
  func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
329
- parent.drawing = canvasView.drawing
261
+ drawing.wrappedValue = canvasView.drawing
330
262
  }
331
263
  }
332
264
  }
333
265
  ```
266
+
267
+ The clear background lets the surface sit over a photo, a PDF page or a
268
+ paper texture.