Clarify ownership for keyframes
diff --git a/include/rive/animation/keyed_object.hpp b/include/rive/animation/keyed_object.hpp
index b22c9a5..39fab61 100644
--- a/include/rive/animation/keyed_object.hpp
+++ b/include/rive/animation/keyed_object.hpp
@@ -7,11 +7,12 @@
     class KeyedProperty;
     class KeyedObject : public KeyedObjectBase {
     private:
-        std::vector<KeyedProperty*> m_KeyedProperties;
+        std::vector<std::unique_ptr<KeyedProperty>> m_KeyedProperties;
 
     public:
+        KeyedObject();
         ~KeyedObject();
-        void addKeyedProperty(KeyedProperty* property);
+        void addKeyedProperty(std::unique_ptr<KeyedProperty>);
 
         StatusCode onAddedDirty(CoreContext* context) override;
         StatusCode onAddedClean(CoreContext* context) override;
diff --git a/include/rive/animation/keyed_property.hpp b/include/rive/animation/keyed_property.hpp
index 3470683..29aaebd 100644
--- a/include/rive/animation/keyed_property.hpp
+++ b/include/rive/animation/keyed_property.hpp
@@ -6,11 +6,12 @@
     class KeyFrame;
     class KeyedProperty : public KeyedPropertyBase {
     private:
-        std::vector<KeyFrame*> m_KeyFrames;
+        std::vector<std::unique_ptr<KeyFrame>> m_KeyFrames;
 
     public:
+        KeyedProperty();
         ~KeyedProperty();
-        void addKeyFrame(KeyFrame* keyframe);
+        void addKeyFrame(std::unique_ptr<KeyFrame>);
         StatusCode onAddedClean(CoreContext* context) override;
         StatusCode onAddedDirty(CoreContext* context) override;
 
diff --git a/include/rive/importers/keyed_object_importer.hpp b/include/rive/importers/keyed_object_importer.hpp
index 945d4d2..6530267 100644
--- a/include/rive/importers/keyed_object_importer.hpp
+++ b/include/rive/importers/keyed_object_importer.hpp
@@ -13,7 +13,7 @@
 
     public:
         KeyedObjectImporter(KeyedObject* keyedObject);
-        void addKeyedProperty(KeyedProperty* property);
+        void addKeyedProperty(std::unique_ptr<KeyedProperty>);
     };
 } // namespace rive
 #endif
diff --git a/include/rive/importers/keyed_property_importer.hpp b/include/rive/importers/keyed_property_importer.hpp
index a07d50d..e5e9e16 100644
--- a/include/rive/importers/keyed_property_importer.hpp
+++ b/include/rive/importers/keyed_property_importer.hpp
@@ -15,7 +15,7 @@
 
     public:
         KeyedPropertyImporter(LinearAnimation* animation, KeyedProperty* keyedProperty);
-        void addKeyFrame(KeyFrame* keyFrame);
+        void addKeyFrame(std::unique_ptr<KeyFrame>);
         bool readNullObject() override;
     };
 } // namespace rive
diff --git a/src/animation/keyed_object.cpp b/src/animation/keyed_object.cpp
index 2c60f02..3b48962 100644
--- a/src/animation/keyed_object.cpp
+++ b/src/animation/keyed_object.cpp
@@ -6,13 +6,11 @@
 
 using namespace rive;
 
