lottie-ios 3.4.3 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/.github/FUNDING.yml +0 -11
  2. package/Lottie.xcodeproj/project.pbxproj +58 -58
  3. package/Lottie.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +22 -0
  4. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +2 -2
  5. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +1 -1
  7. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +10 -7
  8. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +2 -2
  9. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +2 -2
  10. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +2 -2
  11. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
  12. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +3 -3
  13. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +16 -16
  14. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +11 -11
  15. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +4 -4
  16. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +13 -13
  17. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +3 -3
  18. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +1 -1
  19. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +1 -1
  20. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
  21. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
  22. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +9 -9
  23. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +1 -1
  24. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +1 -1
  25. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +2 -2
  26. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +1 -1
  27. package/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +2 -2
  28. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +3 -3
  29. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +10 -10
  30. package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +1 -1
  31. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +3 -3
  32. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +2 -2
  33. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +5 -5
  34. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +3 -3
  35. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +9 -9
  36. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +14 -14
  37. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +2 -2
  38. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +3 -3
  39. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +10 -10
  40. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +14 -14
  41. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +11 -11
  42. package/Sources/Private/Model/Keyframes/KeyframeData.swift +12 -12
  43. package/Sources/Private/Model/Layers/PreCompLayerModel.swift +3 -3
  44. package/Sources/Private/Model/Objects/DashPattern.swift +2 -2
  45. package/Sources/Private/Model/Objects/Marker.swift +4 -0
  46. package/Sources/Private/Model/Objects/Mask.swift +10 -8
  47. package/Sources/Private/Model/Objects/Transform.swift +39 -35
  48. package/Sources/Private/Model/ShapeItems/Ellipse.swift +6 -6
  49. package/Sources/Private/Model/ShapeItems/Fill.swift +6 -6
  50. package/Sources/Private/Model/ShapeItems/GradientFill.swift +15 -15
  51. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +18 -18
  52. package/Sources/Private/Model/ShapeItems/Rectangle.swift +9 -9
  53. package/Sources/Private/Model/ShapeItems/Repeater.swift +37 -32
  54. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +34 -28
  55. package/Sources/Private/Model/ShapeItems/Star.swift +21 -21
  56. package/Sources/Private/Model/ShapeItems/Stroke.swift +9 -9
  57. package/Sources/Private/Model/ShapeItems/Trim.swift +9 -9
  58. package/Sources/Private/Model/Text/TextAnimator.swift +33 -33
  59. package/Sources/Private/Model/Text/TextDocument.swift +8 -8
  60. package/Sources/Private/RootAnimationLayer.swift +4 -4
  61. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +1 -1
  62. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +4 -4
  63. package/Sources/Private/Utility/Primitives/ColorExtension.swift +7 -7
  64. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +29 -21
  65. package/Sources/{Private/Model/Animation.swift → Public/Animation/LottieAnimation.swift} +13 -5
  66. package/Sources/Public/Animation/{AnimationPublic.swift → LottieAnimationHelpers.swift} +32 -17
  67. package/Sources/Public/Animation/{AnimationView.swift → LottieAnimationView.swift} +68 -19
  68. package/Sources/Public/Animation/{AnimationViewInitializers.swift → LottieAnimationViewInitializers.swift} +6 -6
  69. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +3 -3
  70. package/Sources/Public/AnimationCache/LRUAnimationCache.swift +3 -3
  71. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +3 -3
  72. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +2 -2
  73. package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +10 -10
  74. package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +4 -4
  75. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +5 -5
  76. package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +2 -2
  77. package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +2 -2
  78. package/Sources/Public/FontProvider/AnimationFontProvider.swift +1 -1
  79. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +2 -2
  80. package/Sources/Public/Keyframes/Interpolatable.swift +17 -17
  81. package/Sources/Public/Keyframes/Keyframe.swift +10 -10
  82. package/Sources/Public/LottieConfiguration.swift +1 -1
  83. package/Sources/Public/Primitives/{Color.swift → LottieColor.swift} +10 -2
  84. package/Sources/Public/Primitives/Vectors.swift +18 -2
  85. package/Sources/Public/TextProvider/AnimationTextProvider.swift +1 -1
  86. package/Sources/Public/iOS/AnimatedButton.swift +26 -24
  87. package/Sources/Public/iOS/AnimatedControl.swift +6 -6
  88. package/Sources/Public/iOS/AnimatedSwitch.swift +16 -11
  89. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +23 -8
  90. package/Sources/Public/iOS/{AnimationViewBase.swift → LottieAnimationViewBase.swift} +4 -4
  91. package/Sources/Public/iOS/UIColorExtension.swift +2 -2
  92. package/Sources/Public/macOS/{AnimationViewBase.macOS.swift → LottieAnimationViewBase.macOS.swift} +4 -4
  93. package/Tests/AnimationKeypathTests.swift +1 -1
  94. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~22UHuHHSTYh5NFeueXXSDdev_8VAbw8H8yl2ICssaC0vaCLj2G2CGZCjUMEyki9c-k-CecFJRyspvzJLiQTjUw== +0 -0
  95. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +1 -0
  96. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~6DmZhylL-XQx-O08NugyWINI0ugrLVgVOpbrdp0sT2tEqw-jVD2vvBWYRnYHALkM2_qP2yy-VoovSMzfYALY8A== +0 -0
  97. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~9dj3E5foFK2l_1CEpoRxToU1N6jCdhRVc5vhR10fHS938L9w8HxbiVCPGxYy5981O6M1yZsD4tHFbqBMbER4bQ== +0 -0
  98. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Bys36bGK_YkCjRNoPMkq3R0OcyPNrVNka1Gz45ilbXJTqp9xAJexx6qKBh86_fm7OgBCO0WS2gJBy77DUUnOOA== +1 -0
  99. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~QJMKb50ZfaWLSHxBSGPlrzULLCqTlb_6W-X0N1-e5PfwCKjpYKOElImsOwgZKVK0cdyf-6u4Zp3mm3BfGQVQ9Q== +0 -0
  100. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~YyEdK1WNFTPo-R3Og2OWduKSikuFYneXurEZbyNLZeDmJLJkd7Ew8jNxy4mvgZw4f4Sikp4swEjJgVzXqhev5g== +1 -0
  101. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~bZd73QR3pWGndrn46_NXJw2dUT7WdBjkH5fdPZ7EnzlcZ9Ifv6WR14RKeWI9diiEjcRJE7ZOWqZ9fzf2vvTnLw== +0 -0
  102. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~baCaLsz8Sq-r6sHhJcZeowVdrnrIxKwDps5Q1Aq38G2AQ3HaopZ9m3A8IXtTFSiZGNiO2qnM9yH7iJfuzC5K0A== +0 -0
  103. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~iZXYCVJLYHKtR7eFHwefLiejC9CkRbBBSkkZmwfkiDEIdUKE4GgVkdDrcHry91RF7d9y7AuYovfGVp1-fuNg0g== +0 -0
  104. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~pTTJImrF4EktmVXGCigWBn7v6YlbH5eFCXIW35CW-iyypvzFMXXYYbQO1ly6Bf3u6CdaepZko-L9obC1mjigMA== +0 -0
  105. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~sVXLeN9UCp6IsOPeuoY76nF-bP-w2rBm61UYvs5XE3o5XhbM7itN2s1XD5i9COIaVMytmUFB-mvCLCqHfHWwpw== +0 -0
  106. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~t8Vsjx3tjPBGQIElMCvqzxLS0hDmBGuLa_CEiB64N2Vxp3qoUfNF0Sar84QnEDOKfyVF6c1KTn1QYg7fRJrk8g== +0 -0
  107. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~zUmPx8nRHLa8-g1WWSYYzveS_6qmBf-y4xyS-dHzD7c_xWwPZlsfKg8UngImNdn0gxGOBSRmCeXbYwWpLfj_Rg== +0 -0
  108. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~22UHuHHSTYh5NFeueXXSDdev_8VAbw8H8yl2ICssaC0vaCLj2G2CGZCjUMEyki9c-k-CecFJRyspvzJLiQTjUw== +0 -0
  109. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -0
  110. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~6DmZhylL-XQx-O08NugyWINI0ugrLVgVOpbrdp0sT2tEqw-jVD2vvBWYRnYHALkM2_qP2yy-VoovSMzfYALY8A== +0 -0
  111. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~9dj3E5foFK2l_1CEpoRxToU1N6jCdhRVc5vhR10fHS938L9w8HxbiVCPGxYy5981O6M1yZsD4tHFbqBMbER4bQ== +0 -0
  112. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Bys36bGK_YkCjRNoPMkq3R0OcyPNrVNka1Gz45ilbXJTqp9xAJexx6qKBh86_fm7OgBCO0WS2gJBy77DUUnOOA== +0 -0
  113. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~QJMKb50ZfaWLSHxBSGPlrzULLCqTlb_6W-X0N1-e5PfwCKjpYKOElImsOwgZKVK0cdyf-6u4Zp3mm3BfGQVQ9Q== +0 -0
  114. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~YyEdK1WNFTPo-R3Og2OWduKSikuFYneXurEZbyNLZeDmJLJkd7Ew8jNxy4mvgZw4f4Sikp4swEjJgVzXqhev5g== +0 -0
  115. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~bZd73QR3pWGndrn46_NXJw2dUT7WdBjkH5fdPZ7EnzlcZ9Ifv6WR14RKeWI9diiEjcRJE7ZOWqZ9fzf2vvTnLw== +0 -0
  116. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~baCaLsz8Sq-r6sHhJcZeowVdrnrIxKwDps5Q1Aq38G2AQ3HaopZ9m3A8IXtTFSiZGNiO2qnM9yH7iJfuzC5K0A== +0 -0
  117. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~iZXYCVJLYHKtR7eFHwefLiejC9CkRbBBSkkZmwfkiDEIdUKE4GgVkdDrcHry91RF7d9y7AuYovfGVp1-fuNg0g== +0 -0
  118. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~pTTJImrF4EktmVXGCigWBn7v6YlbH5eFCXIW35CW-iyypvzFMXXYYbQO1ly6Bf3u6CdaepZko-L9obC1mjigMA== +0 -0
  119. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~sVXLeN9UCp6IsOPeuoY76nF-bP-w2rBm61UYvs5XE3o5XhbM7itN2s1XD5i9COIaVMytmUFB-mvCLCqHfHWwpw== +0 -0
  120. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~t8Vsjx3tjPBGQIElMCvqzxLS0hDmBGuLa_CEiB64N2Vxp3qoUfNF0Sar84QnEDOKfyVF6c1KTn1QYg7fRJrk8g== +0 -0
  121. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~zUmPx8nRHLa8-g1WWSYYzveS_6qmBf-y4xyS-dHzD7c_xWwPZlsfKg8UngImNdn0gxGOBSRmCeXbYwWpLfj_Rg== +0 -0
  122. package/Tests/Artifacts/LottieTests.xcresult/Info.plist +29 -0
  123. package/Tests/ParsingTests.swift +2 -2
  124. package/Tests/PerformanceTests.swift +9 -9
  125. package/Tests/SnapshotConfiguration.swift +4 -4
  126. package/Tests/SnapshotTests.swift +6 -6
  127. package/lottie-ios.podspec +1 -1
  128. package/package.json +1 -1
