@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1
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 +21 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +285 -285
- package/package.json +3 -3
- package/pipeline/lib/redact.mjs +3 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/scripts/gen-skills-index.mjs +13 -1
- package/pipeline/scripts/pre-commit-check.sh +4 -0
- package/pipeline/skills/.skill-manifest.json +69 -69
- 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 +345 -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 +107 -121
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -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 +335 -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 +277 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -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 +274 -384
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
- 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 +228 -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 +302 -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 +236 -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/localization-reuse-map/SKILL.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -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/skill-creator/template.md +7 -1
- 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 +302 -241
- 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 +304 -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 +183 -162
- 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 +411 -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 +375 -491
- 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 +397 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -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 +201 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
- 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 +160 -315
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,480 +1,353 @@
|
|
|
1
|
-
# RealityKit
|
|
1
|
+
# RealityKit Patterns
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Longer examples for the `realitykit-ar` skill. SKILL.md covers setup, anchoring,
|
|
4
|
+
raycasting and gestures; this file goes deeper.
|
|
4
5
|
|
|
5
6
|
## Contents
|
|
6
7
|
|
|
7
|
-
- [Physics
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [Occlusion and
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
8
|
+
- [Physics](#physics)
|
|
9
|
+
- [Animation](#animation)
|
|
10
|
+
- [Materials and lighting](#materials-and-lighting)
|
|
11
|
+
- [Custom components and systems](#custom-components-and-systems)
|
|
12
|
+
- [Occlusion and environment](#occlusion-and-environment)
|
|
13
|
+
- [A SwiftUI model viewer](#a-swiftui-model-viewer)
|
|
14
|
+
- [Entity accessibility](#entity-accessibility)
|
|
15
|
+
- [Performance](#performance)
|
|
14
16
|
|
|
15
|
-
## Physics
|
|
17
|
+
## Physics
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
A static floor and a bouncing ball:
|
|
18
20
|
|
|
19
21
|
```swift
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
))
|
|
33
|
-
ground.components.set(CollisionComponent(
|
|
34
|
-
shapes: [.generateBox(size: [2, 0.01, 2])]
|
|
35
|
-
))
|
|
36
|
-
ground.position = [0, -0.5, -1]
|
|
37
|
-
content.add(ground)
|
|
38
|
-
|
|
39
|
-
// Falling box (dynamic body)
|
|
40
|
-
let box = ModelEntity(
|
|
41
|
-
mesh: .generateBox(size: 0.1),
|
|
42
|
-
materials: [SimpleMaterial(color: .red, isMetallic: true)]
|
|
43
|
-
)
|
|
44
|
-
box.components.set(PhysicsBodyComponent(
|
|
45
|
-
massProperties: .init(mass: 1.0),
|
|
46
|
-
material: PhysicsMaterialResource.generate(
|
|
47
|
-
staticFriction: 0.5,
|
|
48
|
-
dynamicFriction: 0.5,
|
|
49
|
-
restitution: 0.7
|
|
50
|
-
),
|
|
51
|
-
mode: .dynamic
|
|
52
|
-
))
|
|
53
|
-
box.components.set(CollisionComponent(
|
|
54
|
-
shapes: [.generateBox(size: [0.1, 0.1, 0.1])]
|
|
55
|
-
))
|
|
56
|
-
box.position = [0, 0.5, -1]
|
|
57
|
-
content.add(box)
|
|
22
|
+
@MainActor
|
|
23
|
+
func makeCourt() -> (floor: ModelEntity, ball: ModelEntity) {
|
|
24
|
+
let floor = ModelEntity(mesh: .generatePlane(width: 3, depth: 3))
|
|
25
|
+
floor.components.set(PhysicsBodyComponent(massProperties: .default, material: .default, mode: .static))
|
|
26
|
+
floor.components.set(CollisionComponent(shapes: [.generateBox(size: [3, 0.005, 3])]))
|
|
27
|
+
|
|
28
|
+
let bounce = PhysicsMaterialResource.generate(staticFriction: 0.4, dynamicFriction: 0.3, restitution: 0.8)
|
|
29
|
+
let ball = ModelEntity(mesh: .generateSphere(radius: 0.05))
|
|
30
|
+
ball.components.set(PhysicsBodyComponent(massProperties: .init(mass: 0.6), material: bounce, mode: .dynamic))
|
|
31
|
+
ball.components.set(CollisionComponent(shapes: [.generateSphere(radius: 0.05)]))
|
|
32
|
+
ball.position = [0, 1, 0]
|
|
33
|
+
return (floor, ball)
|
|
58
34
|
}
|
|
59
35
|
```
|
|
60
36
|
|
|
61
|
-
|
|
37
|
+
Entities with a physics body conform to `HasPhysicsBody`, which adds:
|
|
62
38
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Forces are applied per-frame via the physics simulation
|
|
67
|
-
}
|
|
39
|
+
- `addForce(_:relativeTo:)`: a continuous force in newtons, applied each frame
|
|
40
|
+
you call it.
|
|
41
|
+
- `applyLinearImpulse(_:relativeTo:)`: an instant kick.
|
|
68
42
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
43
|
+
```swift
|
|
44
|
+
@MainActor
|
|
45
|
+
func kick(_ ball: ModelEntity) {
|
|
46
|
+
ball.applyLinearImpulse([0.3, 1.2, 0], relativeTo: nil)
|
|
73
47
|
}
|
|
74
48
|
```
|
|
75
49
|
|
|
76
|
-
|
|
50
|
+
Collision events:
|
|
77
51
|
|
|
78
52
|
```swift
|
|
79
53
|
RealityView { content in
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
54
|
+
let court = makeCourt()
|
|
55
|
+
content.add(court.floor)
|
|
56
|
+
content.add(court.ball)
|
|
57
|
+
_ = content.subscribe(to: CollisionEvents.Began.self) { contact in
|
|
58
|
+
Log.scene.debug("\(contact.entityA.name) touched \(contact.entityB.name)")
|
|
84
59
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
print("Collision ended between \(event.entityA.name) and \(event.entityB.name)")
|
|
60
|
+
_ = content.subscribe(to: CollisionEvents.Ended.self) { contact in
|
|
61
|
+
Log.scene.debug("\(contact.entityA.name) separated")
|
|
88
62
|
}
|
|
89
63
|
}
|
|
90
64
|
```
|
|
91
65
|
|
|
92
|
-
##
|
|
66
|
+
## Animation
|
|
93
67
|
|
|
94
|
-
|
|
68
|
+
Move an entity by animating to a changed copy of its transform:
|
|
95
69
|
|
|
96
70
|
```swift
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
var
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
entity.move(
|
|
103
|
-
to: transform,
|
|
104
|
-
relativeTo: entity.parent,
|
|
105
|
-
duration: 2.0,
|
|
106
|
-
timingFunction: .easeInOut
|
|
107
|
-
)
|
|
71
|
+
@MainActor
|
|
72
|
+
func slideUp(_ panel: Entity) {
|
|
73
|
+
var target = panel.transform
|
|
74
|
+
target.translation.y += 0.2
|
|
75
|
+
panel.move(to: target, relativeTo: panel.parent, duration: 0.8, timingFunction: .easeInOut)
|
|
108
76
|
}
|
|
109
77
|
```
|
|
110
78
|
|
|
111
|
-
|
|
79
|
+
Circle an entity around a point with a per-frame subscription:
|
|
112
80
|
|
|
113
81
|
```swift
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
content
|
|
117
|
-
|
|
82
|
+
RealityView { content in
|
|
83
|
+
let moon = ModelEntity(mesh: .generateSphere(radius: 0.02))
|
|
84
|
+
content.add(moon)
|
|
85
|
+
let center: SIMD3<Float> = [0, 0, -0.7]
|
|
118
86
|
var angle: Float = 0
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
_ = content.subscribe(to: SceneEvents.Update.self) { event in
|
|
123
|
-
angle += Float(event.deltaTime) * 1.5
|
|
124
|
-
entity.position = center + SIMD3<Float>(
|
|
125
|
-
cos(angle) * radius,
|
|
126
|
-
0,
|
|
127
|
-
sin(angle) * radius
|
|
128
|
-
)
|
|
87
|
+
_ = content.subscribe(to: SceneEvents.Update.self) { frame in
|
|
88
|
+
angle += Float(frame.deltaTime) * 0.9
|
|
89
|
+
moon.position = center + [0.25 * cos(angle), 0, 0.25 * sin(angle)]
|
|
129
90
|
}
|
|
130
91
|
}
|
|
131
92
|
```
|
|
132
93
|
|
|
133
|
-
|
|
94
|
+
Play an animation baked into a USDZ file:
|
|
134
95
|
|
|
135
96
|
```swift
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
// Play all available animations
|
|
141
|
-
if let animation = character.availableAnimations.first {
|
|
142
|
-
character.playAnimation(
|
|
143
|
-
animation.repeat(duration: .infinity),
|
|
144
|
-
transitionDuration: 0.5,
|
|
145
|
-
startsPaused: false
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
97
|
+
@MainActor
|
|
98
|
+
func startIdleLoop(on robot: Entity) {
|
|
99
|
+
guard let clip = robot.availableAnimations.first else { return }
|
|
100
|
+
robot.playAnimation(clip.repeat(duration: .infinity), transitionDuration: 0.4, startsPaused: false)
|
|
149
101
|
}
|
|
150
102
|
```
|
|
151
103
|
|
|
152
|
-
##
|
|
153
|
-
|
|
154
|
-
### SimpleMaterial Variations
|
|
104
|
+
## Materials and lighting
|
|
155
105
|
|
|
156
106
|
```swift
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
color: .
|
|
160
|
-
roughness: .float(0.1),
|
|
161
|
-
isMetallic: true
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
// Transparent material
|
|
165
|
-
var transparent = SimpleMaterial()
|
|
166
|
-
transparent.color = .init(
|
|
167
|
-
tint: UIColor.blue.withAlphaComponent(0.5),
|
|
168
|
-
texture: nil
|
|
169
|
-
)
|
|
170
|
-
transparent.blending = .transparent(opacity: 0.5)
|
|
171
|
-
|
|
172
|
-
// Textured material
|
|
173
|
-
if let texture = try? await TextureResource(named: "wood") {
|
|
174
|
-
var textured = SimpleMaterial()
|
|
175
|
-
textured.color = .init(
|
|
176
|
-
tint: .white,
|
|
177
|
-
texture: .init(texture)
|
|
178
|
-
)
|
|
107
|
+
@MainActor
|
|
108
|
+
func chrome() -> SimpleMaterial {
|
|
109
|
+
SimpleMaterial(color: .lightGray, roughness: .float(0.05), isMetallic: true)
|
|
179
110
|
}
|
|
180
|
-
```
|
|
181
111
|
|
|
182
|
-
|
|
112
|
+
@MainActor
|
|
113
|
+
func frostedGlass() -> PhysicallyBasedMaterial {
|
|
114
|
+
var glass = PhysicallyBasedMaterial()
|
|
115
|
+
glass.baseColor = .init(tint: .white)
|
|
116
|
+
glass.roughness = 0.3
|
|
117
|
+
glass.blending = .transparent(opacity: 0.5)
|
|
118
|
+
return glass
|
|
119
|
+
}
|
|
183
120
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if let
|
|
188
|
-
|
|
189
|
-
content.environment.lighting.intensityExponent = 1.0
|
|
121
|
+
@MainActor
|
|
122
|
+
func woodGrain() async -> SimpleMaterial {
|
|
123
|
+
var wood = SimpleMaterial()
|
|
124
|
+
if let grain = try? await TextureResource(named: "oak_diffuse") {
|
|
125
|
+
wood.color = .init(tint: .white, texture: .init(grain))
|
|
190
126
|
}
|
|
127
|
+
return wood
|
|
191
128
|
}
|
|
192
129
|
```
|
|
193
130
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
### Custom Components
|
|
131
|
+
`SimpleMaterial` has no `blending` property; transparency needs
|
|
132
|
+
`PhysicallyBasedMaterial` or `UnlitMaterial`.
|
|
197
133
|
|
|
198
|
-
|
|
134
|
+
Image-based lighting from an environment resource: put an
|
|
135
|
+
`ImageBasedLightComponent` on one entity and point each lit entity at it with
|
|
136
|
+
`ImageBasedLightReceiverComponent`. `RealityViewCameraContent.environment` has
|
|
137
|
+
no lighting properties on iOS.
|
|
199
138
|
|
|
200
139
|
```swift
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
140
|
+
RealityView { content in
|
|
141
|
+
guard let studio = try? await EnvironmentResource(named: "softbox") else { return }
|
|
142
|
+
let light = Entity()
|
|
143
|
+
light.components.set(ImageBasedLightComponent(source: .single(studio), intensityExponent: 1.2))
|
|
144
|
+
content.add(light)
|
|
145
|
+
|
|
146
|
+
let vase = ModelEntity(mesh: .generateSphere(radius: 0.1), materials: [chrome()])
|
|
147
|
+
vase.components.set(ImageBasedLightReceiverComponent(imageBasedLight: light))
|
|
148
|
+
content.add(vase)
|
|
210
149
|
}
|
|
211
|
-
|
|
212
|
-
// Register the component (once, at app launch)
|
|
213
|
-
HealthComponent.registerComponent()
|
|
214
|
-
|
|
215
|
-
// Attach to an entity
|
|
216
|
-
let enemy = ModelEntity(
|
|
217
|
-
mesh: .generateBox(size: 0.1),
|
|
218
|
-
materials: [SimpleMaterial(color: .red, isMetallic: false)]
|
|
219
|
-
)
|
|
220
|
-
enemy.components.set(HealthComponent(
|
|
221
|
-
currentHealth: 100,
|
|
222
|
-
maxHealth: 100
|
|
223
|
-
))
|
|
224
150
|
```
|
|
225
151
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
Systems process entities with matching components each frame:
|
|
152
|
+
## Custom components and systems
|
|
229
153
|
|
|
230
154
|
```swift
|
|
231
|
-
struct
|
|
232
|
-
|
|
155
|
+
struct Hover: Component {
|
|
156
|
+
var height: Float = 0.03
|
|
157
|
+
var speed: Float = 2
|
|
158
|
+
var phase: Float = 0
|
|
159
|
+
var offset: Float { sin(phase) * height }
|
|
160
|
+
}
|
|
233
161
|
|
|
234
|
-
|
|
162
|
+
struct HoverSystem: System {
|
|
163
|
+
static let query = EntityQuery(where: .has(Hover.self))
|
|
164
|
+
|
|
165
|
+
init(scene: RealityKit.Scene) {}
|
|
235
166
|
|
|
236
167
|
func update(context: SceneUpdateContext) {
|
|
237
|
-
for entity in context.entities(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
red: CGFloat(1 - ratio),
|
|
248
|
-
green: CGFloat(ratio),
|
|
249
|
-
blue: 0,
|
|
250
|
-
alpha: 1
|
|
251
|
-
)
|
|
252
|
-
model.materials = [SimpleMaterial(
|
|
253
|
-
color: color,
|
|
254
|
-
isMetallic: false
|
|
255
|
-
)]
|
|
256
|
-
entity.components.set(model)
|
|
168
|
+
for entity in context.entities(matching: Self.query, updatingSystemWhen: .rendering) {
|
|
169
|
+
guard var hover = entity.components[Hover.self] else { continue }
|
|
170
|
+
hover.phase += hover.speed * Float(context.deltaTime)
|
|
171
|
+
entity.position.y = hover.offset
|
|
172
|
+
entity.components[Hover.self] = hover
|
|
173
|
+
|
|
174
|
+
if var model = entity.components[ModelComponent.self], hover.offset > 0 {
|
|
175
|
+
model.materials = [SimpleMaterial(color: .systemYellow, isMetallic: false)]
|
|
176
|
+
entity.components[ModelComponent.self] = model
|
|
177
|
+
}
|
|
257
178
|
}
|
|
258
179
|
}
|
|
259
180
|
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Register both once at launch, then attach the component to entities:
|
|
260
184
|
|
|
261
|
-
|
|
262
|
-
|
|
185
|
+
```swift
|
|
186
|
+
Hover.registerComponent()
|
|
187
|
+
HoverSystem.registerSystem()
|
|
188
|
+
lantern.components.set(Hover())
|
|
263
189
|
```
|
|
264
190
|
|
|
265
|
-
|
|
191
|
+
Components are value types, so read, change and write back; the same goes for
|
|
192
|
+
`ModelComponent`.
|
|
266
193
|
|
|
267
|
-
|
|
194
|
+
## Occlusion and environment
|
|
268
195
|
|
|
269
|
-
|
|
196
|
+
An invisible occluder hides virtual objects behind a real table or wall:
|
|
270
197
|
|
|
271
198
|
```swift
|
|
272
|
-
let
|
|
273
|
-
mesh: .generatePlane(width: 1, depth: 1),
|
|
274
|
-
materials: [OcclusionMaterial()]
|
|
275
|
-
)
|
|
276
|
-
occlusionPlane.position = [0, -0.5, -1]
|
|
277
|
-
content.add(occlusionPlane)
|
|
199
|
+
let tableTop = ModelEntity(mesh: .generatePlane(width: 1.2, depth: 0.7), materials: [OcclusionMaterial()])
|
|
278
200
|
```
|
|
279
201
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
### Environment Configuration
|
|
202
|
+
In AR mode the camera feed is the background. With the `.virtual` camera, the
|
|
203
|
+
iOS `RealityViewEnvironment` offers `.default` and `.skybox(_:)`:
|
|
283
204
|
|
|
284
205
|
```swift
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
content.environment
|
|
288
|
-
|
|
289
|
-
// Adjust lighting intensity
|
|
290
|
-
content.environment.lighting.intensityExponent = 1.2
|
|
206
|
+
content.camera = .virtual
|
|
207
|
+
if let sky = try? await EnvironmentResource(named: "softbox") {
|
|
208
|
+
content.environment = .skybox(sky)
|
|
291
209
|
}
|
|
292
210
|
```
|
|
293
211
|
|
|
294
|
-
##
|
|
295
|
-
|
|
296
|
-
### AR Model Viewer with Controls
|
|
212
|
+
## A SwiftUI model viewer
|
|
297
213
|
|
|
298
214
|
```swift
|
|
299
|
-
import SwiftUI
|
|
300
|
-
import RealityKit
|
|
301
215
|
import AVFoundation
|
|
216
|
+
import Observation
|
|
217
|
+
import RealityKit
|
|
218
|
+
import SwiftUI
|
|
302
219
|
|
|
303
|
-
@Observable
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
var
|
|
307
|
-
var
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
model.scale = [modelScale, modelScale, modelScale]
|
|
321
|
-
model.position = [0, -0.2, -0.8]
|
|
322
|
-
model.name = "currentModel"
|
|
323
|
-
|
|
324
|
-
// Enable interaction
|
|
325
|
-
model.generateCollisionShapes(recursive: true)
|
|
326
|
-
model.components.set(InputTargetComponent())
|
|
327
|
-
|
|
328
|
-
content.add(model)
|
|
329
|
-
currentEntity = model
|
|
330
|
-
isPlaced = true
|
|
220
|
+
@Observable @MainActor
|
|
221
|
+
final class ShowroomModel {
|
|
222
|
+
var selection = "chair"
|
|
223
|
+
var scale: Float = 0.01
|
|
224
|
+
private var current: ModelEntity?
|
|
225
|
+
|
|
226
|
+
func show(in content: RealityViewCameraContent) async {
|
|
227
|
+
current?.removeFromParent()
|
|
228
|
+
guard let piece = try? await ModelEntity(named: selection) else { return }
|
|
229
|
+
piece.name = "showpiece"
|
|
230
|
+
piece.scale = SIMD3(repeating: scale)
|
|
231
|
+
piece.position = [0, -0.1, -0.6]
|
|
232
|
+
piece.generateCollisionShapes(recursive: true)
|
|
233
|
+
piece.components.set(InputTargetComponent())
|
|
234
|
+
content.add(piece)
|
|
235
|
+
current = piece
|
|
331
236
|
}
|
|
332
237
|
}
|
|
333
238
|
|
|
334
|
-
struct
|
|
335
|
-
@State private var
|
|
336
|
-
@State private var
|
|
239
|
+
struct ShowroomView: View {
|
|
240
|
+
@State private var model = ShowroomModel()
|
|
241
|
+
@State private var cameraAllowed = false
|
|
337
242
|
|
|
338
243
|
var body: some View {
|
|
339
|
-
|
|
340
|
-
if
|
|
244
|
+
Group {
|
|
245
|
+
if cameraAllowed {
|
|
341
246
|
RealityView { content in
|
|
342
|
-
await
|
|
247
|
+
await model.show(in: content)
|
|
343
248
|
} update: { content in
|
|
344
|
-
|
|
345
|
-
where: { $0.name == "currentModel" }
|
|
346
|
-
) {
|
|
347
|
-
let s = viewModel.modelScale
|
|
348
|
-
model.scale = [s, s, s]
|
|
349
|
-
}
|
|
249
|
+
content.entities.first { $0.name == "showpiece" }?.scale = SIMD3(repeating: model.scale)
|
|
350
250
|
}
|
|
351
251
|
.gesture(
|
|
352
252
|
DragGesture()
|
|
353
253
|
.targetedToAnyEntity()
|
|
354
|
-
.onChanged {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
to: value.entity.parent!
|
|
359
|
-
)
|
|
254
|
+
.onChanged { drag in
|
|
255
|
+
guard let parent = drag.entity.parent,
|
|
256
|
+
let point = drag.unproject(\.location, to: parent) else { return }
|
|
257
|
+
drag.entity.position = point
|
|
360
258
|
}
|
|
361
259
|
)
|
|
260
|
+
.overlay(alignment: .bottom) { controls }
|
|
362
261
|
} else {
|
|
363
|
-
ContentUnavailableView(
|
|
364
|
-
|
|
365
|
-
systemImage: "camera.fill",
|
|
366
|
-
description: Text("Allow camera access for AR.")
|
|
367
|
-
)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
VStack {
|
|
371
|
-
Spacer()
|
|
372
|
-
controlsPanel
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
.task {
|
|
376
|
-
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
|
377
|
-
if status == .authorized {
|
|
378
|
-
cameraAuthorized = true
|
|
379
|
-
} else if status == .notDetermined {
|
|
380
|
-
cameraAuthorized = await AVCaptureDevice
|
|
381
|
-
.requestAccess(for: .video)
|
|
262
|
+
ContentUnavailableView("Camera needed", systemImage: "camera",
|
|
263
|
+
description: Text("Allow camera access in Settings to place furniture."))
|
|
382
264
|
}
|
|
383
265
|
}
|
|
266
|
+
.task { cameraAllowed = await cameraReady() }
|
|
384
267
|
}
|
|
385
268
|
|
|
386
|
-
private var
|
|
269
|
+
private var controls: some View {
|
|
387
270
|
VStack {
|
|
388
|
-
Picker("
|
|
389
|
-
Text("
|
|
390
|
-
Text("
|
|
391
|
-
Text("Lamp").tag("lamp")
|
|
271
|
+
Picker("Item", selection: $model.selection) {
|
|
272
|
+
Text("Armchair").tag("chair")
|
|
273
|
+
Text("Desk lamp").tag("desk_lamp")
|
|
392
274
|
}
|
|
393
275
|
.pickerStyle(.segmented)
|
|
394
|
-
|
|
395
|
-
Slider(
|
|
396
|
-
value: $viewModel.modelScale,
|
|
397
|
-
in: 0.001...0.05,
|
|
398
|
-
step: 0.001
|
|
399
|
-
) {
|
|
400
|
-
Text("Scale")
|
|
401
|
-
}
|
|
276
|
+
Slider(value: $model.scale, in: 0.001...0.05, step: 0.001)
|
|
402
277
|
}
|
|
403
278
|
.padding()
|
|
404
|
-
.background(.ultraThinMaterial)
|
|
405
|
-
.clipShape(.rect(cornerRadius: 16))
|
|
279
|
+
.background(.ultraThinMaterial, in: .rect(cornerRadius: 20))
|
|
406
280
|
.padding()
|
|
407
281
|
}
|
|
408
282
|
}
|
|
409
283
|
```
|
|
410
284
|
|
|
411
|
-
|
|
285
|
+
`cameraReady()` is the permission helper from SKILL.md. The drag handler
|
|
286
|
+
guards for a parent entity instead of assuming one exists.
|
|
287
|
+
`generateCollisionShapes(recursive: true)` together with
|
|
288
|
+
`InputTargetComponent()` makes a loaded model interactive.
|
|
412
289
|
|
|
413
|
-
|
|
290
|
+
## Entity accessibility
|
|
414
291
|
|
|
415
292
|
```swift
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
model.components.set(accessibility)
|
|
293
|
+
@MainActor
|
|
294
|
+
func describe(_ door: Entity) {
|
|
295
|
+
var info = AccessibilityComponent()
|
|
296
|
+
info.isAccessibilityElement = true
|
|
297
|
+
info.label = "Garage door"
|
|
298
|
+
info.value = "Closed"
|
|
299
|
+
info.traits = [.button]
|
|
300
|
+
info.systemActions = [.activate]
|
|
301
|
+
door.components.set(info)
|
|
302
|
+
}
|
|
427
303
|
```
|
|
428
304
|
|
|
429
|
-
## Performance
|
|
430
|
-
|
|
431
|
-
### Entity Pooling
|
|
305
|
+
## Performance
|
|
432
306
|
|
|
433
|
-
|
|
307
|
+
Keep a pool of entities and recycle them, rather than allocating fresh ones
|
|
308
|
+
and throwing them away:
|
|
434
309
|
|
|
435
310
|
```swift
|
|
436
311
|
@MainActor
|
|
437
|
-
final class
|
|
438
|
-
private var
|
|
439
|
-
private let mesh:
|
|
440
|
-
private let
|
|
441
|
-
|
|
442
|
-
init(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
entity.isEnabled = false
|
|
448
|
-
available.append(entity)
|
|
312
|
+
final class DebrisPool {
|
|
313
|
+
private var idle: [ModelEntity] = []
|
|
314
|
+
private let mesh = MeshResource.generateBox(size: 0.02)
|
|
315
|
+
private let paint = [SimpleMaterial(color: .gray, isMetallic: false)]
|
|
316
|
+
|
|
317
|
+
init(size: Int) {
|
|
318
|
+
for _ in 0..<size {
|
|
319
|
+
let chip = ModelEntity(mesh: mesh, materials: paint)
|
|
320
|
+
chip.isEnabled = false
|
|
321
|
+
idle.append(chip)
|
|
449
322
|
}
|
|
450
323
|
}
|
|
451
324
|
|
|
452
|
-
func
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
457
|
-
return ModelEntity(mesh: mesh, materials: materials)
|
|
325
|
+
func take() -> ModelEntity {
|
|
326
|
+
let chip = idle.popLast() ?? ModelEntity(mesh: mesh, materials: paint)
|
|
327
|
+
chip.isEnabled = true
|
|
328
|
+
return chip
|
|
458
329
|
}
|
|
459
330
|
|
|
460
|
-
func
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
331
|
+
func giveBack(_ chip: ModelEntity) {
|
|
332
|
+
chip.isEnabled = false
|
|
333
|
+
chip.removeFromParent()
|
|
334
|
+
idle.append(chip)
|
|
464
335
|
}
|
|
465
336
|
}
|
|
466
337
|
```
|
|
467
338
|
|
|
468
|
-
|
|
339
|
+
Fewer draw calls:
|
|
469
340
|
|
|
470
|
-
- Merge static entities
|
|
471
|
-
- Use instancing for
|
|
472
|
-
-
|
|
473
|
-
-
|
|
341
|
+
- Merge static entities where you can.
|
|
342
|
+
- Use instancing for geometry that repeats.
|
|
343
|
+
- Keep the number of distinct materials low.
|
|
344
|
+
- Swap in lower-detail models as distance grows.
|
|
474
345
|
|
|
475
|
-
|
|
346
|
+
Memory:
|
|
476
347
|
|
|
477
|
-
- Unload entities
|
|
478
|
-
-
|
|
479
|
-
|
|
480
|
-
-
|
|
348
|
+
- Unload entities nobody can see.
|
|
349
|
+
- Load with `ModelEntity(named:in:)` and an explicit bundle to control where
|
|
350
|
+
resources come from.
|
|
351
|
+
- Profile with the RealityKit Trace template in Instruments.
|
|
352
|
+
- For entities you will show again, set `isEnabled = false` rather than removing
|
|
353
|
+
them.
|