-KeyedObject::~KeyedObject() {
-    for (auto property : m_KeyedProperties) {
-        delete property;
-    }
-}
-void KeyedObject::addKeyedProperty(KeyedProperty* property) {
-    m_KeyedProperties.push_back(property);
+KeyedObject::KeyedObject() {}
+KeyedObject::~KeyedObject() {}
+
+void KeyedObject::addKeyedProperty(std::unique_ptr<KeyedProperty> property) {
+    m_KeyedProperties.push_back(std::move(property));
 }
 
 StatusCode KeyedObject::onAddedDirty(CoreContext* context) {
@@ -21,7 +19,7 @@
         return StatusCode::MissingObject;
     }
 
-    for (auto property : m_KeyedProperties) {
+    for (auto& property : m_KeyedProperties) {
         StatusCode code;
         if ((code = property->onAddedDirty(context)) != StatusCode::Ok) {
             return code;
@@ -31,7 +29,7 @@
 }
 
 StatusCode KeyedObject::onAddedClean(CoreContext* context) {
-    for (auto property : m_KeyedProperties) {
+    for (auto& property : m_KeyedProperties) {
         property->onAddedClean(context);
     }
     return StatusCode::Ok;
@@ -42,7 +40,7 @@
     if (object == nullptr) {
         return;
     }
-    for (auto property : m_KeyedProperties) {
+    for (auto& property : m_KeyedProperties) {
         property->apply(object, time, mix);
     }
 }
diff --git a/src/animation/keyed_property.cpp b/src/animation/keyed_property.cpp
index 8c7891c..d952451 100644
--- a/src/animation/keyed_property.cpp
+++ b/src/animation/keyed_property.cpp
@@ -6,13 +6,12 @@
 
 using namespace rive;
 
-KeyedProperty::~KeyedProperty() {
-    for (auto keyframe : m_KeyFrames) {
-        delete keyframe;
-    }
-}
+KeyedProperty::KeyedProperty() {}
+KeyedProperty::~KeyedProperty() {}
 
-void KeyedProperty::addKeyFrame(KeyFrame* keyframe) { m_KeyFrames.push_back(keyframe); }
+void KeyedProperty::addKeyFrame(std::unique_ptr<KeyFrame> keyframe) {
+    m_KeyFrames.push_back(std::move(keyframe));
+}
 
 void KeyedProperty::apply(Core* object, float seconds, float mix) {
     assert(!m_KeyFrames.empty());
@@ -42,8 +41,8 @@
         m_KeyFrames[0]->apply(object, pk, mix);
     } else {
         if (idx < numKeyFrames) {
-            KeyFrame* fromFrame = m_KeyFrames[idx - 1];
-            KeyFrame* toFrame = m_KeyFrames[idx];
+            KeyFrame* fromFrame = m_KeyFrames[idx - 1].get();
+            KeyFrame* toFrame = m_KeyFrames[idx].get();
             if (seconds == toFrame->seconds()) {
                 toFrame->apply(object, pk, mix);
             } else {
@@ -61,7 +60,7 @@
 
 StatusCode KeyedProperty::onAddedDirty(CoreContext* context) {
     StatusCode code;
-    for (auto keyframe : m_KeyFrames) {
+    for (auto& keyframe : m_KeyFrames) {
         if ((code = keyframe->onAddedDirty(context)) != StatusCode::Ok) {
             return code;
         }
@@ -71,7 +70,7 @@
 
 StatusCode KeyedProperty::onAddedClean(CoreContext* context) {
     StatusCode code;
-    for (auto keyframe : m_KeyFrames) {
+    for (auto& keyframe : m_KeyFrames) {
         if ((code = keyframe->onAddedClean(context)) != StatusCode::Ok) {
             return code;
         }
@@ -84,6 +83,6 @@
     if (importer == nullptr) {
         return StatusCode::MissingObject;
     }
-    importer->addKeyedProperty(this);
+    importer->addKeyedProperty(std::unique_ptr<KeyedProperty>(this));
     return Super::import(importStack);
 }
diff --git a/src/animation/keyframe.cpp b/src/animation/keyframe.cpp
index 5190b89..c0eaf9a 100644
--- a/src/animation/keyframe.cpp
+++ b/src/animation/keyframe.cpp
@@ -26,6 +26,6 @@
     if (importer == nullptr) {
         return StatusCode::MissingObject;
     }
-    importer->addKeyFrame(this);
+    importer->addKeyFrame(std::unique_ptr<KeyFrame>(this));
     return Super::import(importStack);
 }
\ No newline at end of file
diff --git a/src/importers/keyed_object_importer.cpp b/src/importers/keyed_object_importer.cpp
index 8cbbf1f..c8477c3 100644
--- a/src/importers/keyed_object_importer.cpp
+++ b/src/importers/keyed_object_importer.cpp
@@ -7,6 +7,6 @@
 
 KeyedObjectImporter::KeyedObjectImporter(KeyedObject* keyedObject) : m_KeyedObject(keyedObject) {}
 
-void KeyedObjectImporter::addKeyedProperty(KeyedProperty* property) {
-    m_KeyedObject->addKeyedProperty(property);
+void KeyedObjectImporter::addKeyedProperty(std::unique_ptr<KeyedProperty> property) {
+    m_KeyedObject->addKeyedProperty(std::move(property));
 }
\ No newline at end of file
diff --git a/src/importers/keyed_property_importer.cpp b/src/importers/keyed_property_importer.cpp
index a664e1a..6789b0f 100644
--- a/src/importers/keyed_property_importer.cpp
+++ b/src/importers/keyed_property_importer.cpp
@@ -9,9 +9,9 @@
                                              KeyedProperty* keyedProperty) :
     m_Animation(animation), m_KeyedProperty(keyedProperty) {}
 
-void KeyedPropertyImporter::addKeyFrame(KeyFrame* keyFrame) {
+void KeyedPropertyImporter::addKeyFrame(std::unique_ptr<KeyFrame> keyFrame) {
     keyFrame->computeSeconds(m_Animation->fps());
-    m_KeyedProperty->addKeyFrame(keyFrame);
+    m_KeyedProperty->addKeyFrame(std::move(keyFrame));
 }
 
 bool KeyedPropertyImporter::readNullObject() {