@@ -15,74 +15,74 @@ final class TextAnimator: Codable, DictionaryInitializable {
15
15
  let container = try decoder.container(keyedBy: TextAnimator.CodingKeys.self)
16
16
  name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
17
17
  let animatorContainer = try container.nestedContainer(keyedBy: TextAnimatorKeys.self, forKey: .textAnimator)
18
- fillColor = try animatorContainer.decodeIfPresent(KeyframeGroup<Color>.self, forKey: .fillColor)
19
- strokeColor = try animatorContainer.decodeIfPresent(KeyframeGroup<Color>.self, forKey: .strokeColor)
20
- strokeWidth = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .strokeWidth)
21
- tracking = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .tracking)
22
- anchor = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector3D>.self, forKey: .anchor)
23
- position = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector3D>.self, forKey: .position)
24
- scale = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector3D>.self, forKey: .scale)
25
- skew = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .skew)
26
- skewAxis = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .skewAxis)
27
- rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .rotation)
28
- opacity = try animatorContainer.decodeIfPresent(KeyframeGroup<Vector1D>.self, forKey: .opacity)
18
+ fillColor = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieColor>.self, forKey: .fillColor)
19
+ strokeColor = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieColor>.self, forKey: .strokeColor)
20
+ strokeWidth = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .strokeWidth)
21
+ tracking = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .tracking)
22
+ anchor = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .anchor)
23
+ position = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .position)
24
+ scale = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .scale)
25
+ skew = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skew)
26
+ skewAxis = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skewAxis)
27
+ rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation)
28
+ opacity = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .opacity)
29
29
  }
