viewmodel transitions runtime

adds support for viewmodel based transition conditions.
added some comments on the most relevant parts.
The rest is mostly boilerplate code from core objects.

Diffs=
d25b9097d viewmodel transitions runtime (#7680)

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index 2080b43..fd8e867 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-1c067cba8e291859c02a6d00dfe68033cf3cda8f
+d25b9097d65eecd2bb8ff35d84b98ad4e2803d30
diff --git a/dev/defs/animation/transition_comparator.json b/dev/defs/animation/transition_comparator.json
new file mode 100644
index 0000000..5d01f6e
--- /dev/null
+++ b/dev/defs/animation/transition_comparator.json
@@ -0,0 +1,8 @@
+{
+  "name": "TransitionComparator",
+  "key": {
+    "int": 477,
+    "string": "transitioncomparator"
+  },
+  "abstract": true
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_condition.json b/dev/defs/animation/transition_condition.json
index 83365b5..660dbfc 100644
--- a/dev/defs/animation/transition_condition.json
+++ b/dev/defs/animation/transition_condition.json
@@ -1,7 +1,7 @@
 {
   "name": "TransitionCondition",
   "key": {
-    "int": 67,
+    "int": 476,
     "string": "transitioncondition"
   },
   "abstract": true,
@@ -28,17 +28,6 @@
       },
       "description": "Order value for condition in a transition.",
       "runtime": false
-    },
-    "inputId": {
-      "type": "Id",
-      "typeRuntime": "uint",
-      "initialValue": "Core.missingId",
-      "initialValueRuntime": "-1",
-      "key": {
-        "int": 155,
-        "string": "inputid"
-      },
-      "description": "Id of the StateMachineInput referenced."
     }
   }
 }
