@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,309 +1,266 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: swiftui-animation
|
|
3
|
-
description: "
|
|
3
|
+
description: "SwiftUI motion: withAnimation, scoped implicit .animation(_:body:) and .animation(_:value:), timing curves and springs (.smooth, .snappy, .bouncy, Spring), PhaseAnimator, KeyframeAnimator, @Animatable, matchedGeometryEffect and matchedTransitionSource zoom transitions, insertion and content transitions, SF Symbol effects (pulse, bounce, wiggle, rotate, breathe, variableColor), custom Transition and CustomAnimation, performance, Core Animation bridging. Use when implementing, reviewing or improving SwiftUI animations and transitions, or making them respect accessibilityReduceMotion."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# SwiftUI Animation (iOS 26+)
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## Contents
|
|
14
|
-
|
|
15
|
-
- [Triage Workflow](#triage-workflow)
|
|
16
|
-
- [withAnimation (Explicit Animation)](#withanimation-explicit-animation)
|
|
17
|
-
- [Implicit Animation](#implicit-animation)
|
|
18
|
-
- [Spring Type (iOS 17+)](#spring-type-ios-17)
|
|
19
|
-
- [PhaseAnimator (iOS 17+)](#phaseanimator-ios-17)
|
|
20
|
-
- [KeyframeAnimator (iOS 17+)](#keyframeanimator-ios-17)
|
|
21
|
-
- [`@Animatable Macro`](#animatable-macro)
|
|
22
|
-
- [matchedGeometryEffect (iOS 14+)](#matchedgeometryeffect-ios-14)
|
|
23
|
-
- [Navigation Zoom Transition (iOS 18+)](#navigation-zoom-transition-ios-18)
|
|
24
|
-
- [Transitions (iOS 17+)](#transitions-ios-17)
|
|
25
|
-
- [ContentTransition (iOS 16+)](#contenttransition-ios-16)
|
|
26
|
-
- [Symbol Effects (iOS 17+)](#symbol-effects-ios-17)
|
|
27
|
-
- [Symbol Rendering Modes](#symbol-rendering-modes)
|
|
28
|
-
- [Common Mistakes](#common-mistakes)
|
|
29
|
-
- [Review Checklist](#review-checklist)
|
|
30
|
-
- [References](#references)
|
|
31
|
-
|
|
32
|
-
## Triage Workflow
|
|
33
|
-
|
|
34
|
-
### Step 1: Identify the animation category
|
|
35
|
-
|
|
36
|
-
| Category | API | When to use |
|
|
37
|
-
|---|---|---|
|
|
38
|
-
| State-driven | `withAnimation`, `.animation(_:body:)`, `.animation(_:value:)` | Explicit state changes, selective modifier animation, or simple value-bound changes |
|
|
39
|
-
| Multi-phase | `PhaseAnimator` | Sequenced multi-step animations |
|
|
40
|
-
| Keyframe | `KeyframeAnimator` | Complex multi-property choreography |
|
|
41
|
-
| Shared element | `matchedGeometryEffect` | Layout-driven hero transitions |
|
|
42
|
-
| Navigation | `matchedTransitionSource` + `.navigationTransition(.zoom)` | NavigationStack push/pop zoom |
|
|
43
|
-
| View lifecycle | `.transition()` | Insertion and removal |
|
|
44
|
-
| Text content | `.contentTransition()` | In-place text/number changes |
|
|
45
|
-
| Symbol | `.symbolEffect()` | SF Symbol animations |
|
|
46
|
-
| Custom | `CustomAnimation` protocol | Novel timing curves |
|
|
47
|
-
|
|
48
|
-
### Step 2: Choose the animation curve
|
|
10
|
+
How to get timing, transitions and accessibility right with the current
|
|
11
|
+
animation APIs. Examples assume iOS 26 and Swift 6.3; sections name the
|
|
12
|
+
release an API first shipped in.
|
|
49
13
|
|
|
50
|
-
|
|
51
|
-
// Timing curves
|
|
52
|
-
.linear // constant speed
|
|
53
|
-
.easeIn(duration: 0.3) // slow start
|
|
54
|
-
.easeOut(duration: 0.3) // slow end
|
|
55
|
-
.easeInOut(duration: 0.3) // slow start and end
|
|
56
|
-
|
|
57
|
-
// Spring presets (preferred for natural motion)
|
|
58
|
-
.smooth // no bounce, fluid
|
|
59
|
-
.smooth(duration: 0.5, extraBounce: 0.0)
|
|
60
|
-
.snappy // small bounce, responsive
|
|
61
|
-
.snappy(duration: 0.4, extraBounce: 0.1)
|
|
62
|
-
.bouncy // visible bounce, playful
|
|
63
|
-
.bouncy(duration: 0.5, extraBounce: 0.2)
|
|
64
|
-
|
|
65
|
-
// Custom spring
|
|
66
|
-
.spring(duration: 0.5, bounce: 0.3, blendDuration: 0.0)
|
|
67
|
-
.spring(Spring(duration: 0.6, bounce: 0.2), blendDuration: 0.0)
|
|
68
|
-
.interactiveSpring(response: 0.15, dampingFraction: 0.86)
|
|
69
|
-
```
|
|
14
|
+
## Triage
|
|
70
15
|
|
|
71
|
-
###
|
|
16
|
+
### 1. Pick the tool for the job
|
|
72
17
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
18
|
+
| What moves | API |
|
|
19
|
+
|---|---|
|
|
20
|
+
| A state change you trigger, a few modifiers, or one value | `withAnimation`; `.animation(_:value:)`; `.animation(_:body:)` |
|
|
21
|
+
| A sequence of distinct steps | `PhaseAnimator` |
|
|
22
|
+
| Several properties on independent timelines | `KeyframeAnimator` |
|
|
23
|
+
| A shared element between two layouts | `matchedGeometryEffect` |
|
|
24
|
+
| A push or pop in `NavigationStack` that grows from a tile | `matchedTransitionSource` + `.navigationTransition(.zoom)` |
|
|
25
|
+
| A view being inserted or removed | `.transition()` |
|
|
26
|
+
| Text, numbers or a symbol changing in place | `.contentTransition()` |
|
|
27
|
+
| An SF Symbol reacting | `.symbolEffect()` |
|
|
28
|
+
| A timing curve no built-in covers | `CustomAnimation` |
|
|
76
29
|
|
|
77
|
-
|
|
30
|
+
### 2. Pick the curve
|
|
31
|
+
|
|
32
|
+
Timing curves suit mechanical motion:
|
|
78
33
|
|
|
79
34
|
```swift
|
|
80
|
-
|
|
35
|
+
.linear // constant speed
|
|
36
|
+
.easeIn(duration: 0.3) // starts slow
|
|
37
|
+
.easeOut(duration: 0.3) // ends slow
|
|
38
|
+
.easeInOut(duration: 0.3) // slow at both ends
|
|
39
|
+
```
|
|
81
40
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
41
|
+
Springs feel physical and are the better default for anything a person
|
|
42
|
+
touches or watches:
|
|
43
|
+
|
|
44
|
+
```swift
|
|
45
|
+
.smooth // settles with no overshoot
|
|
46
|
+
.smooth(duration: 0.6)
|
|
47
|
+
.snappy // quick, a hint of bounce
|
|
48
|
+
.snappy(duration: 0.3, extraBounce: 0.05)
|
|
49
|
+
.bouncy // noticeable, playful overshoot
|
|
50
|
+
.bouncy(duration: 0.6, extraBounce: 0.1)
|
|
51
|
+
|
|
52
|
+
.spring(duration: 0.45, bounce: 0.25, blendDuration: 0.1)
|
|
53
|
+
.spring(Spring(duration: 0.7, bounce: 0.15), blendDuration: 0.2)
|
|
54
|
+
.interactiveSpring(response: 0.2, dampingFraction: 0.8)
|
|
86
55
|
```
|
|
87
56
|
|
|
88
|
-
|
|
57
|
+
### 3. Apply, then check
|
|
58
|
+
|
|
59
|
+
- It fires on the state change you meant, and only that one.
|
|
60
|
+
- It still makes sense with Settings > Accessibility > Motion > Reduce Motion
|
|
61
|
+
on.
|
|
62
|
+
- Closures that run per frame do no expensive work.
|
|
89
63
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
64
|
+
## Explicit animation
|
|
65
|
+
|
|
66
|
+
Wrap the mutation, not the view:
|
|
93
67
|
|
|
94
68
|
```swift
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
content
|
|
99
|
-
.scaleEffect(isActive ? 1.15 : 1.0)
|
|
100
|
-
.opacity(isActive ? 1.0 : 0.7)
|
|
101
|
-
}
|
|
69
|
+
Button("Details") {
|
|
70
|
+
withAnimation(.spring) { showsDetails.toggle() }
|
|
71
|
+
}
|
|
102
72
|
```
|
|
103
73
|
|
|
74
|
+
From iOS 17, a completion runs when the animation is done:
|
|
75
|
+
|
|
104
76
|
```swift
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
77
|
+
withAnimation(.smooth(duration: 0.4), completionCriteria: .logicallyComplete) {
|
|
78
|
+
drawerOpen = true
|
|
79
|
+
} completion: {
|
|
80
|
+
loadDrawerContents()
|
|
81
|
+
}
|
|
109
82
|
```
|
|
110
83
|
|
|
111
|
-
##
|
|
84
|
+
## Implicit animation
|
|
112
85
|
|
|
113
|
-
|
|
86
|
+
- `.animation(_:body:)` (iOS 17) animates only the modifiers inside its body.
|
|
87
|
+
Prefer it when some modifiers should move and others should not.
|
|
88
|
+
- `.animation(_:value:)` animates every animatable modifier on the view when
|
|
89
|
+
`value` changes. Fine when one value drives everything.
|
|
114
90
|
|
|
115
91
|
```swift
|
|
116
|
-
|
|
117
|
-
|
|
92
|
+
Image(systemName: "heart.fill")
|
|
93
|
+
.foregroundStyle(isFavorite ? .pink : .gray) // changes instantly
|
|
94
|
+
.animation(.snappy) { content in
|
|
95
|
+
content
|
|
96
|
+
.scaleEffect(isFavorite ? 1.25 : 1)
|
|
97
|
+
.opacity(isFavorite ? 1 : 0.6)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
RoundedRectangle(cornerRadius: 8)
|
|
101
|
+
.scaleEffect(isRecording ? 1.1 : 1)
|
|
102
|
+
.opacity(isRecording ? 1 : 0.5)
|
|
103
|
+
.animation(.bouncy, value: isRecording)
|
|
104
|
+
```
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
Spring(mass: 1.0, stiffness: 100.0, damping: 10.0)
|
|
106
|
+
## Spring (iOS 17+)
|
|
121
107
|
|
|
122
|
-
|
|
123
|
-
|
|
108
|
+
`Spring` describes the physics on its own, so the same spring can drive
|
|
109
|
+
`Animation`, `CASpringAnimation` or your own math. Four ways to build one:
|
|
124
110
|
|
|
125
|
-
|
|
126
|
-
Spring(
|
|
111
|
+
```swift
|
|
112
|
+
Spring(duration: 0.4, bounce: 0.2) // perceptual: preferred
|
|
113
|
+
Spring(mass: 2.0, stiffness: 150.0, damping: 18.0) // physical
|
|
114
|
+
Spring(response: 0.4, dampingRatio: 0.75) // response-based
|
|
115
|
+
Spring(settlingDuration: 0.9, dampingRatio: 0.85) // settling-based
|
|
127
116
|
```
|
|
128
117
|
|
|
129
|
-
|
|
118
|
+
It has the same three presets as `Animation`: `.smooth`, `.snappy`, `.bouncy`.
|
|
130
119
|
|
|
131
120
|
## PhaseAnimator (iOS 17+)
|
|
132
121
|
|
|
133
|
-
|
|
122
|
+
Steps through a list of phases, with a separate curve for each step.
|
|
134
123
|
|
|
135
124
|
```swift
|
|
136
|
-
enum
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
} animation: { phase in
|
|
148
|
-
switch phase {
|
|
149
|
-
case .idle: .easeIn(duration: 0.2)
|
|
150
|
-
case .grow: .spring(duration: 0.4, bounce: 0.3)
|
|
151
|
-
case .shrink: .easeOut(duration: 0.3)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
125
|
+
enum Nudge: CaseIterable { case rest, lift, drop }
|
|
126
|
+
|
|
127
|
+
PhaseAnimator(Nudge.allCases) { phase in
|
|
128
|
+
Image(systemName: "bell.fill")
|
|
129
|
+
.scaleEffect(phase == .lift ? 1.3 : 1)
|
|
130
|
+
.opacity(phase == .drop ? 0.7 : 1)
|
|
131
|
+
} animation: { phase in
|
|
132
|
+
switch phase {
|
|
133
|
+
case .rest: .easeIn(duration: 0.2)
|
|
134
|
+
case .lift: .spring(duration: 0.35, bounce: 0.45)
|
|
135
|
+
case .drop: .easeOut(duration: 0.25)
|
|
154
136
|
}
|
|
155
137
|
}
|
|
156
138
|
```
|
|
157
139
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```swift
|
|
161
|
-
PhaseAnimator(PulsePhase.allCases, trigger: tapCount) { phase in
|
|
162
|
-
// ...
|
|
163
|
-
} animation: { _ in .spring(duration: 0.4) }
|
|
164
|
-
```
|
|
140
|
+
With no trigger it loops forever. `PhaseAnimator(_:trigger:content:animation:)`
|
|
141
|
+
plays the phases once each time `trigger` changes.
|
|
165
142
|
|
|
166
143
|
## KeyframeAnimator (iOS 17+)
|
|
167
144
|
|
|
168
|
-
|
|
145
|
+
Gives each property its own timeline.
|
|
169
146
|
|
|
170
147
|
```swift
|
|
171
|
-
struct
|
|
172
|
-
var scale
|
|
173
|
-
var
|
|
174
|
-
var opacity
|
|
148
|
+
struct HopValues {
|
|
149
|
+
var scale = 1.0
|
|
150
|
+
var lift = 0.0
|
|
151
|
+
var opacity = 1.0
|
|
175
152
|
}
|
|
176
153
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
KeyframeTrack(\.yOffset) {
|
|
198
|
-
CubicKeyframe(-30, duration: 0.2)
|
|
199
|
-
CubicKeyframe(0, duration: 0.4)
|
|
200
|
-
}
|
|
201
|
-
KeyframeTrack(\.opacity) {
|
|
202
|
-
LinearKeyframe(0.6, duration: 0.15)
|
|
203
|
-
LinearKeyframe(1.0, duration: 0.25)
|
|
204
|
-
}
|
|
205
|
-
}
|
|
154
|
+
Button { hops.toggle() } label: {
|
|
155
|
+
Image(systemName: "hare.fill")
|
|
156
|
+
.keyframeAnimator(initialValue: HopValues(), trigger: hops) { view, value in
|
|
157
|
+
view
|
|
158
|
+
.scaleEffect(value.scale)
|
|
159
|
+
.offset(y: value.lift)
|
|
160
|
+
.opacity(value.opacity)
|
|
161
|
+
} keyframes: { _ in
|
|
162
|
+
KeyframeTrack(\.lift) {
|
|
163
|
+
SpringKeyframe(-40, duration: 0.25)
|
|
164
|
+
CubicKeyframe(0, duration: 0.3)
|
|
165
|
+
}
|
|
166
|
+
KeyframeTrack(\.scale) {
|
|
167
|
+
LinearKeyframe(1.15, duration: 0.2)
|
|
168
|
+
SpringKeyframe(1.0, duration: 0.35)
|
|
169
|
+
}
|
|
170
|
+
KeyframeTrack(\.opacity) {
|
|
171
|
+
CubicKeyframe(0.8, duration: 0.2)
|
|
172
|
+
CubicKeyframe(1.0, duration: 0.35)
|
|
173
|
+
}
|
|
206
174
|
}
|
|
207
|
-
.buttonStyle(.plain)
|
|
208
|
-
}
|
|
209
175
|
}
|
|
176
|
+
.buttonStyle(.plain)
|
|
210
177
|
```
|
|
211
178
|
|
|
212
|
-
Keyframe
|
|
213
|
-
|
|
179
|
+
| Keyframe | Interpolation |
|
|
180
|
+
|---|---|
|
|
181
|
+
| `LinearKeyframe` | straight line |
|
|
182
|
+
| `CubicKeyframe` | smooth cubic curve |
|
|
183
|
+
| `SpringKeyframe` | spring physics |
|
|
184
|
+
| `MoveKeyframe` | jumps instantly |
|
|
214
185
|
|
|
215
|
-
|
|
186
|
+
`KeyframeAnimator(initialValue:repeating: true)` loops the whole sequence.
|
|
216
187
|
|
|
217
|
-
##
|
|
188
|
+
## @Animatable (Xcode 26 SDK)
|
|
218
189
|
|
|
219
|
-
|
|
220
|
-
|
|
190
|
+
The `@Animatable` macro writes the `animatableData` conformance for you.
|
|
191
|
+
Attach it to a type whose stored properties should interpolate. It ships with
|
|
192
|
+
the iOS 26 SDK but is declared available from iOS 13, so it also works in apps
|
|
193
|
+
that deploy to older releases.
|
|
221
194
|
|
|
222
195
|
```swift
|
|
223
|
-
// Replaces manual AnimatableData boilerplate
|
|
224
196
|
@Animatable
|
|
225
|
-
struct
|
|
226
|
-
var
|
|
227
|
-
var
|
|
228
|
-
var
|
|
229
|
-
@AnimatableIgnored var
|
|
197
|
+
struct RippleLine: Shape {
|
|
198
|
+
var wavelength: Double
|
|
199
|
+
var height: Double
|
|
200
|
+
var shift: Double
|
|
201
|
+
@AnimatableIgnored var strokeWidth: Double
|
|
230
202
|
|
|
231
203
|
func path(in rect: CGRect) -> Path {
|
|
232
|
-
|
|
204
|
+
let samples = stride(from: rect.minX, through: rect.maxX, by: 2).map { x in
|
|
205
|
+
CGPoint(x: x, y: rect.midY + sin(x / wavelength + shift) * height)
|
|
206
|
+
}
|
|
207
|
+
return Path { $0.addLines(samples) }
|
|
233
208
|
}
|
|
234
209
|
}
|
|
235
210
|
```
|
|
236
211
|
|
|
237
|
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
240
|
-
- Computed properties are never included.
|
|
212
|
+
- Every animated stored property must conform to `VectorArithmetic`.
|
|
213
|
+
- `@AnimatableIgnored` keeps a stored property out of the animation.
|
|
214
|
+
- Computed properties are never part of the animatable data.
|
|
241
215
|
|
|
242
216
|
## matchedGeometryEffect (iOS 14+)
|
|
243
217
|
|
|
244
|
-
|
|
218
|
+
Links the geometry of two views so one appears to become the other. Needs a
|
|
219
|
+
`@Namespace`.
|
|
245
220
|
|
|
246
221
|
```swift
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
} else {
|
|
263
|
-
Button {
|
|
264
|
-
withAnimation(.spring(duration: 0.4, bounce: 0.2)) {
|
|
265
|
-
isExpanded = true
|
|
266
|
-
}
|
|
267
|
-
} label: {
|
|
268
|
-
ThumbnailCard()
|
|
269
|
-
.matchedGeometryEffect(id: "card", in: heroSpace)
|
|
270
|
-
}
|
|
271
|
-
}
|
|
222
|
+
@Namespace private var photoSpace
|
|
223
|
+
@State private var enlarged = false
|
|
224
|
+
|
|
225
|
+
var body: some View {
|
|
226
|
+
let morph = Animation.spring(duration: 0.45, bounce: 0.15)
|
|
227
|
+
if enlarged {
|
|
228
|
+
Button { withAnimation(morph) { enlarged = false } } label: {
|
|
229
|
+
PhotoDetail(photo: photo)
|
|
230
|
+
.matchedGeometryEffect(id: photo.id, in: photoSpace)
|
|
231
|
+
}
|
|
232
|
+
.buttonStyle(.plain)
|
|
233
|
+
} else {
|
|
234
|
+
Button { withAnimation(morph) { enlarged = true } } label: {
|
|
235
|
+
PhotoThumbnail(photo: photo)
|
|
236
|
+
.matchedGeometryEffect(id: photo.id, in: photoSpace)
|
|
272
237
|
}
|
|
273
238
|
.buttonStyle(.plain)
|
|
274
239
|
}
|
|
275
240
|
}
|
|
276
241
|
```
|
|
277
242
|
|
|
278
|
-
|
|
243
|
+
At any instant only one view per id may be visible, or the interpolation has
|
|
244
|
+
nothing single to follow.
|
|
279
245
|
|
|
280
|
-
## Navigation
|
|
246
|
+
## Navigation zoom (iOS 18+)
|
|
281
247
|
|
|
282
|
-
|
|
283
|
-
`.navigationTransition(.zoom(
|
|
248
|
+
Mark the tile with `.matchedTransitionSource(id:in:)` and the pushed screen
|
|
249
|
+
with `.navigationTransition(.zoom(sourceID:in:))`:
|
|
284
250
|
|
|
285
251
|
```swift
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
.zoom(sourceID: item.id, in: zoomSpace)
|
|
299
|
-
)
|
|
300
|
-
} label: {
|
|
301
|
-
ItemThumbnail(item: item)
|
|
302
|
-
.matchedTransitionSource(
|
|
303
|
-
id: item.id, in: zoomSpace
|
|
304
|
-
)
|
|
305
|
-
}
|
|
306
|
-
}
|
|
252
|
+
@Namespace private var gallery
|
|
253
|
+
|
|
254
|
+
NavigationStack {
|
|
255
|
+
ScrollView {
|
|
256
|
+
LazyVGrid(columns: [GridItem(.adaptive(minimum: 120))]) {
|
|
257
|
+
ForEach(photos) { photo in
|
|
258
|
+
NavigationLink {
|
|
259
|
+
PhotoDetail(photo: photo)
|
|
260
|
+
.navigationTransition(.zoom(sourceID: photo.id, in: gallery))
|
|
261
|
+
} label: {
|
|
262
|
+
PhotoThumbnail(photo: photo)
|
|
263
|
+
.matchedTransitionSource(id: photo.id, in: gallery)
|
|
307
264
|
}
|
|
308
265
|
}
|
|
309
266
|
}
|
|
@@ -311,186 +268,146 @@ struct GalleryView: View {
|
|
|
311
268
|
}
|
|
312
269
|
```
|
|
313
270
|
|
|
314
|
-
|
|
271
|
+
`.navigationTransition` goes on the destination view itself, not on something
|
|
272
|
+
nested inside it.
|
|
315
273
|
|
|
316
|
-
## Transitions
|
|
274
|
+
## Transitions
|
|
317
275
|
|
|
318
|
-
|
|
276
|
+
`.transition()` describes how a view enters and leaves:
|
|
319
277
|
|
|
320
278
|
```swift
|
|
321
|
-
if
|
|
322
|
-
|
|
323
|
-
.transition(.
|
|
279
|
+
if showsToast {
|
|
280
|
+
ToastView(message: message)
|
|
281
|
+
.transition(.opacity.combined(with: .move(edge: .top)))
|
|
324
282
|
}
|
|
325
283
|
```
|
|
326
284
|
|
|
327
|
-
Built
|
|
328
|
-
`.
|
|
329
|
-
`.blurReplace`, `.blurReplace(_:)`, `.symbolEffect
|
|
285
|
+
Built in: `.identity`, `.opacity`, `.scale`, `.scale(_:anchor:)`, `.slide`,
|
|
286
|
+
`.offset(x:y:)`, `.move(edge:)` and `.push(from:)`. iOS 17 added
|
|
287
|
+
`.blurReplace`, `.blurReplace(_:)`, `.symbolEffect` and
|
|
330
288
|
`.symbolEffect(_:options:)`.
|
|
331
289
|
|
|
332
|
-
|
|
290
|
+
Different ways in and out:
|
|
333
291
|
|
|
334
292
|
```swift
|
|
335
|
-
.transition(.asymmetric(
|
|
336
|
-
insertion: .push(from: .bottom),
|
|
337
|
-
removal: .opacity
|
|
338
|
-
))
|
|
293
|
+
.transition(.asymmetric(insertion: .push(from: .trailing), removal: .scale))
|
|
339
294
|
```
|
|
340
295
|
|
|
341
|
-
|
|
296
|
+
Custom `Transition` types are in the advanced reference.
|
|
342
297
|
|
|
343
|
-
|
|
298
|
+
## Content transitions
|
|
299
|
+
|
|
300
|
+
`.contentTransition` animates a change inside a view that stays in place.
|
|
301
|
+
It needs an animation to show anything.
|
|
344
302
|
|
|
345
303
|
```swift
|
|
346
|
-
Text("\(
|
|
304
|
+
Text("\(stepCount)")
|
|
347
305
|
.contentTransition(.numericText(countsDown: false))
|
|
348
|
-
.animation(.snappy, value:
|
|
306
|
+
.animation(.snappy, value: stepCount)
|
|
349
307
|
|
|
350
|
-
|
|
351
|
-
Image(systemName: isMuted ? "speaker.slash" : "speaker.wave.3")
|
|
308
|
+
Image(systemName: isMuted ? "speaker.slash.fill" : "speaker.wave.2.fill")
|
|
352
309
|
.contentTransition(.symbolEffect(.replace.downUp))
|
|
353
310
|
```
|
|
354
311
|
|
|
355
|
-
|
|
356
|
-
`.numericText(
|
|
312
|
+
Kinds: `.identity`, `.interpolate`, `.opacity`, `.numericText(countsDown:)`,
|
|
313
|
+
`.numericText(value:)` (iOS 17), `.symbolEffect` (iOS 17).
|
|
357
314
|
|
|
358
|
-
## Symbol
|
|
315
|
+
## Symbol effects (iOS 17+)
|
|
359
316
|
|
|
360
|
-
|
|
317
|
+
Discrete effects play once when a value changes; indefinite ones run while a
|
|
318
|
+
condition is true.
|
|
361
319
|
|
|
362
320
|
```swift
|
|
363
|
-
|
|
364
|
-
Image(systemName: "bell
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
Image(systemName: "arrow.clockwise")
|
|
368
|
-
.symbolEffect(.wiggle.clockwise, value: refreshCount)
|
|
369
|
-
|
|
370
|
-
// Indefinite (active while condition holds)
|
|
321
|
+
Image(systemName: "envelope").symbolEffect(.bounce, value: unreadCount)
|
|
322
|
+
Image(systemName: "bell").symbolEffect(.wiggle.clockwise, value: alertCount) // iOS 18
|
|
323
|
+
Image(systemName: "mic.fill").symbolEffect(.pulse, isActive: isListening)
|
|
324
|
+
Image(systemName: "lungs.fill").symbolEffect(.breathe, isActive: isResting) // iOS 18
|
|
371
325
|
Image(systemName: "wifi")
|
|
372
|
-
.symbolEffect(.
|
|
373
|
-
|
|
374
|
-
Image(systemName: "mic.fill")
|
|
375
|
-
.symbolEffect(.breathe, isActive: isRecording)
|
|
376
|
-
|
|
377
|
-
// Variable color with chaining
|
|
378
|
-
Image(systemName: "speaker.wave.3.fill")
|
|
379
|
-
.symbolEffect(
|
|
380
|
-
.variableColor.iterative.reversing.dimInactiveLayers,
|
|
381
|
-
options: .repeating,
|
|
382
|
-
isActive: isPlaying
|
|
383
|
-
)
|
|
326
|
+
.symbolEffect(.variableColor.iterative.reversing.dimInactiveLayers,
|
|
327
|
+
options: .repeating, isActive: isSearching)
|
|
384
328
|
```
|
|
385
329
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
330
|
+
Effects: `.appear`, `.disappear`, `.replace`, `.scale`, `.pulse`, `.bounce`
|
|
331
|
+
and `.variableColor`; iOS 18 adds `.wiggle`, `.rotate` and `.breathe`.
|
|
332
|
+
Most accept a scope, `.byLayer` or `.wholeSymbol`; which directions are
|
|
333
|
+
available depends on the effect.
|
|
390
334
|
|
|
391
|
-
|
|
335
|
+
### Rendering modes
|
|
392
336
|
|
|
393
|
-
|
|
337
|
+
`.symbolRenderingMode(_:)` decides how a symbol's layers are coloured.
|
|
394
338
|
|
|
395
|
-
| Mode |
|
|
396
|
-
|
|
397
|
-
| `.monochrome` |
|
|
398
|
-
| `.hierarchical` |
|
|
399
|
-
| `.multicolor` |
|
|
400
|
-
| `.palette` |
|
|
339
|
+
| Mode | Result | Good for |
|
|
340
|
+
|---|---|---|
|
|
341
|
+
| `.monochrome` (default) | one colour everywhere | toolbar icons that match text |
|
|
342
|
+
| `.hierarchical` | one colour, layers at stepped opacity | depth without extra colours |
|
|
343
|
+
| `.multicolor` | the symbol's own fixed colours | weather, file types, the intended palette |
|
|
344
|
+
| `.palette` | your colours per layer via `.foregroundStyle(_:_:)` | brand or custom multi-colour icons |
|
|
401
345
|
|
|
402
346
|
```swift
|
|
403
|
-
|
|
404
|
-
Image(systemName: "speaker.wave.3.fill")
|
|
347
|
+
Image(systemName: "folder.fill.badge.gearshape")
|
|
405
348
|
.symbolRenderingMode(.hierarchical)
|
|
406
|
-
.foregroundStyle(.
|
|
349
|
+
.foregroundStyle(.teal)
|
|
407
350
|
|
|
408
|
-
|
|
409
|
-
Image(systemName: "person.crop.circle.badge.plus")
|
|
351
|
+
Image(systemName: "person.2.badge.plus.fill")
|
|
410
352
|
.symbolRenderingMode(.palette)
|
|
411
|
-
.foregroundStyle(.
|
|
353
|
+
.foregroundStyle(.indigo, .orange)
|
|
412
354
|
|
|
413
|
-
|
|
414
|
-
Image(systemName: "cloud.sun.rain.fill")
|
|
355
|
+
Image(systemName: "cloud.bolt.rain.fill")
|
|
415
356
|
.symbolRenderingMode(.multicolor)
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
**Variable color:** `.symbolVariableColor(value:)` for percentage-based fill (signal strength, volume):
|
|
419
|
-
|
|
420
|
-
```swift
|
|
421
|
-
Image(systemName: "wifi")
|
|
422
|
-
.symbolVariableColor(value: signalStrength) // 0.0-1.0
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
> **Docs:** [SymbolRenderingMode](https://sosumi.ai/documentation/swiftui/symbolrenderingmode) · [symbolRenderingMode(_:)](https://sosumi.ai/documentation/swiftui/view/symbolrenderingmode(_:))
|
|
426
|
-
|
|
427
|
-
## Common Mistakes
|
|
428
|
-
|
|
429
|
-
### 1. Using bare `.animation(_:)` when you need precise scope
|
|
430
|
-
|
|
431
|
-
```swift
|
|
432
|
-
// TOO BROAD - applies when the view changes
|
|
433
|
-
.animation(.easeIn)
|
|
434
|
-
|
|
435
|
-
// CORRECT - bind animation to one value
|
|
436
|
-
.animation(.easeIn, value: isVisible)
|
|
437
357
|
|
|
438
|
-
|
|
439
|
-
.animation(.easeIn) { content in
|
|
440
|
-
content.opacity(isVisible ? 1.0 : 0.0)
|
|
441
|
-
}
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
### 2. Expensive work inside animation closures
|
|
445
|
-
|
|
446
|
-
Never run heavy computation in `keyframeAnimator` / `PhaseAnimator` content closures - they execute every frame. Precompute outside, animate only visual properties.
|
|
447
|
-
|
|
448
|
-
### 3. Missing reduce motion support
|
|
449
|
-
|
|
450
|
-
```swift
|
|
451
|
-
@Environment(\.accessibilityReduceMotion) private var reduceMotion
|
|
452
|
-
withAnimation(reduceMotion ? .none : .bouncy) { showDetail = true }
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### 4. Multiple matchedGeometryEffect sources
|
|
456
|
-
|
|
457
|
-
Only one view per ID should be visible at a time. Two visible views with the same ID causes undefined layout.
|
|
458
|
-
|
|
459
|
-
### 5. Using DispatchQueue or UIView.animate
|
|
460
|
-
|
|
461
|
-
```swift
|
|
462
|
-
// WRONG
|
|
463
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { withAnimation { isVisible = true } }
|
|
464
|
-
// CORRECT
|
|
465
|
-
withAnimation(.spring.delay(0.5)) { isVisible = true }
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
### 6. Forgetting animation on ContentTransition
|
|
469
|
-
|
|
470
|
-
```swift
|
|
471
|
-
// WRONG - no animation, content transition has no effect
|
|
472
|
-
Text("\(count)").contentTransition(.numericText(countsDown: true))
|
|
473
|
-
// CORRECT - pair with animation
|
|
474
|
-
Text("\(count)")
|
|
475
|
-
.contentTransition(.numericText(countsDown: true))
|
|
476
|
-
.animation(.snappy, value: count)
|
|
358
|
+
Image(systemName: "cellularbars", variableValue: signalLevel)
|
|
477
359
|
```
|
|
478
360
|
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
361
|
+
Symbols with variable colour show a level, such as signal strength or volume,
|
|
362
|
+
from a value between 0.0 and 1.0. The value is passed to the image itself
|
|
363
|
+
through `Image(systemName:variableValue:)`; there is no separate modifier for
|
|
364
|
+
it.
|
|
365
|
+
|
|
366
|
+
Apple docs:
|
|
367
|
+
[SymbolRenderingMode](https://developer.apple.com/documentation/swiftui/symbolrenderingmode),
|
|
368
|
+
[symbolRenderingMode(_:)](https://developer.apple.com/documentation/swiftui/view/symbolrenderingmode(_:)).
|
|
369
|
+
|
|
370
|
+
## Common mistakes
|
|
371
|
+
|
|
372
|
+
1. **Bare `.animation(_:)` with no value.** It animates every change that
|
|
373
|
+
reaches the view. Use `.animation(_:value:)` or `.animation(_:body:)`.
|
|
374
|
+
2. **Work inside `KeyframeAnimator` or `PhaseAnimator` content.** Those
|
|
375
|
+
closures run every frame. Compute beforehand; only apply visual modifiers.
|
|
376
|
+
3. **Ignoring Reduce Motion.** Read `@Environment(\.accessibilityReduceMotion)`
|
|
377
|
+
and pass `.none` (or a gentler curve) when it is on.
|
|
378
|
+
4. **Two visible views sharing a `matchedGeometryEffect` id.** Layout becomes
|
|
379
|
+
undefined.
|
|
380
|
+
5. **Delaying with `DispatchQueue.main.asyncAfter` plus `withAnimation`, or
|
|
381
|
+
reaching for `UIView.animate`.** Use `Animation.delay(_:)`, for example
|
|
382
|
+
`.spring.delay(0.5)`.
|
|
383
|
+
6. **`.contentTransition` with no animation.** Nothing visible happens; add
|
|
384
|
+
`.animation(_:value:)`.
|
|
385
|
+
7. **`.navigationTransition(.zoom(sourceID:in:))` on an inner container.** Put
|
|
386
|
+
it on the outermost destination view.
|
|
387
|
+
|
|
388
|
+
## Review checklist
|
|
389
|
+
|
|
390
|
+
- [ ] Curve fits the intent: a spring for natural motion, an ease curve for
|
|
391
|
+
mechanical motion
|
|
392
|
+
- [ ] State changes sit inside `withAnimation`; implicit animation is either
|
|
393
|
+
scoped with `.animation(_:body:)` or tied to a value with
|
|
394
|
+
`.animation(_:value:)`
|
|
395
|
+
- [ ] One visible `matchedGeometryEffect` source per id; zoom source and
|
|
396
|
+
destination share id and namespace
|
|
397
|
+
- [ ] `@Animatable` used instead of hand-written `animatableData`
|
|
398
|
+
- [ ] `accessibilityReduceMotion` respected; no `DispatchQueue` timing, no
|
|
399
|
+
`UIView.animate`
|
|
400
|
+
- [ ] Insertions and removals use `.transition()`; each `contentTransition`
|
|
401
|
+
has an animation, with the narrowest implicit scope that works
|
|
402
|
+
- [ ] State that drives animation changes on `@MainActor`, and the types
|
|
403
|
+
involved are `Sendable`
|
|
492
404
|
|
|
493
405
|
## References
|
|
494
406
|
|
|
495
|
-
-
|
|
496
|
-
|
|
407
|
+
- [Advanced animation](references/animation-advanced.md): `CustomAnimation`,
|
|
408
|
+
every `Spring` initializer, `UnitCurve`, deeper `PhaseAnimator` and
|
|
409
|
+
`KeyframeAnimator` patterns, `Transaction` and `TransactionKey`, all
|
|
410
|
+
transition types including custom ones, every symbol effect option, Reduce
|
|
411
|
+
Motion patterns, performance.
|
|
412
|
+
- [Core Animation bridge](references/core-animation-bridge.md): when to drop to
|
|
413
|
+
`CALayer` animation and how to host it in SwiftUI.
|