30
30
 
31
31
  init(dictionary: [String: Any]) throws {
32
32
  name = (try? dictionary.value(for: CodingKeys.name)) ?? ""
33
33
  let animatorDictionary: [String: Any] = try dictionary.value(for: CodingKeys.textAnimator)
34
34
  if let fillColorDictionary = animatorDictionary[TextAnimatorKeys.fillColor.rawValue] as? [String: Any] {
35
- fillColor = try? KeyframeGroup<Color>(dictionary: fillColorDictionary)
35
+ fillColor = try? KeyframeGroup<LottieColor>(dictionary: fillColorDictionary)
36
36
  } else {
37
37
  fillColor = nil
38
38
  }
39
39
  if let strokeColorDictionary = animatorDictionary[TextAnimatorKeys.strokeColor.rawValue] as? [String: Any] {
40
- strokeColor = try? KeyframeGroup<Color>(dictionary: strokeColorDictionary)
40
+ strokeColor = try? KeyframeGroup<LottieColor>(dictionary: strokeColorDictionary)
41
41
  } else {
42
42
  strokeColor = nil
43
43
  }
44
44
  if let strokeWidthDictionary = animatorDictionary[TextAnimatorKeys.strokeWidth.rawValue] as? [String: Any] {
45
- strokeWidth = try? KeyframeGroup<Vector1D>(dictionary: strokeWidthDictionary)
45
+ strokeWidth = try? KeyframeGroup<LottieVector1D>(dictionary: strokeWidthDictionary)
46
46
  } else {
47
47
  strokeWidth = nil
48
48
  }
49
49
  if let trackingDictionary = animatorDictionary[TextAnimatorKeys.tracking.rawValue] as? [String: Any] {
50
- tracking = try? KeyframeGroup<Vector1D>(dictionary: trackingDictionary)
50
+ tracking = try? KeyframeGroup<LottieVector1D>(dictionary: trackingDictionary)
51
51
  } else {
52
52
  tracking = nil
53
53
  }
54
54
  if let anchorDictionary = animatorDictionary[TextAnimatorKeys.anchor.rawValue] as? [String: Any] {
55
- anchor = try? KeyframeGroup<Vector3D>(dictionary: anchorDictionary)
55
+ anchor = try? KeyframeGroup<LottieVector3D>(dictionary: anchorDictionary)
56
56
  } else {
57
57
  anchor = nil
58
58
  }
59
59
  if let positionDictionary = animatorDictionary[TextAnimatorKeys.position.rawValue] as? [String: Any] {
60
- position = try? KeyframeGroup<Vector3D>(dictionary: positionDictionary)
60
+ position = try? KeyframeGroup<LottieVector3D>(dictionary: positionDictionary)
61
61
  } else {
62
62
  position = nil
63
63
  }
64
64
  if let scaleDictionary = animatorDictionary[TextAnimatorKeys.scale.rawValue] as? [String: Any] {
65
- scale = try? KeyframeGroup<Vector3D>(dictionary: scaleDictionary)
65
+ scale = try? KeyframeGroup<LottieVector3D>(dictionary: scaleDictionary)
66
66
  } else {
67
67
  scale = nil
68
68
  }
69
69
  if let skewDictionary = animatorDictionary[TextAnimatorKeys.skew.rawValue] as? [String: Any] {
70
- skew = try? KeyframeGroup<Vector1D>(dictionary: skewDictionary)
70
+ skew = try? KeyframeGroup<LottieVector1D>(dictionary: skewDictionary)
71
71
  } else {
72
72
  skew = nil
73
73
  }
74
74
  if let skewAxisDictionary = animatorDictionary[TextAnimatorKeys.skewAxis.rawValue] as? [String: Any] {
75
- skewAxis = try? KeyframeGroup<Vector1D>(dictionary: skewAxisDictionary)
75
+ skewAxis = try? KeyframeGroup<LottieVector1D>(dictionary: skewAxisDictionary)
76
76
  } else {
77
77
  skewAxis = nil
78
78
  }
79
79
  if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotation.rawValue] as? [String: Any] {
80
- rotation = try? KeyframeGroup<Vector1D>(dictionary: rotationDictionary)
80
+ rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
81
81
  } else {
82
82
  rotation = nil
83
83
  }