\ No newline at end of file
diff --git a/dev/defs/animation/transition_input_condition.json b/dev/defs/animation/transition_input_condition.json
new file mode 100644
index 0000000..6a6331f
--- /dev/null
+++ b/dev/defs/animation/transition_input_condition.json
@@ -0,0 +1,22 @@
+{
+  "name": "TransitionInputCondition",
+  "key": {
+    "int": 67,
+    "string": "transitioninputcondition"
+  },
+  "abstract": true,
+  "extends": "animation/transition_condition.json",
+  "properties": {
+    "inputId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 155,
+        "string": "inputid"
+      },
+      "description": "Id of the StateMachineInput referenced."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_property_comparator.json b/dev/defs/animation/transition_property_comparator.json
new file mode 100644
index 0000000..ee708a2
--- /dev/null
+++ b/dev/defs/animation/transition_property_comparator.json
@@ -0,0 +1,9 @@
+{
+  "name": "TransitionPropertyComparator",
+  "key": {
+    "int": 478,
+    "string": "transitionpropertycomparator"
+  },
+  "abstract": true,
+  "extends": "animation/transition_comparator.json"
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_property_viewmodel_comparator.json b/dev/defs/animation/transition_property_viewmodel_comparator.json
new file mode 100644
index 0000000..94b11fb
--- /dev/null
+++ b/dev/defs/animation/transition_property_viewmodel_comparator.json
@@ -0,0 +1,19 @@
+{
+  "name": "TransitionPropertyViewModelComparator",
+  "key": {
+    "int": 479,
+    "string": "transitionpropertyviewmodelcomparator"
+  },
+  "extends": "animation/transition_property_comparator.json",
+  "properties": {
+    "bindablePropertyId": {
+      "type": "Id",
+      "key": {
+        "int": 646,
+        "string": "bindablepropertyid"
+      },
+      "description": "Id of the bindable property used as comparator",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_trigger_condition.json b/dev/defs/animation/transition_trigger_condition.json
index 63c9e49..855dc65 100644
--- a/dev/defs/animation/transition_trigger_condition.json
+++ b/dev/defs/animation/transition_trigger_condition.json
@@ -4,5 +4,5 @@
     "int": 68,
     "string": "transitiontriggercondition"
   },
-  "extends": "animation/transition_condition.json"
+  "extends": "animation/transition_input_condition.json"
 }
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_boolean_comparator.json b/dev/defs/animation/transition_value_boolean_comparator.json
new file mode 100644
index 0000000..c2ee3bf
--- /dev/null
+++ b/dev/defs/animation/transition_value_boolean_comparator.json
@@ -0,0 +1,18 @@
+{
+  "name": "TransitionValueBooleanComparator",
+  "key": {
+    "int": 481,
+    "string": "transitionvaluebooleancomparator"
+  },
+  "extends": "animation/transition_value_comparator.json",
+  "properties": {
+    "value": {
+      "type": "bool",
+      "initialValue": "false",
+      "key": {
+        "int": 647,
+        "string": "value"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_color_comparator.json b/dev/defs/animation/transition_value_color_comparator.json
new file mode 100644
index 0000000..ec5d41f
--- /dev/null
+++ b/dev/defs/animation/transition_value_color_comparator.json
@@ -0,0 +1,18 @@
+{
+  "name": "TransitionValueColorComparator",
+  "key": {
+    "int": 483,
+    "string": "transitionvaluecolorcomparator"
+  },
+  "extends": "animation/transition_value_comparator.json",
+  "properties": {
+    "value": {
+      "type": "Color",
+      "initialValue": "0xFF1D1D1D",
+      "key": {
+        "int": 651,
+        "string": "value"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_comparator.json b/dev/defs/animation/transition_value_comparator.json
new file mode 100644
index 0000000..d428fad
--- /dev/null
+++ b/dev/defs/animation/transition_value_comparator.json
@@ -0,0 +1,9 @@
+{
+  "name": "TransitionValueComparator",
+  "key": {
+    "int": 480,
+    "string": "transitionvaluecomparator"
+  },
+  "abstract": true,
+  "extends": "animation/transition_comparator.json"
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_condition.json b/dev/defs/animation/transition_value_condition.json
index 8f5a883..381326f 100644
--- a/dev/defs/animation/transition_value_condition.json
+++ b/dev/defs/animation/transition_value_condition.json
@@ -5,7 +5,7 @@
     "string": "transitionvaluecondition"
   },
   "abstract": true,
-  "extends": "animation/transition_condition.json",
+  "extends": "animation/transition_input_condition.json",
   "properties": {
     "opValue": {
       "type": "uint",
diff --git a/dev/defs/animation/transition_value_enum_comparator.json b/dev/defs/animation/transition_value_enum_comparator.json
new file mode 100644
index 0000000..54c364c
--- /dev/null
+++ b/dev/defs/animation/transition_value_enum_comparator.json
@@ -0,0 +1,21 @@
+{
+  "name": "TransitionValueEnumComparator",
+  "key": {
+    "int": 485,
+    "string": "transitionvalueenumcomparator"
+  },
+  "extends": "animation/transition_value_comparator.json",
+  "properties": {
+    "value": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 653,
+        "string": "value"
+      },
+      "description": "The id of the enum to compare the condition to"
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_number_comparator.json b/dev/defs/animation/transition_value_number_comparator.json
new file mode 100644
index 0000000..7ad7656
--- /dev/null
+++ b/dev/defs/animation/transition_value_number_comparator.json
@@ -0,0 +1,18 @@
+{
+  "name": "TransitionValueNumberComparator",
+  "key": {
+    "int": 484,
+    "string": "transitionvaluenumbercomparator"
+  },
+  "extends": "animation/transition_value_comparator.json",
+  "properties": {
+    "value": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 652,
+        "string": "value"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_value_string_comparator.json b/dev/defs/animation/transition_value_string_comparator.json
new file mode 100644
index 0000000..7f7cdd7
--- /dev/null
+++ b/dev/defs/animation/transition_value_string_comparator.json
@@ -0,0 +1,18 @@
+{
+  "name": "TransitionValueStringComparator",
+  "key": {
+    "int": 486,
+    "string": "transitionvaluestringcomparator"
+  },
+  "extends": "animation/transition_value_comparator.json",
+  "properties": {
+    "value": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 654,
+        "string": "value"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/transition_viewmodel_condition.json b/dev/defs/animation/transition_viewmodel_condition.json
new file mode 100644
index 0000000..714abb1
--- /dev/null
+++ b/dev/defs/animation/transition_viewmodel_condition.json
@@ -0,0 +1,41 @@
+{
+  "name": "TransitionViewModelCondition",
+  "key": {
+    "int": 482,
+    "string": "transitionviewmodelcondition"
+  },
+  "extends": "animation/transition_condition.json",
+  "properties": {
+    "leftComparatorId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 648,
+        "string": "leftcomparatorid"
+      },
+      "description": "The id of the left comaprand to use for this condition"
+    },
+    "rightComparatorId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 649,
+        "string": "rightcomparatorid"
+      },
+      "description": "The id of the right comaprand to use for this condition"
+    },
+    "opValue": {
+      "type": "uint",
+      "initialValue": "0",
+      "key": {
+        "int": 650,
+        "string": "opvalue"
+      },
+      "description": "Integer representation of the StateMachineOp enum."
+    }
+  }
+}
\ No newline at end of file
diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp
index f7ffea1..a2c8600 100644
--- a/include/rive/animation/state_machine_instance.hpp
+++ b/include/rive/animation/state_machine_instance.hpp
@@ -147,6 +147,7 @@
         return nullptr;
     }
 #endif
+    void updateDataBinds();
 
 private:
     std::vector<EventReport> m_reportedEvents;
@@ -160,6 +161,7 @@
     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/animation/transition_comparator.hpp b/include/rive/animation/transition_comparator.hpp
new file mode 100644
index 0000000..5757ad2
--- /dev/null
+++ b/include/rive/animation/transition_comparator.hpp
@@ -0,0 +1,28 @@
+#ifndef _RIVE_TRANSITION_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_comparator_base.hpp"
+#include "rive/animation/transition_condition_op.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include <stdio.h>
+namespace rive
+{
+class StateMachineInstance;
+class TransitionComparator : public TransitionComparatorBase
+{
+public:
+    StatusCode import(ImportStack& importStack) override;
+    virtual bool compare(TransitionComparator* comparand,
+                         TransitionConditionOp operation,
+                         StateMachineInstance* stateMachineInstance);
+
+protected:
+    bool compareNumbers(float left, float right, TransitionConditionOp op);
+    bool compareBooleans(bool left, bool right, TransitionConditionOp op);
+    bool compareEnums(uint16_t left, uint16_t right, TransitionConditionOp op);
+    bool compareColors(int left, int right, TransitionConditionOp op);
+    bool compareStrings(std::string left, std::string right, TransitionConditionOp op);
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_condition.hpp b/include/rive/animation/transition_condition.hpp
index 5198013..5336f4d 100644
--- a/include/rive/animation/transition_condition.hpp
+++ b/include/rive/animation/transition_condition.hpp
@@ -15,8 +15,6 @@
 
     StatusCode import(ImportStack& importStack) override;
 
-    virtual bool evaluate(const SMIInput* inputInstance) const { return true; }
-
 protected:
     virtual bool validateInputType(const StateMachineInput* input) const { return true; }
 };
diff --git a/include/rive/animation/transition_input_condition.hpp b/include/rive/animation/transition_input_condition.hpp
new file mode 100644
index 0000000..b6c6517
--- /dev/null
+++ b/include/rive/animation/transition_input_condition.hpp
@@ -0,0 +1,16 @@
+#ifndef _RIVE_TRANSITION_INPUT_CONDITION_HPP_
+#define _RIVE_TRANSITION_INPUT_CONDITION_HPP_
+#include "rive/generated/animation/transition_input_condition_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionInputCondition : public TransitionInputConditionBase
+{
+public:
+    virtual bool evaluate(const SMIInput* inputInstance) const { return true; }
+
+    StatusCode import(ImportStack& importStack) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_property_comparator.hpp b/include/rive/animation/transition_property_comparator.hpp
new file mode 100644
index 0000000..e2d9914
--- /dev/null
+++ b/include/rive/animation/transition_property_comparator.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_TRANSITION_PROPERTY_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_PROPERTY_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_property_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionPropertyComparator : public TransitionPropertyComparatorBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_property_viewmodel_comparator.hpp b/include/rive/animation/transition_property_viewmodel_comparator.hpp
new file mode 100644
index 0000000..6dec8ed
--- /dev/null
+++ b/include/rive/animation/transition_property_viewmodel_comparator.hpp
@@ -0,0 +1,26 @@
+#ifndef _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_property_viewmodel_comparator_base.hpp"
+#include "rive/data_bind/bindable_property.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionPropertyViewModelComparator : public TransitionPropertyViewModelComparatorBase
+{
+public:
+    StatusCode import(ImportStack& importStack) override;
+    bool compare(TransitionComparator* comparand,
+                 TransitionConditionOp operation,
+                 StateMachineInstance* stateMachineInstance) override;
+    float propertyValueNumber(StateMachineInstance* stateMachineInstance);
+    std::string propertyValueString(StateMachineInstance* stateMachineInstance);
+    int propertyValueColor(StateMachineInstance* stateMachineInstance);
+    bool propertyValueBoolean(StateMachineInstance* stateMachineInstance);
+    uint16_t propertyValueEnum(StateMachineInstance* stateMachineInstance);
+
+protected:
+    BindableProperty* m_bindableProperty;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_boolean_comparator.hpp b/include/rive/animation/transition_value_boolean_comparator.hpp
new file mode 100644
index 0000000..de5590b
--- /dev/null
+++ b/include/rive/animation/transition_value_boolean_comparator.hpp
@@ -0,0 +1,16 @@
+#ifndef _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_boolean_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueBooleanComparator : public TransitionValueBooleanComparatorBase
+{
+public:
+    bool compare(TransitionComparator* comparand,
+                 TransitionConditionOp operation,
+                 StateMachineInstance* stateMachineInstance) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_color_comparator.hpp b/include/rive/animation/transition_value_color_comparator.hpp
new file mode 100644
index 0000000..6e13bb1
--- /dev/null
+++ b/include/rive/animation/transition_value_color_comparator.hpp
@@ -0,0 +1,16 @@
+#ifndef _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_color_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueColorComparator : public TransitionValueColorComparatorBase
+{
+public:
+    bool compare(TransitionComparator* comparand,
+                 TransitionConditionOp operation,
+                 StateMachineInstance* stateMachineInstance) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_comparator.hpp b/include/rive/animation/transition_value_comparator.hpp
new file mode 100644
index 0000000..4ebba61
--- /dev/null
+++ b/include/rive/animation/transition_value_comparator.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_TRANSITION_VALUE_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueComparator : public TransitionValueComparatorBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_enum_comparator.hpp b/include/rive/animation/transition_value_enum_comparator.hpp
new file mode 100644
index 0000000..62bd13d
--- /dev/null
+++ b/include/rive/animation/transition_value_enum_comparator.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_enum_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueEnumComparator : public TransitionValueEnumComparatorBase
+{};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_number_comparator.hpp b/include/rive/animation/transition_value_number_comparator.hpp
new file mode 100644
index 0000000..cd88207
--- /dev/null
+++ b/include/rive/animation/transition_value_number_comparator.hpp
@@ -0,0 +1,16 @@
+#ifndef _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_number_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueNumberComparator : public TransitionValueNumberComparatorBase
+{
+public:
+    bool compare(TransitionComparator* comparand,
+                 TransitionConditionOp operation,
+                 StateMachineInstance* stateMachineInstance) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_value_string_comparator.hpp b/include/rive/animation/transition_value_string_comparator.hpp
new file mode 100644
index 0000000..ac0136d
--- /dev/null
+++ b/include/rive/animation/transition_value_string_comparator.hpp
@@ -0,0 +1,16 @@
+#ifndef _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_HPP_
+#define _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_HPP_
+#include "rive/generated/animation/transition_value_string_comparator_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionValueStringComparator : public TransitionValueStringComparatorBase
+{
+public:
+    bool compare(TransitionComparator* comparand,
+                 TransitionConditionOp operation,
+                 StateMachineInstance* stateMachineInstance) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/transition_viewmodel_condition.hpp b/include/rive/animation/transition_viewmodel_condition.hpp
new file mode 100644
index 0000000..2d5efb9
--- /dev/null
+++ b/include/rive/animation/transition_viewmodel_condition.hpp
@@ -0,0 +1,35 @@
+#ifndef _RIVE_TRANSITION_VIEW_MODEL_CONDITION_HPP_
+#define _RIVE_TRANSITION_VIEW_MODEL_CONDITION_HPP_
+#include "rive/generated/animation/transition_viewmodel_condition_base.hpp"
+#include "rive/animation/transition_comparator.hpp"
+#include "rive/animation/transition_condition_op.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include <stdio.h>
+namespace rive
+{
+class TransitionViewModelCondition : public TransitionViewModelConditionBase
+{
+protected:
+    TransitionComparator* m_leftComparator;
+    TransitionComparator* m_rightComparator;
+
+public:
+    bool evaluateCondition(StateMachineInstance* stateMachineInstance);
+    TransitionComparator* leftComparator() { return m_leftComparator; };
+    TransitionComparator* rightComparator() { return m_rightComparator; };
+    void comparator(TransitionComparator* value)
+    {
+        if (m_leftComparator == nullptr)
+        {
+            m_leftComparator = value;
+        }
+        else
+        {
+            m_rightComparator = value;
+        }
+    };
+    TransitionConditionOp op() const { return (TransitionConditionOp)opValue(); }
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_bool_condition_base.hpp b/include/rive/generated/animation/transition_bool_condition_base.hpp
index 8567f37..c9783ea 100644
--- a/include/rive/generated/animation/transition_bool_condition_base.hpp
+++ b/include/rive/generated/animation/transition_bool_condition_base.hpp
@@ -19,6 +19,7 @@
         {
             case TransitionBoolConditionBase::typeKey:
             case TransitionValueConditionBase::typeKey:
+            case TransitionInputConditionBase::typeKey:
             case TransitionConditionBase::typeKey:
                 return true;
             default:
diff --git a/include/rive/generated/animation/transition_comparator_base.hpp b/include/rive/generated/animation/transition_comparator_base.hpp
new file mode 100644
index 0000000..7b66f88
--- /dev/null
+++ b/include/rive/generated/animation/transition_comparator_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_TRANSITION_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_COMPARATOR_BASE_HPP_
+#include "rive/core.hpp"
+namespace rive
+{
+class TransitionComparatorBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 477;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    void copy(const TransitionComparatorBase& 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/animation/transition_condition_base.hpp b/include/rive/generated/animation/transition_condition_base.hpp
index e0ec5da..23145d5 100644
--- a/include/rive/generated/animation/transition_condition_base.hpp
+++ b/include/rive/generated/animation/transition_condition_base.hpp
@@ -1,7 +1,6 @@
 #ifndef _RIVE_TRANSITION_CONDITION_BASE_HPP_
 #define _RIVE_TRANSITION_CONDITION_BASE_HPP_
 #include "rive/core.hpp"
-#include "rive/core/field_types/core_uint_type.hpp"
 namespace rive
 {
 class TransitionConditionBase : public Core
@@ -10,7 +9,7 @@
     typedef Core Super;
 
 public:
-    static const uint16_t typeKey = 67;
+    static const uint16_t typeKey = 476;
 
     /// Helper to quickly determine if a core object extends another without RTTI
     /// at runtime.
@@ -27,38 +26,11 @@
 
     uint16_t coreType() const override { return typeKey; }
 
-    static const uint16_t inputIdPropertyKey = 155;
+    void copy(const TransitionConditionBase& object) {}
 
-private:
-    uint32_t m_InputId = -1;
-
-public:
-    inline uint32_t inputId() const { return m_InputId; }
-    void inputId(uint32_t value)
-    {
-        if (m_InputId == value)
-        {
-            return;
-        }
-        m_InputId = value;
-        inputIdChanged();
-    }
-
-    void copy(const TransitionConditionBase& object) { m_InputId = object.m_InputId; }
-
-    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
-    {
-        switch (propertyKey)
-        {
-            case inputIdPropertyKey:
-                m_InputId = CoreUintType::deserialize(reader);
-                return true;
-        }
-        return false;
-    }
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override { return false; }
 
 protected:
-    virtual void inputIdChanged() {}
 };
 } // namespace rive
 
diff --git a/include/rive/generated/animation/transition_input_condition_base.hpp b/include/rive/generated/animation/transition_input_condition_base.hpp
new file mode 100644
index 0000000..1440bf7
--- /dev/null
+++ b/include/rive/generated/animation/transition_input_condition_base.hpp
@@ -0,0 +1,70 @@
+#ifndef _RIVE_TRANSITION_INPUT_CONDITION_BASE_HPP_
+#define _RIVE_TRANSITION_INPUT_CONDITION_BASE_HPP_
+#include "rive/animation/transition_condition.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class TransitionInputConditionBase : public TransitionCondition
+{
+protected:
+    typedef TransitionCondition Super;
+
+public:
+    static const uint16_t typeKey = 67;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionInputConditionBase::typeKey:
+            case TransitionConditionBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t inputIdPropertyKey = 155;
+
+private:
+    uint32_t m_InputId = -1;
+
+public:
+    inline uint32_t inputId() const { return m_InputId; }
+    void inputId(uint32_t value)
+    {
+        if (m_InputId == value)
+        {
+            return;
+        }
+        m_InputId = value;
+        inputIdChanged();
+    }
+
+    void copy(const TransitionInputConditionBase& object)
+    {
+        m_InputId = object.m_InputId;
+        TransitionCondition::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case inputIdPropertyKey:
+                m_InputId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return TransitionCondition::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void inputIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_number_condition_base.hpp b/include/rive/generated/animation/transition_number_condition_base.hpp
index 5d4cc79..82e1a81 100644
--- a/include/rive/generated/animation/transition_number_condition_base.hpp
+++ b/include/rive/generated/animation/transition_number_condition_base.hpp
@@ -20,6 +20,7 @@
         {
             case TransitionNumberConditionBase::typeKey:
             case TransitionValueConditionBase::typeKey:
+            case TransitionInputConditionBase::typeKey:
             case TransitionConditionBase::typeKey:
                 return true;
             default:
diff --git a/include/rive/generated/animation/transition_property_comparator_base.hpp b/include/rive/generated/animation/transition_property_comparator_base.hpp
new file mode 100644
index 0000000..33497c2
--- /dev/null
+++ b/include/rive/generated/animation/transition_property_comparator_base.hpp
@@ -0,0 +1,34 @@
+#ifndef _RIVE_TRANSITION_PROPERTY_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_PROPERTY_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_comparator.hpp"
+namespace rive
+{
+class TransitionPropertyComparatorBase : public TransitionComparator
+{
+protected:
+    typedef TransitionComparator Super;
+
+public:
+    static const uint16_t typeKey = 478;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionPropertyComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+protected:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp b/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp
new file mode 100644
index 0000000..d7d2168
--- /dev/null
+++ b/include/rive/generated/animation/transition_property_viewmodel_comparator_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_PROPERTY_VIEW_MODEL_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_property_comparator.hpp"
+namespace rive
+{
+class TransitionPropertyViewModelComparatorBase : public TransitionPropertyComparator
+{
+protected:
+    typedef TransitionPropertyComparator Super;
+
+public:
+    static const uint16_t typeKey = 479;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionPropertyViewModelComparatorBase::typeKey:
+            case TransitionPropertyComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    Core* clone() const override;
+
+protected:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_trigger_condition_base.hpp b/include/rive/generated/animation/transition_trigger_condition_base.hpp
index b10c559..902f1a4 100644
--- a/include/rive/generated/animation/transition_trigger_condition_base.hpp
+++ b/include/rive/generated/animation/transition_trigger_condition_base.hpp
@@ -1,12 +1,12 @@
 #ifndef _RIVE_TRANSITION_TRIGGER_CONDITION_BASE_HPP_
 #define _RIVE_TRANSITION_TRIGGER_CONDITION_BASE_HPP_
-#include "rive/animation/transition_condition.hpp"
+#include "rive/animation/transition_input_condition.hpp"
 namespace rive
 {
-class TransitionTriggerConditionBase : public TransitionCondition
+class TransitionTriggerConditionBase : public TransitionInputCondition
 {
 protected:
-    typedef TransitionCondition Super;
+    typedef TransitionInputCondition Super;
 
 public:
     static const uint16_t typeKey = 68;
@@ -18,6 +18,7 @@
         switch (typeKey)
         {
             case TransitionTriggerConditionBase::typeKey:
+            case TransitionInputConditionBase::typeKey:
             case TransitionConditionBase::typeKey:
                 return true;
             default:
diff --git a/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp b/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp
new file mode 100644
index 0000000..bdbcf28
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_boolean_comparator_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_BOOLEAN_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_value_comparator.hpp"
+#include "rive/core/field_types/core_bool_type.hpp"
+namespace rive
+{
+class TransitionValueBooleanComparatorBase : public TransitionValueComparator
+{
+protected:
+    typedef TransitionValueComparator Super;
+
+public:
+    static const uint16_t typeKey = 481;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueBooleanComparatorBase::typeKey:
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t valuePropertyKey = 647;
+
+private:
+    bool m_Value = false;
+
+public:
+    inline bool value() const { return m_Value; }
+    void value(bool value)
+    {
+        if (m_Value == value)
+        {
+            return;
+        }
+        m_Value = value;
+        valueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionValueBooleanComparatorBase& object)
+    {
+        m_Value = object.m_Value;
+        TransitionValueComparator::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case valuePropertyKey:
+                m_Value = CoreBoolType::deserialize(reader);
+                return true;
+        }
+        return TransitionValueComparator::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_value_color_comparator_base.hpp b/include/rive/generated/animation/transition_value_color_comparator_base.hpp
new file mode 100644
index 0000000..f44d2be
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_color_comparator_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_COLOR_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_value_comparator.hpp"
+#include "rive/core/field_types/core_color_type.hpp"
+namespace rive
+{
+class TransitionValueColorComparatorBase : public TransitionValueComparator
+{
+protected:
+    typedef TransitionValueComparator Super;
+
+public:
+    static const uint16_t typeKey = 483;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueColorComparatorBase::typeKey:
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t valuePropertyKey = 651;
+
+private:
+    int m_Value = 0xFF1D1D1D;
+
+public:
+    inline int value() const { return m_Value; }
+    void value(int value)
+    {
+        if (m_Value == value)
+        {
+            return;
+        }
+        m_Value = value;
+        valueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionValueColorComparatorBase& object)
+    {
+        m_Value = object.m_Value;
+        TransitionValueComparator::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case valuePropertyKey:
+                m_Value = CoreColorType::deserialize(reader);
+                return true;
+        }
+        return TransitionValueComparator::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_value_comparator_base.hpp b/include/rive/generated/animation/transition_value_comparator_base.hpp
new file mode 100644
index 0000000..aced372
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_comparator_base.hpp
@@ -0,0 +1,34 @@
+#ifndef _RIVE_TRANSITION_VALUE_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_comparator.hpp"
+namespace rive
+{
+class TransitionValueComparatorBase : public TransitionComparator
+{
+protected:
+    typedef TransitionComparator Super;
+
+public:
+    static const uint16_t typeKey = 480;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+protected:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_value_condition_base.hpp b/include/rive/generated/animation/transition_value_condition_base.hpp
index 9fe2c46..e9c680e 100644
--- a/include/rive/generated/animation/transition_value_condition_base.hpp
+++ b/include/rive/generated/animation/transition_value_condition_base.hpp
@@ -1,13 +1,13 @@
 #ifndef _RIVE_TRANSITION_VALUE_CONDITION_BASE_HPP_
 #define _RIVE_TRANSITION_VALUE_CONDITION_BASE_HPP_
-#include "rive/animation/transition_condition.hpp"
+#include "rive/animation/transition_input_condition.hpp"
 #include "rive/core/field_types/core_uint_type.hpp"
 namespace rive
 {
-class TransitionValueConditionBase : public TransitionCondition
+class TransitionValueConditionBase : public TransitionInputCondition
 {
 protected:
-    typedef TransitionCondition Super;
+    typedef TransitionInputCondition Super;
 
 public:
     static const uint16_t typeKey = 69;
@@ -19,6 +19,7 @@
         switch (typeKey)
         {
             case TransitionValueConditionBase::typeKey:
+            case TransitionInputConditionBase::typeKey:
             case TransitionConditionBase::typeKey:
                 return true;
             default:
@@ -48,7 +49,7 @@
     void copy(const TransitionValueConditionBase& object)
     {
         m_OpValue = object.m_OpValue;
-        TransitionCondition::copy(object);
+        TransitionInputCondition::copy(object);
     }
 
     bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
@@ -59,7 +60,7 @@
                 m_OpValue = CoreUintType::deserialize(reader);
                 return true;
         }
-        return TransitionCondition::deserialize(propertyKey, reader);
+        return TransitionInputCondition::deserialize(propertyKey, reader);
     }
 
 protected:
diff --git a/include/rive/generated/animation/transition_value_enum_comparator_base.hpp b/include/rive/generated/animation/transition_value_enum_comparator_base.hpp
new file mode 100644
index 0000000..ec9bb45
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_enum_comparator_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_ENUM_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_value_comparator.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class TransitionValueEnumComparatorBase : public TransitionValueComparator
+{
+protected:
+    typedef TransitionValueComparator Super;
+
+public:
+    static const uint16_t typeKey = 485;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueEnumComparatorBase::typeKey:
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t valuePropertyKey = 653;
+
+private:
+    uint32_t m_Value = -1;
+
+public:
+    inline uint32_t value() const { return m_Value; }
+    void value(uint32_t value)
+    {
+        if (m_Value == value)
+        {
+            return;
+        }
+        m_Value = value;
+        valueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionValueEnumComparatorBase& object)
+    {
+        m_Value = object.m_Value;
+        TransitionValueComparator::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case valuePropertyKey:
+                m_Value = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return TransitionValueComparator::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_value_number_comparator_base.hpp b/include/rive/generated/animation/transition_value_number_comparator_base.hpp
new file mode 100644
index 0000000..7fc7e7c
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_number_comparator_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_NUMBER_COMPARATOR_BASE_HPP_
+#include "rive/animation/transition_value_comparator.hpp"
+#include "rive/core/field_types/core_double_type.hpp"
+namespace rive
+{
+class TransitionValueNumberComparatorBase : public TransitionValueComparator
+{
+protected:
+    typedef TransitionValueComparator Super;
+
+public:
+    static const uint16_t typeKey = 484;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueNumberComparatorBase::typeKey:
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t valuePropertyKey = 652;
+
+private:
+    float m_Value = 0.0f;
+
+public:
+    inline float value() const { return m_Value; }
+    void value(float value)
+    {
+        if (m_Value == value)
+        {
+            return;
+        }
+        m_Value = value;
+        valueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionValueNumberComparatorBase& object)
+    {
+        m_Value = object.m_Value;
+        TransitionValueComparator::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case valuePropertyKey:
+                m_Value = CoreDoubleType::deserialize(reader);
+                return true;
+        }
+        return TransitionValueComparator::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_value_string_comparator_base.hpp b/include/rive/generated/animation/transition_value_string_comparator_base.hpp
new file mode 100644
index 0000000..ecd1740
--- /dev/null
+++ b/include/rive/generated/animation/transition_value_string_comparator_base.hpp
@@ -0,0 +1,73 @@
+#ifndef _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_BASE_HPP_
+#define _RIVE_TRANSITION_VALUE_STRING_COMPARATOR_BASE_HPP_
+#include <string>
+#include "rive/animation/transition_value_comparator.hpp"
+#include "rive/core/field_types/core_string_type.hpp"
+namespace rive
+{
+class TransitionValueStringComparatorBase : public TransitionValueComparator
+{
+protected:
+    typedef TransitionValueComparator Super;
+
+public:
+    static const uint16_t typeKey = 486;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionValueStringComparatorBase::typeKey:
+            case TransitionValueComparatorBase::typeKey:
+            case TransitionComparatorBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t valuePropertyKey = 654;
+
+private:
+    std::string m_Value = "";
+
+public:
+    inline const std::string& value() const { return m_Value; }
+    void value(std::string value)
+    {
+        if (m_Value == value)
+        {
+            return;
+        }
+        m_Value = value;
+        valueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionValueStringComparatorBase& object)
+    {
+        m_Value = object.m_Value;
+        TransitionValueComparator::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case valuePropertyKey:
+                m_Value = CoreStringType::deserialize(reader);
+                return true;
+        }
+        return TransitionValueComparator::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/transition_viewmodel_condition_base.hpp b/include/rive/generated/animation/transition_viewmodel_condition_base.hpp
new file mode 100644
index 0000000..7c156a4
--- /dev/null
+++ b/include/rive/generated/animation/transition_viewmodel_condition_base.hpp
@@ -0,0 +1,107 @@
+#ifndef _RIVE_TRANSITION_VIEW_MODEL_CONDITION_BASE_HPP_
+#define _RIVE_TRANSITION_VIEW_MODEL_CONDITION_BASE_HPP_
+#include "rive/animation/transition_condition.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class TransitionViewModelConditionBase : public TransitionCondition
+{
+protected:
+    typedef TransitionCondition Super;
+
+public:
+    static const uint16_t typeKey = 482;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case TransitionViewModelConditionBase::typeKey:
+            case TransitionConditionBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t leftComparatorIdPropertyKey = 648;
+    static const uint16_t rightComparatorIdPropertyKey = 649;
+    static const uint16_t opValuePropertyKey = 650;
+
+private:
+    uint32_t m_LeftComparatorId = -1;
+    uint32_t m_RightComparatorId = -1;
+    uint32_t m_OpValue = 0;
+
+public:
+    inline uint32_t leftComparatorId() const { return m_LeftComparatorId; }
+    void leftComparatorId(uint32_t value)
+    {
+        if (m_LeftComparatorId == value)
+        {
+            return;
+        }
+        m_LeftComparatorId = value;
+        leftComparatorIdChanged();
+    }
+
+    inline uint32_t rightComparatorId() const { return m_RightComparatorId; }
+    void rightComparatorId(uint32_t value)
+    {
+        if (m_RightComparatorId == value)
+        {
+            return;
+        }
+        m_RightComparatorId = value;
+        rightComparatorIdChanged();
+    }
+
+    inline uint32_t opValue() const { return m_OpValue; }
+    void opValue(uint32_t value)
+    {
+        if (m_OpValue == value)
+        {
+            return;
+        }
+        m_OpValue = value;
+        opValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const TransitionViewModelConditionBase& object)
+    {
+        m_LeftComparatorId = object.m_LeftComparatorId;
+        m_RightComparatorId = object.m_RightComparatorId;
+        m_OpValue = object.m_OpValue;
+        TransitionCondition::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case leftComparatorIdPropertyKey:
+                m_LeftComparatorId = CoreUintType::deserialize(reader);
+                return true;
+            case rightComparatorIdPropertyKey:
+                m_RightComparatorId = CoreUintType::deserialize(reader);
+                return true;
+            case opValuePropertyKey:
+                m_OpValue = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return TransitionCondition::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void leftComparatorIdChanged() {}
+    virtual void rightComparatorIdChanged() {}
+    virtual void opValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp
index 9563b20..65a3ac9 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -59,10 +59,21 @@
 #include "rive/animation/state_machine_trigger.hpp"
 #include "rive/animation/state_transition.hpp"
 #include "rive/animation/transition_bool_condition.hpp"
+#include "rive/animation/transition_comparator.hpp"
 #include "rive/animation/transition_condition.hpp"
+#include "rive/animation/transition_input_condition.hpp"
 #include "rive/animation/transition_number_condition.hpp"
+#include "rive/animation/transition_property_comparator.hpp"
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
 #include "rive/animation/transition_trigger_condition.hpp"
+#include "rive/animation/transition_value_boolean_comparator.hpp"
+#include "rive/animation/transition_value_color_comparator.hpp"
+#include "rive/animation/transition_value_comparator.hpp"
 #include "rive/animation/transition_value_condition.hpp"
+#include "rive/animation/transition_value_enum_comparator.hpp"
+#include "rive/animation/transition_value_number_comparator.hpp"
+#include "rive/animation/transition_value_string_comparator.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
 #include "rive/artboard.hpp"
 #include "rive/assets/asset.hpp"
 #include "rive/assets/audio_asset.hpp"
@@ -290,6 +301,8 @@
                 return new KeyedProperty();
             case StateMachineListenerBase::typeKey:
                 return new StateMachineListener();
+            case TransitionPropertyViewModelComparatorBase::typeKey:
+                return new TransitionPropertyViewModelComparator();
             case KeyFrameIdBase::typeKey:
                 return new KeyFrameId();
             case KeyFrameBoolBase::typeKey:
@@ -300,6 +313,8 @@
                 return new ListenerAlignTarget();
             case TransitionNumberConditionBase::typeKey:
                 return new TransitionNumberCondition();
+            case TransitionValueBooleanComparatorBase::typeKey:
+                return new TransitionValueBooleanComparator();
             case AnyStateBase::typeKey:
                 return new AnyState();
             case CubicInterpolatorComponentBase::typeKey:
@@ -310,6 +325,8 @@
                 return new KeyFrameString();
             case ListenerNumberChangeBase::typeKey:
                 return new ListenerNumberChange();
+            case TransitionViewModelConditionBase::typeKey:
+                return new TransitionViewModelCondition();
             case CubicEaseInterpolatorBase::typeKey:
                 return new CubicEaseInterpolator();
             case StateTransitionBase::typeKey:
@@ -330,10 +347,14 @@
                 return new LinearAnimation();
             case StateMachineTriggerBase::typeKey:
                 return new StateMachineTrigger();
+            case TransitionValueColorComparatorBase::typeKey:
+                return new TransitionValueColorComparator();
             case ListenerTriggerChangeBase::typeKey:
                 return new ListenerTriggerChange();
             case BlendStateDirectBase::typeKey:
                 return new BlendStateDirect();
+            case TransitionValueNumberComparatorBase::typeKey:
+                return new TransitionValueNumberComparator();
             case NestedStateMachineBase::typeKey:
                 return new NestedStateMachine();
             case ElasticInterpolatorBase::typeKey:
@@ -344,8 +365,12 @@
                 return new NestedNumber();
             case BlendState1DBase::typeKey:
                 return new BlendState1D();
+            case TransitionValueEnumComparatorBase::typeKey:
+                return new TransitionValueEnumComparator();
             case KeyFrameCallbackBase::typeKey:
                 return new KeyFrameCallback();
+            case TransitionValueStringComparatorBase::typeKey:
+                return new TransitionValueStringComparator();
             case NestedRemapAnimationBase::typeKey:
                 return new NestedRemapAnimation();
             case TransitionBoolConditionBase::typeKey:
@@ -534,6 +559,9 @@
             case ListenerAlignTargetBase::preserveOffsetPropertyKey:
                 object->as<ListenerAlignTargetBase>()->preserveOffset(value);
                 break;
+            case TransitionValueBooleanComparatorBase::valuePropertyKey:
+                object->as<TransitionValueBooleanComparatorBase>()->value(value);
+                break;
             case NestedBoolBase::nestedValuePropertyKey:
                 object->as<NestedBoolBase>()->nestedValue(value);
                 break;
@@ -813,8 +841,8 @@
             case BlendAnimationDirectBase::blendSourcePropertyKey:
                 object->as<BlendAnimationDirectBase>()->blendSource(value);
                 break;
-            case TransitionConditionBase::inputIdPropertyKey:
-                object->as<TransitionConditionBase>()->inputId(value);
+            case TransitionInputConditionBase::inputIdPropertyKey:
+                object->as<TransitionInputConditionBase>()->inputId(value);
                 break;
             case KeyedPropertyBase::propertyKeyPropertyKey:
                 object->as<KeyedPropertyBase>()->propertyKey(value);
@@ -840,6 +868,15 @@
             case TransitionValueConditionBase::opValuePropertyKey:
                 object->as<TransitionValueConditionBase>()->opValue(value);
                 break;
+            case TransitionViewModelConditionBase::leftComparatorIdPropertyKey:
+                object->as<TransitionViewModelConditionBase>()->leftComparatorId(value);
+                break;
+            case TransitionViewModelConditionBase::rightComparatorIdPropertyKey:
+                object->as<TransitionViewModelConditionBase>()->rightComparatorId(value);
+                break;
+            case TransitionViewModelConditionBase::opValuePropertyKey:
+                object->as<TransitionViewModelConditionBase>()->opValue(value);
+                break;
             case StateTransitionBase::stateToIdPropertyKey:
                 object->as<StateTransitionBase>()->stateToId(value);
                 break;
@@ -888,6 +925,9 @@
             case BlendState1DBase::inputIdPropertyKey:
                 object->as<BlendState1DBase>()->inputId(value);
                 break;
+            case TransitionValueEnumComparatorBase::valuePropertyKey:
+                object->as<TransitionValueEnumComparatorBase>()->value(value);
+                break;
             case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey:
                 object->as<BlendStateTransitionBase>()->exitBlendAnimationId(value);
                 break;
@@ -1041,6 +1081,9 @@
             case KeyFrameColorBase::valuePropertyKey:
                 object->as<KeyFrameColorBase>()->value(value);
                 break;
+            case TransitionValueColorComparatorBase::valuePropertyKey:
+                object->as<TransitionValueColorComparatorBase>()->value(value);
+                break;
             case SolidColorBase::colorValuePropertyKey:
                 object->as<SolidColorBase>()->colorValue(value);
                 break;
@@ -1080,6 +1123,9 @@
             case KeyFrameStringBase::valuePropertyKey:
                 object->as<KeyFrameStringBase>()->value(value);
                 break;
+            case TransitionValueStringComparatorBase::valuePropertyKey:
+                object->as<TransitionValueStringComparatorBase>()->value(value);
+                break;
             case OpenUrlEventBase::urlPropertyKey:
                 object->as<OpenUrlEventBase>()->url(value);
                 break;
@@ -1310,6 +1356,9 @@
             case LinearAnimationBase::speedPropertyKey:
                 object->as<LinearAnimationBase>()->speed(value);
                 break;
+            case TransitionValueNumberComparatorBase::valuePropertyKey:
+                object->as<TransitionValueNumberComparatorBase>()->value(value);
+                break;
             case ElasticInterpolatorBase::amplitudePropertyKey:
                 object->as<ElasticInterpolatorBase>()->amplitude(value);
                 break;
@@ -1656,6 +1705,8 @@
                 return object->as<KeyFrameBoolBase>()->value();
             case ListenerAlignTargetBase::preserveOffsetPropertyKey:
                 return object->as<ListenerAlignTargetBase>()->preserveOffset();
+            case TransitionValueBooleanComparatorBase::valuePropertyKey:
+                return object->as<TransitionValueBooleanComparatorBase>()->value();
             case NestedBoolBase::nestedValuePropertyKey:
                 return object->as<NestedBoolBase>()->nestedValue();
             case LinearAnimationBase::enableWorkAreaPropertyKey:
@@ -1845,8 +1896,8 @@
                 return object->as<BlendAnimationDirectBase>()->inputId();
             case BlendAnimationDirectBase::blendSourcePropertyKey:
                 return object->as<BlendAnimationDirectBase>()->blendSource();
-            case TransitionConditionBase::inputIdPropertyKey:
-                return object->as<TransitionConditionBase>()->inputId();
+            case TransitionInputConditionBase::inputIdPropertyKey:
+                return object->as<TransitionInputConditionBase>()->inputId();
             case KeyedPropertyBase::propertyKeyPropertyKey:
                 return object->as<KeyedPropertyBase>()->propertyKey();
             case StateMachineListenerBase::targetIdPropertyKey:
@@ -1863,6 +1914,12 @@
                 return object->as<ListenerAlignTargetBase>()->targetId();
             case TransitionValueConditionBase::opValuePropertyKey:
                 return object->as<TransitionValueConditionBase>()->opValue();
+            case TransitionViewModelConditionBase::leftComparatorIdPropertyKey:
+                return object->as<TransitionViewModelConditionBase>()->leftComparatorId();
+            case TransitionViewModelConditionBase::rightComparatorIdPropertyKey:
+                return object->as<TransitionViewModelConditionBase>()->rightComparatorId();
+            case TransitionViewModelConditionBase::opValuePropertyKey:
+                return object->as<TransitionViewModelConditionBase>()->opValue();
             case StateTransitionBase::stateToIdPropertyKey:
                 return object->as<StateTransitionBase>()->stateToId();
             case StateTransitionBase::flagsPropertyKey:
@@ -1895,6 +1952,8 @@
                 return object->as<ElasticInterpolatorBase>()->easingValue();
             case BlendState1DBase::inputIdPropertyKey:
                 return object->as<BlendState1DBase>()->inputId();
+            case TransitionValueEnumComparatorBase::valuePropertyKey:
+                return object->as<TransitionValueEnumComparatorBase>()->value();
             case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey:
                 return object->as<BlendStateTransitionBase>()->exitBlendAnimationId();
             case StrokeBase::capPropertyKey:
@@ -2000,6 +2059,8 @@
                 return object->as<ViewModelInstanceColorBase>()->propertyValue();
             case KeyFrameColorBase::valuePropertyKey:
                 return object->as<KeyFrameColorBase>()->value();
+            case TransitionValueColorComparatorBase::valuePropertyKey:
+                return object->as<TransitionValueColorComparatorBase>()->value();
             case SolidColorBase::colorValuePropertyKey:
                 return object->as<SolidColorBase>()->colorValue();
             case GradientStopBase::colorValuePropertyKey:
@@ -2029,6 +2090,8 @@
                 return object->as<StateMachineComponentBase>()->name();
             case KeyFrameStringBase::valuePropertyKey:
                 return object->as<KeyFrameStringBase>()->value();
+            case TransitionValueStringComparatorBase::valuePropertyKey:
+                return object->as<TransitionValueStringComparatorBase>()->value();
             case OpenUrlEventBase::urlPropertyKey:
                 return object->as<OpenUrlEventBase>()->url();
             case BindablePropertyStringBase::propertyValuePropertyKey:
@@ -2186,6 +2249,8 @@
                 return object->as<KeyFrameDoubleBase>()->value();
             case LinearAnimationBase::speedPropertyKey:
                 return object->as<LinearAnimationBase>()->speed();
+            case TransitionValueNumberComparatorBase::valuePropertyKey:
+                return object->as<TransitionValueNumberComparatorBase>()->value();
             case ElasticInterpolatorBase::amplitudePropertyKey:
                 return object->as<ElasticInterpolatorBase>()->amplitude();
             case ElasticInterpolatorBase::periodPropertyKey:
@@ -2406,6 +2471,7 @@
             case NestedSimpleAnimationBase::isPlayingPropertyKey:
             case KeyFrameBoolBase::valuePropertyKey:
             case ListenerAlignTargetBase::preserveOffsetPropertyKey:
+            case TransitionValueBooleanComparatorBase::valuePropertyKey:
             case NestedBoolBase::nestedValuePropertyKey:
             case LinearAnimationBase::enableWorkAreaPropertyKey:
             case LinearAnimationBase::quantizePropertyKey:
@@ -2498,7 +2564,7 @@
             case BlendAnimationBase::animationIdPropertyKey:
             case BlendAnimationDirectBase::inputIdPropertyKey:
             case BlendAnimationDirectBase::blendSourcePropertyKey:
-            case TransitionConditionBase::inputIdPropertyKey:
+            case TransitionInputConditionBase::inputIdPropertyKey:
             case KeyedPropertyBase::propertyKeyPropertyKey:
             case StateMachineListenerBase::targetIdPropertyKey:
             case StateMachineListenerBase::listenerTypeValuePropertyKey:
@@ -2507,6 +2573,9 @@
             case ListenerBoolChangeBase::valuePropertyKey:
             case ListenerAlignTargetBase::targetIdPropertyKey:
             case TransitionValueConditionBase::opValuePropertyKey:
+            case TransitionViewModelConditionBase::leftComparatorIdPropertyKey:
+            case TransitionViewModelConditionBase::rightComparatorIdPropertyKey:
+            case TransitionViewModelConditionBase::opValuePropertyKey:
             case StateTransitionBase::stateToIdPropertyKey:
             case StateTransitionBase::flagsPropertyKey:
             case StateTransitionBase::durationPropertyKey:
@@ -2523,6 +2592,7 @@
             case LinearAnimationBase::workEndPropertyKey:
             case ElasticInterpolatorBase::easingValuePropertyKey:
             case BlendState1DBase::inputIdPropertyKey:
+            case TransitionValueEnumComparatorBase::valuePropertyKey:
             case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey:
             case StrokeBase::capPropertyKey:
             case StrokeBase::joinPropertyKey:
@@ -2573,6 +2643,7 @@
                 return CoreUintType::id;
             case ViewModelInstanceColorBase::propertyValuePropertyKey:
             case KeyFrameColorBase::valuePropertyKey:
+            case TransitionValueColorComparatorBase::valuePropertyKey:
             case SolidColorBase::colorValuePropertyKey:
             case GradientStopBase::colorValuePropertyKey:
             case BindablePropertyColorBase::propertyValuePropertyKey:
@@ -2585,6 +2656,7 @@
             case AnimationBase::namePropertyKey:
             case StateMachineComponentBase::namePropertyKey:
             case KeyFrameStringBase::valuePropertyKey:
+            case TransitionValueStringComparatorBase::valuePropertyKey:
             case OpenUrlEventBase::urlPropertyKey:
             case BindablePropertyStringBase::propertyValuePropertyKey:
             case TextValueRunBase::textPropertyKey:
@@ -2662,6 +2734,7 @@
             case ListenerNumberChangeBase::valuePropertyKey:
             case KeyFrameDoubleBase::valuePropertyKey:
             case LinearAnimationBase::speedPropertyKey:
+            case TransitionValueNumberComparatorBase::valuePropertyKey:
             case ElasticInterpolatorBase::amplitudePropertyKey:
             case ElasticInterpolatorBase::periodPropertyKey:
             case NestedNumberBase::nestedValuePropertyKey:
@@ -2820,6 +2893,8 @@
                 return object->is<KeyFrameBoolBase>();
             case ListenerAlignTargetBase::preserveOffsetPropertyKey:
                 return object->is<ListenerAlignTargetBase>();
+            case TransitionValueBooleanComparatorBase::valuePropertyKey:
+                return object->is<TransitionValueBooleanComparatorBase>();
             case NestedBoolBase::nestedValuePropertyKey:
                 return object->is<NestedBoolBase>();
             case LinearAnimationBase::enableWorkAreaPropertyKey:
@@ -3002,8 +3077,8 @@
                 return object->is<BlendAnimationDirectBase>();
             case BlendAnimationDirectBase::blendSourcePropertyKey:
                 return object->is<BlendAnimationDirectBase>();
-            case TransitionConditionBase::inputIdPropertyKey:
-                return object->is<TransitionConditionBase>();
+            case TransitionInputConditionBase::inputIdPropertyKey:
+                return object->is<TransitionInputConditionBase>();
             case KeyedPropertyBase::propertyKeyPropertyKey:
                 return object->is<KeyedPropertyBase>();
             case StateMachineListenerBase::targetIdPropertyKey:
@@ -3020,6 +3095,12 @@
                 return object->is<ListenerAlignTargetBase>();
             case TransitionValueConditionBase::opValuePropertyKey:
                 return object->is<TransitionValueConditionBase>();
+            case TransitionViewModelConditionBase::leftComparatorIdPropertyKey:
+                return object->is<TransitionViewModelConditionBase>();
+            case TransitionViewModelConditionBase::rightComparatorIdPropertyKey:
+                return object->is<TransitionViewModelConditionBase>();
+            case TransitionViewModelConditionBase::opValuePropertyKey:
+                return object->is<TransitionViewModelConditionBase>();
             case StateTransitionBase::stateToIdPropertyKey:
                 return object->is<StateTransitionBase>();
             case StateTransitionBase::flagsPropertyKey:
@@ -3052,6 +3133,8 @@
                 return object->is<ElasticInterpolatorBase>();
             case BlendState1DBase::inputIdPropertyKey:
                 return object->is<BlendState1DBase>();
+            case TransitionValueEnumComparatorBase::valuePropertyKey:
+                return object->is<TransitionValueEnumComparatorBase>();
             case BlendStateTransitionBase::exitBlendAnimationIdPropertyKey:
                 return object->is<BlendStateTransitionBase>();
             case StrokeBase::capPropertyKey:
@@ -3150,6 +3233,8 @@
                 return object->is<ViewModelInstanceColorBase>();
             case KeyFrameColorBase::valuePropertyKey:
                 return object->is<KeyFrameColorBase>();
+            case TransitionValueColorComparatorBase::valuePropertyKey:
+                return object->is<TransitionValueColorComparatorBase>();
             case SolidColorBase::colorValuePropertyKey:
                 return object->is<SolidColorBase>();
             case GradientStopBase::colorValuePropertyKey:
@@ -3172,6 +3257,8 @@
                 return object->is<StateMachineComponentBase>();
             case KeyFrameStringBase::valuePropertyKey:
                 return object->is<KeyFrameStringBase>();
+            case TransitionValueStringComparatorBase::valuePropertyKey:
+                return object->is<TransitionValueStringComparatorBase>();
             case OpenUrlEventBase::urlPropertyKey:
                 return object->is<OpenUrlEventBase>();
             case BindablePropertyStringBase::propertyValuePropertyKey:
@@ -3322,6 +3409,8 @@
                 return object->is<KeyFrameDoubleBase>();
             case LinearAnimationBase::speedPropertyKey:
                 return object->is<LinearAnimationBase>();
+            case TransitionValueNumberComparatorBase::valuePropertyKey:
+                return object->is<TransitionValueNumberComparatorBase>();
             case ElasticInterpolatorBase::amplitudePropertyKey:
                 return object->is<ElasticInterpolatorBase>();
             case ElasticInterpolatorBase::periodPropertyKey:
diff --git a/include/rive/importers/transition_viewmodel_condition_importer.hpp b/include/rive/importers/transition_viewmodel_condition_importer.hpp
new file mode 100644
index 0000000..7cf92bd
--- /dev/null
+++ b/include/rive/importers/transition_viewmodel_condition_importer.hpp
@@ -0,0 +1,23 @@
+#ifndef _RIVE_TRANSITION_VIEWMODEL_CONDITION_IMPORTER_HPP_
+#define _RIVE_TRANSITION_VIEWMODEL_CONDITION_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class TransitionViewModelCondition;
+class TransitionComparator;
+class DataBind;
+
+class TransitionViewModelConditionImporter : public ImportStackObject
+{
+private:
+    TransitionViewModelCondition* m_TransitionViewModelCondition;
+
+public:
+    TransitionViewModelConditionImporter(
+        TransitionViewModelCondition* transitionViewModelCondition);
+    void setComparator(TransitionComparator* comparator);
+};
+} // namespace rive
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance.hpp b/include/rive/viewmodel/viewmodel_instance.hpp
index f5ecd5a..3a6375a 100644
--- a/include/rive/viewmodel/viewmodel_instance.hpp
+++ b/include/rive/viewmodel/viewmodel_instance.hpp
@@ -18,6 +18,7 @@
     ViewModelInstanceValue* propertyValue(const uint32_t id);
     ViewModelInstanceValue* propertyValue(const std::string& name);
     std::vector<ViewModelInstanceValue*> propertyValues();
+    ViewModelInstanceValue* propertyFromPath(std::vector<uint32_t>* path, size_t index);
     void viewModel(ViewModel* value);
     ViewModel* viewModel() const;
     void onComponentDirty(Component* component);
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp
index 0b8a112..6f006f7 100644
--- a/src/animation/state_machine_instance.cpp
+++ b/src/animation/state_machine_instance.cpp
@@ -20,7 +20,11 @@
 #include "rive/animation/state_machine.hpp"
 #include "rive/animation/state_transition.hpp"
 #include "rive/animation/transition_condition.hpp"
+#include "rive/animation/transition_comparator.hpp"
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
 #include "rive/animation/state_machine_fire_event.hpp"
+#include "rive/data_bind_flags.hpp"
 #include "rive/event_report.hpp"
 #include "rive/hit_result.hpp"
 #include "rive/math/aabb.hpp"
@@ -746,6 +750,36 @@
         m_layers[i].init(this, machine->layer(i), m_artboardInstance);
     }
 
+    // Initialize dataBinds. All databinds are cloned for the state machine instance.
+    // That enables binding each instance to its own context without polluting the rest.
+    auto dataBindCount = machine->dataBindCount();
+    for (size_t i = 0; i < dataBindCount; i++)
+    {
+        auto dataBind = machine->dataBind(i);
+        auto dataBindClone = static_cast<DataBind*>(dataBind->clone());
+        m_dataBinds.push_back(dataBindClone);
+        if (dataBind->target()->is<BindableProperty>())
+        {
+            auto bindableProperty = dataBind->target()->as<BindableProperty>();
+            auto bindablePropertyInstance = m_bindablePropertyInstances.find(bindableProperty);
+            BindableProperty* bindablePropertyClone;
+            if (bindablePropertyInstance == m_bindablePropertyInstances.end())
+            {
+                bindablePropertyClone = bindableProperty->clone()->as<BindableProperty>();
+                m_bindablePropertyInstances[bindableProperty] = bindablePropertyClone;
+            }
+            else
+            {
+                bindablePropertyClone = bindablePropertyInstance->second;
+            }
+            dataBindClone->target(bindablePropertyClone);
+            if (static_cast<DataBindFlags>(dataBindClone->flags()) == DataBindFlags::ToSource)
+            {
+                bindablePropertyClone->dataBind(dataBindClone);
+            }
+        }
+    }
+
     // Initialize listeners. Store a lookup table of shape id to hit shape
     // representation (an object that stores all the listeners triggered by the
     // shape producing a listener).
@@ -855,8 +889,22 @@
     }
 }
 
+void StateMachineInstance::updateDataBinds()
+{
+    for (auto dataBind : m_dataBinds)
+    {
+        auto d = dataBind->dirt();
+        if (d != ComponentDirt::None)
+        {
+            dataBind->dirt(ComponentDirt::None);
+            dataBind->update(d);
+        }
+    }
+}
+
 bool StateMachineInstance::advance(float seconds)
 {
+    updateDataBinds();
     if (m_artboardInstance->hasChangedDrawOrderInLastUpdate())
     {
         sortHitComponents();
diff --git a/src/animation/state_transition.cpp b/src/animation/state_transition.cpp
index 1d9bf08..560f82c 100644
--- a/src/animation/state_transition.cpp
+++ b/src/animation/state_transition.cpp
@@ -8,7 +8,10 @@
 #include "rive/animation/state_transition.hpp"
 #include "rive/animation/transition_condition.hpp"
 #include "rive/animation/transition_trigger_condition.hpp"
+#include "rive/animation/transition_input_condition.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
 #include "rive/animation/state_machine_instance.hpp"
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
 #include "rive/importers/import_stack.hpp"
 #include "rive/importers/layer_state_importer.hpp"
 
@@ -147,13 +150,26 @@
 
     for (auto condition : m_Conditions)
     {
-        // N.B. state machine instance sanitizes these for us...
-        auto input = stateMachineInstance->input(condition->inputId());
-
-        if ((ignoreTriggers && condition->is<TransitionTriggerCondition>()) ||
-            !condition->evaluate(input))
+        if (condition->is<TransitionInputCondition>())
         {
-            return AllowTransition::no;
+            auto inputCondition = condition->as<TransitionInputCondition>();
+            // N.B. state machine instance sanitizes these for us...
+            auto input = stateMachineInstance->input(inputCondition->inputId());
+
+            if ((ignoreTriggers && inputCondition->is<TransitionTriggerCondition>()) ||
+                !inputCondition->evaluate(input))
+            {
+                return AllowTransition::no;
+            }
+        }
+        else if (condition->is<TransitionViewModelCondition>())
+        {
+            auto transitionViewModelCondition = condition->as<TransitionViewModelCondition>();
+
+            if (!transitionViewModelCondition->evaluateCondition(stateMachineInstance))
+            {
+                return AllowTransition::no;
+            }
         }
     }
 
diff --git a/src/animation/transition_comparator.cpp b/src/animation/transition_comparator.cpp
new file mode 100644
index 0000000..73b9db9
--- /dev/null
+++ b/src/animation/transition_comparator.cpp
@@ -0,0 +1,101 @@
+#include "rive/animation/transition_comparator.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/importers/transition_viewmodel_condition_importer.hpp"
+
+using namespace rive;
+
+StatusCode TransitionComparator::import(ImportStack& importStack)
+{
+    auto transitionViewModelConditionImporter =
+        importStack.latest<TransitionViewModelConditionImporter>(
+            TransitionViewModelCondition::typeKey);
+    if (transitionViewModelConditionImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    transitionViewModelConditionImporter->setComparator(this);
+    return Super::import(importStack);
+}
+
+bool TransitionComparator::compareNumbers(float left, float right, TransitionConditionOp op)
+{
+    switch (op)
+    {
+        case TransitionConditionOp::equal:
+            return left == right;
+        case TransitionConditionOp::notEqual:
+            return left != right;
+        case TransitionConditionOp::lessThanOrEqual:
+            return left <= right;
+        case TransitionConditionOp::lessThan:
+            return left < right;
+        case TransitionConditionOp::greaterThanOrEqual:
+            return left >= right;
+        case TransitionConditionOp::greaterThan:
+            return left > right;
+        default:
+            return false;
+    }
+}
+
+bool TransitionComparator::compareStrings(std::string left,
+                                          std::string right,
+                                          TransitionConditionOp op)
+{
+    switch (op)
+    {
+        case TransitionConditionOp::equal:
+            return left == right;
+        case TransitionConditionOp::notEqual:
+            return left != right;
+        default:
+            return false;
+    }
+}
+
+bool TransitionComparator::compareBooleans(bool left, bool right, TransitionConditionOp op)
+{
+    switch (op)
+    {
+        case TransitionConditionOp::equal:
+            return left == right;
+        case TransitionConditionOp::notEqual:
+            return left != right;
+        default:
+            return false;
+    }
+}
+
+bool TransitionComparator::compareEnums(uint16_t left, uint16_t right, TransitionConditionOp op)
+{
+    switch (op)
+    {
+        case TransitionConditionOp::equal:
+            return left == right;
+        case TransitionConditionOp::notEqual:
+            return left != right;
+        default:
+            return false;
+    }
+}
+
+bool TransitionComparator::compareColors(int left, int right, TransitionConditionOp op)
+{
+    switch (op)
+    {
+        case TransitionConditionOp::equal:
+            return left == right;
+        case TransitionConditionOp::notEqual:
+            return left != right;
+        default:
+            return false;
+    }
+}
+
+bool TransitionComparator::compare(TransitionComparator* comparand,
+                                   TransitionConditionOp operation,
+                                   StateMachineInstance* stateMachineInstance)
+{
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_condition.cpp b/src/animation/transition_condition.cpp
index 23b0fe6..6385f28 100644
--- a/src/animation/transition_condition.cpp
+++ b/src/animation/transition_condition.cpp
@@ -1,8 +1,6 @@
 #include "rive/animation/transition_bool_condition.hpp"
 #include "rive/animation/state_transition.hpp"
 #include "rive/importers/state_transition_importer.hpp"
-#include "rive/importers/state_machine_importer.hpp"
-#include "rive/animation/state_machine.hpp"
 
 using namespace rive;
 
@@ -12,21 +10,6 @@
 
 StatusCode TransitionCondition::import(ImportStack& importStack)
 {
-    auto stateMachineImporter = importStack.latest<StateMachineImporter>(StateMachine::typeKey);
-    if (stateMachineImporter == nullptr)
-    {
-        return StatusCode::MissingObject;
-    }
-
-    // Make sure the inputId doesn't overflow the input buffer.
-    if ((size_t)inputId() >= stateMachineImporter->stateMachine()->inputCount())
-    {
-        return StatusCode::InvalidObject;
-    }
-    if (!validateInputType(stateMachineImporter->stateMachine()->input((size_t)inputId())))
-    {
-        return StatusCode::InvalidObject;
-    }
 
     auto transitionImporter = importStack.latest<StateTransitionImporter>(StateTransition::typeKey);
     if (transitionImporter == nullptr)
diff --git a/src/animation/transition_input_condition.cpp b/src/animation/transition_input_condition.cpp
new file mode 100644
index 0000000..52fd89e
--- /dev/null
+++ b/src/animation/transition_input_condition.cpp
@@ -0,0 +1,26 @@
+#include "rive/animation/transition_input_condition.hpp"
+#include "rive/importers/state_machine_importer.hpp"
+#include "rive/animation/state_machine.hpp"
+
+using namespace rive;
+
+StatusCode TransitionInputCondition::import(ImportStack& importStack)
+{
+    auto stateMachineImporter = importStack.latest<StateMachineImporter>(StateMachine::typeKey);
+    if (stateMachineImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+
+    // Make sure the inputId doesn't overflow the input buffer.
+    if ((size_t)inputId() >= stateMachineImporter->stateMachine()->inputCount())
+    {
+        return StatusCode::InvalidObject;
+    }
+    if (!validateInputType(stateMachineImporter->stateMachine()->input((size_t)inputId())))
+    {
+        return StatusCode::InvalidObject;
+    }
+
+    return Super::import(importStack);
+}
\ No newline at end of file
diff --git a/src/animation/transition_property_comparator.cpp b/src/animation/transition_property_comparator.cpp
new file mode 100644
index 0000000..05d25ae
--- /dev/null
+++ b/src/animation/transition_property_comparator.cpp
@@ -0,0 +1,3 @@
+#include "rive/animation/transition_property_comparator.hpp"
+
+using namespace rive;
\ No newline at end of file
diff --git a/src/animation/transition_property_viewmodel_comparator.cpp b/src/animation/transition_property_viewmodel_comparator.cpp
new file mode 100644
index 0000000..8d93152
--- /dev/null
+++ b/src/animation/transition_property_viewmodel_comparator.cpp
@@ -0,0 +1,159 @@
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
+#include "rive/animation/transition_value_number_comparator.hpp"
+#include "rive/animation/transition_value_string_comparator.hpp"
+#include "rive/animation/transition_value_color_comparator.hpp"
+#include "rive/animation/transition_value_boolean_comparator.hpp"
+#include "rive/animation/transition_value_enum_comparator.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/importers/bindable_property_importer.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"
+
+using namespace rive;
+
+StatusCode TransitionPropertyViewModelComparator::import(ImportStack& importStack)
+{
+    auto bindablePropertyImporter =
+        importStack.latest<BindablePropertyImporter>(BindablePropertyBase::typeKey);
+    if (bindablePropertyImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    m_bindableProperty = bindablePropertyImporter->bindableProperty();
+
+    return Super::import(importStack);
+}
+
+float TransitionPropertyViewModelComparator::propertyValueNumber(
+    StateMachineInstance* stateMachineInstance)
+{
+    auto bindableInstance = stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
+    return bindableInstance->as<BindablePropertyNumber>()->propertyValue();
+}
+
+std::string TransitionPropertyViewModelComparator::propertyValueString(
+    StateMachineInstance* stateMachineInstance)
+{
+    auto bindableInstance = stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
+    return bindableInstance->as<BindablePropertyString>()->propertyValue();
+}
+
+int TransitionPropertyViewModelComparator::propertyValueColor(
+    StateMachineInstance* stateMachineInstance)
+{
+    auto bindableInstance = stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
+    return bindableInstance->as<BindablePropertyColor>()->propertyValue();
+}
+
+bool TransitionPropertyViewModelComparator::propertyValueBoolean(
+    StateMachineInstance* stateMachineInstance)
+{
+    auto bindableInstance = stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
+    return bindableInstance->as<BindablePropertyBoolean>()->propertyValue();
+}
+
+uint16_t TransitionPropertyViewModelComparator::propertyValueEnum(
+    StateMachineInstance* stateMachineInstance)
+{
+    auto bindableInstance = stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
+    return bindableInstance->as<BindablePropertyEnum>()->propertyValue();
+}
+
+bool TransitionPropertyViewModelComparator::compare(TransitionComparator* comparand,
+                                                    TransitionConditionOp operation,
+                                                    StateMachineInstance* stateMachineInstance)
+{
+    switch (m_bindableProperty->coreType())
+    {
+        case BindablePropertyNumber::typeKey:
+            if (comparand->is<TransitionPropertyViewModelComparator>())
+            {
+                auto rightValue =
+                    comparand->as<TransitionPropertyViewModelComparator>()->propertyValueNumber(
+                        stateMachineInstance);
+                return compareNumbers(propertyValueNumber(stateMachineInstance),
+                                      rightValue,
+                                      operation);
+            }
+            else if (comparand->is<TransitionValueNumberComparator>())
+            {
+                auto rightValue = comparand->as<TransitionValueNumberComparator>()->value();
+                return compareNumbers(propertyValueNumber(stateMachineInstance),
+                                      rightValue,
+                                      operation);
+            }
+            break;
+        case BindablePropertyString::typeKey:
+            if (comparand->is<TransitionPropertyViewModelComparator>())
+            {
+                auto rightValue =
+                    comparand->as<TransitionPropertyViewModelComparator>()->propertyValueString(
+                        stateMachineInstance);
+                return compareStrings(propertyValueString(stateMachineInstance),
+                                      rightValue,
+                                      operation);
+            }
+            else if (comparand->is<TransitionValueStringComparator>())
+            {
+                auto rightValue = comparand->as<TransitionValueStringComparator>()->value();
+                return compareStrings(propertyValueString(stateMachineInstance),
+                                      rightValue,
+                                      operation);
+            }
+            break;
+        case BindablePropertyColor::typeKey:
+            if (comparand->is<TransitionPropertyViewModelComparator>())
+            {
+                auto rightValue =
+                    comparand->as<TransitionPropertyViewModelComparator>()->propertyValueColor(
+                        stateMachineInstance);
+                return compareColors(propertyValueColor(stateMachineInstance),
+                                     rightValue,
+                                     operation);
+            }
+            else if (comparand->is<TransitionValueColorComparator>())
+            {
+                auto rightValue = comparand->as<TransitionValueColorComparator>()->value();
+                return compareColors(propertyValueColor(stateMachineInstance),
+                                     rightValue,
+                                     operation);
+            }
+            break;
+        case BindablePropertyBoolean::typeKey:
+            if (comparand->is<TransitionPropertyViewModelComparator>())
+            {
+                auto rightValue =
+                    comparand->as<TransitionPropertyViewModelComparator>()->propertyValueBoolean(
+                        stateMachineInstance);
+                return compareBooleans(propertyValueBoolean(stateMachineInstance),
+                                       rightValue,
+                                       operation);
+            }
+            else if (comparand->is<TransitionValueBooleanComparator>())
+            {
+                auto rightValue = comparand->as<TransitionValueBooleanComparator>()->value();
+                return compareBooleans(propertyValueBoolean(stateMachineInstance),
+                                       rightValue,
+                                       operation);
+            }
+            break;
+        case BindablePropertyEnum::typeKey:
+            if (comparand->is<TransitionPropertyViewModelComparator>())
+            {
+                auto rightValue =
+                    comparand->as<TransitionPropertyViewModelComparator>()->propertyValueEnum(
+                        stateMachineInstance);
+                return compareEnums(propertyValueEnum(stateMachineInstance), rightValue, operation);
+            }
+            else if (comparand->is<TransitionValueEnumComparator>())
+            {
+                auto rightValue = comparand->as<TransitionValueEnumComparator>()->value();
+                return compareEnums(propertyValueEnum(stateMachineInstance), rightValue, operation);
+            }
+            break;
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_value_boolean_comparator.cpp b/src/animation/transition_value_boolean_comparator.cpp
new file mode 100644
index 0000000..e26f868
--- /dev/null
+++ b/src/animation/transition_value_boolean_comparator.cpp
@@ -0,0 +1,16 @@
+#include "rive/animation/transition_value_boolean_comparator.hpp"
+
+using namespace rive;
+
+bool TransitionValueBooleanComparator::compare(TransitionComparator* comparand,
+                                               TransitionConditionOp operation,
+                                               StateMachineInstance* stateMachineInstance)
+{
+    if (comparand->is<TransitionValueBooleanComparator>())
+    {
+        return compareBooleans(value(),
+                               comparand->as<TransitionValueBooleanComparator>()->value(),
+                               operation);
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_value_color_comparator.cpp b/src/animation/transition_value_color_comparator.cpp
new file mode 100644
index 0000000..c4fe60e
--- /dev/null
+++ b/src/animation/transition_value_color_comparator.cpp
@@ -0,0 +1,16 @@
+#include "rive/animation/transition_value_color_comparator.hpp"
+
+using namespace rive;
+
+bool TransitionValueColorComparator::compare(TransitionComparator* comparand,
+                                             TransitionConditionOp operation,
+                                             StateMachineInstance* stateMachineInstance)
+{
+    if (comparand->is<TransitionValueColorComparator>())
+    {
+        return compareColors(value(),
+                             comparand->as<TransitionValueColorComparator>()->value(),
+                             operation);
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_value_enum_comparator.cpp b/src/animation/transition_value_enum_comparator.cpp
new file mode 100644
index 0000000..8742e37
--- /dev/null
+++ b/src/animation/transition_value_enum_comparator.cpp
@@ -0,0 +1,4 @@
+#include "rive/animation/transition_value_enum_comparator.hpp"
+#include "rive/viewmodel/viewmodel_instance_enum.hpp"
+
+using namespace rive;
\ No newline at end of file
diff --git a/src/animation/transition_value_number_comparator.cpp b/src/animation/transition_value_number_comparator.cpp
new file mode 100644
index 0000000..c4f05d5
--- /dev/null
+++ b/src/animation/transition_value_number_comparator.cpp
@@ -0,0 +1,16 @@
+#include "rive/animation/transition_value_number_comparator.hpp"
+
+using namespace rive;
+
+bool TransitionValueNumberComparator::compare(TransitionComparator* comparand,
+                                              TransitionConditionOp operation,
+                                              StateMachineInstance* stateMachineInstance)
+{
+    if (comparand->is<TransitionValueNumberComparator>())
+    {
+        return compareNumbers(value(),
+                              comparand->as<TransitionValueNumberComparator>()->value(),
+                              operation);
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_value_string_comparator.cpp b/src/animation/transition_value_string_comparator.cpp
new file mode 100644
index 0000000..d62a1a3
--- /dev/null
+++ b/src/animation/transition_value_string_comparator.cpp
@@ -0,0 +1,16 @@
+#include "rive/animation/transition_value_string_comparator.hpp"
+
+using namespace rive;
+
+bool TransitionValueStringComparator::compare(TransitionComparator* comparand,
+                                              TransitionConditionOp operation,
+                                              StateMachineInstance* stateMachineInstance)
+{
+    if (comparand->is<TransitionValueStringComparator>())
+    {
+        return compareStrings(value(),
+                              comparand->as<TransitionValueStringComparator>()->value(),
+                              operation);
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/animation/transition_viewmodel_condition.cpp b/src/animation/transition_viewmodel_condition.cpp
new file mode 100644
index 0000000..40d2a07
--- /dev/null
+++ b/src/animation/transition_viewmodel_condition.cpp
@@ -0,0 +1,18 @@
+#include "rive/animation/transition_viewmodel_condition.hpp"
+#include "rive/animation/state_transition.hpp"
+#include "rive/importers/state_transition_importer.hpp"
+#include "rive/importers/state_machine_importer.hpp"
+#include "rive/animation/state_machine.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+bool TransitionViewModelCondition::evaluateCondition(StateMachineInstance* stateMachineInstance)
+{
+    if (leftComparator() != nullptr && rightComparator() != nullptr)
+    {
+        return leftComparator()->compare(rightComparator(), op(), stateMachineInstance);
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/data_bind/data_bind.cpp b/src/data_bind/data_bind.cpp
index a1ab715..9877f5b 100644
--- a/src/data_bind/data_bind.cpp
+++ b/src/data_bind/data_bind.cpp
@@ -14,6 +14,7 @@
 #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/transition_viewmodel_condition.hpp"
 #include "rive/animation/state_machine.hpp"
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/importers/state_machine_importer.hpp"
@@ -42,6 +43,7 @@
             case BindablePropertyBooleanBase::typeKey:
             case BindablePropertyEnumBase::typeKey:
             case BindablePropertyColorBase::typeKey:
+            case TransitionPropertyViewModelComparatorBase::typeKey:
             {
                 auto stateMachineImporter =
                     importStack.latest<StateMachineImporter>(StateMachineBase::typeKey);
diff --git a/src/file.cpp b/src/file.cpp
index 57fb4a7..96da684 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -21,6 +21,7 @@
 #include "rive/importers/layer_state_importer.hpp"
 #include "rive/importers/state_transition_importer.hpp"
 #include "rive/importers/state_machine_layer_component_importer.hpp"
+#include "rive/importers/transition_viewmodel_condition_importer.hpp"
 #include "rive/importers/viewmodel_importer.hpp"
 #include "rive/importers/viewmodel_instance_importer.hpp"
 #include "rive/importers/viewmodel_instance_list_importer.hpp"
@@ -31,6 +32,7 @@
 #include "rive/animation/animation_state.hpp"
 #include "rive/animation/blend_state_1d.hpp"
 #include "rive/animation/blend_state_direct.hpp"
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
 #include "rive/data_bind/bindable_property.hpp"
 #include "rive/data_bind/bindable_property_number.hpp"
 #include "rive/data_bind/bindable_property_string.hpp"
@@ -372,6 +374,11 @@
                     object->as<ViewModelInstanceList>());
                 stackType = ViewModelInstanceList::typeKey;
                 break;
+            case TransitionViewModelCondition::typeKey:
+                stackObject = rivestd::make_unique<TransitionViewModelConditionImporter>(
+                    object->as<TransitionViewModelCondition>());
+                stackType = TransitionViewModelCondition::typeKey;
+                break;
             case BindablePropertyNumber::typeKey:
             case BindablePropertyString::typeKey:
             case BindablePropertyColor::typeKey:
diff --git a/src/generated/animation/transition_property_viewmodel_comparator_base.cpp b/src/generated/animation/transition_property_viewmodel_comparator_base.cpp
new file mode 100644
index 0000000..8c0c2d6
--- /dev/null
+++ b/src/generated/animation/transition_property_viewmodel_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_property_viewmodel_comparator_base.hpp"
+#include "rive/animation/transition_property_viewmodel_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionPropertyViewModelComparatorBase::clone() const
+{
+    auto cloned = new TransitionPropertyViewModelComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_value_boolean_comparator_base.cpp b/src/generated/animation/transition_value_boolean_comparator_base.cpp
new file mode 100644
index 0000000..3e9a2ef
--- /dev/null
+++ b/src/generated/animation/transition_value_boolean_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_value_boolean_comparator_base.hpp"
+#include "rive/animation/transition_value_boolean_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionValueBooleanComparatorBase::clone() const
+{
+    auto cloned = new TransitionValueBooleanComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_value_color_comparator_base.cpp b/src/generated/animation/transition_value_color_comparator_base.cpp
new file mode 100644
index 0000000..a199f5f
--- /dev/null
+++ b/src/generated/animation/transition_value_color_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_value_color_comparator_base.hpp"
+#include "rive/animation/transition_value_color_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionValueColorComparatorBase::clone() const
+{
+    auto cloned = new TransitionValueColorComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_value_enum_comparator_base.cpp b/src/generated/animation/transition_value_enum_comparator_base.cpp
new file mode 100644
index 0000000..dad8789
--- /dev/null
+++ b/src/generated/animation/transition_value_enum_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_value_enum_comparator_base.hpp"
+#include "rive/animation/transition_value_enum_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionValueEnumComparatorBase::clone() const
+{
+    auto cloned = new TransitionValueEnumComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_value_number_comparator_base.cpp b/src/generated/animation/transition_value_number_comparator_base.cpp
new file mode 100644
index 0000000..8ebecac
--- /dev/null
+++ b/src/generated/animation/transition_value_number_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_value_number_comparator_base.hpp"
+#include "rive/animation/transition_value_number_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionValueNumberComparatorBase::clone() const
+{
+    auto cloned = new TransitionValueNumberComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_value_string_comparator_base.cpp b/src/generated/animation/transition_value_string_comparator_base.cpp
new file mode 100644
index 0000000..07db01d
--- /dev/null
+++ b/src/generated/animation/transition_value_string_comparator_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_value_string_comparator_base.hpp"
+#include "rive/animation/transition_value_string_comparator.hpp"
+
+using namespace rive;
+
+Core* TransitionValueStringComparatorBase::clone() const
+{
+    auto cloned = new TransitionValueStringComparator();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/transition_viewmodel_condition_base.cpp b/src/generated/animation/transition_viewmodel_condition_base.cpp
new file mode 100644
index 0000000..a0d3b25
--- /dev/null
+++ b/src/generated/animation/transition_viewmodel_condition_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/animation/transition_viewmodel_condition_base.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
+
+using namespace rive;
+
+Core* TransitionViewModelConditionBase::clone() const
+{
+    auto cloned = new TransitionViewModelCondition();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/importers/transition_viewmodel_condition_importer.cpp b/src/importers/transition_viewmodel_condition_importer.cpp
new file mode 100644
index 0000000..97d4cb0
--- /dev/null
+++ b/src/importers/transition_viewmodel_condition_importer.cpp
@@ -0,0 +1,16 @@
+#include "rive/importers/transition_viewmodel_condition_importer.hpp"
+#include "rive/animation/transition_viewmodel_condition.hpp"
+#include "rive/animation/transition_comparator.hpp"
+#include "rive/data_bind/data_bind.hpp"
+
+using namespace rive;
+
+TransitionViewModelConditionImporter::TransitionViewModelConditionImporter(
+    TransitionViewModelCondition* transitionViewModelCondition) :
+    m_TransitionViewModelCondition(transitionViewModelCondition)
+{}
+
+void TransitionViewModelConditionImporter::setComparator(TransitionComparator* comparator)
+{
+    m_TransitionViewModelCondition->comparator(comparator);
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance.cpp b/src/viewmodel/viewmodel_instance.cpp
index f3e741d..b2656b5 100644
--- a/src/viewmodel/viewmodel_instance.cpp
+++ b/src/viewmodel/viewmodel_instance.cpp
@@ -5,6 +5,7 @@
 #include "rive/viewmodel/viewmodel_instance.hpp"
 #include "rive/viewmodel/viewmodel.hpp"
 #include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
 #include "rive/importers/viewmodel_importer.hpp"
 #include "rive/core_context.hpp"
 
@@ -88,3 +89,27 @@
     viewModelImporter->addInstance(this);
     return StatusCode::Ok;
 }
+
+ViewModelInstanceValue* ViewModelInstance::propertyFromPath(std::vector<uint32_t>* path,
+                                                            size_t index)
+{
+    if (index < path->size())
+    {
+        auto propertyId = (*path)[index];
+        auto property = propertyValue(propertyId);
+        if (property != nullptr)
+        {
+            if (index == path->size() - 1)
+            {
+                return property;
+            }
+            if (property->is<ViewModelInstanceViewModel>())
+            {
+                auto propertyViewModel = property->as<ViewModelInstanceViewModel>();
+                auto viewModelInstance = propertyViewModel->referenceViewModelInstance();
+                return viewModelInstance->propertyFromPath(path, index + 1);
+            }
+        }
+    }
+    return nullptr;
+}
\ No newline at end of file