add bindable properties for state machines

This PR sets the fundamental pieces for PRs that will be coming afterward to support data binding state machines.
The most important parts are:
- bindable properties that will be used as binding points for conditions, listeners, and blend animations
- data bind objects don't extend from Component anymore to decouple them from artboards
- because of that, now data bind objects are written in the context of their bound object so there is a unified way for setting data bind targets

The rest is the usual boilerplate code from core objects and some inheritance changes

Diffs=
b5f342002 add bindable properties for state machines (#7640)

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index 080a680..518b856 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-f55ebd34f3938bfe1e36ebf83bbc92c0e5d34a62
+b5f342002be71c61608ad6c37835349eb4e7c719
diff --git a/dev/defs/data_bind/bindable_property.json b/dev/defs/data_bind/bindable_property.json
new file mode 100644
index 0000000..dbc57e5
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property.json
@@ -0,0 +1,20 @@
+{
+  "name": "BindableProperty",
+  "key": {
+    "int": 9,
+    "string": "bindableproperty"
+  },
+  "abstract": true,
+  "properties": {
+    "dataBindId": {
+      "type": "Id",
+      "initialValue": "Core.missingId",
+      "key": {
+        "int": 633,
+        "string": "databindid"
+      },
+      "description": "Id of the data bind binded to this property",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/bindable_property_boolean.json b/dev/defs/data_bind/bindable_property_boolean.json
new file mode 100644
index 0000000..78c24f2
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property_boolean.json
@@ -0,0 +1,19 @@
+{
+  "name": "BindablePropertyBoolean",
+  "key": {
+    "int": 472,
+    "string": "bindablepropertyboolean"
+  },
+  "extends": "data_bind/bindable_property.json",
+  "properties": {
+    "propertyValue": {
+      "type": "bool",
+      "initialValue": "false",
+      "key": {
+        "int": 634,
+        "string": "propertyvalue"
+      },
+      "description": "A property of type bool that can be used for data binding."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/bindable_property_color.json b/dev/defs/data_bind/bindable_property_color.json
new file mode 100644
index 0000000..1dd5134
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property_color.json
@@ -0,0 +1,19 @@
+{
+  "name": "BindablePropertyColor",
+  "key": {
+    "int": 475,
+    "string": "bindablepropertycolor"
+  },
+  "extends": "data_bind/bindable_property.json",
+  "properties": {
+    "propertyValue": {
+      "type": "Color",
+      "initialValue": "0xFF1D1D1D",
+      "key": {
+        "int": 638,
+        "string": "propertyvalue"
+      },
+      "description": "A property of type int that can be used for data binding."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/bindable_property_enum.json b/dev/defs/data_bind/bindable_property_enum.json
new file mode 100644
index 0000000..b3faf03
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property_enum.json
@@ -0,0 +1,21 @@
+{
+  "name": "BindablePropertyEnum",
+  "key": {
+    "int": 474,
+    "string": "bindablepropertyenum"
+  },
+  "extends": "data_bind/bindable_property.json",
+  "properties": {
+    "propertyValue": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 637,
+        "string": "propertyvalue"
+      },
+      "description": "The id of the enum that can be used for data binding."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/bindable_property_number.json b/dev/defs/data_bind/bindable_property_number.json
new file mode 100644
index 0000000..a2ab667
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property_number.json
@@ -0,0 +1,19 @@
+{
+  "name": "BindablePropertyNumber",
+  "key": {
+    "int": 473,
+    "string": "bindablepropertynumber"
+  },
+  "extends": "data_bind/bindable_property.json",
+  "properties": {
+    "propertyValue": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 636,
+        "string": "propertyvalue"
+      },
+      "description": "A property of type double that can be used for data binding."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/bindable_property_string.json b/dev/defs/data_bind/bindable_property_string.json
new file mode 100644
index 0000000..aac63df
--- /dev/null
+++ b/dev/defs/data_bind/bindable_property_string.json
@@ -0,0 +1,19 @@
+{
+  "name": "BindablePropertyString",
+  "key": {
+    "int": 471,
+    "string": "bindablepropertystring"
+  },
+  "extends": "data_bind/bindable_property.json",
+  "properties": {
+    "propertyValue": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 635,
+        "string": "propertyvalue"
+      },
+      "description": "A property of type String that can be used for data binding."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/data_bind.json b/dev/defs/data_bind/data_bind.json
index c93b559..3e3124d 100644
--- a/dev/defs/data_bind/data_bind.json
+++ b/dev/defs/data_bind/data_bind.json
@@ -4,18 +4,16 @@
     "int": 446,
     "string": "databind"
   },
-  "extends": "component.json",
   "properties": {
     "targetId": {
       "type": "Id",
-      "typeRuntime": "uint",
       "initialValue": "Core.missingId",
-      "initialValueRuntime": "-1",
       "key": {
         "int": 585,
         "string": "targetid"
       },
-      "description": "Identifier used to track the object that is targetted."
+      "description": "Identifier used to track the object that is targetted.",
+      "runtime": false
     },
     "propertyKey": {
       "type": "uint",
diff --git a/include/rive/animation/nested_state_machine.hpp b/include/rive/animation/nested_state_machine.hpp
index 8c0476b..f3e557c 100644
--- a/include/rive/animation/nested_state_machine.hpp
+++ b/include/rive/animation/nested_state_machine.hpp
@@ -36,6 +36,8 @@
     size_t inputCount() { return m_nestedInputs.size(); }
     NestedInput* input(size_t index);
     NestedInput* input(std::string name);
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance);
+    void dataContext(DataContext* dataContext);
 };
 } // namespace rive
 
diff --git a/include/rive/animation/state_machine.hpp b/include/rive/animation/state_machine.hpp
index 9899893..258fe61 100644
--- a/include/rive/animation/state_machine.hpp
+++ b/include/rive/animation/state_machine.hpp
@@ -10,6 +10,7 @@
 class StateMachineInput;
 class StateMachineListener;
 class StateMachineImporter;
+class DataBind;
 class StateMachine : public StateMachineBase
 {
     friend class StateMachineImporter;
@@ -18,10 +19,12 @@
     std::vector<std::unique_ptr<StateMachineLayer>> m_Layers;
     std::vector<std::unique_ptr<StateMachineInput>> m_Inputs;
     std::vector<std::unique_ptr<StateMachineListener>> m_Listeners;
+    std::vector<std::unique_ptr<DataBind>> m_dataBinds;
 
     void addLayer(std::unique_ptr<StateMachineLayer>);
     void addInput(std::unique_ptr<StateMachineInput>);
     void addListener(std::unique_ptr<StateMachineListener>);
+    void addDataBind(std::unique_ptr<DataBind>);
 
 public:
     StateMachine();
@@ -32,11 +35,13 @@
     size_t layerCount() const { return m_Layers.size(); }
     size_t inputCount() const { return m_Inputs.size(); }
     size_t listenerCount() const { return m_Listeners.size(); }
+    size_t dataBindCount() const { return m_dataBinds.size(); }
 
     const StateMachineInput* input(std::string name) const;
     const StateMachineInput* input(size_t index) const;
     const StateMachineLayer* layer(std::string name) const;
     const StateMachineLayer* layer(size_t index) const;
+    const DataBind* dataBind(size_t index) const;
     const StateMachineListener* listener(size_t index) const;
 
     StatusCode onAddedDirty(CoreContext* context) override;
diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp
index c59ee17..679ade0 100644
--- a/include/rive/animation/state_machine_instance.hpp
+++ b/include/rive/animation/state_machine_instance.hpp
@@ -4,6 +4,7 @@
 #include <string>
 #include <stddef.h>
 #include <vector>
+#include <unordered_map>
 #include "rive/animation/linear_animation_instance.hpp"
 #include "rive/animation/state_instance.hpp"
 #include "rive/animation/state_transition.hpp"
@@ -31,6 +32,8 @@
 class Event;
 class KeyedProperty;
 class EventReport;
+class DataBind;
+class BindableProperty;
 
 #ifdef WITH_RIVE_TOOLS
 class StateMachineInstance;
@@ -56,6 +59,7 @@
     double randomValue();
     StateTransition* findRandomTransition(StateInstance* stateFromInstance, bool ignoreTriggers);
     StateTransition* findAllowedTransition(StateInstance* stateFromInstance, bool ignoreTriggers);
+    DataContext* m_DataContext;
 
 public:
     StateMachineInstance(const StateMachine* machine, ArtboardInstance* instance);
@@ -78,6 +82,8 @@
     SMIBool* getBool(const std::string& name) const override;
     SMINumber* getNumber(const std::string& name) const override;
     SMITrigger* getTrigger(const std::string& name) const override;
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance) override;
+    void dataContext(DataContext* dataContext);
 
     size_t currentAnimationCount() const;
     const LinearAnimationInstance* currentAnimationByIndex(size_t index) const;
@@ -128,6 +134,7 @@
     /// Gets a reported event at an index < reportedEventCount().
     const EventReport reportedEventAt(std::size_t index) const;
     bool playsAudio() override { return true; }
+    BindableProperty* bindablePropertyInstance(BindableProperty* bindableProperty);
 
 private:
     std::vector<EventReport> m_reportedEvents;
@@ -139,6 +146,8 @@
     std::vector<std::unique_ptr<HitComponent>> m_hitComponents;
     StateMachineInstance* m_parentStateMachineInstance = nullptr;
     NestedArtboard* m_parentNestedArtboard = nullptr;
+    std::vector<DataBind*> m_dataBinds;
+    std::unordered_map<BindableProperty*, BindableProperty*> m_bindablePropertyInstances;
 #ifdef WITH_RIVE_TOOLS
 public:
     void onInputChanged(InputChanged callback) { m_inputChangedCallback = callback; }
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index 85353c1..9411ceb 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -182,9 +182,9 @@
                                  DataContext* parent,
                                  bool isRoot);
     void dataContextFromInstance(ViewModelInstance* viewModelInstance);
-    void populateDataBinds(std::vector<Component*>* dataBinds);
-    void buildDataBindDependencies(std::vector<Component*>* dataBinds);
-    void sortDataBinds(std::vector<Component*> dataBinds);
+    void addDataBind(DataBind* dataBind);
+    void populateDataBinds(std::vector<DataBind*>* dataBinds);
+    void sortDataBinds(std::vector<DataBind*> dataBinds);
     bool hasAudio() const;
 
     template <typename T = Component> T* find(const std::string& name)
@@ -284,6 +284,16 @@
             {
                 auto object = *itr;
                 cloneObjects.push_back(object == nullptr ? nullptr : object->clone());
+                // For each object, clone its data bind objects and target their clones
+                for (auto dataBind : m_DataBinds)
+                {
+                    if (dataBind->target() == object)
+                    {
+                        auto dataBindClone = static_cast<DataBind*>(dataBind->clone());
+                        dataBindClone->target(cloneObjects.back());
+                        artboardClone->m_DataBinds.push_back(dataBindClone);
+                    }
+                }
             }
         }
 
diff --git a/include/rive/data_bind/bindable_property.hpp b/include/rive/data_bind/bindable_property.hpp
new file mode 100644
index 0000000..3294401
--- /dev/null
+++ b/include/rive/data_bind/bindable_property.hpp
@@ -0,0 +1,19 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_HPP_
+#define _RIVE_BINDABLE_PROPERTY_HPP_
+#include "rive/generated/data_bind/bindable_property_base.hpp"
+#include "rive/data_bind/data_bind.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindableProperty : public BindablePropertyBase
+{
+public:
+    void dataBind(DataBind* value) { m_dataBind = value; };
+    DataBind* dataBind() { return m_dataBind; };
+
+private:
+    DataBind* m_dataBind;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/bindable_property_boolean.hpp b/include/rive/data_bind/bindable_property_boolean.hpp
new file mode 100644
index 0000000..18037b6
--- /dev/null
+++ b/include/rive/data_bind/bindable_property_boolean.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_BOOLEAN_HPP_
+#define _RIVE_BINDABLE_PROPERTY_BOOLEAN_HPP_
+#include "rive/generated/data_bind/bindable_property_boolean_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindablePropertyBoolean : public BindablePropertyBooleanBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/bindable_property_color.hpp b/include/rive/data_bind/bindable_property_color.hpp
new file mode 100644
index 0000000..dd128ca
--- /dev/null
+++ b/include/rive/data_bind/bindable_property_color.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_COLOR_HPP_
+#define _RIVE_BINDABLE_PROPERTY_COLOR_HPP_
+#include "rive/generated/data_bind/bindable_property_color_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindablePropertyColor : public BindablePropertyColorBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/bindable_property_enum.hpp b/include/rive/data_bind/bindable_property_enum.hpp
new file mode 100644
index 0000000..48692c2
--- /dev/null
+++ b/include/rive/data_bind/bindable_property_enum.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_ENUM_HPP_
+#define _RIVE_BINDABLE_PROPERTY_ENUM_HPP_
+#include "rive/generated/data_bind/bindable_property_enum_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindablePropertyEnum : public BindablePropertyEnumBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/bindable_property_number.hpp b/include/rive/data_bind/bindable_property_number.hpp
new file mode 100644
index 0000000..38a72fd
--- /dev/null
+++ b/include/rive/data_bind/bindable_property_number.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_NUMBER_HPP_
+#define _RIVE_BINDABLE_PROPERTY_NUMBER_HPP_
+#include "rive/generated/data_bind/bindable_property_number_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindablePropertyNumber : public BindablePropertyNumberBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/bindable_property_string.hpp b/include/rive/data_bind/bindable_property_string.hpp
new file mode 100644
index 0000000..302caf0
--- /dev/null
+++ b/include/rive/data_bind/bindable_property_string.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_STRING_HPP_
+#define _RIVE_BINDABLE_PROPERTY_STRING_HPP_
+#include "rive/generated/data_bind/bindable_property_string_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class BindablePropertyString : public BindablePropertyStringBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value.hpp b/include/rive/data_bind/context/context_value.hpp
index 1f08e45..370f46f 100644
--- a/include/rive/data_bind/context/context_value.hpp
+++ b/include/rive/data_bind/context/context_value.hpp
@@ -13,9 +13,9 @@
 public:
     DataBindContextValue(){};
     virtual ~DataBindContextValue(){};
-    virtual void applyToSource(Component* component, uint32_t propertyKey){};
-    virtual void apply(Component* component, uint32_t propertyKey){};
-    virtual void update(Component* component){};
+    virtual void applyToSource(Core* component, uint32_t propertyKey){};
+    virtual void apply(Core* component, uint32_t propertyKey){};
+    virtual void update(Core* component){};
 };
 } // namespace rive
 
diff --git a/include/rive/data_bind/context/context_value_boolean.hpp b/include/rive/data_bind/context/context_value_boolean.hpp
index b7a963b..82e9a7f 100644
--- a/include/rive/data_bind/context/context_value_boolean.hpp
+++ b/include/rive/data_bind/context/context_value_boolean.hpp
@@ -8,8 +8,8 @@
 
 public:
     DataBindContextValueBoolean(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     bool m_Value;
diff --git a/include/rive/data_bind/context/context_value_color.hpp b/include/rive/data_bind/context/context_value_color.hpp
index c1c7f48..22fe8f8 100644
--- a/include/rive/data_bind/context/context_value_color.hpp
+++ b/include/rive/data_bind/context/context_value_color.hpp
@@ -8,8 +8,8 @@
 
 public:
     DataBindContextValueColor(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     double m_Value;
diff --git a/include/rive/data_bind/context/context_value_enum.hpp b/include/rive/data_bind/context/context_value_enum.hpp
index e78a1b5..98c21c4 100644
--- a/include/rive/data_bind/context/context_value_enum.hpp
+++ b/include/rive/data_bind/context/context_value_enum.hpp
@@ -8,8 +8,8 @@
 
 public:
     DataBindContextValueEnum(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     int m_Value;
diff --git a/include/rive/data_bind/context/context_value_list.hpp b/include/rive/data_bind/context/context_value_list.hpp
index 3ee4f2d..0c12f91 100644
--- a/include/rive/data_bind/context/context_value_list.hpp
+++ b/include/rive/data_bind/context/context_value_list.hpp
@@ -12,17 +12,15 @@
 
 public:
     DataBindContextValueList(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    void update(Component* target) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    void update(Core* target) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     std::vector<std::unique_ptr<DataBindContextValueListItem>> m_ListItemsCache;
-    void insertItem(Component* target,
-                    ViewModelInstanceListItem* viewModelInstanceListItem,
-                    int index);
-    void swapItems(Component* target, int index1, int index2);
-    void popItem(Component* target);
+    void insertItem(Core* target, ViewModelInstanceListItem* viewModelInstanceListItem, int index);
+    void swapItems(Core* target, int index1, int index2);
+    void popItem(Core* target);
     std::unique_ptr<ArtboardInstance> createArtboard(Component* target,
                                                      Artboard* artboard,
                                                      ViewModelInstanceListItem* listItem) const;
diff --git a/include/rive/data_bind/context/context_value_number.hpp b/include/rive/data_bind/context/context_value_number.hpp
index da866d3..b2d850a 100644
--- a/include/rive/data_bind/context/context_value_number.hpp
+++ b/include/rive/data_bind/context/context_value_number.hpp
@@ -8,8 +8,8 @@
 
 public:
     DataBindContextValueNumber(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     double m_Value;
diff --git a/include/rive/data_bind/context/context_value_string.hpp b/include/rive/data_bind/context/context_value_string.hpp
index 52f2ac3..0b32528 100644
--- a/include/rive/data_bind/context/context_value_string.hpp
+++ b/include/rive/data_bind/context/context_value_string.hpp
@@ -8,8 +8,8 @@
 
 public:
     DataBindContextValueString(ViewModelInstanceValue* value);
-    void apply(Component* component, uint32_t propertyKey) override;
-    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+    void apply(Core* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Core* component, uint32_t propertyKey) override;
 
 private:
     std::string m_Value;
diff --git a/include/rive/data_bind/data_bind.hpp b/include/rive/data_bind/data_bind.hpp
index 7efbcc8..0ccccb3 100644
--- a/include/rive/data_bind/data_bind.hpp
+++ b/include/rive/data_bind/data_bind.hpp
@@ -1,8 +1,10 @@
 #ifndef _RIVE_DATA_BIND_HPP_
 #define _RIVE_DATA_BIND_HPP_
+#include "rive/component_dirt.hpp"
 #include "rive/generated/data_bind/data_bind_base.hpp"
 #include "rive/viewmodel/viewmodel_instance_value.hpp"
 #include "rive/data_bind/context/context_value.hpp"
+#include "rive/data_bind/data_context.hpp"
 #include <stdio.h>
 namespace rive
 {
@@ -11,14 +13,18 @@
 public:
     StatusCode onAddedDirty(CoreContext* context) override;
     StatusCode import(ImportStack& importStack) override;
-    void buildDependencies() override;
     virtual void updateSourceBinding();
-    void update(ComponentDirt value) override;
-    Component* target() { return m_target; };
+    virtual void update(ComponentDirt value);
+    Core* target() const { return m_target; };
+    void target(Core* value) { m_target = value; };
     virtual void bind();
+    ComponentDirt dirt() { return m_Dirt; };
+    void dirt(ComponentDirt value) { m_Dirt = value; };
+    bool addDirt(ComponentDirt value, bool recurse);
 
 protected:
-    Component* m_target;
+    ComponentDirt m_Dirt = ComponentDirt::Filthy;
+    Core* m_target;
     ViewModelInstanceValue* m_Source;
     std::unique_ptr<DataBindContextValue> m_ContextValue;
 };
diff --git a/include/rive/data_bind/data_bind_context.hpp b/include/rive/data_bind/data_bind_context.hpp
index a6bdd46..b7e2ad4 100644
--- a/include/rive/data_bind/data_bind_context.hpp
+++ b/include/rive/data_bind/data_bind_context.hpp
@@ -3,6 +3,7 @@
 #include "rive/generated/data_bind/data_bind_context_base.hpp"
 #include "rive/viewmodel/viewmodel_instance_value.hpp"
 #include "rive/data_bind/context/context_value.hpp"
+#include "rive/data_bind/data_context.hpp"
 #include "rive/refcnt.hpp"
 #include <stdio.h>
 namespace rive
@@ -15,7 +16,7 @@
 public:
     void decodeSourcePathIds(Span<const uint8_t> value) override;
     void copySourcePathIds(const DataBindContextBase& object) override;
-    void bind() override;
+    void bindFromContext(DataContext* dataContext);
     ViewModelInstanceValue* source() { return m_Source; };
 };
 } // namespace rive
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp
index eb3a240..3096b79 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -100,6 +100,12 @@
 #include "rive/custom_property_boolean.hpp"
 #include "rive/custom_property_number.hpp"
 #include "rive/custom_property_string.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+#include "rive/data_bind/bindable_property_boolean.hpp"
+#include "rive/data_bind/bindable_property_color.hpp"
+#include "rive/data_bind/bindable_property_enum.hpp"
+#include "rive/data_bind/bindable_property_number.hpp"
+#include "rive/data_bind/bindable_property_string.hpp"
 #include "rive/data_bind/data_bind.hpp"
 #include "rive/data_bind/data_bind_context.hpp"
 #include "rive/draw_rules.hpp"
@@ -408,10 +414,20 @@
                 return new Backboard();
             case OpenUrlEventBase::typeKey:
                 return new OpenUrlEvent();
+            case BindablePropertyBooleanBase::typeKey:
+                return new BindablePropertyBoolean();
             case DataBindBase::typeKey:
                 return new DataBind();
             case DataBindContextBase::typeKey:
                 return new DataBindContext();
+            case BindablePropertyStringBase::typeKey:
+                return new BindablePropertyString();
+            case BindablePropertyNumberBase::typeKey:
+                return new BindablePropertyNumber();
+            case BindablePropertyEnumBase::typeKey:
+                return new BindablePropertyEnum();
+            case BindablePropertyColorBase::typeKey:
+                return new BindablePropertyColor();
             case WeightBase::typeKey:
                 return new Weight();
             case BoneBase::typeKey:
@@ -542,6 +558,9 @@
             case LayoutComponentBase::clipPropertyKey:
                 object->as<LayoutComponentBase>()->clip(value);
                 break;
+            case BindablePropertyBooleanBase::propertyValuePropertyKey:
+                object->as<BindablePropertyBooleanBase>()->propertyValue(value);
+                break;
             case TextModifierRangeBase::clampPropertyKey:
                 object->as<TextModifierRangeBase>()->clamp(value);
                 break;
@@ -920,15 +939,15 @@
             case OpenUrlEventBase::targetValuePropertyKey:
                 object->as<OpenUrlEventBase>()->targetValue(value);
                 break;
-            case DataBindBase::targetIdPropertyKey:
-                object->as<DataBindBase>()->targetId(value);
-                break;
             case DataBindBase::propertyKeyPropertyKey:
                 object->as<DataBindBase>()->propertyKey(value);
                 break;
             case DataBindBase::flagsPropertyKey:
                 object->as<DataBindBase>()->flags(value);
                 break;
+            case BindablePropertyEnumBase::propertyValuePropertyKey:
+                object->as<BindablePropertyEnumBase>()->propertyValue(value);
+                break;
             case WeightBase::valuesPropertyKey:
                 object->as<WeightBase>()->values(value);
                 break;
@@ -1019,6 +1038,9 @@
             case GradientStopBase::colorValuePropertyKey:
                 object->as<GradientStopBase>()->colorValue(value);
                 break;
+            case BindablePropertyColorBase::propertyValuePropertyKey:
+                object->as<BindablePropertyColorBase>()->propertyValue(value);
+                break;
         }
     }
     static void setString(Core* object, int propertyKey, std::string value)
@@ -1052,6 +1074,9 @@
             case OpenUrlEventBase::urlPropertyKey:
                 object->as<OpenUrlEventBase>()->url(value);
                 break;
+            case BindablePropertyStringBase::propertyValuePropertyKey:
+                object->as<BindablePropertyStringBase>()->propertyValue(value);
+                break;
             case TextValueRunBase::textPropertyKey:
                 object->as<TextValueRunBase>()->text(value);
                 break;
@@ -1427,6 +1452,9 @@
             case JoystickBase::heightPropertyKey:
                 object->as<JoystickBase>()->height(value);
                 break;
+            case BindablePropertyNumberBase::propertyValuePropertyKey:
+                object->as<BindablePropertyNumberBase>()->propertyValue(value);
+                break;
             case BoneBase::lengthPropertyKey:
                 object->as<BoneBase>()->length(value);
                 break;
@@ -1625,6 +1653,8 @@
                 return object->as<CustomPropertyBooleanBase>()->propertyValue();
             case LayoutComponentBase::clipPropertyKey:
                 return object->as<LayoutComponentBase>()->clip();
+            case BindablePropertyBooleanBase::propertyValuePropertyKey:
+                return object->as<BindablePropertyBooleanBase>()->propertyValue();
             case TextModifierRangeBase::clampPropertyKey:
                 return object->as<TextModifierRangeBase>()->clamp();
         }
@@ -1880,12 +1910,12 @@
                 return object->as<JoystickBase>()->handleSourceId();
             case OpenUrlEventBase::targetValuePropertyKey:
                 return object->as<OpenUrlEventBase>()->targetValue();
-            case DataBindBase::targetIdPropertyKey:
-                return object->as<DataBindBase>()->targetId();
             case DataBindBase::propertyKeyPropertyKey:
                 return object->as<DataBindBase>()->propertyKey();
             case DataBindBase::flagsPropertyKey:
                 return object->as<DataBindBase>()->flags();
+            case BindablePropertyEnumBase::propertyValuePropertyKey:
+                return object->as<BindablePropertyEnumBase>()->propertyValue();
             case WeightBase::valuesPropertyKey:
                 return object->as<WeightBase>()->values();
             case WeightBase::indicesPropertyKey:
@@ -1949,6 +1979,8 @@
                 return object->as<SolidColorBase>()->colorValue();
             case GradientStopBase::colorValuePropertyKey:
                 return object->as<GradientStopBase>()->colorValue();
+            case BindablePropertyColorBase::propertyValuePropertyKey:
+                return object->as<BindablePropertyColorBase>()->propertyValue();
         }
         return 0;
     }
@@ -1974,6 +2006,8 @@
                 return object->as<KeyFrameStringBase>()->value();
             case OpenUrlEventBase::urlPropertyKey:
                 return object->as<OpenUrlEventBase>()->url();
+            case BindablePropertyStringBase::propertyValuePropertyKey:
+                return object->as<BindablePropertyStringBase>()->propertyValue();
             case TextValueRunBase::textPropertyKey:
                 return object->as<TextValueRunBase>()->text();
             case CustomPropertyStringBase::propertyValuePropertyKey:
@@ -2227,6 +2261,8 @@
                 return object->as<JoystickBase>()->width();
             case JoystickBase::heightPropertyKey:
                 return object->as<JoystickBase>()->height();
+            case BindablePropertyNumberBase::propertyValuePropertyKey:
+                return object->as<BindablePropertyNumberBase>()->propertyValue();
             case BoneBase::lengthPropertyKey:
                 return object->as<BoneBase>()->length();
             case RootBoneBase::xPropertyKey:
@@ -2345,6 +2381,7 @@
             case ClippingShapeBase::isVisiblePropertyKey:
             case CustomPropertyBooleanBase::propertyValuePropertyKey:
             case LayoutComponentBase::clipPropertyKey:
+            case BindablePropertyBooleanBase::propertyValuePropertyKey:
             case TextModifierRangeBase::clampPropertyKey:
                 return CoreBoolType::id;
             case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
@@ -2470,9 +2507,9 @@
             case JoystickBase::joystickFlagsPropertyKey:
             case JoystickBase::handleSourceIdPropertyKey:
             case OpenUrlEventBase::targetValuePropertyKey:
-            case DataBindBase::targetIdPropertyKey:
             case DataBindBase::propertyKeyPropertyKey:
             case DataBindBase::flagsPropertyKey:
+            case BindablePropertyEnumBase::propertyValuePropertyKey:
             case WeightBase::valuesPropertyKey:
             case WeightBase::indicesPropertyKey:
             case TendonBase::boneIdPropertyKey:
@@ -2502,6 +2539,7 @@
             case KeyFrameColorBase::valuePropertyKey:
             case SolidColorBase::colorValuePropertyKey:
             case GradientStopBase::colorValuePropertyKey:
+            case BindablePropertyColorBase::propertyValuePropertyKey:
                 return CoreColorType::id;
             case ViewModelComponentBase::namePropertyKey:
             case ViewModelInstanceStringBase::propertyValuePropertyKey:
@@ -2512,6 +2550,7 @@
             case StateMachineComponentBase::namePropertyKey:
             case KeyFrameStringBase::valuePropertyKey:
             case OpenUrlEventBase::urlPropertyKey:
+            case BindablePropertyStringBase::propertyValuePropertyKey:
             case TextValueRunBase::textPropertyKey:
             case CustomPropertyStringBase::propertyValuePropertyKey:
             case AssetBase::namePropertyKey:
@@ -2636,6 +2675,7 @@
             case JoystickBase::originYPropertyKey:
             case JoystickBase::widthPropertyKey:
             case JoystickBase::heightPropertyKey:
+            case BindablePropertyNumberBase::propertyValuePropertyKey:
             case BoneBase::lengthPropertyKey:
             case RootBoneBase::xPropertyKey:
             case RootBoneBase::yPropertyKey:
@@ -2758,6 +2798,8 @@
                 return object->is<CustomPropertyBooleanBase>();
             case LayoutComponentBase::clipPropertyKey:
                 return object->is<LayoutComponentBase>();
+            case BindablePropertyBooleanBase::propertyValuePropertyKey:
+                return object->is<BindablePropertyBooleanBase>();
             case TextModifierRangeBase::clampPropertyKey:
                 return object->is<TextModifierRangeBase>();
             case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
@@ -3006,12 +3048,12 @@
                 return object->is<JoystickBase>();
             case OpenUrlEventBase::targetValuePropertyKey:
                 return object->is<OpenUrlEventBase>();
-            case DataBindBase::targetIdPropertyKey:
-                return object->is<DataBindBase>();
             case DataBindBase::propertyKeyPropertyKey:
                 return object->is<DataBindBase>();
             case DataBindBase::flagsPropertyKey:
                 return object->is<DataBindBase>();
+            case BindablePropertyEnumBase::propertyValuePropertyKey:
+                return object->is<BindablePropertyEnumBase>();
             case WeightBase::valuesPropertyKey:
                 return object->is<WeightBase>();
             case WeightBase::indicesPropertyKey:
@@ -3068,6 +3110,8 @@
                 return object->is<SolidColorBase>();
             case GradientStopBase::colorValuePropertyKey:
                 return object->is<GradientStopBase>();
+            case BindablePropertyColorBase::propertyValuePropertyKey:
+                return object->is<BindablePropertyColorBase>();
             case ViewModelComponentBase::namePropertyKey:
                 return object->is<ViewModelComponentBase>();
             case ViewModelInstanceStringBase::propertyValuePropertyKey:
@@ -3086,6 +3130,8 @@
                 return object->is<KeyFrameStringBase>();
             case OpenUrlEventBase::urlPropertyKey:
                 return object->is<OpenUrlEventBase>();
+            case BindablePropertyStringBase::propertyValuePropertyKey:
+                return object->is<BindablePropertyStringBase>();
             case TextValueRunBase::textPropertyKey:
                 return object->is<TextValueRunBase>();
             case CustomPropertyStringBase::propertyValuePropertyKey:
@@ -3332,6 +3378,8 @@
                 return object->is<JoystickBase>();
             case JoystickBase::heightPropertyKey:
                 return object->is<JoystickBase>();
+            case BindablePropertyNumberBase::propertyValuePropertyKey:
+                return object->is<BindablePropertyNumberBase>();
             case BoneBase::lengthPropertyKey:
                 return object->is<BoneBase>();
             case RootBoneBase::xPropertyKey:
diff --git a/include/rive/generated/data_bind/bindable_property_base.hpp b/include/rive/generated/data_bind/bindable_property_base.hpp
new file mode 100644
index 0000000..b5d5f14
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_BASE_HPP_
+#include "rive/core.hpp"
+namespace rive
+{
+class BindablePropertyBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 9;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    void copy(const BindablePropertyBase& object) {}
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override { return false; }
+
+protected:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/bindable_property_boolean_base.hpp b/include/rive/generated/data_bind/bindable_property_boolean_base.hpp
new file mode 100644
index 0000000..366b551
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_boolean_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_BOOLEAN_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_BOOLEAN_BASE_HPP_
+#include "rive/core/field_types/core_bool_type.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+namespace rive
+{
+class BindablePropertyBooleanBase : public BindableProperty
+{
+protected:
+    typedef BindableProperty Super;
+
+public:
+    static const uint16_t typeKey = 472;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyBooleanBase::typeKey:
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 634;
+
+private:
+    bool m_PropertyValue = false;
+
+public:
+    inline bool propertyValue() const { return m_PropertyValue; }
+    void propertyValue(bool value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const BindablePropertyBooleanBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        BindableProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreBoolType::deserialize(reader);
+                return true;
+        }
+        return BindableProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/bindable_property_color_base.hpp b/include/rive/generated/data_bind/bindable_property_color_base.hpp
new file mode 100644
index 0000000..a14617d
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_color_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_COLOR_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_COLOR_BASE_HPP_
+#include "rive/core/field_types/core_color_type.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+namespace rive
+{
+class BindablePropertyColorBase : public BindableProperty
+{
+protected:
+    typedef BindableProperty Super;
+
+public:
+    static const uint16_t typeKey = 475;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyColorBase::typeKey:
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 638;
+
+private:
+    int m_PropertyValue = 0xFF1D1D1D;
+
+public:
+    inline int propertyValue() const { return m_PropertyValue; }
+    void propertyValue(int value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const BindablePropertyColorBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        BindableProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreColorType::deserialize(reader);
+                return true;
+        }
+        return BindableProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/bindable_property_enum_base.hpp b/include/rive/generated/data_bind/bindable_property_enum_base.hpp
new file mode 100644
index 0000000..30c6f44
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_enum_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_ENUM_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_ENUM_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+namespace rive
+{
+class BindablePropertyEnumBase : public BindableProperty
+{
+protected:
+    typedef BindableProperty Super;
+
+public:
+    static const uint16_t typeKey = 474;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyEnumBase::typeKey:
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 637;
+
+private:
+    uint32_t m_PropertyValue = -1;
+
+public:
+    inline uint32_t propertyValue() const { return m_PropertyValue; }
+    void propertyValue(uint32_t value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const BindablePropertyEnumBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        BindableProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return BindableProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/bindable_property_number_base.hpp b/include/rive/generated/data_bind/bindable_property_number_base.hpp
new file mode 100644
index 0000000..72596c1
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_number_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_NUMBER_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_NUMBER_BASE_HPP_
+#include "rive/core/field_types/core_double_type.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+namespace rive
+{
+class BindablePropertyNumberBase : public BindableProperty
+{
+protected:
+    typedef BindableProperty Super;
+
+public:
+    static const uint16_t typeKey = 473;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyNumberBase::typeKey:
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 636;
+
+private:
+    float m_PropertyValue = 0.0f;
+
+public:
+    inline float propertyValue() const { return m_PropertyValue; }
+    void propertyValue(float value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const BindablePropertyNumberBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        BindableProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreDoubleType::deserialize(reader);
+                return true;
+        }
+        return BindableProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/bindable_property_string_base.hpp b/include/rive/generated/data_bind/bindable_property_string_base.hpp
new file mode 100644
index 0000000..88d5121
--- /dev/null
+++ b/include/rive/generated/data_bind/bindable_property_string_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_STRING_BASE_HPP_
+#define _RIVE_BINDABLE_PROPERTY_STRING_BASE_HPP_
+#include <string>
+#include "rive/core/field_types/core_string_type.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+namespace rive
+{
+class BindablePropertyStringBase : public BindableProperty
+{
+protected:
+    typedef BindableProperty Super;
+
+public:
+    static const uint16_t typeKey = 471;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case BindablePropertyStringBase::typeKey:
+            case BindablePropertyBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 635;
+
+private:
+    std::string m_PropertyValue = "";
+
+public:
+    inline const std::string& propertyValue() const { return m_PropertyValue; }
+    void propertyValue(std::string value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const BindablePropertyStringBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        BindableProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreStringType::deserialize(reader);
+                return true;
+        }
+        return BindableProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/data_bind_base.hpp b/include/rive/generated/data_bind/data_bind_base.hpp
index 4c73ffc..b900663 100644
--- a/include/rive/generated/data_bind/data_bind_base.hpp
+++ b/include/rive/generated/data_bind/data_bind_base.hpp
@@ -1,13 +1,13 @@
 #ifndef _RIVE_DATA_BIND_BASE_HPP_
 #define _RIVE_DATA_BIND_BASE_HPP_
-#include "rive/component.hpp"
+#include "rive/core.hpp"
 #include "rive/core/field_types/core_uint_type.hpp"
 namespace rive
 {
-class DataBindBase : public Component
+class DataBindBase : public Core
 {
 protected:
-    typedef Component Super;
+    typedef Core Super;
 
 public:
     static const uint16_t typeKey = 446;
@@ -19,7 +19,6 @@
         switch (typeKey)
         {
             case DataBindBase::typeKey:
-            case ComponentBase::typeKey:
                 return true;
             default:
                 return false;
@@ -28,27 +27,14 @@
 
     uint16_t coreType() const override { return typeKey; }
 
-    static const uint16_t targetIdPropertyKey = 585;
     static const uint16_t propertyKeyPropertyKey = 586;
     static const uint16_t flagsPropertyKey = 587;
 
 private:
-    uint32_t m_TargetId = -1;
     uint32_t m_PropertyKey = Core::invalidPropertyKey;
     uint32_t m_Flags = 0;
 
 public:
-    inline uint32_t targetId() const { return m_TargetId; }
-    void targetId(uint32_t value)
-    {
-        if (m_TargetId == value)
-        {
-            return;
-        }
-        m_TargetId = value;
-        targetIdChanged();
-    }
-
     inline uint32_t propertyKey() const { return m_PropertyKey; }
     void propertyKey(uint32_t value)
     {
@@ -74,19 +60,14 @@
     Core* clone() const override;
     void copy(const DataBindBase& object)
     {
-        m_TargetId = object.m_TargetId;
         m_PropertyKey = object.m_PropertyKey;
         m_Flags = object.m_Flags;
-        Component::copy(object);
     }
 
     bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
     {
         switch (propertyKey)
         {
-            case targetIdPropertyKey:
-                m_TargetId = CoreUintType::deserialize(reader);
-                return true;
             case propertyKeyPropertyKey:
                 m_PropertyKey = CoreUintType::deserialize(reader);
                 return true;
@@ -94,11 +75,10 @@
                 m_Flags = CoreUintType::deserialize(reader);
                 return true;
         }
-        return Component::deserialize(propertyKey, reader);
+        return false;
     }
 
 protected:
-    virtual void targetIdChanged() {}
     virtual void propertyKeyChanged() {}
     virtual void flagsChanged() {}
 };
diff --git a/include/rive/generated/data_bind/data_bind_context_base.hpp b/include/rive/generated/data_bind/data_bind_context_base.hpp
index d1871d4..e8b772a 100644
--- a/include/rive/generated/data_bind/data_bind_context_base.hpp
+++ b/include/rive/generated/data_bind/data_bind_context_base.hpp
@@ -21,7 +21,6 @@
         {
             case DataBindContextBase::typeKey:
             case DataBindBase::typeKey:
-            case ComponentBase::typeKey:
                 return true;
             default:
                 return false;
diff --git a/include/rive/importers/artboard_importer.hpp b/include/rive/importers/artboard_importer.hpp
index 1525803..102bfd0 100644
--- a/include/rive/importers/artboard_importer.hpp
+++ b/include/rive/importers/artboard_importer.hpp
@@ -11,6 +11,7 @@
 class StateMachine;
 class TextValueRun;
 class Event;
+class DataBind;
 class ArtboardImporter : public ImportStackObject
 {
 private:
@@ -21,6 +22,7 @@
     void addComponent(Core* object);
     void addAnimation(LinearAnimation* animation);
     void addStateMachine(StateMachine* stateMachine);
+    void addDataBind(DataBind* dataBind);
     StatusCode resolve() override;
     const Artboard* artboard() const { return m_Artboard; }
 
diff --git a/include/rive/importers/bindable_property_importer.hpp b/include/rive/importers/bindable_property_importer.hpp
new file mode 100644
index 0000000..002ebe7
--- /dev/null
+++ b/include/rive/importers/bindable_property_importer.hpp
@@ -0,0 +1,20 @@
+#ifndef _RIVE_BINDABLE_PROPERTY_IMPORTER_HPP_
+#define _RIVE_BINDABLE_PROPERTY_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class Core;
+class BindableProperty;
+class BindablePropertyImporter : public ImportStackObject
+{
+private:
+    BindableProperty* m_bindableProperty;
+
+public:
+    BindablePropertyImporter(BindableProperty* bindableProperty);
+    BindableProperty* bindableProperty() { return m_bindableProperty; }
+};
+} // namespace rive
+#endif
\ No newline at end of file
diff --git a/include/rive/importers/state_machine_importer.hpp b/include/rive/importers/state_machine_importer.hpp
index f00ae45..dc08236 100644
--- a/include/rive/importers/state_machine_importer.hpp
+++ b/include/rive/importers/state_machine_importer.hpp
@@ -9,6 +9,7 @@
 class StateMachineLayer;
 class StateMachineListener;
 class StateMachine;
+class DataBind;
 class StateMachineImporter : public ImportStackObject
 {
 private:
@@ -21,6 +22,7 @@
     void addLayer(std::unique_ptr<StateMachineLayer>);
     void addInput(std::unique_ptr<StateMachineInput>);
     void addListener(std::unique_ptr<StateMachineListener>);
+    void addDataBind(std::unique_ptr<DataBind>);
 
     StatusCode resolve() override;
     bool readNullObject() override;
diff --git a/include/rive/nested_artboard.hpp b/include/rive/nested_artboard.hpp
index 9f57ec4..5759815 100644
--- a/include/rive/nested_artboard.hpp
+++ b/include/rive/nested_artboard.hpp
@@ -2,6 +2,8 @@
 #define _RIVE_NESTED_ARTBOARD_HPP_
 
 #include "rive/generated/nested_artboard_base.hpp"
+#include "rive/data_bind/data_context.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
 #include "rive/hit_info.hpp"
 #include "rive/span.hpp"
 #include <stdio.h>
@@ -97,6 +99,8 @@
     void decodeDataBindPathIds(Span<const uint8_t> value) override;
     void copyDataBindPathIds(const NestedArtboardBase& object) override;
     std::vector<uint32_t> dataBindPathIds() { return m_DataBindPathIdsBuffer; };
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance, DataContext* parent);
+    void internalDataContext(DataContext* dataContext, DataContext* parent);
 };
 } // namespace rive
 
diff --git a/include/rive/scene.hpp b/include/rive/scene.hpp
index fd96d8e..7d36204 100644
--- a/include/rive/scene.hpp
+++ b/include/rive/scene.hpp
@@ -13,6 +13,7 @@
 {
 class ArtboardInstance;
 class Renderer;
+class ViewModelInstance;
 
 class SMIInput;
 class SMIBool;
@@ -47,6 +48,8 @@
 
     void draw(Renderer*);
 
+    virtual void dataContextFromInstance(ViewModelInstance* viewModelInstance);
+
     virtual HitResult pointerDown(Vec2D);
     virtual HitResult pointerMove(Vec2D);
     virtual HitResult pointerUp(Vec2D);
diff --git a/src/animation/nested_state_machine.cpp b/src/animation/nested_state_machine.cpp
index 6045b56..8176757 100644
--- a/src/animation/nested_state_machine.cpp
+++ b/src/animation/nested_state_machine.cpp
@@ -107,4 +107,20 @@
     return nullptr;
 }
 
-void NestedStateMachine::addNestedInput(NestedInput* input) { m_nestedInputs.push_back(input); }
\ No newline at end of file
+void NestedStateMachine::addNestedInput(NestedInput* input) { m_nestedInputs.push_back(input); }
+
+void NestedStateMachine::dataContextFromInstance(ViewModelInstance* viewModelInstance)
+{
+    if (m_StateMachineInstance != nullptr)
+    {
+        m_StateMachineInstance->dataContextFromInstance(viewModelInstance);
+    }
+}
+
+void NestedStateMachine::dataContext(DataContext* dataContext)
+{
+    if (m_StateMachineInstance != nullptr)
+    {
+        m_StateMachineInstance->dataContext(dataContext);
+    }
+}
\ No newline at end of file
diff --git a/src/animation/state_machine.cpp b/src/animation/state_machine.cpp
index 0450691..9b44672 100644
--- a/src/animation/state_machine.cpp
+++ b/src/animation/state_machine.cpp
@@ -91,6 +91,11 @@
     m_Listeners.push_back(std::move(listener));
 }
 
+void StateMachine::addDataBind(std::unique_ptr<DataBind> dataBind)
+{
+    m_dataBinds.push_back(std::move(dataBind));
+}
+
 const StateMachineInput* StateMachine::input(std::string name) const
 {
     for (auto& input : m_Inputs)
@@ -140,4 +145,13 @@
         return m_Listeners[index].get();
     }
     return nullptr;
+}
+
+const DataBind* StateMachine::dataBind(size_t index) const
+{
+    if (index < m_dataBinds.size())
+    {
+        return m_dataBinds[index].get();
+    }
+    return nullptr;
 }
\ No newline at end of file
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp
index 90bafbc..274ea78 100644
--- a/src/animation/state_machine_instance.cpp
+++ b/src/animation/state_machine_instance.cpp
@@ -904,6 +904,23 @@
     return getNamedInput<StateMachineTrigger, SMITrigger>(name);
 }
 
+void StateMachineInstance::dataContextFromInstance(ViewModelInstance* viewModelInstance)
+{
+    dataContext(new DataContext(viewModelInstance));
+}
+
+void StateMachineInstance::dataContext(DataContext* dataContext)
+{
+    m_DataContext = dataContext;
+    for (auto dataBind : m_dataBinds)
+    {
+        if (dataBind->is<DataBindContext>())
+        {
+            dataBind->as<DataBindContext>()->bindFromContext(dataContext);
+        }
+    }
+}
+
 size_t StateMachineInstance::stateChangedCount() const
 {
     size_t count = 0;
@@ -1039,4 +1056,14 @@
             }
         }
     }
+}
+
+BindableProperty* StateMachineInstance::bindablePropertyInstance(BindableProperty* bindableProperty)
+{
+    auto bindablePropertyInstance = m_bindablePropertyInstances.find(bindableProperty);
+    if (bindablePropertyInstance == m_bindablePropertyInstances.end())
+    {
+        return nullptr;
+    }
+    return bindablePropertyInstance->second;
 }
\ No newline at end of file
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 47c5d04..3a0b299 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -173,9 +173,6 @@
             case NestedArtboardBase::typeKey:
                 m_NestedArtboards.push_back(object->as<NestedArtboard>());
                 break;
-            case DataBindContext::typeKey:
-                m_DataBinds.push_back(object->as<DataBind>());
-                break;
 
             case JoystickBase::typeKey:
             {
@@ -515,12 +512,12 @@
     for (auto dataBind : m_AllDataBinds)
     {
         dataBind->updateSourceBinding();
-        auto d = dataBind->m_Dirt;
+        auto d = dataBind->dirt();
         if (d == ComponentDirt::None)
         {
             continue;
         }
-        dataBind->m_Dirt = ComponentDirt::None;
+        dataBind->dirt(ComponentDirt::None);
         dataBind->update(d);
     }
 }
@@ -1004,102 +1001,38 @@
         auto value = m_DataContext->getViewModelInstance(nestedArtboard->dataBindPathIds());
         if (value != nullptr && value->is<ViewModelInstance>())
         {
-            nestedArtboard->artboard()->dataContextFromInstance(value, m_DataContext, false);
+            nestedArtboard->dataContextFromInstance(value, m_DataContext);
         }
         else
         {
-            nestedArtboard->artboard()->internalDataContext(m_DataContext,
-                                                            m_DataContext->parent(),
-                                                            false);
+            nestedArtboard->internalDataContext(m_DataContext, m_DataContext->parent());
         }
     }
     for (auto dataBind : m_DataBinds)
     {
         if (dataBind->is<DataBindContext>())
         {
-            dataBind->as<DataBindContext>()->bind();
+            dataBind->as<DataBindContext>()->bindFromContext(m_DataContext);
         }
     }
     if (isRoot)
     {
-        std::vector<Component*> dataBinds;
+        std::vector<DataBind*> dataBinds;
         populateDataBinds(&dataBinds);
-        buildDataBindDependencies(&dataBinds);
         sortDataBinds(dataBinds);
     }
 }
 
-void Artboard::sortDataBinds(std::vector<Component*> dataBinds)
+void Artboard::sortDataBinds(std::vector<DataBind*> dataBinds)
 {
-    DependencySorter sorter;
     // TODO: @hernan review this. Should not need to push to a component list to sort.
 
-    std::vector<Component*> dbOrder;
-    sorter.sort(dataBinds, dbOrder);
-    for (auto dataBind : dbOrder)
+    for (auto dataBind : dataBinds)
     {
         m_AllDataBinds.push_back(dataBind->as<DataBind>());
     }
 }
 
-void Artboard::buildDataBindDependencies(std::vector<Component*>* dataBinds)
-{
-    // TODO: @hernan review this dependency building
-    // Do we really need this? If a property is bound to a data bind, it can't be bound
-    // to a second data bind object.
-    for (auto component : *dataBinds)
-    {
-        auto dataBind = component->as<DataBind>();
-        auto flags = static_cast<DataBindFlags>(dataBind->flags());
-        // If the data bind reads from the target, we want to add it as dependent from any other
-        // parent data bind that writes into that target.
-        if (((flags & DataBindFlags::Direction) == DataBindFlags::ToSource) ||
-            ((flags & DataBindFlags::TwoWay) == DataBindFlags::TwoWay))
-        {
-            for (auto innerComponent : *dataBinds)
-            {
-                auto dataBindParent = innerComponent->as<DataBind>();
-                auto parentFlags = static_cast<DataBindFlags>(dataBindParent->flags());
-                if (dataBindParent != dataBind &&
-                    (((parentFlags & DataBindFlags::Direction) == DataBindFlags::ToTarget) ||
-                     ((parentFlags & DataBindFlags::TwoWay) == DataBindFlags::TwoWay)) &&
-                    dataBindParent->target() == dataBind->target() &&
-                    dataBindParent->propertyKey() == dataBind->propertyKey())
-                {
-                    dataBindParent->addDependent(dataBind);
-                    break;
-                }
-            }
-        }
-        else
-        {
-            // If the data bind reads from a source we want to add it as dependent
-            // from any other parent data bind that writes into that source.
-            if (dataBind->is<DataBindContext>())
-            {
-                for (auto innerComponent : *dataBinds)
-                {
-                    auto dataBindParent = innerComponent->as<DataBind>();
-                    if (dataBindParent != dataBind)
-                    {
-                        auto parentFlags = static_cast<DataBindFlags>(dataBindParent->flags());
-                        if (((parentFlags & DataBindFlags::Direction) == DataBindFlags::ToSource) ||
-                            ((parentFlags & DataBindFlags::TwoWay) == DataBindFlags::TwoWay))
-                        {
-                            if (dataBindParent->is<DataBindContext>() &&
-                                dataBindParent->as<DataBindContext>()->source() ==
-                                    dataBind->as<DataBindContext>()->source())
-                            {
-                                dataBindParent->addDependent(dataBind);
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
 float Artboard::volume() const { return m_volume; }
 void Artboard::volume(float value)
 {
@@ -1114,7 +1047,7 @@
     }
 }
 
-void Artboard::populateDataBinds(std::vector<Component*>* dataBinds)
+void Artboard::populateDataBinds(std::vector<DataBind*>* dataBinds)
 {
     for (auto dataBind : m_DataBinds)
     {
@@ -1129,6 +1062,8 @@
     }
 }
 
+void Artboard::addDataBind(DataBind* dataBind) { m_DataBinds.push_back(dataBind); }
+
 void Artboard::dataContext(DataContext* value, DataContext* parent)
 {
     internalDataContext(value, parent, true);
diff --git a/src/data_bind/context/context_value_boolean.cpp b/src/data_bind/context/context_value_boolean.cpp
index 3116aa9..b7b708b 100644
--- a/src/data_bind/context/context_value_boolean.cpp
+++ b/src/data_bind/context/context_value_boolean.cpp
@@ -6,16 +6,17 @@
 DataBindContextValueBoolean::DataBindContextValueBoolean(ViewModelInstanceValue* value)
 {
     m_Source = value;
+    m_Value = m_Source->as<ViewModelInstanceBoolean>()->propertyValue();
 }
 
-void DataBindContextValueBoolean::apply(Component* target, uint32_t propertyKey)
+void DataBindContextValueBoolean::apply(Core* target, uint32_t propertyKey)
 {
     CoreRegistry::setBool(target,
                           propertyKey,
                           m_Source->as<ViewModelInstanceBoolean>()->propertyValue());
 }
 
-void DataBindContextValueBoolean::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueBoolean::applyToSource(Core* target, uint32_t propertyKey)
 {
     auto value = CoreRegistry::getBool(target, propertyKey);
     if (m_Value != value)
diff --git a/src/data_bind/context/context_value_color.cpp b/src/data_bind/context/context_value_color.cpp
index 18d392f..44a1857 100644
--- a/src/data_bind/context/context_value_color.cpp
+++ b/src/data_bind/context/context_value_color.cpp
@@ -6,16 +6,17 @@
 DataBindContextValueColor::DataBindContextValueColor(ViewModelInstanceValue* value)
 {
     m_Source = value;
+    m_Value = m_Source->as<ViewModelInstanceColor>()->propertyValue();
 }
 
-void DataBindContextValueColor::apply(Component* target, uint32_t propertyKey)
+void DataBindContextValueColor::apply(Core* target, uint32_t propertyKey)
 {
     CoreRegistry::setColor(target,
                            propertyKey,
                            m_Source->as<ViewModelInstanceColor>()->propertyValue());
 }
 
-void DataBindContextValueColor::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueColor::applyToSource(Core* target, uint32_t propertyKey)
 {
     auto value = CoreRegistry::getColor(target, propertyKey);
     if (m_Value != value)
diff --git a/src/data_bind/context/context_value_enum.cpp b/src/data_bind/context/context_value_enum.cpp
index 8569ce9..a0064bc 100644
--- a/src/data_bind/context/context_value_enum.cpp
+++ b/src/data_bind/context/context_value_enum.cpp
@@ -6,17 +6,23 @@
 DataBindContextValueEnum::DataBindContextValueEnum(ViewModelInstanceValue* value)
 {
     m_Source = value;
+    m_Value = m_Source->as<ViewModelInstanceEnum>()->propertyValue();
 }
 
-void DataBindContextValueEnum::apply(Component* target, uint32_t propertyKey)
+void DataBindContextValueEnum::apply(Core* target, uint32_t propertyKey)
 {
     auto enumSource = m_Source->as<ViewModelInstanceEnum>();
     auto enumProperty = enumSource->viewModelProperty()->as<ViewModelPropertyEnum>();
     auto enumValue = enumProperty->value(m_Source->as<ViewModelInstanceEnum>()->propertyValue());
+    // TODO: @hernan decide which one makes more sense. Probably setUint, but setString was used to
+    // update text input with enum values.
     CoreRegistry::setString(target, propertyKey, enumValue);
+    CoreRegistry::setUint(target,
+                          propertyKey,
+                          m_Source->as<ViewModelInstanceEnum>()->propertyValue());
 }
 
-void DataBindContextValueEnum::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueEnum::applyToSource(Core* target, uint32_t propertyKey)
 {
     auto value = CoreRegistry::getString(target, propertyKey);
     auto enumSource = m_Source->as<ViewModelInstanceEnum>();
diff --git a/src/data_bind/context/context_value_list.cpp b/src/data_bind/context/context_value_list.cpp
index 59f0f55..f0aa427 100644
--- a/src/data_bind/context/context_value_list.cpp
+++ b/src/data_bind/context/context_value_list.cpp
@@ -40,12 +40,12 @@
     return nullptr;
 }
 
-void DataBindContextValueList::insertItem(Component* target,
+void DataBindContextValueList::insertItem(Core* target,
                                           ViewModelInstanceListItem* listItem,
                                           int index)
 {
     auto artboard = listItem->artboard();
-    auto artboardCopy = createArtboard(target, artboard, listItem);
+    auto artboardCopy = createArtboard(target->as<Component>(), artboard, listItem);
     auto stateMachineInstance = createStateMachineInstance(artboardCopy.get());
     std::unique_ptr<DataBindContextValueListItem> cacheListItem =
         rivestd::make_unique<DataBindContextValueListItem>(std::move(artboardCopy),
@@ -61,14 +61,14 @@
     }
 }
 
-void DataBindContextValueList::swapItems(Component* target, int index1, int index2)
+void DataBindContextValueList::swapItems(Core* target, int index1, int index2)
 {
     std::iter_swap(m_ListItemsCache.begin() + index1, m_ListItemsCache.begin() + index2);
 }
 
-void DataBindContextValueList::popItem(Component* target) { m_ListItemsCache.pop_back(); }
+void DataBindContextValueList::popItem(Core* target) { m_ListItemsCache.pop_back(); }
 
-void DataBindContextValueList::update(Component* target)
+void DataBindContextValueList::update(Core* target)
 {
     if (target != nullptr)
     {
@@ -125,9 +125,9 @@
     }
 }
 
-void DataBindContextValueList::apply(Component* target, uint32_t propertyKey) {}
+void DataBindContextValueList::apply(Core* target, uint32_t propertyKey) {}
 
-void DataBindContextValueList::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueList::applyToSource(Core* target, uint32_t propertyKey)
 {
     // TODO: @hernan does applyToSource make sense? Should we block it somehow?
 }
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_number.cpp b/src/data_bind/context/context_value_number.cpp
index ecc5b7f..63fabf8 100644
--- a/src/data_bind/context/context_value_number.cpp
+++ b/src/data_bind/context/context_value_number.cpp
@@ -6,16 +6,17 @@
 DataBindContextValueNumber::DataBindContextValueNumber(ViewModelInstanceValue* value)
 {
     m_Source = value;
+    m_Value = m_Source->as<ViewModelInstanceNumber>()->propertyValue();
 }
 
-void DataBindContextValueNumber::apply(Component* target, uint32_t propertyKey)
+void DataBindContextValueNumber::apply(Core* target, uint32_t propertyKey)
 {
     CoreRegistry::setDouble(target,
                             propertyKey,
                             m_Source->as<ViewModelInstanceNumber>()->propertyValue());
 }
 
-void DataBindContextValueNumber::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueNumber::applyToSource(Core* target, uint32_t propertyKey)
 {
     auto value = CoreRegistry::getDouble(target, propertyKey);
     if (m_Value != value)
diff --git a/src/data_bind/context/context_value_string.cpp b/src/data_bind/context/context_value_string.cpp
index 6a62e75..9cf19f7 100644
--- a/src/data_bind/context/context_value_string.cpp
+++ b/src/data_bind/context/context_value_string.cpp
@@ -6,16 +6,17 @@
 DataBindContextValueString::DataBindContextValueString(ViewModelInstanceValue* value)
 {
     m_Source = value;
+    m_Value = m_Source->as<ViewModelInstanceString>()->propertyValue();
 }
 
-void DataBindContextValueString::apply(Component* target, uint32_t propertyKey)
+void DataBindContextValueString::apply(Core* target, uint32_t propertyKey)
 {
     CoreRegistry::setString(target,
                             propertyKey,
                             m_Source->as<ViewModelInstanceString>()->propertyValue());
 }
 
-void DataBindContextValueString::applyToSource(Component* target, uint32_t propertyKey)
+void DataBindContextValueString::applyToSource(Core* target, uint32_t propertyKey)
 {
     auto value = CoreRegistry::getString(target, propertyKey);
     if (m_Value != value)
diff --git a/src/data_bind/data_bind.cpp b/src/data_bind/data_bind.cpp
index adfa276..a1ab715 100644
--- a/src/data_bind/data_bind.cpp
+++ b/src/data_bind/data_bind.cpp
@@ -2,6 +2,11 @@
 #include "rive/artboard.hpp"
 #include "rive/data_bind_flags.hpp"
 #include "rive/generated/core_registry.hpp"
+#include "rive/data_bind/bindable_property_number.hpp"
+#include "rive/data_bind/bindable_property_string.hpp"
+#include "rive/data_bind/bindable_property_color.hpp"
+#include "rive/data_bind/bindable_property_enum.hpp"
+#include "rive/data_bind/bindable_property_boolean.hpp"
 #include "rive/data_bind/context/context_value.hpp"
 #include "rive/data_bind/context/context_value_boolean.hpp"
 #include "rive/data_bind/context/context_value_number.hpp"
@@ -9,14 +14,12 @@
 #include "rive/data_bind/context/context_value_enum.hpp"
 #include "rive/data_bind/context/context_value_list.hpp"
 #include "rive/data_bind/context/context_value_color.hpp"
+#include "rive/animation/state_machine.hpp"
+#include "rive/importers/artboard_importer.hpp"
+#include "rive/importers/state_machine_importer.hpp"
 
 using namespace rive;
 
-// StatusCode DataBind::onAddedClean(CoreContext* context)
-// {
-//     return Super::onAddedClean(context);
-// }
-
 StatusCode DataBind::onAddedDirty(CoreContext* context)
 {
     StatusCode code = Super::onAddedDirty(context);
@@ -24,28 +27,44 @@
     {
         return code;
     }
-    auto coreObject = context->resolve(targetId());
-    if (coreObject == nullptr || !coreObject->is<Component>())
-    {
-        return StatusCode::MissingObject;
-    }
-
-    m_target = static_cast<Component*>(coreObject);
 
     return StatusCode::Ok;
 }
 
-StatusCode DataBind::import(ImportStack& importStack) { return Super::import(importStack); }
-
-void DataBind::buildDependencies()
+StatusCode DataBind::import(ImportStack& importStack)
 {
-    Super::buildDependencies();
-    auto flagsValue = static_cast<DataBindFlags>(flags());
-    if (((flagsValue & DataBindFlags::Direction) == DataBindFlags::ToSource) ||
-        ((flagsValue & DataBindFlags::TwoWay) == DataBindFlags::TwoWay))
+    if (target())
     {
-        m_target->addDependent(this);
+        switch (target()->coreType())
+        {
+            case BindablePropertyNumberBase::typeKey:
+            case BindablePropertyStringBase::typeKey:
+            case BindablePropertyBooleanBase::typeKey:
+            case BindablePropertyEnumBase::typeKey:
+            case BindablePropertyColorBase::typeKey:
+            {
+                auto stateMachineImporter =
+                    importStack.latest<StateMachineImporter>(StateMachineBase::typeKey);
+                if (stateMachineImporter != nullptr)
+                {
+                    stateMachineImporter->addDataBind(std::unique_ptr<DataBind>(this));
+                    return Super::import(importStack);
+                }
+                break;
+            }
+            default:
+            {
+                auto artboardImporter = importStack.latest<ArtboardImporter>(ArtboardBase::typeKey);
+                if (artboardImporter != nullptr)
+                {
+                    artboardImporter->addDataBind(this);
+                    return Super::import(importStack);
+                }
+                break;
+            }
+        }
     }
+    return Super::import(importStack);
 }
 
 void DataBind::bind()
@@ -97,7 +116,6 @@
             }
         }
     }
-    Super::update(value);
 }
 
 void DataBind::updateSourceBinding()
@@ -111,4 +129,16 @@
             m_ContextValue->applyToSource(m_target, propertyKey());
         }
     }
+}
+
+bool DataBind::addDirt(ComponentDirt value, bool recurse)
+{
+    if ((m_Dirt & value) == value)
+    {
+        // Already marked.
+        return false;
+    }
+
+    m_Dirt |= value;
+    return true;
 }
\ No newline at end of file
diff --git a/src/data_bind/data_bind_context.cpp b/src/data_bind/data_bind_context.cpp
index 4bb86f6..62eae73 100644
--- a/src/data_bind/data_bind_context.cpp
+++ b/src/data_bind/data_bind_context.cpp
@@ -26,9 +26,8 @@
     m_SourcePathIdsBuffer = object.as<DataBindContext>()->m_SourcePathIdsBuffer;
 }
 
-void DataBindContext::bind()
+void DataBindContext::bindFromContext(DataContext* dataContext)
 {
-    auto dataContext = artboard()->dataContext();
     if (dataContext != nullptr)
     {
         auto value = dataContext->getViewModelProperty(m_SourcePathIdsBuffer);
@@ -36,7 +35,7 @@
         {
             value->addDependent(this);
             m_Source = value;
-            Super::bind();
+            bind();
         }
     }
 }
\ No newline at end of file
diff --git a/src/file.cpp b/src/file.cpp
index 93bdf04..57fb4a7 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -8,6 +8,7 @@
 #include "rive/generated/core_registry.hpp"
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/importers/backboard_importer.hpp"
+#include "rive/importers/bindable_property_importer.hpp"
 #include "rive/importers/enum_importer.hpp"
 #include "rive/importers/file_asset_importer.hpp"
 #include "rive/importers/import_stack.hpp"
@@ -30,6 +31,12 @@
 #include "rive/animation/animation_state.hpp"
 #include "rive/animation/blend_state_1d.hpp"
 #include "rive/animation/blend_state_direct.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+#include "rive/data_bind/bindable_property_number.hpp"
+#include "rive/data_bind/bindable_property_string.hpp"
+#include "rive/data_bind/bindable_property_color.hpp"
+#include "rive/data_bind/bindable_property_enum.hpp"
+#include "rive/data_bind/bindable_property_boolean.hpp"
 #include "rive/assets/file_asset.hpp"
 #include "rive/assets/audio_asset.hpp"
 #include "rive/assets/file_asset_contents.hpp"
@@ -204,6 +211,10 @@
 ImportResult File::read(BinaryReader& reader, const RuntimeHeader& header)
 {
     ImportStack importStack;
+    // TODO: @hernan consider moving this to a special importer. It's not that
+    // simple because Core doesn't have a typeKey, so it should be treated as
+    // a special case. In any case, it's not that bad having it here for now.
+    Core* lastBindableObject;
     while (!reader.reachedEnd())
     {
         auto object = readRuntimeObject(reader, header);
@@ -212,6 +223,14 @@
             importStack.readNullObject();
             continue;
         }
+        if (!object->is<DataBind>())
+        {
+            lastBindableObject = object;
+        }
+        else if (lastBindableObject != nullptr)
+        {
+            object->as<DataBind>()->target(lastBindableObject);
+        }
         if (object->import(importStack) == StatusCode::Ok)
         {
             switch (object->coreType())
@@ -353,6 +372,15 @@
                     object->as<ViewModelInstanceList>());
                 stackType = ViewModelInstanceList::typeKey;
                 break;
+            case BindablePropertyNumber::typeKey:
+            case BindablePropertyString::typeKey:
+            case BindablePropertyColor::typeKey:
+            case BindablePropertyEnum::typeKey:
+            case BindablePropertyBoolean::typeKey:
+                stackObject =
+                    rivestd::make_unique<BindablePropertyImporter>(object->as<BindableProperty>());
+                stackType = BindablePropertyBase::typeKey;
+                break;
         }
         if (importStack.makeLatest(stackType, std::move(stackObject)) != StatusCode::Ok)
         {
diff --git a/src/generated/data_bind/bindable_property_boolean_base.cpp b/src/generated/data_bind/bindable_property_boolean_base.cpp
new file mode 100644
index 0000000..4e3dcc2
--- /dev/null
+++ b/src/generated/data_bind/bindable_property_boolean_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/bindable_property_boolean_base.hpp"
+#include "rive/data_bind/bindable_property_boolean.hpp"
+
+using namespace rive;
+
+Core* BindablePropertyBooleanBase::clone() const
+{
+    auto cloned = new BindablePropertyBoolean();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/data_bind/bindable_property_color_base.cpp b/src/generated/data_bind/bindable_property_color_base.cpp
new file mode 100644
index 0000000..fa64a07
--- /dev/null
+++ b/src/generated/data_bind/bindable_property_color_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/bindable_property_color_base.hpp"
+#include "rive/data_bind/bindable_property_color.hpp"
+
+using namespace rive;
+
+Core* BindablePropertyColorBase::clone() const
+{
+    auto cloned = new BindablePropertyColor();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/data_bind/bindable_property_enum_base.cpp b/src/generated/data_bind/bindable_property_enum_base.cpp
new file mode 100644
index 0000000..acd5be6
--- /dev/null
+++ b/src/generated/data_bind/bindable_property_enum_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/bindable_property_enum_base.hpp"
+#include "rive/data_bind/bindable_property_enum.hpp"
+
+using namespace rive;
+
+Core* BindablePropertyEnumBase::clone() const
+{
+    auto cloned = new BindablePropertyEnum();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/data_bind/bindable_property_number_base.cpp b/src/generated/data_bind/bindable_property_number_base.cpp
new file mode 100644
index 0000000..95b0453
--- /dev/null
+++ b/src/generated/data_bind/bindable_property_number_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/bindable_property_number_base.hpp"
+#include "rive/data_bind/bindable_property_number.hpp"
+
+using namespace rive;
+
+Core* BindablePropertyNumberBase::clone() const
+{
+    auto cloned = new BindablePropertyNumber();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/data_bind/bindable_property_string_base.cpp b/src/generated/data_bind/bindable_property_string_base.cpp
new file mode 100644
index 0000000..04133c7
--- /dev/null
+++ b/src/generated/data_bind/bindable_property_string_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/bindable_property_string_base.hpp"
+#include "rive/data_bind/bindable_property_string.hpp"
+
+using namespace rive;
+
+Core* BindablePropertyStringBase::clone() const
+{
+    auto cloned = new BindablePropertyString();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/importers/artboard_importer.cpp b/src/importers/artboard_importer.cpp
index d0d93df..f2957b0 100644
--- a/src/importers/artboard_importer.cpp
+++ b/src/importers/artboard_importer.cpp
@@ -2,6 +2,7 @@
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/animation/linear_animation.hpp"
 #include "rive/animation/state_machine.hpp"
+#include "rive/data_bind/data_bind.hpp"
 #include "rive/text/text_value_run.hpp"
 #include "rive/event.hpp"
 #include "rive/artboard.hpp"
@@ -22,6 +23,8 @@
     m_Artboard->addStateMachine(stateMachine);
 }
 
+void ArtboardImporter::addDataBind(DataBind* dataBind) { m_Artboard->addDataBind(dataBind); }
+
 StatusCode ArtboardImporter::resolve() { return m_Artboard->initialize(); }
 
 bool ArtboardImporter::readNullObject()
diff --git a/src/importers/bindable_property_importer.cpp b/src/importers/bindable_property_importer.cpp
new file mode 100644
index 0000000..1d992af
--- /dev/null
+++ b/src/importers/bindable_property_importer.cpp
@@ -0,0 +1,9 @@
+#include "rive/artboard.hpp"
+#include "rive/importers/bindable_property_importer.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+
+using namespace rive;
+
+BindablePropertyImporter::BindablePropertyImporter(BindableProperty* bindableProperty) :
+    m_bindableProperty(bindableProperty)
+{}
\ No newline at end of file
diff --git a/src/importers/state_machine_importer.cpp b/src/importers/state_machine_importer.cpp
index 7994c37..70a3985 100644
--- a/src/importers/state_machine_importer.cpp
+++ b/src/importers/state_machine_importer.cpp
@@ -3,6 +3,7 @@
 #include "rive/animation/state_machine_listener.hpp"
 #include "rive/animation/state_machine_input.hpp"
 #include "rive/animation/state_machine_layer.hpp"
+#include "rive/data_bind/data_bind.hpp"
 
 using namespace rive;
 
@@ -23,6 +24,11 @@
     m_StateMachine->addListener(std::move(listener));
 }
 
+void StateMachineImporter::addDataBind(std::unique_ptr<DataBind> dataBind)
+{
+    m_StateMachine->addDataBind(std::move(dataBind));
+}
+
 bool StateMachineImporter::readNullObject()
 {
     // Hard assumption that we won't add new layer types...
diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp
index 6ef8cf3..19437dc 100644
--- a/src/nested_artboard.cpp
+++ b/src/nested_artboard.cpp
@@ -273,4 +273,29 @@
 void NestedArtboard::copyDataBindPathIds(const NestedArtboardBase& object)
 {
     m_DataBindPathIdsBuffer = object.as<NestedArtboard>()->m_DataBindPathIdsBuffer;
+}
+
+void NestedArtboard::internalDataContext(DataContext* value, DataContext* parent)
+{
+    artboard()->internalDataContext(value, parent, false);
+    for (auto animation : m_NestedAnimations)
+    {
+        if (animation->is<NestedStateMachine>())
+        {
+            animation->as<NestedStateMachine>()->dataContext(value);
+        }
+    }
+}
+
+void NestedArtboard::dataContextFromInstance(ViewModelInstance* viewModelInstance,
+                                             DataContext* parent)
+{
+    artboard()->dataContextFromInstance(viewModelInstance, parent, false);
+    for (auto animation : m_NestedAnimations)
+    {
+        if (animation->is<NestedStateMachine>())
+        {
+            animation->as<NestedStateMachine>()->dataContextFromInstance(viewModelInstance);
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/scene.cpp b/src/scene.cpp
index a987dfe..679f33e 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -25,6 +25,7 @@
 SMIBool* Scene::getBool(const std::string&) const { return nullptr; }
 SMINumber* Scene::getNumber(const std::string&) const { return nullptr; }
 SMITrigger* Scene::getTrigger(const std::string&) const { return nullptr; }
+void Scene::dataContextFromInstance(ViewModelInstance* viewModelInstance) {}
 
 void Scene::reportKeyedCallback(uint32_t objectId, uint32_t propertyKey, float elapsedSeconds)
 {
diff --git a/src/viewmodel/viewmodel_instance_enum.cpp b/src/viewmodel/viewmodel_instance_enum.cpp
index 0cdbc60..3b7a755 100644
--- a/src/viewmodel/viewmodel_instance_enum.cpp
+++ b/src/viewmodel/viewmodel_instance_enum.cpp
@@ -8,7 +8,7 @@
 
 using namespace rive;
 
-void ViewModelInstanceEnum::propertyValueChanged() { addDirt(ComponentDirt::Components); }
+void ViewModelInstanceEnum::propertyValueChanged() { addDirt(ComponentDirt::Bindings); }
 
 bool ViewModelInstanceEnum::value(std::string name)
 {