84
84
  if let opacityDictionary = animatorDictionary[TextAnimatorKeys.opacity.rawValue] as? [String: Any] {
85
- opacity = try KeyframeGroup<Vector1D>(dictionary: opacityDictionary)
85
+ opacity = try KeyframeGroup<LottieVector1D>(dictionary: opacityDictionary)
86
86
  } else {
87
87
  opacity = nil
88
88
  }
@@ -93,37 +93,37 @@ final class TextAnimator: Codable, DictionaryInitializable {
93
93
  let name: String
94
94
 
95
95
  /// Anchor
96
- let anchor: KeyframeGroup<Vector3D>?
96
+ let anchor: KeyframeGroup<LottieVector3D>?
97
97
 
98
98
  /// Position
99
- let position: KeyframeGroup<Vector3D>?
99
+ let position: KeyframeGroup<LottieVector3D>?
100
100
 
101
101
  /// Scale
102
- let scale: KeyframeGroup<Vector3D>?
102
+ let scale: KeyframeGroup<LottieVector3D>?
103
103
 
104
104
  /// Skew
105
- let skew: KeyframeGroup<Vector1D>?
105
+ let skew: KeyframeGroup<LottieVector1D>?
106
106
 
107
107
  /// Skew Axis
108
- let skewAxis: KeyframeGroup<Vector1D>?
108
+ let skewAxis: KeyframeGroup<LottieVector1D>?
109
109
 
110
110
  /// Rotation
111
- let rotation: KeyframeGroup<Vector1D>?
111
+ let rotation: KeyframeGroup<LottieVector1D>?
112
112
 
113
113
  /// Opacity
114
- let opacity: KeyframeGroup<Vector1D>?
114
+ let opacity: KeyframeGroup<LottieVector1D>?
115
115
 
116
116
  /// Stroke Color
117
- let strokeColor: KeyframeGroup<Color>?
117
+ let strokeColor: KeyframeGroup<LottieColor>?
118
118
 
119
119
  /// Fill Color
120
- let fillColor: KeyframeGroup<Color>?
120
+ let fillColor: KeyframeGroup<LottieColor>?
121
121
 
122
122
  /// Stroke Width
123
- let strokeWidth: KeyframeGroup<Vector1D>?
123
+ let strokeWidth: KeyframeGroup<LottieVector1D>?
124
124
 
125
125
  /// Tracking
126
- let tracking: KeyframeGroup<Vector1D>?
126
+ let tracking: KeyframeGroup<LottieVector1D>?
127
127
 
128
128
  func encode(to encoder: Encoder) throws {
129
129
  var container = encoder.container(keyedBy: CodingKeys.self)
@@ -34,24 +34,24 @@ final class TextDocument: Codable, DictionaryInitializable, AnyInitializable {
34
34
  lineHeight = try dictionary.value(for: CodingKeys.lineHeight)
35
35
  baseline = try dictionary.value(for: CodingKeys.baseline)
36
36
  if let fillColorRawValue = dictionary[CodingKeys.fillColorData.rawValue] {
37
- fillColorData = try? Color(value: fillColorRawValue)
37
+ fillColorData = try? LottieColor(value: fillColorRawValue)
38
38
  } else {
39
39
  fillColorData = nil
40
40
  }
41
41
  if let strokeColorRawValue = dictionary[CodingKeys.strokeColorData.rawValue] {
42
- strokeColorData = try? Color(value: strokeColorRawValue)
42
+ strokeColorData = try? LottieColor(value: strokeColorRawValue)
43
43
  } else {
44
44
  strokeColorData = nil
45
45
  }
46
46
  strokeWidth = try? dictionary.value(for: CodingKeys.strokeWidth)
47
47
  strokeOverFill = try? dictionary.value(for: CodingKeys.strokeOverFill)
48
48
  if let textFramePositionRawValue = dictionary[CodingKeys.textFramePosition.rawValue] {
49
- textFramePosition = try? Vector3D(value: textFramePositionRawValue)
49
+ textFramePosition = try? LottieVector3D(value: textFramePositionRawValue)
50
50
  } else {
51
51
  textFramePosition = nil
52
52
  }
53
53
  if let textFrameSizeRawValue = dictionary[CodingKeys.textFrameSize.rawValue] {
54
- textFrameSize = try? Vector3D(value: textFrameSizeRawValue)
54
+ textFrameSize = try? LottieVector3D(value: textFrameSizeRawValue)
55
55
  } else {
56
56
  textFrameSize = nil
57
57
  }
@@ -88,10 +88,10 @@ final class TextDocument: Codable, DictionaryInitializable, AnyInitializable {
88
88
  let baseline: Double?
89
89
 
90
90
  /// Fill Color data
91
- let fillColorData: Color?
91
+ let fillColorData: LottieColor?
92
92
 
93
93
  /// Scroke Color data
94
- let strokeColorData: Color?
94
+ let strokeColorData: LottieColor?
95
95
 
96
96
  /// Stroke Width
97
97
  let strokeWidth: Double?
@@ -99,9 +99,9 @@ final class TextDocument: Codable, DictionaryInitializable, AnyInitializable {
99
99
  /// Stroke Over Fill
100
100
  let strokeOverFill: Bool?
101
101
 
102
- let textFramePosition: Vector3D?
102
+ let textFramePosition: LottieVector3D?
103
103
 
104
- let textFrameSize: Vector3D?
104
+ let textFrameSize: LottieVector3D?
105
105
 
106
106
  // MARK: Private
107
107
 
@@ -17,16 +17,16 @@ protocol RootAnimationLayer: CALayer {
17
17
  var fontProvider: AnimationFontProvider { get set }
18
18
 
19
19
  /// The `CAAnimation` key corresponding to the primary animation.
20
- /// - `AnimationView` uses this key to check if the animation is still active
20
+ /// - `LottieAnimationView` uses this key to check if the animation is still active
21
21
  var primaryAnimationKey: AnimationKey { get }
22
22
 
23
23
  /// Whether or not this layer is currently playing an animation
24
- /// - If the layer returns `nil`, `AnimationView` determines if an animation
24
+ /// - If the layer returns `nil`, `LottieAnimationView` determines if an animation
25
25
  /// is playing by checking if there is an active animation for `primaryAnimationKey`
26
26
  var isAnimationPlaying: Bool? { get }
27
27
 
28
28
  /// Instructs this layer to remove all `CAAnimation`s,
29
- /// other than the `CAAnimation` managed by `AnimationView` (if applicable)
29
+ /// other than the `CAAnimation` managed by `LottieAnimationView` (if applicable)
30
30
  func removeAnimations()
31
31
 
32
32
  func reloadImages()
@@ -44,7 +44,7 @@ protocol RootAnimationLayer: CALayer {
44
44
  // MARK: - AnimationKey
45
45
 
46
46
  enum AnimationKey {
47
- /// The primary animation and its key should be managed by `AnimationView`
47
+ /// The primary animation and its key should be managed by `LottieAnimationView`
48
48
  case managed
49
49
  /// The primary animation always uses the given key
50
50
  case specific(String)
@@ -8,7 +8,7 @@
8
8
  import CoreGraphics
9
9
  import Foundation
10
10
 
11
- extension Color {
11
+ extension LottieColor {
12
12
 
13
13
  // MARK: Lifecycle
14
14
 
@@ -8,7 +8,7 @@
8
8
  import CoreGraphics
9
9
  import Foundation
10
10
 
11
- extension KeyframeGroup where T == Vector1D {
11
+ extension KeyframeGroup where T == LottieVector1D {
12
12
  /// Manually interpolates the keyframes so that they are defined linearly
13
13
  ///
14
14
  /// This method uses `UnitBezier` to perform the interpolation. It will create one keyframe
@@ -19,7 +19,7 @@ extension KeyframeGroup where T == Vector1D {
19
19
  return keyframes
20
20
  }
21
21
 
22
- var output = ContiguousArray<Keyframe<Vector1D>>()
22
+ var output = ContiguousArray<Keyframe<LottieVector1D>>()
23
23
 
24
24
  for idx in 1 ..< keyframes.count {
25
25
  let prev = keyframes[idx - 1]
@@ -43,8 +43,8 @@ extension KeyframeGroup where T == Vector1D {
43
43
  epsilon: 0.005)
44
44
  let value = startValue + Double(progress) * difference
45
45
  output.append(
46
- Keyframe<Vector1D>(
47
- value: Vector1D(value),
46
+ Keyframe<LottieVector1D>(
47
+ value: LottieVector1D(value),
48
48
  time: startTime + CGFloat(t),
49
49
  isHold: false,
50
50
  inTangent: nil,
@@ -1,5 +1,5 @@
1
1
  //
2
- // Color.swift
2
+ // LottieColor.swift
3
3
  // lottie-swift
4
4
  //
5
5
  // Created by Brandon Withrow on 1/14/19.
@@ -8,9 +8,9 @@
8
8
  import CoreGraphics
9
9
  import Foundation
10
10
 
11
- // MARK: - Color + Codable
11
+ // MARK: - LottieColor + Codable
12
12
 
13
- extension Color: Codable {
13
+ extension LottieColor: Codable {
14
14
 
15
15
  // MARK: Lifecycle
16
16
 
@@ -68,9 +68,9 @@ extension Color: Codable {
68
68
 
69
69
  }
70
70
 
71
- // MARK: - Color + AnyInitializable
71
+ // MARK: - LottieColor + AnyInitializable
72
72
 
73
- extension Color: AnyInitializable {
73
+ extension LottieColor: AnyInitializable {
74
74
 
75
75
  init(value: Any) throws {
76
76
  guard var array = value as? [Double] else {
@@ -94,7 +94,7 @@ extension Color: AnyInitializable {
94
94
 
95
95
  }
96
96
 
97
- extension Color {
97
+ extension LottieColor {
98
98
 
99
99
  static var clearColor: CGColor {
100
100
  CGColor(colorSpace: CGColorSpaceCreateDeviceRGB(), components: [0, 0, 0, 0])!
@@ -103,6 +103,6 @@ extension Color {
103
103
  var cgColorValue: CGColor {
104
104
  // TODO: Fix color spaces
105
105
  let colorspace = CGColorSpaceCreateDeviceRGB()
106
- return CGColor(colorSpace: colorspace, components: [CGFloat(r), CGFloat(g), CGFloat(b), CGFloat(a)]) ?? Color.clearColor
106
+ return CGColor(colorSpace: colorspace, components: [CGFloat(r), CGFloat(g), CGFloat(b), CGFloat(a)]) ?? LottieColor.clearColor
107
107
  }
108
108
  }
@@ -9,10 +9,10 @@ import CoreGraphics
9
9
  import Foundation
10
10
  import QuartzCore
11
11
 
12
- // MARK: - Vector1D + Codable
12
+ // MARK: - LottieVector1D + Codable
13
13
 
14
14
  /// Single value container. Needed because lottie sometimes wraps a Double in an array.
15
- extension Vector1D: Codable {
15
+ extension LottieVector1D: Codable {
16
16
 
17
17
  // MARK: Lifecycle
18
18
 
@@ -41,9 +41,9 @@ extension Vector1D: Codable {
41
41
 
42
42
  }
43
43
 
44
- // MARK: - Vector1D + AnyInitializable
44
+ // MARK: - LottieVector1D + AnyInitializable
45
45
 
46
- extension Vector1D: AnyInitializable {
46
+ extension LottieVector1D: AnyInitializable {
47
47
 
48
48
  init(value: Any) throws {
49
49
  if
@@ -61,15 +61,23 @@ extension Vector1D: AnyInitializable {
61
61
  }
62
62
 
63
63
  extension Double {
64
- var vectorValue: Vector1D {
65
- Vector1D(self)
64
+ var vectorValue: LottieVector1D {
65
+ LottieVector1D(self)
66
66
  }
67
67
  }
68
68
 
69
69
  // MARK: - Vector2D
70
70
 
71
+ @available(*, deprecated, renamed: "LottieVector2D", message: """
72
+ `Lottie.Vector2D` has been renamed to `LottieVector2D` for consistency with \
73
+ the new `LottieVector3D` type. This notice will be removed in Lottie 4.0.
74
+ """)
75
+ public typealias Vector2D = LottieVector2D
76
+
77
+ // MARK: - LottieVector2D
78
+
71
79
  /// Needed for decoding json {x: y:} to a CGPoint
72
- public struct Vector2D: Codable, Hashable {
80
+ public struct LottieVector2D: Codable, Hashable {
73
81
 
74
82
  // MARK: Lifecycle
75
83
 
@@ -79,7 +87,7 @@ public struct Vector2D: Codable, Hashable {
79
87
  }
80
88
 
81
89
  public init(from decoder: Decoder) throws {
82
- let container = try decoder.container(keyedBy: Vector2D.CodingKeys.self)
90
+ let container = try decoder.container(keyedBy: LottieVector2D.CodingKeys.self)
83
91
 
84
92
  do {
85
93
  let xValue: [Double] = try container.decode([Double].self, forKey: .x)
@@ -99,7 +107,7 @@ public struct Vector2D: Codable, Hashable {
99
107
  // MARK: Public
100
108
 
101
109
  public func encode(to encoder: Encoder) throws {
102
- var container = encoder.container(keyedBy: Vector2D.CodingKeys.self)
110
+ var container = encoder.container(keyedBy: LottieVector2D.CodingKeys.self)
103
111
  try container.encode(x, forKey: .x)
104
112
  try container.encode(y, forKey: .y)
105
113
  }
@@ -123,7 +131,7 @@ public struct Vector2D: Codable, Hashable {
123
131
 
124
132
  // MARK: AnyInitializable
125
133
 
126
- extension Vector2D: AnyInitializable {
134
+ extension LottieVector2D: AnyInitializable {
127
135
 
128
136
  init(value: Any) throws {
129
137
  guard let dictionary = value as? [String: Any] else {
@@ -154,17 +162,17 @@ extension Vector2D: AnyInitializable {
154
162
  }
155
163
 
156
164
  extension CGPoint {
157
- var vector2dValue: Vector2D {
158
- Vector2D(x: Double(x), y: Double(y))
165
+ var vector2dValue: LottieVector2D {
166
+ LottieVector2D(x: Double(x), y: Double(y))
159
167
  }
160
168
  }
161
169
 
162
- // MARK: - Vector3D + Codable
170
+ // MARK: - LottieVector3D + Codable
163
171
 
164
172
  /// A three dimensional vector.
165
173
  /// These vectors are encoded and decoded from [Double]
166
174
 
167
- extension Vector3D: Codable {
175
+ extension LottieVector3D: Codable {
168
176
 
169
177
  // MARK: Lifecycle
170
178
 
@@ -207,9 +215,9 @@ extension Vector3D: Codable {
207
215
 
208
216
  }
209
217
 
210
- // MARK: - Vector3D + AnyInitializable
218
+ // MARK: - LottieVector3D + AnyInitializable
211
219
 
212
- extension Vector3D: AnyInitializable {
220
+ extension LottieVector3D: AnyInitializable {
213
221
 
214
222
  init(value: Any) throws {
215
223
  guard var array = value as? [Double] else {
@@ -222,7 +230,7 @@ extension Vector3D: AnyInitializable {
222
230
 
223
231
  }
224
232
 
225
- extension Vector3D {
233
+ extension LottieVector3D {
226
234
  public var pointValue: CGPoint {
227
235
  CGPoint(x: x, y: y)
228
236
  }
@@ -233,14 +241,14 @@ extension Vector3D {
233
241
  }
234
242
 
235
243
  extension CGPoint {
236
- var vector3dValue: Vector3D {
237
- Vector3D(x: x, y: y, z: 0)
244
+ var vector3dValue: LottieVector3D {
245
+ LottieVector3D(x: x, y: y, z: 0)
238
246
  }
239
247
  }
240
248
 
241
249
  extension CGSize {
242
- var vector3dValue: Vector3D {
243
- Vector3D(x: width, y: height, z: 1)
250
+ var vector3dValue: LottieVector3D {
251
+ LottieVector3D(x: width, y: height, z: 1)
244
252
  }
245
253
  }
246
254
 
@@ -1,5 +1,5 @@
1
1
  //
2
- // Animation.swift
2
+ // LottieAnimation.swift
3
3
  // lottie-swift
4
4
  //
5
5
  // Created by Brandon Withrow on 1/7/19.
@@ -16,16 +16,24 @@ public enum CoordinateSpace: Int, Codable {
16
16
 
17
17
  // MARK: - Animation
18
18
 
19
- /// The `Animation` model is the top level model object in Lottie.
19
+ @available(*, deprecated, renamed: "LottieAnimation", message: """
20
+ `Lottie.Animation` has been renamed to `LottieAnimation`, to prevent conflicts \
21
+ with the `SwiftUI.Animation` type. This notice will be removed in Lottie 4.0.
22
+ """)
23
+ public typealias Animation = LottieAnimation
24
+
25
+ // MARK: - LottieAnimation
26
+
27
+ /// The `LottieAnimation` model is the top level model object in Lottie.
20
28
  ///
21
- /// An `Animation` holds all of the animation data backing a Lottie Animation.
29
+ /// A `LottieAnimation` holds all of the animation data backing a Lottie Animation.
22
30
  /// Codable, see JSON schema [here](https://github.com/airbnb/lottie-web/tree/master/docs/json).
23
- public final class Animation: Codable, DictionaryInitializable {
31
+ public final class LottieAnimation: Codable, DictionaryInitializable {
24
32
 
25
33
  // MARK: Lifecycle
26
34
 
27
35
  required public init(from decoder: Decoder) throws {
28
- let container = try decoder.container(keyedBy: Animation.CodingKeys.self)
36
+ let container = try decoder.container(keyedBy: LottieAnimation.CodingKeys.self)
29
37
  version = try container.decode(String.self, forKey: .version)
30
38
  type = try container.decodeIfPresent(CoordinateSpace.self, forKey: .type) ?? .type2d
31
39
  startFrame = try container.decode(AnimationFrameTime.self, forKey: .startFrame)
@@ -8,10 +8,10 @@
8
8
  import CoreGraphics
9
9
  import Foundation
10
10
 
11
- extension Animation {
11
+ extension LottieAnimation {
12
12
 
13
13
  /// A closure for an Animation download. The closure is passed `nil` if there was an error.
14
- public typealias DownloadClosure = (Animation?) -> Void
14
+ public typealias DownloadClosure = (LottieAnimation?) -> Void
15
15
 
16
16
  /// The duration in seconds of the animation.
17
17
  public var duration: TimeInterval {
@@ -37,13 +37,13 @@ extension Animation {
37
37
  /// - Parameter subdirectory: A subdirectory in the bundle in which the animation is located. Optional.
38
38
  /// - Parameter animationCache: A cache for holding loaded animations. Optional.
39
39
  ///
40
- /// - Returns: Deserialized `Animation`. Optional.
40
+ /// - Returns: Deserialized `LottieAnimation`. Optional.
41
41
  public static func named(
42
42
  _ name: String,
43
43
  bundle: Bundle = Bundle.main,
44
44
  subdirectory: String? = nil,
45
45
  animationCache: AnimationCacheProvider? = nil)
46
- -> Animation?
46
+ -> LottieAnimation?
47
47
  {
48
48
  /// Create a cache key for the animation.
49
49
  let cacheKey = bundle.bundlePath + (subdirectory ?? "") + "/" + name
@@ -62,7 +62,7 @@ extension Animation {
62
62
  guard let json = try bundle.getAnimationData(name, subdirectory: subdirectory) else {
63
63
  return nil
64
64
  }
65
- let animation = try Animation.from(data: json)
65
+ let animation = try LottieAnimation.from(data: json)
66
66
  animationCache?.setAnimation(animation, forKey: cacheKey)
67
67
  return animation
68
68
  } catch {
@@ -76,11 +76,11 @@ extension Animation {
76
76
  /// - Parameter filepath: The absolute filepath of the animation to load. EG "/User/Me/starAnimation.json"
77
77
  /// - Parameter animationCache: A cache for holding loaded animations. Optional.
78
78
  ///
79
- /// - Returns: Deserialized `Animation`. Optional.
79
+ /// - Returns: Deserialized `LottieAnimation`. Optional.
80
80
  public static func filepath(
81
81
  _ filepath: String,
82
82
  animationCache: AnimationCacheProvider? = nil)
83
- -> Animation?
83
+ -> LottieAnimation?
84
84
  {
85
85
  /// Check cache for animation
86
86
  if
@@ -93,7 +93,7 @@ extension Animation {
93
93
  do {
94
94
  /// Decode the animation.
95
95
  let json = try Data(contentsOf: URL(fileURLWithPath: filepath))
96
- let animation = try Animation.from(data: json)
96
+ let animation = try LottieAnimation.from(data: json)
97
97
  animationCache?.setAnimation(animation, forKey: filepath)
98
98
  return animation
99
99
  } catch {
@@ -106,12 +106,12 @@ extension Animation {
106
106
  /// - Parameter name: The name of the json file in the asset catalog. EG "StarAnimation"
107
107
  /// - Parameter bundle: The bundle in which the animation is located. Defaults to `Bundle.main`
108
108
  /// - Parameter animationCache: A cache for holding loaded animations. Optional.
109
- /// - Returns: Deserialized `Animation`. Optional.
109
+ /// - Returns: Deserialized `LottieAnimation`. Optional.
110
110
  public static func asset(
111
111
  _ name: String,
112
112
  bundle: Bundle = Bundle.main,
113
113
  animationCache: AnimationCacheProvider? = nil)
114
- -> Animation?
114
+ -> LottieAnimation?
115
115
  {
116
116
  /// Create a cache key for the animation.
117
117
  let cacheKey = bundle.bundlePath + "/" + name
@@ -132,7 +132,7 @@ extension Animation {
132
132
 
133
133
  do {
134
134
  /// Decode animation.
135
- let animation = try Animation.from(data: json)
135
+ let animation = try LottieAnimation.from(data: json)
136
136
  animationCache?.setAnimation(animation, forKey: cacheKey)
137
137
  return animation
138
138
  } catch {
@@ -145,22 +145,22 @@ extension Animation {
145
145
  ///
146
146
  /// - Parameter data: The object to load the animation from.
147
147
  /// - Parameter strategy: How the data should be decoded. Defaults to using the strategy set in `LottieConfiguration.shared`.
148
- /// - Returns: Deserialized `Animation`. Optional.
148
+ /// - Returns: Deserialized `LottieAnimation`. Optional.
149
149
  ///
150
150
  public static func from(
151
151
  data: Data,
152
152
  strategy: DecodingStrategy = LottieConfiguration.shared.decodingStrategy) throws
153
- -> Animation
153
+ -> LottieAnimation
154
154
  {
155
155
  switch strategy {
156
156
  case .codable:
157
- return try JSONDecoder().decode(Animation.self, from: data)
157
+ return try JSONDecoder().decode(LottieAnimation.self, from: data)
158
158
  case .dictionaryBased:
159
159
  let json = try JSONSerialization.jsonObject(with: data)
160
160
  guard let dict = json as? [String: Any] else {
161
161
  throw InitializableError.invalidInput
162
162
  }
163
- return try Animation(dictionary: dict)
163
+ return try LottieAnimation(dictionary: dict)
164
164
  }
165
165
  }
166
166
 
@@ -173,7 +173,7 @@ extension Animation {
173
173
  public static func loadedFrom(
174
174
  url: URL,
175
175
  session: URLSession = .shared,
176
- closure: @escaping Animation.DownloadClosure,
176
+ closure: @escaping LottieAnimation.DownloadClosure,
177
177
  animationCache: AnimationCacheProvider?)
178
178
  {
179
179
  if let animationCache = animationCache, let animation = animationCache.animation(forKey: url.absoluteString) {
@@ -187,7 +187,7 @@ extension Animation {
187
187
  return
188
188
  }
189
189
  do {
190
- let animation = try Animation.from(data: jsonData)
190
+ let animation = try LottieAnimation.from(data: jsonData)
191
191
  DispatchQueue.main.async {
192
192
  animationCache?.setAnimation(animation, forKey: url.absoluteString)
193
193
  closure(animation)
@@ -234,6 +234,21 @@ extension Animation {
234
234
  return marker.frameTime
235
235
  }
236
236
 
237
+ /// Markers are a way to describe a point in time and a duration by a key name.
238
+ ///
239
+ /// Markers are encoded into animation JSON. By using markers a designer can mark
240
+ /// playback points for a developer to use without having to worry about keeping
241
+ /// track of animation frames. If the animation file is updated, the developer
242
+ /// does not need to update playback code.
243
+ ///
244
+ /// - Returns: The duration frame time for the marker, or `nil` if no marker found.
245
+ public func durationFrameTime(forMarker named: String) -> AnimationFrameTime? {
246
+ guard let marker = markerMap?[named] else {
247
+ return nil
248
+ }
249
+ return marker.durationFrameTime
250
+ }
251
+
237
252
  /// Converts Frame Time (Seconds * Framerate) into Progress Time
238
253
  /// (optionally clamped to between 0 and 1).
239
254
  public func progressTime(