@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.
- package/CHANGELOG.md +9 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +266 -267
- package/package.json +2 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +68 -68
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- 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
|
-
"
|
|
7
|
-
"
|
|
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
|
-
"
|
|
11
|
-
"Retains
|
|
12
|
-
"Explains
|
|
13
|
-
"
|
|
14
|
-
"
|
|
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
|
-
"
|
|
20
|
-
"
|
|
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
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
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
|
-
"
|
|
33
|
-
"
|
|
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
|
|
37
|
-
"
|
|
38
|
-
"Mentions
|
|
39
|
-
"
|
|
40
|
-
"
|
|
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
|
|
1
|
+
# PencilKit patterns
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
that exceed the main skill file's scope.
|
|
3
|
+
Longer recipes for the `pencilkit-drawing` skill ([../SKILL.md](../SKILL.md)).
|
|
5
4
|
|
|
6
|
-
##
|
|
5
|
+
## Listening to the tool picker
|
|
7
6
|
|
|
8
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
let
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
|
36
|
-
|
|
26
|
+
let chosen = toolPicker.selectedToolItem.identifier
|
|
27
|
+
title = "Tool: \(chosen)"
|
|
37
28
|
}
|
|
38
29
|
|
|
39
30
|
func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
|
|
40
|
-
|
|
31
|
+
navigationController?.setToolbarHidden(toolPicker.isVisible, animated: true)
|
|
41
32
|
}
|
|
42
33
|
|
|
43
34
|
func toolPickerFramesObscuredDidChange(_ toolPicker: PKToolPicker) {
|
|
44
|
-
let
|
|
45
|
-
|
|
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
|
-
|
|
41
|
+
The last callback keeps the bottom of the drawing reachable when the docked
|
|
42
|
+
palette covers part of the screen.
|
|
52
43
|
|
|
53
|
-
|
|
54
|
-
require iOS/iPadOS 18+, Mac Catalyst 18+, or visionOS 2+.
|
|
44
|
+
## A custom picker item
|
|
55
45
|
|
|
56
|
-
|
|
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
|
-
|
|
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
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
##
|
|
85
|
-
|
|
86
|
-
Track the complete drawing lifecycle.
|
|
73
|
+
## Delegate lifecycle
|
|
87
74
|
|
|
88
75
|
```swift
|
|
89
|
-
|
|
90
|
-
var hasUnsavedChanges = false
|
|
91
|
-
var isCurrentlyDrawing = false
|
|
92
|
-
|
|
76
|
+
extension StudioViewController: PKCanvasViewDelegate {
|
|
93
77
|
func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {
|
|
94
|
-
|
|
78
|
+
autosaveTimer?.invalidate() // user is mid-stroke
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
func canvasViewDidEndUsingTool(_ canvasView: PKCanvasView) {
|
|
98
|
-
|
|
82
|
+
scheduleAutosave()
|
|
99
83
|
}
|
|
100
84
|
|
|
101
85
|
func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
|
|
102
|
-
|
|
86
|
+
hasPendingChanges = true
|
|
103
87
|
}
|
|
104
88
|
|
|
105
89
|
func canvasViewDidFinishRendering(_ canvasView: PKCanvasView) {
|
|
106
|
-
//
|
|
90
|
+
refreshPreviewTile() // rendering has settled; safe to snapshot
|
|
107
91
|
}
|
|
108
92
|
}
|
|
109
93
|
```
|
|
110
94
|
|
|
111
|
-
|
|
95
|
+
`autosaveTimer`, `hasPendingChanges`, `scheduleAutosave()` and
|
|
96
|
+
`refreshPreviewTile()` stand for the app's own state.
|
|
112
97
|
|
|
113
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
##
|
|
140
|
-
|
|
141
|
-
Generate thumbnails for document browsers or galleries.
|
|
116
|
+
## Thumbnails with a fixed aspect ratio
|
|
142
117
|
|
|
143
118
|
```swift
|
|
144
|
-
func
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
##
|
|
138
|
+
## Scoring a tracing exercise
|
|
179
139
|
|
|
180
|
-
|
|
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
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
162
|
+
## Managing content versions
|
|
212
163
|
|
|
213
|
-
|
|
164
|
+
The version map and the cap from the main skill, in one place:
|
|
214
165
|
|
|
215
166
|
```swift
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
case .
|
|
222
|
-
|
|
223
|
-
|
|
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
|
-
|
|
238
|
-
|
|
239
|
-
if #available(iOS 17.0, *) {
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
246
|
-
|
|
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
|
|
250
|
-
switch
|
|
192
|
+
func payloadForOldestDevice(_ sketch: PKDrawing) -> PKDrawing? {
|
|
193
|
+
switch sketch.requiredContentVersion {
|
|
251
194
|
case .version1:
|
|
252
|
-
return
|
|
195
|
+
return sketch
|
|
253
196
|
case .version2, .version3, .version4:
|
|
254
|
-
let
|
|
255
|
-
guard
|
|
256
|
-
//
|
|
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
|
|
201
|
+
return simplified
|
|
261
202
|
@unknown default:
|
|
262
203
|
return nil
|
|
263
204
|
}
|
|
264
205
|
}
|
|
265
206
|
|
|
266
|
-
func
|
|
267
|
-
let
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
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
|
|
222
|
+
## A configurable SwiftUI wrapper
|
|
279
223
|
|
|
280
224
|
```swift
|
|
281
|
-
import SwiftUI
|
|
282
225
|
import PencilKit
|
|
226
|
+
import SwiftUI
|
|
283
227
|
|
|
284
|
-
struct
|
|
228
|
+
struct SketchSurface: UIViewRepresentable {
|
|
285
229
|
@Binding var drawing: PKDrawing
|
|
286
|
-
var
|
|
287
|
-
var
|
|
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
|
-
|
|
298
|
-
|
|
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(_
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
|
|
317
|
-
|
|
318
|
-
|
|
254
|
+
final class Coordinator: NSObject, PKCanvasViewDelegate {
|
|
255
|
+
let palette = PKToolPicker()
|
|
256
|
+
private let drawing: Binding<PKDrawing>
|
|
319
257
|
|
|
320
|
-
|
|
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
|
-
|
|
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.
|