databinding

Diffs=
75823467d databinding (#7341)

Co-authored-by: hernan <hernan@rive.app>
diff --git a/.rive_head b/.rive_head
index 2cdb2c0..3fd5c8b 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-7e1b3027d5ea97c7950b8f5951b0b44f33413987
+75823467d0c007983e66df245f1e9c27d707728c
diff --git a/dev/core_generator/lib/src/property.dart b/dev/core_generator/lib/src/property.dart
index e147e81..46993b1 100644
--- a/dev/core_generator/lib/src/property.dart
+++ b/dev/core_generator/lib/src/property.dart
@@ -20,6 +20,7 @@
   bool isSetOverride = false;
   bool isGetOverride = false;
   bool isEncoded = false;
+  bool isBindable = false;
   bool isPureVirtual = false;
   FieldType? typeRuntime;
 
@@ -94,6 +95,10 @@
     if (rt is String) {
       typeRuntime = FieldType.find(rt);
     }
+    dynamic b = data['bindable'];
+    if (b is bool) {
+      isBindable = b;
+    }
     dynamic pv = data['pureVirtual'];
     if (pv is bool) {
       isPureVirtual = pv;
diff --git a/dev/defs/artboard.json b/dev/defs/artboard.json
index 4d482a9..4079ccb 100644
--- a/dev/defs/artboard.json
+++ b/dev/defs/artboard.json
@@ -96,6 +96,27 @@
       "description": "List of selected animations",
       "runtime": false,
       "coop": false
+    },
+    "viewModelId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 583,
+        "string": "viewmodelid"
+      },
+      "description": "The view model attached to this artboard data context."
+    },
+    "viewModelInstanceId": {
+      "type": "Id",
+      "initialValue": "Core.missingId",
+      "key": {
+        "int": 584,
+        "string": "viewmodelinstanceid"
+      },
+      "description": "A view model instance attached for editing purposes.",
+      "runtime": false
     }
   }
 }
\ No newline at end of file
diff --git a/dev/defs/data_bind/data_bind.json b/dev/defs/data_bind/data_bind.json
new file mode 100644
index 0000000..eaf9be2
--- /dev/null
+++ b/dev/defs/data_bind/data_bind.json
@@ -0,0 +1,40 @@
+{
+  "name": "DataBind",
+  "key": {
+    "int": 446,
+    "string": "databind"
+  },
+  "extends": "component.json",
+  "properties": {
+    "targetId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 585,
+        "string": "targetid"
+      },
+      "description": "Identifier used to track the object that is targetted."
+    },
+    "propertyKey": {
+      "type": "uint",
+      "initialValue": "CoreContext.invalidPropertyKey",
+      "key": {
+        "int": 586,
+        "string": "propertykey"
+      },
+      "description": "The property that is targeted."
+    },
+    "modeValue": {
+      "type": "uint",
+      "typeRuntime": "uint",
+      "initialValue": "0",
+      "key": {
+        "int": 587,
+        "string": "modevalue"
+      },
+      "description": "Backing enum value for the binding mode."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/data_bind/data_bind_context.json b/dev/defs/data_bind/data_bind_context.json
new file mode 100644
index 0000000..d9e04e6
--- /dev/null
+++ b/dev/defs/data_bind/data_bind_context.json
@@ -0,0 +1,21 @@
+{
+  "name": "DataBindContext",
+  "key": {
+    "int": 447,
+    "string": "databindcontext"
+  },
+  "extends": "data_bind/data_bind.json",
+  "properties": {
+    "sourcePathIds": {
+      "type": "List<Id>",
+      "typeRuntime": "Bytes",
+      "encoded": true,
+      "initialValue": "[]",
+      "key": {
+        "int": 588,
+        "string": "sourcepathids"
+      },
+      "description": "Path to the selected property."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/nested_artboard.json b/dev/defs/nested_artboard.json
index e6a5211..112415c 100644
--- a/dev/defs/nested_artboard.json
+++ b/dev/defs/nested_artboard.json
@@ -32,6 +32,17 @@
         "string": "alignment"
       },
       "description": "Alignment type for the nested artboard's runtime artboard."
+    },
+    "dataBindPathIds": {
+      "type": "List<Id>",
+      "typeRuntime": "Bytes",
+      "encoded": true,
+      "initialValue": "[]",
+      "key": {
+        "int": 580,
+        "string": "databindpathids"
+      },
+      "description": "Path to the selected property."
     }
   }
 }
\ No newline at end of file
diff --git a/dev/defs/viewmodel/data_enum.json b/dev/defs/viewmodel/data_enum.json
new file mode 100644
index 0000000..c65b252
--- /dev/null
+++ b/dev/defs/viewmodel/data_enum.json
@@ -0,0 +1,40 @@
+{
+  "name": "DataEnum",
+  "key": {
+    "int": 438,
+    "string": "dataenum"
+  },
+  "properties": {
+    "order": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 570,
+        "string": "order"
+      },
+      "description": "Order value for sorting data enums.",
+      "runtime": false
+    },
+    "splitKeyValues": {
+      "type": "bool",
+      "initialValue": "false",
+      "key": {
+        "int": 571,
+        "string": "splitkeyvalues"
+      },
+      "description": "Whether the user can edit keys and values separately.",
+      "runtime": false
+    },
+    "name": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 572,
+        "string": "name"
+      },
+      "description": "Non-unique identifier, used to give friendly names to enums.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/data_enum_value.json b/dev/defs/viewmodel/data_enum_value.json
new file mode 100644
index 0000000..d597785
--- /dev/null
+++ b/dev/defs/viewmodel/data_enum_value.json
@@ -0,0 +1,48 @@
+{
+  "name": "DataEnumValue",
+  "key": {
+    "int": 445,
+    "string": "dataenumvalue"
+  },
+  "properties": {
+    "key": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 578,
+        "string": "key"
+      },
+      "description": "The key of this key value enum pair."
+    },
+    "value": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 579,
+        "string": "value"
+      },
+      "description": "The value of this key value enum pair."
+    },
+    "enumId": {
+      "type": "Id",
+      "initialValue": "Core.missingId",
+      "key": {
+        "int": 580,
+        "string": "enumid"
+      },
+      "description": "The id of the enum property this value belongs to.",
+      "runtime": false
+    },
+    "order": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 581,
+        "string": "order"
+      },
+      "description": "Order value for sorting enum values.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel.json b/dev/defs/viewmodel/viewmodel.json
new file mode 100644
index 0000000..bff9a16
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel.json
@@ -0,0 +1,32 @@
+{
+  "name": "ViewModel",
+  "key": {
+    "int": 435,
+    "string": "viewmodel"
+  },
+  "extends": "viewmodel/viewmodel_component.json",
+  "properties": {
+    "viewModelOrder": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 563,
+        "string": "viewmodelorder"
+      },
+      "description": "Order value for sorting View Models.",
+      "runtime": false
+    },
+    "defaultInstanceId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 564,
+        "string": "defaultinstanceid"
+      },
+      "description": "The default instance attached to the view model."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_component.json b/dev/defs/viewmodel/viewmodel_component.json
new file mode 100644
index 0000000..fd68e1e
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_component.json
@@ -0,0 +1,18 @@
+{
+  "name": "ViewModelComponent",
+  "key": {
+    "int": 429,
+    "string": "viewmodelcomponent"
+  },
+  "properties": {
+    "name": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 557,
+        "string": "name"
+      },
+      "description": "Non-unique identifier, used to give friendly names to any view model component."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance.json b/dev/defs/viewmodel/viewmodel_instance.json
new file mode 100644
index 0000000..1ac4447
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance.json
@@ -0,0 +1,50 @@
+{
+  "name": "ViewModelInstance",
+  "key": {
+    "int": 437,
+    "string": "viewmodelinstance"
+  },
+  "extends": "component.json",
+  "properties": {
+    "viewModelId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 566,
+        "string": "viewmodelid"
+      }
+    },
+    "x": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 567,
+        "string": "x"
+      },
+      "description": "The x coordinate of the stage representation.",
+      "runtime": false
+    },
+    "y": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 568,
+        "string": "y"
+      },
+      "description": "The y coordinate of the stage representation.",
+      "runtime": false
+    },
+    "onStage": {
+      "type": "bool",
+      "initialValue": "false",
+      "key": {
+        "int": 569,
+        "string": "onstage"
+      },
+      "description": "Whether it is visible on stage or not.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_color.json b/dev/defs/viewmodel/viewmodel_instance_color.json
new file mode 100644
index 0000000..23ae5df
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_color.json
@@ -0,0 +1,29 @@
+{
+  "name": "ViewModelInstanceColor",
+  "key": {
+    "int": 426,
+    "string": "viewmodelinstancecolor"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json",
+  "properties": {
+    "propertyValue": {
+      "type": "Color",
+      "initialValue": "0xFF1D1D1D",
+      "key": {
+        "int": 555,
+        "string": "propertyvalue"
+      },
+      "description": "The color value"
+    },
+    "playbackValue": {
+      "type": "Color",
+      "initialValue": "0xFF1D1D1D",
+      "key": {
+        "int": 556,
+        "string": "playbackvalue"
+      },
+      "runtime": false,
+      "coop": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_enum.json b/dev/defs/viewmodel/viewmodel_instance_enum.json
new file mode 100644
index 0000000..7dd93df
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_enum.json
@@ -0,0 +1,21 @@
+{
+  "name": "ViewModelInstanceEnum",
+  "key": {
+    "int": 432,
+    "string": "viewmodelinstanceenum"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json",
+  "properties": {
+    "propertyValue": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 560,
+        "string": "propertyvalue"
+      },
+      "description": "The id of the enum value."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_list.json b/dev/defs/viewmodel/viewmodel_instance_list.json
new file mode 100644
index 0000000..d38e669
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_list.json
@@ -0,0 +1,8 @@
+{
+  "name": "ViewModelInstanceList",
+  "key": {
+    "int": 441,
+    "string": "viewmodelinstancelist"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json"
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_list_item.json b/dev/defs/viewmodel/viewmodel_instance_list_item.json
new file mode 100644
index 0000000..30938fb
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_list_item.json
@@ -0,0 +1,71 @@
+{
+  "name": "ViewModelInstanceListItem",
+  "key": {
+    "int": 427,
+    "string": "viewmodelinstancelistitem"
+  },
+  "properties": {
+    "useLinkedArtboard": {
+      "type": "bool",
+      "initialValue": "true",
+      "key": {
+        "int": 547,
+        "string": "uselinkedartboard"
+      },
+      "description": "Whether the artboard linked to the view model should be used."
+    },
+    "instanceListId": {
+      "type": "Id",
+      "initialValue": "Core.missingId",
+      "key": {
+        "int": 548,
+        "string": "instancelistid"
+      },
+      "description": "The id of the list it belongs to.",
+      "runtime": false
+    },
+    "viewModelId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 549,
+        "string": "viewmodelid"
+      },
+      "description": "The view model id."
+    },
+    "viewModelInstanceId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 550,
+        "string": "viewmodelinstanceid"
+      },
+      "description": "The view model instance id."
+    },
+    "artboardId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 551,
+        "string": "artboardid"
+      },
+      "description": "The artboard id to link the viewmodel to if implicit is set to false."
+    },
+    "order": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "key": {
+        "int": 552,
+        "string": "order"
+      },
+      "description": "The order position in the list.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_number.json b/dev/defs/viewmodel/viewmodel_instance_number.json
new file mode 100644
index 0000000..e0637f9
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_number.json
@@ -0,0 +1,29 @@
+{
+  "name": "ViewModelInstanceNumber",
+  "key": {
+    "int": 442,
+    "string": "viewmodelinstancenumber"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json",
+  "properties": {
+    "propertyValue": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 575,
+        "string": "propertyvalue"
+      },
+      "description": "The number value."
+    },
+    "playbackValue": {
+      "type": "double",
+      "initialValue": "0",
+      "key": {
+        "int": 576,
+        "string": "playbackvalue"
+      },
+      "runtime": false,
+      "coop": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_string.json b/dev/defs/viewmodel/viewmodel_instance_string.json
new file mode 100644
index 0000000..bd12abb
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_string.json
@@ -0,0 +1,29 @@
+{
+  "name": "ViewModelInstanceString",
+  "key": {
+    "int": 433,
+    "string": "viewmodelinstancestring"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json",
+  "properties": {
+    "propertyValue": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 561,
+        "string": "propertyvalue"
+      },
+      "description": "The string value."
+    },
+    "playbackValue": {
+      "type": "String",
+      "initialValue": "''",
+      "key": {
+        "int": 562,
+        "string": "playbackvalue"
+      },
+      "runtime": false,
+      "coop": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_value.json b/dev/defs/viewmodel/viewmodel_instance_value.json
new file mode 100644
index 0000000..df37f83
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_value.json
@@ -0,0 +1,33 @@
+{
+  "name": "ViewModelInstanceValue",
+  "key": {
+    "int": 428,
+    "string": "viewmodelinstancevalue"
+  },
+  "abstract": true,
+  "properties": {
+    "viewModelInstanceId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 553,
+        "string": "viewmodelinstanceid"
+      },
+      "description": "Identifier of the view model instance this value is for, at runtime this is expected in context (after) a ViewModelInstance object.",
+      "runtime": false
+    },
+    "viewModelPropertyId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 554,
+        "string": "viewmodelpropertyid"
+      },
+      "description": "Identifier of the property this value will provide data for. At runtime these ids are normalized relative to the ViewModel itself."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_instance_viewmodel.json b/dev/defs/viewmodel/viewmodel_instance_viewmodel.json
new file mode 100644
index 0000000..e156b14
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_instance_viewmodel.json
@@ -0,0 +1,21 @@
+{
+  "name": "ViewModelInstanceViewModel",
+  "key": {
+    "int": 444,
+    "string": "viewmodelinstanceviewmodel"
+  },
+  "extends": "viewmodel/viewmodel_instance_value.json",
+  "properties": {
+    "propertyValue": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 577,
+        "string": "propertyvalue"
+      },
+      "description": "The id of the viewmodel instance."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property.json b/dev/defs/viewmodel/viewmodel_property.json
new file mode 100644
index 0000000..5ee2482
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property.json
@@ -0,0 +1,33 @@
+{
+  "name": "ViewModelProperty",
+  "key": {
+    "int": 430,
+    "string": "viewmodelproperty"
+  },
+  "extends": "viewmodel/viewmodel_component.json",
+  "properties": {
+    "viewModelId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 558,
+        "string": "viewmodelid"
+      },
+      "description": "Identifier used to track parent View Model.",
+      "runtime": false
+    },
+    "propertyOrder": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 559,
+        "string": "propertyorder"
+      },
+      "description": "Order value for sorting child elements in View Model.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_color.json b/dev/defs/viewmodel/viewmodel_property_color.json
new file mode 100644
index 0000000..c64d0ff
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_color.json
@@ -0,0 +1,8 @@
+{
+  "name": "ViewModelPropertyColor",
+  "key": {
+    "int": 440,
+    "string": "viewmodelpropertycolor"
+  },
+  "extends": "viewmodel/viewmodel_property.json"
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_enum.json b/dev/defs/viewmodel/viewmodel_property_enum.json
new file mode 100644
index 0000000..2706486
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_enum.json
@@ -0,0 +1,31 @@
+{
+  "name": "ViewModelPropertyEnum",
+  "key": {
+    "int": 439,
+    "string": "viewmodelpropertyenum"
+  },
+  "extends": "viewmodel/viewmodel_property.json",
+  "properties": {
+    "splitKeyValues": {
+      "type": "bool",
+      "initialValue": "false",
+      "key": {
+        "int": 573,
+        "string": "splitkeyvalues"
+      },
+      "description": "Whether the user can edit keys and values separately.",
+      "runtime": false
+    },
+    "enumId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 574,
+        "string": "enumid"
+      },
+      "description": "The id of the enum."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_list.json b/dev/defs/viewmodel/viewmodel_property_list.json
new file mode 100644
index 0000000..1fa6b0e
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_list.json
@@ -0,0 +1,8 @@
+{
+  "name": "ViewModelPropertyList",
+  "key": {
+    "int": 434,
+    "string": "viewmodelpropertylist"
+  },
+  "extends": "viewmodel/viewmodel_property.json"
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_number.json b/dev/defs/viewmodel/viewmodel_property_number.json
new file mode 100644
index 0000000..ef9cced
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_number.json
@@ -0,0 +1,8 @@
+{
+  "name": "ViewModelPropertyNumber",
+  "key": {
+    "int": 431,
+    "string": "viewmodelpropertynumber"
+  },
+  "extends": "viewmodel/viewmodel_property.json"
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_string.json b/dev/defs/viewmodel/viewmodel_property_string.json
new file mode 100644
index 0000000..ca95b29
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_string.json
@@ -0,0 +1,8 @@
+{
+  "name": "ViewModelPropertyString",
+  "key": {
+    "int": 443,
+    "string": "viewmodelpropertystring"
+  },
+  "extends": "viewmodel/viewmodel_property.json"
+}
\ No newline at end of file
diff --git a/dev/defs/viewmodel/viewmodel_property_viewmodel.json b/dev/defs/viewmodel/viewmodel_property_viewmodel.json
new file mode 100644
index 0000000..10d615a
--- /dev/null
+++ b/dev/defs/viewmodel/viewmodel_property_viewmodel.json
@@ -0,0 +1,21 @@
+{
+  "name": "ViewModelPropertyViewModel",
+  "key": {
+    "int": 436,
+    "string": "viewmodelpropertyviewmodel"
+  },
+  "extends": "viewmodel/viewmodel_property.json",
+  "properties": {
+    "viewModelReferenceId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 565,
+        "string": "viewmodelreferenceid"
+      },
+      "description": "Identifier used to track the viewmodel this property points to."
+    }
+  }
+}
\ No newline at end of file
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index 97d6afd..ad869a9 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -4,6 +4,11 @@
 #include "rive/animation/linear_animation.hpp"
 #include "rive/animation/state_machine.hpp"
 #include "rive/core_context.hpp"
+#include "rive/data_bind/data_bind.hpp"
+#include "rive/data_bind/data_context.hpp"
+#include "rive/data_bind/data_bind_context.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
 #include "rive/generated/artboard_base.hpp"
 #include "rive/hit_info.hpp"
 #include "rive/math/aabb.hpp"
@@ -54,6 +59,9 @@
     std::vector<DrawTarget*> m_DrawTargets;
     std::vector<NestedArtboard*> m_NestedArtboards;
     std::vector<Joystick*> m_Joysticks;
+    std::vector<DataBind*> m_DataBinds;
+    std::vector<DataBind*> m_AllDataBinds;
+    DataContext* m_DataContext = nullptr;
     bool m_JoysticksApplyBeforeUpdate = true;
     bool m_HasChangedDrawOrderInLastUpdate = false;
 
@@ -75,6 +83,7 @@
 
     void sortDependencies();
     void sortDrawOrder();
+    void updateDataBinds();
 
     Artboard* getArtboard() override { return this; }
 
@@ -116,8 +125,9 @@
     }
 
     bool advance(double elapsedSeconds);
-    bool hasChangedDrawOrderInLastUpdate() { return m_HasChangedDrawOrderInLastUpdate; }
-    Drawable* firstDrawable() { return m_FirstDrawable; }
+    bool advanceInternal(double elapsedSeconds, bool isRoot);
+    bool hasChangedDrawOrderInLastUpdate() { return m_HasChangedDrawOrderInLastUpdate; };
+    Drawable* firstDrawable() { return m_FirstDrawable; };
 
     enum class DrawOption
     {
@@ -135,6 +145,8 @@
 
     const std::vector<Core*>& objects() const { return m_Objects; }
     const std::vector<NestedArtboard*> nestedArtboards() const { return m_NestedArtboards; }
+    const std::vector<DataBind*> dataBinds() const { return m_DataBinds; }
+    DataContext* dataContext() { return m_DataContext; }
     NestedArtboard* nestedArtboard(const std::string& name) const;
     NestedArtboard* nestedArtboardAtPath(const std::string& path) const;
 
@@ -147,6 +159,16 @@
     bool isTranslucent() const;
     bool isTranslucent(const LinearAnimation*) const;
     bool isTranslucent(const LinearAnimationInstance*) const;
+    void dataContext(DataContext* dataContext, DataContext* parent);
+    void internalDataContext(DataContext* dataContext, DataContext* parent, bool isRoot);
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance, DataContext* parent);
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance,
+                                 DataContext* parent,
+                                 bool isRoot);
+    void dataContextFromInstance(ViewModelInstance* viewModelInstance);
+    void populateDataBinds(std::vector<Component*>* dataBinds);
+    void buildDataBindDependencies(std::vector<Component*>* dataBinds);
+    void sortDataBinds(std::vector<Component*> dataBinds);
     bool hasAudio() const;
 
     template <typename T = Component> T* find(const std::string& name)
@@ -230,6 +252,7 @@
 
         artboardClone->m_Factory = m_Factory;
         artboardClone->m_FrameOrigin = m_FrameOrigin;
+        artboardClone->m_DataContext = m_DataContext;
         artboardClone->m_IsInstance = true;
         artboardClone->m_originalWidth = m_originalWidth;
         artboardClone->m_originalHeight = m_originalHeight;
diff --git a/include/rive/component.hpp b/include/rive/component.hpp
index 7c26099..ba06a69 100644
--- a/include/rive/component.hpp
+++ b/include/rive/component.hpp
@@ -2,6 +2,7 @@
 #define _RIVE_COMPONENT_HPP_
 #include "rive/component_dirt.hpp"
 #include "rive/generated/component_base.hpp"
+#include "rive/dependency_helper.hpp"
 
 #include <vector>
 #include <functional>
@@ -17,7 +18,6 @@
 
 private:
     ContainerComponent* m_Parent = nullptr;
-    std::vector<Component*> m_Dependents;
 
     unsigned int m_GraphOrder;
     Artboard* m_Artboard = nullptr;
@@ -26,11 +26,12 @@
     ComponentDirt m_Dirt = ComponentDirt::Filthy;
 
 public:
+    DependencyHelper<Artboard, Component> m_DependencyHelper;
     virtual bool collapse(bool value);
     inline Artboard* artboard() const { return m_Artboard; }
     StatusCode onAddedDirty(CoreContext* context) override;
     inline ContainerComponent* parent() const { return m_Parent; }
-    const std::vector<Component*>& dependents() const { return m_Dependents; }
+    const std::vector<Component*>& dependents() const { return m_DependencyHelper.dependents(); }
 
     void addDependent(Component* component);
 
diff --git a/include/rive/component_dirt.hpp b/include/rive/component_dirt.hpp
index 73f465e..fedb0c7 100644
--- a/include/rive/component_dirt.hpp
+++ b/include/rive/component_dirt.hpp
@@ -56,6 +56,9 @@
     /// Used by the gradients track when the stops need to be re-ordered.
     Stops = 1 << 10,
 
+    /// Used by data binds to track  the value has changed.
+    Bindings = 1 << 11,
+
     /// Blend modes need to be updated
     // TODO: do we need this?
     // BlendMode = 1 << 9,
diff --git a/include/rive/data_bind/context/context_value.hpp b/include/rive/data_bind/context/context_value.hpp
new file mode 100644
index 0000000..1f08e45
--- /dev/null
+++ b/include/rive/data_bind/context/context_value.hpp
@@ -0,0 +1,22 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_HPP_
+#include "rive/refcnt.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataBindContextValue
+{
+protected:
+    ViewModelInstanceValue* m_Source;
+
+public:
+    DataBindContextValue(){};
+    virtual ~DataBindContextValue(){};
+    virtual void applyToSource(Component* component, uint32_t propertyKey){};
+    virtual void apply(Component* component, uint32_t propertyKey){};
+    virtual void update(Component* component){};
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_color.hpp b/include/rive/data_bind/context/context_value_color.hpp
new file mode 100644
index 0000000..c1c7f48
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_color.hpp
@@ -0,0 +1,19 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+namespace rive
+{
+class DataBindContextValueColor : public DataBindContextValue
+{
+
+public:
+    DataBindContextValueColor(ViewModelInstanceValue* value);
+    void apply(Component* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+
+private:
+    double m_Value;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_enum.hpp b/include/rive/data_bind/context/context_value_enum.hpp
new file mode 100644
index 0000000..e78a1b5
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_enum.hpp
@@ -0,0 +1,19 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+namespace rive
+{
+class DataBindContextValueEnum : public DataBindContextValue
+{
+
+public:
+    DataBindContextValueEnum(ViewModelInstanceValue* value);
+    void apply(Component* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+
+private:
+    int m_Value;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_list.hpp b/include/rive/data_bind/context/context_value_list.hpp
new file mode 100644
index 0000000..3ee4f2d
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_list.hpp
@@ -0,0 +1,33 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+#include "rive/data_bind/context/context_value_list_item.hpp"
+#include "rive/artboard.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+namespace rive
+{
+class DataBindContextValueList : public DataBindContextValue
+{
+
+public:
+    DataBindContextValueList(ViewModelInstanceValue* value);
+    void apply(Component* component, uint32_t propertyKey) override;
+    void update(Component* target) override;
+    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+
+private:
+    std::vector<std::unique_ptr<DataBindContextValueListItem>> m_ListItemsCache;
+    void insertItem(Component* target,
+                    ViewModelInstanceListItem* viewModelInstanceListItem,
+                    int index);
+    void swapItems(Component* target, int index1, int index2);
+    void popItem(Component* target);
+    std::unique_ptr<ArtboardInstance> createArtboard(Component* target,
+                                                     Artboard* artboard,
+                                                     ViewModelInstanceListItem* listItem) const;
+    std::unique_ptr<StateMachineInstance> createStateMachineInstance(ArtboardInstance* artboard);
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_list_item.hpp b/include/rive/data_bind/context/context_value_list_item.hpp
new file mode 100644
index 0000000..f15493b
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_list_item.hpp
@@ -0,0 +1,25 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_ITEM_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_LIST_ITEM_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+#include "rive/artboard.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+namespace rive
+{
+class DataBindContextValueListItem
+{
+
+private:
+    std::unique_ptr<ArtboardInstance> m_Artboard;
+    std::unique_ptr<StateMachineInstance> m_StateMachine;
+    ViewModelInstanceListItem* m_ListItem;
+
+public:
+    DataBindContextValueListItem(std::unique_ptr<ArtboardInstance> artboard,
+                                 std::unique_ptr<StateMachineInstance> stateMachine,
+                                 ViewModelInstanceListItem* listItem);
+    ViewModelInstanceListItem* listItem() { return m_ListItem; };
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_number.hpp b/include/rive/data_bind/context/context_value_number.hpp
new file mode 100644
index 0000000..da866d3
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_number.hpp
@@ -0,0 +1,19 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+namespace rive
+{
+class DataBindContextValueNumber : public DataBindContextValue
+{
+
+public:
+    DataBindContextValueNumber(ViewModelInstanceValue* value);
+    void apply(Component* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+
+private:
+    double m_Value;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/context/context_value_string.hpp b/include/rive/data_bind/context/context_value_string.hpp
new file mode 100644
index 0000000..52f2ac3
--- /dev/null
+++ b/include/rive/data_bind/context/context_value_string.hpp
@@ -0,0 +1,19 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_
+#include "rive/data_bind/context/context_value.hpp"
+namespace rive
+{
+class DataBindContextValueString : public DataBindContextValue
+{
+
+public:
+    DataBindContextValueString(ViewModelInstanceValue* value);
+    void apply(Component* component, uint32_t propertyKey) override;
+    virtual void applyToSource(Component* component, uint32_t propertyKey) override;
+
+private:
+    std::string m_Value;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/data_bind.hpp b/include/rive/data_bind/data_bind.hpp
new file mode 100644
index 0000000..ec9b5ae
--- /dev/null
+++ b/include/rive/data_bind/data_bind.hpp
@@ -0,0 +1,21 @@
+#ifndef _RIVE_DATA_BIND_HPP_
+#define _RIVE_DATA_BIND_HPP_
+#include "rive/generated/data_bind/data_bind_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataBind : public DataBindBase
+{
+public:
+    StatusCode onAddedDirty(CoreContext* context) override;
+    StatusCode import(ImportStack& importStack) override;
+    void buildDependencies() override;
+    virtual void updateSourceBinding();
+    Component* target() { return m_target; };
+
+protected:
+    Component* m_target;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/data_bind_context.hpp b/include/rive/data_bind/data_bind_context.hpp
new file mode 100644
index 0000000..93028b4
--- /dev/null
+++ b/include/rive/data_bind/data_bind_context.hpp
@@ -0,0 +1,27 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_HPP_
+#include "rive/generated/data_bind/data_bind_context_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/data_bind/context/context_value.hpp"
+#include "rive/refcnt.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataBindContext : public DataBindContextBase
+{
+protected:
+    std::vector<uint32_t> m_SourcePathIdsBuffer;
+    ViewModelInstanceValue* m_Source;
+    std::unique_ptr<DataBindContextValue> m_ContextValue;
+
+public:
+    void update(ComponentDirt value) override;
+    void decodeSourcePathIds(Span<const uint8_t> value) override;
+    void copySourcePathIds(const DataBindContextBase& object) override;
+    void bindToContext();
+    void updateSourceBinding() override;
+    ViewModelInstanceValue* source() { return m_Source; };
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/data_bind_mode.hpp b/include/rive/data_bind/data_bind_mode.hpp
new file mode 100644
index 0000000..692e62d
--- /dev/null
+++ b/include/rive/data_bind/data_bind_mode.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_DATA_BIND_MODE_HPP_
+#define _RIVE_DATA_BIND_MODE_HPP_
+namespace rive
+{
+enum class DataBindMode : unsigned int
+{
+    oneWay = 0,
+    twoWay = 1,
+    oneWayToSource = 2,
+    once = 3,
+};
+}
+#endif
\ No newline at end of file
diff --git a/include/rive/data_bind/data_context.hpp b/include/rive/data_bind/data_context.hpp
new file mode 100644
index 0000000..5bc6528
--- /dev/null
+++ b/include/rive/data_bind/data_context.hpp
@@ -0,0 +1,38 @@
+#ifndef _RIVE_DATA_CONTEXT_HPP_
+#define _RIVE_DATA_CONTEXT_HPP_
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+
+namespace rive
+{
+class DataContext
+{
+private:
+    DataContext* m_Parent = nullptr;
+    std::vector<ViewModelInstance*> m_ViewModelInstances;
+    ViewModelInstance* m_ViewModelInstance;
+
+public:
+    DataContext();
+    DataContext(ViewModelInstance* viewModelInstance);
+    ~DataContext();
+
+    DataContext* parent() { return m_Parent; }
+    void parent(DataContext* value) { m_Parent = value; }
+    void addViewModelInstance(ViewModelInstance* value);
+    ViewModelInstanceValue* getViewModelProperty(const std::vector<uint32_t> path) const;
+    ViewModelInstance* getViewModelInstance(const std::vector<uint32_t> path) const;
+    void viewModelInstance(ViewModelInstance* value);
+    ViewModelInstance* viewModelInstance() { return m_ViewModelInstance; };
+
+    ViewModelInstanceValue* viewModelValue()
+    {
+        if (m_Parent)
+        {
+            return m_Parent->viewModelValue();
+        }
+        return nullptr;
+    }
+};
+} // namespace rive
+#endif
diff --git a/include/rive/dependency_helper.hpp b/include/rive/dependency_helper.hpp
new file mode 100644
index 0000000..59ef805
--- /dev/null
+++ b/include/rive/dependency_helper.hpp
@@ -0,0 +1,46 @@
+#ifndef _RIVE_DEPENDENCY_HELPER_HPP_
+#define _RIVE_DEPENDENCY_HELPER_HPP_
+
+#include "rive/component_dirt.hpp"
+
+namespace rive
+{
+class Component;
+// class DependencyRoot
+// {
+// public:
+//     virtual void onComponentDirty(Component* component) {};
+// };
+
+template <typename T, typename U> class DependencyHelper
+{
+    std::vector<U*> m_Dependents;
+    T* m_dependecyRoot;
+
+public:
+    void dependecyRoot(T* value) { m_dependecyRoot = value; }
+    DependencyHelper(T* value) : m_dependecyRoot(value) {}
+    DependencyHelper() {}
+    void addDependent(U* component)
+    {
+        // Make it's not already a dependent.
+        if (std::find(m_Dependents.begin(), m_Dependents.end(), component) != m_Dependents.end())
+        {
+            return;
+        }
+        m_Dependents.push_back(component);
+    }
+    void addDirt(ComponentDirt value)
+    {
+        for (auto d : m_Dependents)
+        {
+            d->addDirt(value, true);
+        }
+    }
+
+    void onComponentDirty(U* component) { m_dependecyRoot->onComponentDirty(component); }
+
+    const std::vector<U*>& dependents() const { return m_Dependents; }
+};
+} // namespace rive
+#endif
diff --git a/include/rive/dependency_sorter.hpp b/include/rive/dependency_sorter.hpp
index 3c9cea3..17ac825 100644
--- a/include/rive/dependency_sorter.hpp
+++ b/include/rive/dependency_sorter.hpp
@@ -15,6 +15,7 @@
 
 public:
     void sort(Component* root, std::vector<Component*>& order);
+    void sort(std::vector<Component*> roots, std::vector<Component*>& order);
     bool visit(Component* component, std::vector<Component*>& order);
 };
 } // namespace rive
diff --git a/include/rive/file.hpp b/include/rive/file.hpp
index 9f6659d..52c1dfe 100644
--- a/include/rive/file.hpp
+++ b/include/rive/file.hpp
@@ -5,6 +5,12 @@
 #include "rive/backboard.hpp"
 #include "rive/factory.hpp"
 #include "rive/file_asset_loader.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/viewmodel_component.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
 #include <vector>
 #include <set>
 
@@ -82,6 +88,23 @@
     /// index is out of range.
     Artboard* artboard(size_t index) const;
 
+    /// @returns a view model instance of the view model with the specified name.
+    ViewModelInstance* createViewModelInstance(std::string name);
+
+    /// @returns a view model instance attached to the artboard if it exists.
+    ViewModelInstance* createViewModelInstance(Artboard* artboard);
+
+    /// @returns a view model instance of the viewModel.
+    ViewModelInstance* createViewModelInstance(ViewModel* viewModel);
+
+    /// @returns a view model instance of the viewModel by name and instance name.
+    ViewModelInstance* createViewModelInstance(std::string name, std::string instanceName);
+
+    ViewModel* viewModel(std::string name);
+    ViewModelInstanceListItem* viewModelInstanceListItem(ViewModelInstance* viewModelInstance);
+    ViewModelInstanceListItem* viewModelInstanceListItem(ViewModelInstance* viewModelInstance,
+                                                         Artboard* artboard);
+
 #ifdef WITH_RIVE_TOOLS
     /// Strips FileAssetContents for FileAssets of given typeKeys.
     /// @param data the raw data of the file.
@@ -107,11 +130,17 @@
     /// Rive components and animations.
     std::vector<Artboard*> m_artboards;
 
+    std::vector<ViewModel*> m_ViewModels;
+    std::vector<DataEnum*> m_Enums;
+
     Factory* m_factory;
 
     /// The helper used to load assets when they're not provided in-band
     /// with the file.
     FileAssetLoader* m_assetLoader;
+
+    void completeViewModelInstance(ViewModelInstance* viewModelInstance);
+    ViewModelInstance* copyViewModelInstance(ViewModelInstance* viewModelInstance);
 };
 } // namespace rive
 #endif
diff --git a/include/rive/generated/artboard_base.hpp b/include/rive/generated/artboard_base.hpp
index 54a378b..ff19a02 100644
--- a/include/rive/generated/artboard_base.hpp
+++ b/include/rive/generated/artboard_base.hpp
@@ -37,6 +37,7 @@
     static const uint16_t originXPropertyKey = 11;
     static const uint16_t originYPropertyKey = 12;
     static const uint16_t defaultStateMachineIdPropertyKey = 236;
+    static const uint16_t viewModelIdPropertyKey = 583;
 
 private:
     float m_X = 0.0f;
@@ -44,6 +45,7 @@
     float m_OriginX = 0.0f;
     float m_OriginY = 0.0f;
     uint32_t m_DefaultStateMachineId = -1;
+    uint32_t m_ViewModelId = -1;
 
 public:
     inline float x() const { return m_X; }
@@ -101,6 +103,17 @@
         defaultStateMachineIdChanged();
     }
 
+    inline uint32_t viewModelId() const { return m_ViewModelId; }
+    void viewModelId(uint32_t value)
+    {
+        if (m_ViewModelId == value)
+        {
+            return;
+        }
+        m_ViewModelId = value;
+        viewModelIdChanged();
+    }
+
     Core* clone() const override;
     void copy(const ArtboardBase& object)
     {
@@ -109,6 +122,7 @@
         m_OriginX = object.m_OriginX;
         m_OriginY = object.m_OriginY;
         m_DefaultStateMachineId = object.m_DefaultStateMachineId;
+        m_ViewModelId = object.m_ViewModelId;
         LayoutComponent::copy(object);
     }
 
@@ -131,6 +145,9 @@
             case defaultStateMachineIdPropertyKey:
                 m_DefaultStateMachineId = CoreUintType::deserialize(reader);
                 return true;
+            case viewModelIdPropertyKey:
+                m_ViewModelId = CoreUintType::deserialize(reader);
+                return true;
         }
         return LayoutComponent::deserialize(propertyKey, reader);
     }
@@ -141,6 +158,7 @@
     virtual void originXChanged() {}
     virtual void originYChanged() {}
     virtual void defaultStateMachineIdChanged() {}
+    virtual void viewModelIdChanged() {}
 };
 } // namespace rive
 
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp
index f941648..c4018d2 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -99,6 +99,8 @@
 #include "rive/custom_property_boolean.hpp"
 #include "rive/custom_property_number.hpp"
 #include "rive/custom_property_string.hpp"
+#include "rive/data_bind/data_bind.hpp"
+#include "rive/data_bind/data_bind_context.hpp"
 #include "rive/draw_rules.hpp"
 #include "rive/draw_target.hpp"
 #include "rive/drawable.hpp"
@@ -152,6 +154,26 @@
 #include "rive/text/text_value_run.hpp"
 #include "rive/text/text_variation_modifier.hpp"
 #include "rive/transform_component.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_component.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_color.hpp"
+#include "rive/viewmodel/viewmodel_instance_enum.hpp"
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+#include "rive/viewmodel/viewmodel_instance_number.hpp"
+#include "rive/viewmodel/viewmodel_instance_string.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/viewmodel/viewmodel_property_color.hpp"
+#include "rive/viewmodel/viewmodel_property_enum.hpp"
+#include "rive/viewmodel/viewmodel_property_list.hpp"
+#include "rive/viewmodel/viewmodel_property_number.hpp"
+#include "rive/viewmodel/viewmodel_property_string.hpp"
+#include "rive/viewmodel/viewmodel_property_viewmodel.hpp"
 #include "rive/world_transform_component.hpp"
 namespace rive
 {
@@ -162,6 +184,44 @@
     {
         switch (typeKey)
         {
+            case ViewModelInstanceListItemBase::typeKey:
+                return new ViewModelInstanceListItem();
+            case ViewModelInstanceColorBase::typeKey:
+                return new ViewModelInstanceColor();
+            case ViewModelComponentBase::typeKey:
+                return new ViewModelComponent();
+            case ViewModelPropertyBase::typeKey:
+                return new ViewModelProperty();
+            case ViewModelPropertyNumberBase::typeKey:
+                return new ViewModelPropertyNumber();
+            case ViewModelInstanceEnumBase::typeKey:
+                return new ViewModelInstanceEnum();
+            case ViewModelInstanceStringBase::typeKey:
+                return new ViewModelInstanceString();
+            case ViewModelPropertyListBase::typeKey:
+                return new ViewModelPropertyList();
+            case ViewModelBase::typeKey:
+                return new ViewModel();
+            case ViewModelPropertyViewModelBase::typeKey:
+                return new ViewModelPropertyViewModel();
+            case ViewModelInstanceBase::typeKey:
+                return new ViewModelInstance();
+            case DataEnumBase::typeKey:
+                return new DataEnum();
+            case ViewModelPropertyEnumBase::typeKey:
+                return new ViewModelPropertyEnum();
+            case ViewModelPropertyColorBase::typeKey:
+                return new ViewModelPropertyColor();
+            case ViewModelInstanceListBase::typeKey:
+                return new ViewModelInstanceList();
+            case ViewModelInstanceNumberBase::typeKey:
+                return new ViewModelInstanceNumber();
+            case ViewModelPropertyStringBase::typeKey:
+                return new ViewModelPropertyString();
+            case ViewModelInstanceViewModelBase::typeKey:
+                return new ViewModelInstanceViewModel();
+            case DataEnumValueBase::typeKey:
+                return new DataEnumValue();
             case DrawTargetBase::typeKey:
                 return new DrawTarget();
             case CustomPropertyNumberBase::typeKey:
@@ -342,6 +402,10 @@
                 return new AbsoluteLayoutComponent();
             case OpenUrlEventBase::typeKey:
                 return new OpenUrlEvent();
+            case DataBindBase::typeKey:
+                return new DataBind();
+            case DataBindContextBase::typeKey:
+                return new DataBindContext();
             case WeightBase::typeKey:
                 return new Weight();
             case BoneBase::typeKey:
@@ -387,36 +451,87 @@
         }
         return nullptr;
     }
-    static void setString(Core* object, int propertyKey, std::string value)
+    static void setBool(Core* object, int propertyKey, bool value)
     {
         switch (propertyKey)
         {
-            case ComponentBase::namePropertyKey:
-                object->as<ComponentBase>()->name(value);
+            case ViewModelInstanceListItemBase::useLinkedArtboardPropertyKey:
+                object->as<ViewModelInstanceListItemBase>()->useLinkedArtboard(value);
                 break;
-            case AnimationBase::namePropertyKey:
-                object->as<AnimationBase>()->name(value);
+            case TransformComponentConstraintBase::offsetPropertyKey:
+                object->as<TransformComponentConstraintBase>()->offset(value);
                 break;
-            case StateMachineComponentBase::namePropertyKey:
-                object->as<StateMachineComponentBase>()->name(value);
+            case TransformComponentConstraintBase::doesCopyPropertyKey:
+                object->as<TransformComponentConstraintBase>()->doesCopy(value);
                 break;
-            case KeyFrameStringBase::valuePropertyKey:
-                object->as<KeyFrameStringBase>()->value(value);
+            case TransformComponentConstraintBase::minPropertyKey:
+                object->as<TransformComponentConstraintBase>()->min(value);
                 break;
-            case OpenUrlEventBase::urlPropertyKey:
-                object->as<OpenUrlEventBase>()->url(value);
+            case TransformComponentConstraintBase::maxPropertyKey:
+                object->as<TransformComponentConstraintBase>()->max(value);
                 break;
-            case TextValueRunBase::textPropertyKey:
-                object->as<TextValueRunBase>()->text(value);
+            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
+                object->as<TransformComponentConstraintYBase>()->doesCopyY(value);
                 break;
-            case CustomPropertyStringBase::propertyValuePropertyKey:
-                object->as<CustomPropertyStringBase>()->propertyValue(value);
+            case TransformComponentConstraintYBase::minYPropertyKey:
+                object->as<TransformComponentConstraintYBase>()->minY(value);
                 break;
-            case AssetBase::namePropertyKey:
-                object->as<AssetBase>()->name(value);
+            case TransformComponentConstraintYBase::maxYPropertyKey:
+                object->as<TransformComponentConstraintYBase>()->maxY(value);
                 break;
-            case FileAssetBase::cdnBaseUrlPropertyKey:
-                object->as<FileAssetBase>()->cdnBaseUrl(value);
+            case IKConstraintBase::invertDirectionPropertyKey:
+                object->as<IKConstraintBase>()->invertDirection(value);
+                break;
+            case FollowPathConstraintBase::orientPropertyKey:
+                object->as<FollowPathConstraintBase>()->orient(value);
+                break;
+            case FollowPathConstraintBase::offsetPropertyKey:
+                object->as<FollowPathConstraintBase>()->offset(value);
+                break;
+            case NestedSimpleAnimationBase::isPlayingPropertyKey:
+                object->as<NestedSimpleAnimationBase>()->isPlaying(value);
+                break;
+            case KeyFrameBoolBase::valuePropertyKey:
+                object->as<KeyFrameBoolBase>()->value(value);
+                break;
+            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
+                object->as<ListenerAlignTargetBase>()->preserveOffset(value);
+                break;
+            case NestedBoolBase::nestedValuePropertyKey:
+                object->as<NestedBoolBase>()->nestedValue(value);
+                break;
+            case LinearAnimationBase::enableWorkAreaPropertyKey:
+                object->as<LinearAnimationBase>()->enableWorkArea(value);
+                break;
+            case LinearAnimationBase::quantizePropertyKey:
+                object->as<LinearAnimationBase>()->quantize(value);
+                break;
+            case StateMachineBoolBase::valuePropertyKey:
+                object->as<StateMachineBoolBase>()->value(value);
+                break;
+            case ShapePaintBase::isVisiblePropertyKey:
+                object->as<ShapePaintBase>()->isVisible(value);
+                break;
+            case StrokeBase::transformAffectsStrokePropertyKey:
+                object->as<StrokeBase>()->transformAffectsStroke(value);
+                break;
+            case PointsPathBase::isClosedPropertyKey:
+                object->as<PointsPathBase>()->isClosed(value);
+                break;
+            case RectangleBase::linkCornerRadiusPropertyKey:
+                object->as<RectangleBase>()->linkCornerRadius(value);
+                break;
+            case ClippingShapeBase::isVisiblePropertyKey:
+                object->as<ClippingShapeBase>()->isVisible(value);
+                break;
+            case CustomPropertyBooleanBase::propertyValuePropertyKey:
+                object->as<CustomPropertyBooleanBase>()->propertyValue(value);
+                break;
+            case LayoutComponentBase::clipPropertyKey:
+                object->as<LayoutComponentBase>()->clip(value);
+                break;
+            case TextModifierRangeBase::clampPropertyKey:
+                object->as<TextModifierRangeBase>()->clamp(value);
                 break;
         }
     }
@@ -424,9 +539,39 @@
     {
         switch (propertyKey)
         {
+            case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
+                object->as<ViewModelInstanceListItemBase>()->viewModelId(value);
+                break;
+            case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey:
+                object->as<ViewModelInstanceListItemBase>()->viewModelInstanceId(value);
+                break;
+            case ViewModelInstanceListItemBase::artboardIdPropertyKey:
+                object->as<ViewModelInstanceListItemBase>()->artboardId(value);
+                break;
+            case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey:
+                object->as<ViewModelInstanceValueBase>()->viewModelPropertyId(value);
+                break;
+            case ViewModelInstanceEnumBase::propertyValuePropertyKey:
+                object->as<ViewModelInstanceEnumBase>()->propertyValue(value);
+                break;
+            case ViewModelBase::defaultInstanceIdPropertyKey:
+                object->as<ViewModelBase>()->defaultInstanceId(value);
+                break;
+            case ViewModelPropertyViewModelBase::viewModelReferenceIdPropertyKey:
+                object->as<ViewModelPropertyViewModelBase>()->viewModelReferenceId(value);
+                break;
             case ComponentBase::parentIdPropertyKey:
                 object->as<ComponentBase>()->parentId(value);
                 break;
+            case ViewModelInstanceBase::viewModelIdPropertyKey:
+                object->as<ViewModelInstanceBase>()->viewModelId(value);
+                break;
+            case ViewModelPropertyEnumBase::enumIdPropertyKey:
+                object->as<ViewModelPropertyEnumBase>()->enumId(value);
+                break;
+            case ViewModelInstanceViewModelBase::propertyValuePropertyKey:
+                object->as<ViewModelInstanceViewModelBase>()->propertyValue(value);
+                break;
             case DrawTargetBase::drawableIdPropertyKey:
                 object->as<DrawTargetBase>()->drawableId(value);
                 break;
@@ -634,6 +779,9 @@
             case ArtboardBase::defaultStateMachineIdPropertyKey:
                 object->as<ArtboardBase>()->defaultStateMachineId(value);
                 break;
+            case ArtboardBase::viewModelIdPropertyKey:
+                object->as<ArtboardBase>()->viewModelId(value);
+                break;
             case JoystickBase::xIdPropertyKey:
                 object->as<JoystickBase>()->xId(value);
                 break;
@@ -649,6 +797,15 @@
             case OpenUrlEventBase::targetValuePropertyKey:
                 object->as<OpenUrlEventBase>()->targetValue(value);
                 break;
+            case DataBindBase::targetIdPropertyKey:
+                object->as<DataBindBase>()->targetId(value);
+                break;
+            case DataBindBase::propertyKeyPropertyKey:
+                object->as<DataBindBase>()->propertyKey(value);
+                break;
+            case DataBindBase::modeValuePropertyKey:
+                object->as<DataBindBase>()->modeValue(value);
+                break;
             case WeightBase::valuesPropertyKey:
                 object->as<WeightBase>()->values(value);
                 break;
@@ -723,10 +880,76 @@
                 break;
         }
     }
+    static void setColor(Core* object, int propertyKey, int value)
+    {
+        switch (propertyKey)
+        {
+            case ViewModelInstanceColorBase::propertyValuePropertyKey:
+                object->as<ViewModelInstanceColorBase>()->propertyValue(value);
+                break;
+            case KeyFrameColorBase::valuePropertyKey:
+                object->as<KeyFrameColorBase>()->value(value);
+                break;
+            case SolidColorBase::colorValuePropertyKey:
+                object->as<SolidColorBase>()->colorValue(value);
+                break;
+            case GradientStopBase::colorValuePropertyKey:
+                object->as<GradientStopBase>()->colorValue(value);
+                break;
+        }
+    }
+    static void setString(Core* object, int propertyKey, std::string value)
+    {
+        switch (propertyKey)
+        {
+            case ViewModelComponentBase::namePropertyKey:
+                object->as<ViewModelComponentBase>()->name(value);
+                break;
+            case ViewModelInstanceStringBase::propertyValuePropertyKey:
+                object->as<ViewModelInstanceStringBase>()->propertyValue(value);
+                break;
+            case ComponentBase::namePropertyKey:
+                object->as<ComponentBase>()->name(value);
+                break;
+            case DataEnumValueBase::keyPropertyKey:
+                object->as<DataEnumValueBase>()->key(value);
+                break;
+            case DataEnumValueBase::valuePropertyKey:
+                object->as<DataEnumValueBase>()->value(value);
+                break;
+            case AnimationBase::namePropertyKey:
+                object->as<AnimationBase>()->name(value);
+                break;
+            case StateMachineComponentBase::namePropertyKey:
+                object->as<StateMachineComponentBase>()->name(value);
+                break;
+            case KeyFrameStringBase::valuePropertyKey:
+                object->as<KeyFrameStringBase>()->value(value);
+                break;
+            case OpenUrlEventBase::urlPropertyKey:
+                object->as<OpenUrlEventBase>()->url(value);
+                break;
+            case TextValueRunBase::textPropertyKey:
+                object->as<TextValueRunBase>()->text(value);
+                break;
+            case CustomPropertyStringBase::propertyValuePropertyKey:
+                object->as<CustomPropertyStringBase>()->propertyValue(value);
+                break;
+            case AssetBase::namePropertyKey:
+                object->as<AssetBase>()->name(value);
+                break;
+            case FileAssetBase::cdnBaseUrlPropertyKey:
+                object->as<FileAssetBase>()->cdnBaseUrl(value);
+                break;
+        }
+    }
     static void setDouble(Core* object, int propertyKey, float value)
     {
         switch (propertyKey)
         {
+            case ViewModelInstanceNumberBase::propertyValuePropertyKey:
+                object->as<ViewModelInstanceNumberBase>()->propertyValue(value);
+                break;
             case CustomPropertyNumberBase::propertyValuePropertyKey:
                 object->as<CustomPropertyNumberBase>()->propertyValue(value);
                 break;
@@ -1206,87 +1429,6 @@
                 break;
         }
     }
-    static void setBool(Core* object, int propertyKey, bool value)
-    {
-        switch (propertyKey)
-        {
-            case TransformComponentConstraintBase::offsetPropertyKey:
-                object->as<TransformComponentConstraintBase>()->offset(value);
-                break;
-            case TransformComponentConstraintBase::doesCopyPropertyKey:
-                object->as<TransformComponentConstraintBase>()->doesCopy(value);
-                break;
-            case TransformComponentConstraintBase::minPropertyKey:
-                object->as<TransformComponentConstraintBase>()->min(value);
-                break;
-            case TransformComponentConstraintBase::maxPropertyKey:
-                object->as<TransformComponentConstraintBase>()->max(value);
-                break;
-            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
-                object->as<TransformComponentConstraintYBase>()->doesCopyY(value);
-                break;
-            case TransformComponentConstraintYBase::minYPropertyKey:
-                object->as<TransformComponentConstraintYBase>()->minY(value);
-                break;
-            case TransformComponentConstraintYBase::maxYPropertyKey:
-                object->as<TransformComponentConstraintYBase>()->maxY(value);
-                break;
-            case IKConstraintBase::invertDirectionPropertyKey:
-                object->as<IKConstraintBase>()->invertDirection(value);
-                break;
-            case FollowPathConstraintBase::orientPropertyKey:
-                object->as<FollowPathConstraintBase>()->orient(value);
-                break;
-            case FollowPathConstraintBase::offsetPropertyKey:
-                object->as<FollowPathConstraintBase>()->offset(value);
-                break;
-            case NestedSimpleAnimationBase::isPlayingPropertyKey:
-                object->as<NestedSimpleAnimationBase>()->isPlaying(value);
-                break;
-            case KeyFrameBoolBase::valuePropertyKey:
-                object->as<KeyFrameBoolBase>()->value(value);
-                break;
-            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
-                object->as<ListenerAlignTargetBase>()->preserveOffset(value);
-                break;
-            case NestedBoolBase::nestedValuePropertyKey:
-                object->as<NestedBoolBase>()->nestedValue(value);
-                break;
-            case LinearAnimationBase::enableWorkAreaPropertyKey:
-                object->as<LinearAnimationBase>()->enableWorkArea(value);
-                break;
-            case LinearAnimationBase::quantizePropertyKey:
-                object->as<LinearAnimationBase>()->quantize(value);
-                break;
-            case StateMachineBoolBase::valuePropertyKey:
-                object->as<StateMachineBoolBase>()->value(value);
-                break;
-            case ShapePaintBase::isVisiblePropertyKey:
-                object->as<ShapePaintBase>()->isVisible(value);
-                break;
-            case StrokeBase::transformAffectsStrokePropertyKey:
-                object->as<StrokeBase>()->transformAffectsStroke(value);
-                break;
-            case PointsPathBase::isClosedPropertyKey:
-                object->as<PointsPathBase>()->isClosed(value);
-                break;
-            case RectangleBase::linkCornerRadiusPropertyKey:
-                object->as<RectangleBase>()->linkCornerRadius(value);
-                break;
-            case ClippingShapeBase::isVisiblePropertyKey:
-                object->as<ClippingShapeBase>()->isVisible(value);
-                break;
-            case CustomPropertyBooleanBase::propertyValuePropertyKey:
-                object->as<CustomPropertyBooleanBase>()->propertyValue(value);
-                break;
-            case LayoutComponentBase::clipPropertyKey:
-                object->as<LayoutComponentBase>()->clip(value);
-                break;
-            case TextModifierRangeBase::clampPropertyKey:
-                object->as<TextModifierRangeBase>()->clamp(value);
-                break;
-        }
-    }
     static void setCallback(Core* object, int propertyKey, CallbackData value)
     {
         switch (propertyKey)
@@ -1299,52 +1441,91 @@
                 break;
         }
     }
-    static void setColor(Core* object, int propertyKey, int value)
+    static bool getBool(Core* object, int propertyKey)
     {
         switch (propertyKey)
         {
-            case KeyFrameColorBase::valuePropertyKey:
-                object->as<KeyFrameColorBase>()->value(value);
-                break;
-            case SolidColorBase::colorValuePropertyKey:
-                object->as<SolidColorBase>()->colorValue(value);
-                break;
-            case GradientStopBase::colorValuePropertyKey:
-                object->as<GradientStopBase>()->colorValue(value);
-                break;
+            case ViewModelInstanceListItemBase::useLinkedArtboardPropertyKey:
+                return object->as<ViewModelInstanceListItemBase>()->useLinkedArtboard();
+            case TransformComponentConstraintBase::offsetPropertyKey:
+                return object->as<TransformComponentConstraintBase>()->offset();
+            case TransformComponentConstraintBase::doesCopyPropertyKey:
+                return object->as<TransformComponentConstraintBase>()->doesCopy();
+            case TransformComponentConstraintBase::minPropertyKey:
+                return object->as<TransformComponentConstraintBase>()->min();
+            case TransformComponentConstraintBase::maxPropertyKey:
+                return object->as<TransformComponentConstraintBase>()->max();
+            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
+                return object->as<TransformComponentConstraintYBase>()->doesCopyY();
+            case TransformComponentConstraintYBase::minYPropertyKey:
+                return object->as<TransformComponentConstraintYBase>()->minY();
+            case TransformComponentConstraintYBase::maxYPropertyKey:
+                return object->as<TransformComponentConstraintYBase>()->maxY();
+            case IKConstraintBase::invertDirectionPropertyKey:
+                return object->as<IKConstraintBase>()->invertDirection();
+            case FollowPathConstraintBase::orientPropertyKey:
+                return object->as<FollowPathConstraintBase>()->orient();
+            case FollowPathConstraintBase::offsetPropertyKey:
+                return object->as<FollowPathConstraintBase>()->offset();
+            case NestedSimpleAnimationBase::isPlayingPropertyKey:
+                return object->as<NestedSimpleAnimationBase>()->isPlaying();
+            case KeyFrameBoolBase::valuePropertyKey:
+                return object->as<KeyFrameBoolBase>()->value();
+            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
+                return object->as<ListenerAlignTargetBase>()->preserveOffset();
+            case NestedBoolBase::nestedValuePropertyKey:
+                return object->as<NestedBoolBase>()->nestedValue();
+            case LinearAnimationBase::enableWorkAreaPropertyKey:
+                return object->as<LinearAnimationBase>()->enableWorkArea();
+            case LinearAnimationBase::quantizePropertyKey:
+                return object->as<LinearAnimationBase>()->quantize();
+            case StateMachineBoolBase::valuePropertyKey:
+                return object->as<StateMachineBoolBase>()->value();
+            case ShapePaintBase::isVisiblePropertyKey:
+                return object->as<ShapePaintBase>()->isVisible();
+            case StrokeBase::transformAffectsStrokePropertyKey:
+                return object->as<StrokeBase>()->transformAffectsStroke();
+            case PointsPathBase::isClosedPropertyKey:
+                return object->as<PointsPathBase>()->isClosed();
+            case RectangleBase::linkCornerRadiusPropertyKey:
+                return object->as<RectangleBase>()->linkCornerRadius();
+            case ClippingShapeBase::isVisiblePropertyKey:
+                return object->as<ClippingShapeBase>()->isVisible();
+            case CustomPropertyBooleanBase::propertyValuePropertyKey:
+                return object->as<CustomPropertyBooleanBase>()->propertyValue();
+            case LayoutComponentBase::clipPropertyKey:
+                return object->as<LayoutComponentBase>()->clip();
+            case TextModifierRangeBase::clampPropertyKey:
+                return object->as<TextModifierRangeBase>()->clamp();
         }
-    }
-    static std::string getString(Core* object, int propertyKey)
-    {
-        switch (propertyKey)
-        {
-            case ComponentBase::namePropertyKey:
-                return object->as<ComponentBase>()->name();
-            case AnimationBase::namePropertyKey:
-                return object->as<AnimationBase>()->name();
-            case StateMachineComponentBase::namePropertyKey:
-                return object->as<StateMachineComponentBase>()->name();
-            case KeyFrameStringBase::valuePropertyKey:
-                return object->as<KeyFrameStringBase>()->value();
-            case OpenUrlEventBase::urlPropertyKey:
-                return object->as<OpenUrlEventBase>()->url();
-            case TextValueRunBase::textPropertyKey:
-                return object->as<TextValueRunBase>()->text();
-            case CustomPropertyStringBase::propertyValuePropertyKey:
-                return object->as<CustomPropertyStringBase>()->propertyValue();
-            case AssetBase::namePropertyKey:
-                return object->as<AssetBase>()->name();
-            case FileAssetBase::cdnBaseUrlPropertyKey:
-                return object->as<FileAssetBase>()->cdnBaseUrl();
-        }
-        return "";
+        return false;
     }
     static uint32_t getUint(Core* object, int propertyKey)
     {
         switch (propertyKey)
         {
+            case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
+                return object->as<ViewModelInstanceListItemBase>()->viewModelId();
+            case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey:
+                return object->as<ViewModelInstanceListItemBase>()->viewModelInstanceId();
+            case ViewModelInstanceListItemBase::artboardIdPropertyKey:
+                return object->as<ViewModelInstanceListItemBase>()->artboardId();
+            case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey:
+                return object->as<ViewModelInstanceValueBase>()->viewModelPropertyId();
+            case ViewModelInstanceEnumBase::propertyValuePropertyKey:
+                return object->as<ViewModelInstanceEnumBase>()->propertyValue();
+            case ViewModelBase::defaultInstanceIdPropertyKey:
+                return object->as<ViewModelBase>()->defaultInstanceId();
+            case ViewModelPropertyViewModelBase::viewModelReferenceIdPropertyKey:
+                return object->as<ViewModelPropertyViewModelBase>()->viewModelReferenceId();
             case ComponentBase::parentIdPropertyKey:
                 return object->as<ComponentBase>()->parentId();
+            case ViewModelInstanceBase::viewModelIdPropertyKey:
+                return object->as<ViewModelInstanceBase>()->viewModelId();
+            case ViewModelPropertyEnumBase::enumIdPropertyKey:
+                return object->as<ViewModelPropertyEnumBase>()->enumId();
+            case ViewModelInstanceViewModelBase::propertyValuePropertyKey:
+                return object->as<ViewModelInstanceViewModelBase>()->propertyValue();
             case DrawTargetBase::drawableIdPropertyKey:
                 return object->as<DrawTargetBase>()->drawableId();
             case DrawTargetBase::placementValuePropertyKey:
@@ -1483,6 +1664,8 @@
                 return object->as<LayoutComponentBase>()->styleId();
             case ArtboardBase::defaultStateMachineIdPropertyKey:
                 return object->as<ArtboardBase>()->defaultStateMachineId();
+            case ArtboardBase::viewModelIdPropertyKey:
+                return object->as<ArtboardBase>()->viewModelId();
             case JoystickBase::xIdPropertyKey:
                 return object->as<JoystickBase>()->xId();
             case JoystickBase::yIdPropertyKey:
@@ -1493,6 +1676,12 @@
                 return object->as<JoystickBase>()->handleSourceId();
             case OpenUrlEventBase::targetValuePropertyKey:
                 return object->as<OpenUrlEventBase>()->targetValue();
+            case DataBindBase::targetIdPropertyKey:
+                return object->as<DataBindBase>()->targetId();
+            case DataBindBase::propertyKeyPropertyKey:
+                return object->as<DataBindBase>()->propertyKey();
+            case DataBindBase::modeValuePropertyKey:
+                return object->as<DataBindBase>()->modeValue();
             case WeightBase::valuesPropertyKey:
                 return object->as<WeightBase>()->values();
             case WeightBase::indicesPropertyKey:
@@ -1544,10 +1733,60 @@
         }
         return 0;
     }
+    static int getColor(Core* object, int propertyKey)
+    {
+        switch (propertyKey)
+        {
+            case ViewModelInstanceColorBase::propertyValuePropertyKey:
+                return object->as<ViewModelInstanceColorBase>()->propertyValue();
+            case KeyFrameColorBase::valuePropertyKey:
+                return object->as<KeyFrameColorBase>()->value();
+            case SolidColorBase::colorValuePropertyKey:
+                return object->as<SolidColorBase>()->colorValue();
+            case GradientStopBase::colorValuePropertyKey:
+                return object->as<GradientStopBase>()->colorValue();
+        }
+        return 0;
+    }
+    static std::string getString(Core* object, int propertyKey)
+    {
+        switch (propertyKey)
+        {
+            case ViewModelComponentBase::namePropertyKey:
+                return object->as<ViewModelComponentBase>()->name();
+            case ViewModelInstanceStringBase::propertyValuePropertyKey:
+                return object->as<ViewModelInstanceStringBase>()->propertyValue();
+            case ComponentBase::namePropertyKey:
+                return object->as<ComponentBase>()->name();
+            case DataEnumValueBase::keyPropertyKey:
+                return object->as<DataEnumValueBase>()->key();
+            case DataEnumValueBase::valuePropertyKey:
+                return object->as<DataEnumValueBase>()->value();
+            case AnimationBase::namePropertyKey:
+                return object->as<AnimationBase>()->name();
+            case StateMachineComponentBase::namePropertyKey:
+                return object->as<StateMachineComponentBase>()->name();
+            case KeyFrameStringBase::valuePropertyKey:
+                return object->as<KeyFrameStringBase>()->value();
+            case OpenUrlEventBase::urlPropertyKey:
+                return object->as<OpenUrlEventBase>()->url();
+            case TextValueRunBase::textPropertyKey:
+                return object->as<TextValueRunBase>()->text();
+            case CustomPropertyStringBase::propertyValuePropertyKey:
+                return object->as<CustomPropertyStringBase>()->propertyValue();
+            case AssetBase::namePropertyKey:
+                return object->as<AssetBase>()->name();
+            case FileAssetBase::cdnBaseUrlPropertyKey:
+                return object->as<FileAssetBase>()->cdnBaseUrl();
+        }
+        return "";
+    }
     static float getDouble(Core* object, int propertyKey)
     {
         switch (propertyKey)
         {
+            case ViewModelInstanceNumberBase::propertyValuePropertyKey:
+                return object->as<ViewModelInstanceNumberBase>()->propertyValue();
             case CustomPropertyNumberBase::propertyValuePropertyKey:
                 return object->as<CustomPropertyNumberBase>()->propertyValue();
             case ConstraintBase::strengthPropertyKey:
@@ -1869,91 +2108,48 @@
         }
         return 0.0f;
     }
-    static bool getBool(Core* object, int propertyKey)
-    {
-        switch (propertyKey)
-        {
-            case TransformComponentConstraintBase::offsetPropertyKey:
-                return object->as<TransformComponentConstraintBase>()->offset();
-            case TransformComponentConstraintBase::doesCopyPropertyKey:
-                return object->as<TransformComponentConstraintBase>()->doesCopy();
-            case TransformComponentConstraintBase::minPropertyKey:
-                return object->as<TransformComponentConstraintBase>()->min();
-            case TransformComponentConstraintBase::maxPropertyKey:
-                return object->as<TransformComponentConstraintBase>()->max();
-            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
-                return object->as<TransformComponentConstraintYBase>()->doesCopyY();
-            case TransformComponentConstraintYBase::minYPropertyKey:
-                return object->as<TransformComponentConstraintYBase>()->minY();
-            case TransformComponentConstraintYBase::maxYPropertyKey:
-                return object->as<TransformComponentConstraintYBase>()->maxY();
-            case IKConstraintBase::invertDirectionPropertyKey:
-                return object->as<IKConstraintBase>()->invertDirection();
-            case FollowPathConstraintBase::orientPropertyKey:
-                return object->as<FollowPathConstraintBase>()->orient();
-            case FollowPathConstraintBase::offsetPropertyKey:
-                return object->as<FollowPathConstraintBase>()->offset();
-            case NestedSimpleAnimationBase::isPlayingPropertyKey:
-                return object->as<NestedSimpleAnimationBase>()->isPlaying();
-            case KeyFrameBoolBase::valuePropertyKey:
-                return object->as<KeyFrameBoolBase>()->value();
-            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
-                return object->as<ListenerAlignTargetBase>()->preserveOffset();
-            case NestedBoolBase::nestedValuePropertyKey:
-                return object->as<NestedBoolBase>()->nestedValue();
-            case LinearAnimationBase::enableWorkAreaPropertyKey:
-                return object->as<LinearAnimationBase>()->enableWorkArea();
-            case LinearAnimationBase::quantizePropertyKey:
-                return object->as<LinearAnimationBase>()->quantize();
-            case StateMachineBoolBase::valuePropertyKey:
-                return object->as<StateMachineBoolBase>()->value();
-            case ShapePaintBase::isVisiblePropertyKey:
-                return object->as<ShapePaintBase>()->isVisible();
-            case StrokeBase::transformAffectsStrokePropertyKey:
-                return object->as<StrokeBase>()->transformAffectsStroke();
-            case PointsPathBase::isClosedPropertyKey:
-                return object->as<PointsPathBase>()->isClosed();
-            case RectangleBase::linkCornerRadiusPropertyKey:
-                return object->as<RectangleBase>()->linkCornerRadius();
-            case ClippingShapeBase::isVisiblePropertyKey:
-                return object->as<ClippingShapeBase>()->isVisible();
-            case CustomPropertyBooleanBase::propertyValuePropertyKey:
-                return object->as<CustomPropertyBooleanBase>()->propertyValue();
-            case LayoutComponentBase::clipPropertyKey:
-                return object->as<LayoutComponentBase>()->clip();
-            case TextModifierRangeBase::clampPropertyKey:
-                return object->as<TextModifierRangeBase>()->clamp();
-        }
-        return false;
-    }
-    static int getColor(Core* object, int propertyKey)
-    {
-        switch (propertyKey)
-        {
-            case KeyFrameColorBase::valuePropertyKey:
-                return object->as<KeyFrameColorBase>()->value();
-            case SolidColorBase::colorValuePropertyKey:
-                return object->as<SolidColorBase>()->colorValue();
-            case GradientStopBase::colorValuePropertyKey:
-                return object->as<GradientStopBase>()->colorValue();
-        }
-        return 0;
-    }
     static int propertyFieldId(int propertyKey)
     {
         switch (propertyKey)
         {
-            case ComponentBase::namePropertyKey:
-            case AnimationBase::namePropertyKey:
-            case StateMachineComponentBase::namePropertyKey:
-            case KeyFrameStringBase::valuePropertyKey:
-            case OpenUrlEventBase::urlPropertyKey:
-            case TextValueRunBase::textPropertyKey:
-            case CustomPropertyStringBase::propertyValuePropertyKey:
-            case AssetBase::namePropertyKey:
-            case FileAssetBase::cdnBaseUrlPropertyKey:
-                return CoreStringType::id;
+            case ViewModelInstanceListItemBase::useLinkedArtboardPropertyKey:
+            case TransformComponentConstraintBase::offsetPropertyKey:
+            case TransformComponentConstraintBase::doesCopyPropertyKey:
+            case TransformComponentConstraintBase::minPropertyKey:
+            case TransformComponentConstraintBase::maxPropertyKey:
+            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
+            case TransformComponentConstraintYBase::minYPropertyKey:
+            case TransformComponentConstraintYBase::maxYPropertyKey:
+            case IKConstraintBase::invertDirectionPropertyKey:
+            case FollowPathConstraintBase::orientPropertyKey:
+            case FollowPathConstraintBase::offsetPropertyKey:
+            case NestedSimpleAnimationBase::isPlayingPropertyKey:
+            case KeyFrameBoolBase::valuePropertyKey:
+            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
+            case NestedBoolBase::nestedValuePropertyKey:
+            case LinearAnimationBase::enableWorkAreaPropertyKey:
+            case LinearAnimationBase::quantizePropertyKey:
+            case StateMachineBoolBase::valuePropertyKey:
+            case ShapePaintBase::isVisiblePropertyKey:
+            case StrokeBase::transformAffectsStrokePropertyKey:
+            case PointsPathBase::isClosedPropertyKey:
+            case RectangleBase::linkCornerRadiusPropertyKey:
+            case ClippingShapeBase::isVisiblePropertyKey:
+            case CustomPropertyBooleanBase::propertyValuePropertyKey:
+            case LayoutComponentBase::clipPropertyKey:
+            case TextModifierRangeBase::clampPropertyKey:
+                return CoreBoolType::id;
+            case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
+            case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey:
+            case ViewModelInstanceListItemBase::artboardIdPropertyKey:
+            case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey:
+            case ViewModelInstanceEnumBase::propertyValuePropertyKey:
+            case ViewModelBase::defaultInstanceIdPropertyKey:
+            case ViewModelPropertyViewModelBase::viewModelReferenceIdPropertyKey:
             case ComponentBase::parentIdPropertyKey:
+            case ViewModelInstanceBase::viewModelIdPropertyKey:
+            case ViewModelPropertyEnumBase::enumIdPropertyKey:
+            case ViewModelInstanceViewModelBase::propertyValuePropertyKey:
             case DrawTargetBase::drawableIdPropertyKey:
             case DrawTargetBase::placementValuePropertyKey:
             case TargetedConstraintBase::targetIdPropertyKey:
@@ -2023,11 +2219,15 @@
             case DrawRulesBase::drawTargetIdPropertyKey:
             case LayoutComponentBase::styleIdPropertyKey:
             case ArtboardBase::defaultStateMachineIdPropertyKey:
+            case ArtboardBase::viewModelIdPropertyKey:
             case JoystickBase::xIdPropertyKey:
             case JoystickBase::yIdPropertyKey:
             case JoystickBase::joystickFlagsPropertyKey:
             case JoystickBase::handleSourceIdPropertyKey:
             case OpenUrlEventBase::targetValuePropertyKey:
+            case DataBindBase::targetIdPropertyKey:
+            case DataBindBase::propertyKeyPropertyKey:
+            case DataBindBase::modeValuePropertyKey:
             case WeightBase::valuesPropertyKey:
             case WeightBase::indicesPropertyKey:
             case TendonBase::boneIdPropertyKey:
@@ -2053,6 +2253,26 @@
             case FileAssetBase::assetIdPropertyKey:
             case AudioEventBase::assetIdPropertyKey:
                 return CoreUintType::id;
+            case ViewModelInstanceColorBase::propertyValuePropertyKey:
+            case KeyFrameColorBase::valuePropertyKey:
+            case SolidColorBase::colorValuePropertyKey:
+            case GradientStopBase::colorValuePropertyKey:
+                return CoreColorType::id;
+            case ViewModelComponentBase::namePropertyKey:
+            case ViewModelInstanceStringBase::propertyValuePropertyKey:
+            case ComponentBase::namePropertyKey:
+            case DataEnumValueBase::keyPropertyKey:
+            case DataEnumValueBase::valuePropertyKey:
+            case AnimationBase::namePropertyKey:
+            case StateMachineComponentBase::namePropertyKey:
+            case KeyFrameStringBase::valuePropertyKey:
+            case OpenUrlEventBase::urlPropertyKey:
+            case TextValueRunBase::textPropertyKey:
+            case CustomPropertyStringBase::propertyValuePropertyKey:
+            case AssetBase::namePropertyKey:
+            case FileAssetBase::cdnBaseUrlPropertyKey:
+                return CoreStringType::id;
+            case ViewModelInstanceNumberBase::propertyValuePropertyKey:
             case CustomPropertyNumberBase::propertyValuePropertyKey:
             case ConstraintBase::strengthPropertyKey:
             case DistanceConstraintBase::distancePropertyKey:
@@ -2213,37 +2433,9 @@
             case DrawableAssetBase::widthPropertyKey:
             case ExportAudioBase::volumePropertyKey:
                 return CoreDoubleType::id;
-            case TransformComponentConstraintBase::offsetPropertyKey:
-            case TransformComponentConstraintBase::doesCopyPropertyKey:
-            case TransformComponentConstraintBase::minPropertyKey:
-            case TransformComponentConstraintBase::maxPropertyKey:
-            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
-            case TransformComponentConstraintYBase::minYPropertyKey:
-            case TransformComponentConstraintYBase::maxYPropertyKey:
-            case IKConstraintBase::invertDirectionPropertyKey:
-            case FollowPathConstraintBase::orientPropertyKey:
-            case FollowPathConstraintBase::offsetPropertyKey:
-            case NestedSimpleAnimationBase::isPlayingPropertyKey:
-            case KeyFrameBoolBase::valuePropertyKey:
-            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
-            case NestedBoolBase::nestedValuePropertyKey:
-            case LinearAnimationBase::enableWorkAreaPropertyKey:
-            case LinearAnimationBase::quantizePropertyKey:
-            case StateMachineBoolBase::valuePropertyKey:
-            case ShapePaintBase::isVisiblePropertyKey:
-            case StrokeBase::transformAffectsStrokePropertyKey:
-            case PointsPathBase::isClosedPropertyKey:
-            case RectangleBase::linkCornerRadiusPropertyKey:
-            case ClippingShapeBase::isVisiblePropertyKey:
-            case CustomPropertyBooleanBase::propertyValuePropertyKey:
-            case LayoutComponentBase::clipPropertyKey:
-            case TextModifierRangeBase::clampPropertyKey:
-                return CoreBoolType::id;
-            case KeyFrameColorBase::valuePropertyKey:
-            case SolidColorBase::colorValuePropertyKey:
-            case GradientStopBase::colorValuePropertyKey:
-                return CoreColorType::id;
+            case NestedArtboardBase::dataBindPathIdsPropertyKey:
             case MeshBase::triangleIndexBytesPropertyKey:
+            case DataBindContextBase::sourcePathIdsPropertyKey:
             case FileAssetBase::cdnUuidPropertyKey:
             case FileAssetContentsBase::bytesPropertyKey:
                 return CoreBytesType::id;
@@ -2266,26 +2458,80 @@
     {
         switch (propertyKey)
         {
-            case ComponentBase::namePropertyKey:
-                return object->is<ComponentBase>();
-            case AnimationBase::namePropertyKey:
-                return object->is<AnimationBase>();
-            case StateMachineComponentBase::namePropertyKey:
-                return object->is<StateMachineComponentBase>();
-            case KeyFrameStringBase::valuePropertyKey:
-                return object->is<KeyFrameStringBase>();
-            case OpenUrlEventBase::urlPropertyKey:
-                return object->is<OpenUrlEventBase>();
-            case TextValueRunBase::textPropertyKey:
-                return object->is<TextValueRunBase>();
-            case CustomPropertyStringBase::propertyValuePropertyKey:
-                return object->is<CustomPropertyStringBase>();
-            case AssetBase::namePropertyKey:
-                return object->is<AssetBase>();
-            case FileAssetBase::cdnBaseUrlPropertyKey:
-                return object->is<FileAssetBase>();
+            case ViewModelInstanceListItemBase::useLinkedArtboardPropertyKey:
+                return object->is<ViewModelInstanceListItemBase>();
+            case TransformComponentConstraintBase::offsetPropertyKey:
+                return object->is<TransformComponentConstraintBase>();
+            case TransformComponentConstraintBase::doesCopyPropertyKey:
+                return object->is<TransformComponentConstraintBase>();
+            case TransformComponentConstraintBase::minPropertyKey:
+                return object->is<TransformComponentConstraintBase>();
+            case TransformComponentConstraintBase::maxPropertyKey:
+                return object->is<TransformComponentConstraintBase>();
+            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
+                return object->is<TransformComponentConstraintYBase>();
+            case TransformComponentConstraintYBase::minYPropertyKey:
+                return object->is<TransformComponentConstraintYBase>();
+            case TransformComponentConstraintYBase::maxYPropertyKey:
+                return object->is<TransformComponentConstraintYBase>();
+            case IKConstraintBase::invertDirectionPropertyKey:
+                return object->is<IKConstraintBase>();
+            case FollowPathConstraintBase::orientPropertyKey:
+                return object->is<FollowPathConstraintBase>();
+            case FollowPathConstraintBase::offsetPropertyKey:
+                return object->is<FollowPathConstraintBase>();
+            case NestedSimpleAnimationBase::isPlayingPropertyKey:
+                return object->is<NestedSimpleAnimationBase>();
+            case KeyFrameBoolBase::valuePropertyKey:
+                return object->is<KeyFrameBoolBase>();
+            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
+                return object->is<ListenerAlignTargetBase>();
+            case NestedBoolBase::nestedValuePropertyKey:
+                return object->is<NestedBoolBase>();
+            case LinearAnimationBase::enableWorkAreaPropertyKey:
+                return object->is<LinearAnimationBase>();
+            case LinearAnimationBase::quantizePropertyKey:
+                return object->is<LinearAnimationBase>();
+            case StateMachineBoolBase::valuePropertyKey:
+                return object->is<StateMachineBoolBase>();
+            case ShapePaintBase::isVisiblePropertyKey:
+                return object->is<ShapePaintBase>();
+            case StrokeBase::transformAffectsStrokePropertyKey:
+                return object->is<StrokeBase>();
+            case PointsPathBase::isClosedPropertyKey:
+                return object->is<PointsPathBase>();
+            case RectangleBase::linkCornerRadiusPropertyKey:
+                return object->is<RectangleBase>();
+            case ClippingShapeBase::isVisiblePropertyKey:
+                return object->is<ClippingShapeBase>();
+            case CustomPropertyBooleanBase::propertyValuePropertyKey:
+                return object->is<CustomPropertyBooleanBase>();
+            case LayoutComponentBase::clipPropertyKey:
+                return object->is<LayoutComponentBase>();
+            case TextModifierRangeBase::clampPropertyKey:
+                return object->is<TextModifierRangeBase>();
+            case ViewModelInstanceListItemBase::viewModelIdPropertyKey:
+                return object->is<ViewModelInstanceListItemBase>();
+            case ViewModelInstanceListItemBase::viewModelInstanceIdPropertyKey:
+                return object->is<ViewModelInstanceListItemBase>();
+            case ViewModelInstanceListItemBase::artboardIdPropertyKey:
+                return object->is<ViewModelInstanceListItemBase>();
+            case ViewModelInstanceValueBase::viewModelPropertyIdPropertyKey:
+                return object->is<ViewModelInstanceValueBase>();
+            case ViewModelInstanceEnumBase::propertyValuePropertyKey:
+                return object->is<ViewModelInstanceEnumBase>();
+            case ViewModelBase::defaultInstanceIdPropertyKey:
+                return object->is<ViewModelBase>();
+            case ViewModelPropertyViewModelBase::viewModelReferenceIdPropertyKey:
+                return object->is<ViewModelPropertyViewModelBase>();
             case ComponentBase::parentIdPropertyKey:
                 return object->is<ComponentBase>();
+            case ViewModelInstanceBase::viewModelIdPropertyKey:
+                return object->is<ViewModelInstanceBase>();
+            case ViewModelPropertyEnumBase::enumIdPropertyKey:
+                return object->is<ViewModelPropertyEnumBase>();
+            case ViewModelInstanceViewModelBase::propertyValuePropertyKey:
+                return object->is<ViewModelInstanceViewModelBase>();
             case DrawTargetBase::drawableIdPropertyKey:
                 return object->is<DrawTargetBase>();
             case DrawTargetBase::placementValuePropertyKey:
@@ -2424,6 +2670,8 @@
                 return object->is<LayoutComponentBase>();
             case ArtboardBase::defaultStateMachineIdPropertyKey:
                 return object->is<ArtboardBase>();
+            case ArtboardBase::viewModelIdPropertyKey:
+                return object->is<ArtboardBase>();
             case JoystickBase::xIdPropertyKey:
                 return object->is<JoystickBase>();
             case JoystickBase::yIdPropertyKey:
@@ -2434,6 +2682,12 @@
                 return object->is<JoystickBase>();
             case OpenUrlEventBase::targetValuePropertyKey:
                 return object->is<OpenUrlEventBase>();
+            case DataBindBase::targetIdPropertyKey:
+                return object->is<DataBindBase>();
+            case DataBindBase::propertyKeyPropertyKey:
+                return object->is<DataBindBase>();
+            case DataBindBase::modeValuePropertyKey:
+                return object->is<DataBindBase>();
             case WeightBase::valuesPropertyKey:
                 return object->is<WeightBase>();
             case WeightBase::indicesPropertyKey:
@@ -2482,6 +2736,42 @@
                 return object->is<FileAssetBase>();
             case AudioEventBase::assetIdPropertyKey:
                 return object->is<AudioEventBase>();
+            case ViewModelInstanceColorBase::propertyValuePropertyKey:
+                return object->is<ViewModelInstanceColorBase>();
+            case KeyFrameColorBase::valuePropertyKey:
+                return object->is<KeyFrameColorBase>();
+            case SolidColorBase::colorValuePropertyKey:
+                return object->is<SolidColorBase>();
+            case GradientStopBase::colorValuePropertyKey:
+                return object->is<GradientStopBase>();
+            case ViewModelComponentBase::namePropertyKey:
+                return object->is<ViewModelComponentBase>();
+            case ViewModelInstanceStringBase::propertyValuePropertyKey:
+                return object->is<ViewModelInstanceStringBase>();
+            case ComponentBase::namePropertyKey:
+                return object->is<ComponentBase>();
+            case DataEnumValueBase::keyPropertyKey:
+                return object->is<DataEnumValueBase>();
+            case DataEnumValueBase::valuePropertyKey:
+                return object->is<DataEnumValueBase>();
+            case AnimationBase::namePropertyKey:
+                return object->is<AnimationBase>();
+            case StateMachineComponentBase::namePropertyKey:
+                return object->is<StateMachineComponentBase>();
+            case KeyFrameStringBase::valuePropertyKey:
+                return object->is<KeyFrameStringBase>();
+            case OpenUrlEventBase::urlPropertyKey:
+                return object->is<OpenUrlEventBase>();
+            case TextValueRunBase::textPropertyKey:
+                return object->is<TextValueRunBase>();
+            case CustomPropertyStringBase::propertyValuePropertyKey:
+                return object->is<CustomPropertyStringBase>();
+            case AssetBase::namePropertyKey:
+                return object->is<AssetBase>();
+            case FileAssetBase::cdnBaseUrlPropertyKey:
+                return object->is<FileAssetBase>();
+            case ViewModelInstanceNumberBase::propertyValuePropertyKey:
+                return object->is<ViewModelInstanceNumberBase>();
             case CustomPropertyNumberBase::propertyValuePropertyKey:
                 return object->is<CustomPropertyNumberBase>();
             case ConstraintBase::strengthPropertyKey:
@@ -2800,66 +3090,10 @@
                 return object->is<DrawableAssetBase>();
             case ExportAudioBase::volumePropertyKey:
                 return object->is<ExportAudioBase>();
-            case TransformComponentConstraintBase::offsetPropertyKey:
-                return object->is<TransformComponentConstraintBase>();
-            case TransformComponentConstraintBase::doesCopyPropertyKey:
-                return object->is<TransformComponentConstraintBase>();
-            case TransformComponentConstraintBase::minPropertyKey:
-                return object->is<TransformComponentConstraintBase>();
-            case TransformComponentConstraintBase::maxPropertyKey:
-                return object->is<TransformComponentConstraintBase>();
-            case TransformComponentConstraintYBase::doesCopyYPropertyKey:
-                return object->is<TransformComponentConstraintYBase>();
-            case TransformComponentConstraintYBase::minYPropertyKey:
-                return object->is<TransformComponentConstraintYBase>();
-            case TransformComponentConstraintYBase::maxYPropertyKey:
-                return object->is<TransformComponentConstraintYBase>();
-            case IKConstraintBase::invertDirectionPropertyKey:
-                return object->is<IKConstraintBase>();
-            case FollowPathConstraintBase::orientPropertyKey:
-                return object->is<FollowPathConstraintBase>();
-            case FollowPathConstraintBase::offsetPropertyKey:
-                return object->is<FollowPathConstraintBase>();
-            case NestedSimpleAnimationBase::isPlayingPropertyKey:
-                return object->is<NestedSimpleAnimationBase>();
-            case KeyFrameBoolBase::valuePropertyKey:
-                return object->is<KeyFrameBoolBase>();
-            case ListenerAlignTargetBase::preserveOffsetPropertyKey:
-                return object->is<ListenerAlignTargetBase>();
-            case NestedBoolBase::nestedValuePropertyKey:
-                return object->is<NestedBoolBase>();
-            case LinearAnimationBase::enableWorkAreaPropertyKey:
-                return object->is<LinearAnimationBase>();
-            case LinearAnimationBase::quantizePropertyKey:
-                return object->is<LinearAnimationBase>();
-            case StateMachineBoolBase::valuePropertyKey:
-                return object->is<StateMachineBoolBase>();
-            case ShapePaintBase::isVisiblePropertyKey:
-                return object->is<ShapePaintBase>();
-            case StrokeBase::transformAffectsStrokePropertyKey:
-                return object->is<StrokeBase>();
-            case PointsPathBase::isClosedPropertyKey:
-                return object->is<PointsPathBase>();
-            case RectangleBase::linkCornerRadiusPropertyKey:
-                return object->is<RectangleBase>();
-            case ClippingShapeBase::isVisiblePropertyKey:
-                return object->is<ClippingShapeBase>();
-            case CustomPropertyBooleanBase::propertyValuePropertyKey:
-                return object->is<CustomPropertyBooleanBase>();
-            case LayoutComponentBase::clipPropertyKey:
-                return object->is<LayoutComponentBase>();
-            case TextModifierRangeBase::clampPropertyKey:
-                return object->is<TextModifierRangeBase>();
             case NestedTriggerBase::firePropertyKey:
                 return object->is<NestedTriggerBase>();
             case EventBase::triggerPropertyKey:
                 return object->is<EventBase>();
-            case KeyFrameColorBase::valuePropertyKey:
-                return object->is<KeyFrameColorBase>();
-            case SolidColorBase::colorValuePropertyKey:
-                return object->is<SolidColorBase>();
-            case GradientStopBase::colorValuePropertyKey:
-                return object->is<GradientStopBase>();
         }
         return false;
     }
diff --git a/include/rive/generated/data_bind/data_bind_base.hpp b/include/rive/generated/data_bind/data_bind_base.hpp
new file mode 100644
index 0000000..ed0d48d
--- /dev/null
+++ b/include/rive/generated/data_bind/data_bind_base.hpp
@@ -0,0 +1,107 @@
+#ifndef _RIVE_DATA_BIND_BASE_HPP_
+#define _RIVE_DATA_BIND_BASE_HPP_
+#include "rive/component.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class DataBindBase : public Component
+{
+protected:
+    typedef Component Super;
+
+public:
+    static const uint16_t typeKey = 446;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case DataBindBase::typeKey:
+            case ComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t targetIdPropertyKey = 585;
+    static const uint16_t propertyKeyPropertyKey = 586;
+    static const uint16_t modeValuePropertyKey = 587;
+
+private:
+    uint32_t m_TargetId = -1;
+    uint32_t m_PropertyKey = Core::invalidPropertyKey;
+    uint32_t m_ModeValue = 0;
+
+public:
+    inline uint32_t targetId() const { return m_TargetId; }
+    void targetId(uint32_t value)
+    {
+        if (m_TargetId == value)
+        {
+            return;
+        }
+        m_TargetId = value;
+        targetIdChanged();
+    }
+
+    inline uint32_t propertyKey() const { return m_PropertyKey; }
+    void propertyKey(uint32_t value)
+    {
+        if (m_PropertyKey == value)
+        {
+            return;
+        }
+        m_PropertyKey = value;
+        propertyKeyChanged();
+    }
+
+    inline uint32_t modeValue() const { return m_ModeValue; }
+    void modeValue(uint32_t value)
+    {
+        if (m_ModeValue == value)
+        {
+            return;
+        }
+        m_ModeValue = value;
+        modeValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const DataBindBase& object)
+    {
+        m_TargetId = object.m_TargetId;
+        m_PropertyKey = object.m_PropertyKey;
+        m_ModeValue = object.m_ModeValue;
+        Component::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case targetIdPropertyKey:
+                m_TargetId = CoreUintType::deserialize(reader);
+                return true;
+            case propertyKeyPropertyKey:
+                m_PropertyKey = CoreUintType::deserialize(reader);
+                return true;
+            case modeValuePropertyKey:
+                m_ModeValue = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return Component::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void targetIdChanged() {}
+    virtual void propertyKeyChanged() {}
+    virtual void modeValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/data_bind/data_bind_context_base.hpp b/include/rive/generated/data_bind/data_bind_context_base.hpp
new file mode 100644
index 0000000..d1871d4
--- /dev/null
+++ b/include/rive/generated/data_bind/data_bind_context_base.hpp
@@ -0,0 +1,62 @@
+#ifndef _RIVE_DATA_BIND_CONTEXT_BASE_HPP_
+#define _RIVE_DATA_BIND_CONTEXT_BASE_HPP_
+#include "rive/core/field_types/core_bytes_type.hpp"
+#include "rive/data_bind/data_bind.hpp"
+#include "rive/span.hpp"
+namespace rive
+{
+class DataBindContextBase : public DataBind
+{
+protected:
+    typedef DataBind Super;
+
+public:
+    static const uint16_t typeKey = 447;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case DataBindContextBase::typeKey:
+            case DataBindBase::typeKey:
+            case ComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t sourcePathIdsPropertyKey = 588;
+
+public:
+    virtual void decodeSourcePathIds(Span<const uint8_t> value) = 0;
+    virtual void copySourcePathIds(const DataBindContextBase& object) = 0;
+
+    Core* clone() const override;
+    void copy(const DataBindContextBase& object)
+    {
+        copySourcePathIds(object);
+        DataBind::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case sourcePathIdsPropertyKey:
+                decodeSourcePathIds(CoreBytesType::deserialize(reader));
+                return true;
+        }
+        return DataBind::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void sourcePathIdsChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/nested_artboard_base.hpp b/include/rive/generated/nested_artboard_base.hpp
index 141aa60..a115ba2 100644
--- a/include/rive/generated/nested_artboard_base.hpp
+++ b/include/rive/generated/nested_artboard_base.hpp
@@ -1,7 +1,9 @@
 #ifndef _RIVE_NESTED_ARTBOARD_BASE_HPP_
 #define _RIVE_NESTED_ARTBOARD_BASE_HPP_
+#include "rive/core/field_types/core_bytes_type.hpp"
 #include "rive/core/field_types/core_uint_type.hpp"
 #include "rive/drawable.hpp"
+#include "rive/span.hpp"
 namespace rive
 {
 class NestedArtboardBase : public Drawable
@@ -36,6 +38,7 @@
     static const uint16_t artboardIdPropertyKey = 197;
     static const uint16_t fitPropertyKey = 538;
     static const uint16_t alignmentPropertyKey = 539;
+    static const uint16_t dataBindPathIdsPropertyKey = 580;
 
 private:
     uint32_t m_ArtboardId = -1;
@@ -76,12 +79,16 @@
         alignmentChanged();
     }
 
+    virtual void decodeDataBindPathIds(Span<const uint8_t> value) = 0;
+    virtual void copyDataBindPathIds(const NestedArtboardBase& object) = 0;
+
     Core* clone() const override;
     void copy(const NestedArtboardBase& object)
     {
         m_ArtboardId = object.m_ArtboardId;
         m_Fit = object.m_Fit;
         m_Alignment = object.m_Alignment;
+        copyDataBindPathIds(object);
         Drawable::copy(object);
     }
 
@@ -98,6 +105,9 @@
             case alignmentPropertyKey:
                 m_Alignment = CoreUintType::deserialize(reader);
                 return true;
+            case dataBindPathIdsPropertyKey:
+                decodeDataBindPathIds(CoreBytesType::deserialize(reader));
+                return true;
         }
         return Drawable::deserialize(propertyKey, reader);
     }
@@ -106,6 +116,7 @@
     virtual void artboardIdChanged() {}
     virtual void fitChanged() {}
     virtual void alignmentChanged() {}
+    virtual void dataBindPathIdsChanged() {}
 };
 } // namespace rive
 
diff --git a/include/rive/generated/viewmodel/data_enum_base.hpp b/include/rive/generated/viewmodel/data_enum_base.hpp
new file mode 100644
index 0000000..dc5860d
--- /dev/null
+++ b/include/rive/generated/viewmodel/data_enum_base.hpp
@@ -0,0 +1,38 @@
+#ifndef _RIVE_DATA_ENUM_BASE_HPP_
+#define _RIVE_DATA_ENUM_BASE_HPP_
+#include "rive/core.hpp"
+namespace rive
+{
+class DataEnumBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 438;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case DataEnumBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    Core* clone() const override;
+    void copy(const DataEnumBase& 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/viewmodel/data_enum_value_base.hpp b/include/rive/generated/viewmodel/data_enum_value_base.hpp
new file mode 100644
index 0000000..53c89f9
--- /dev/null
+++ b/include/rive/generated/viewmodel/data_enum_value_base.hpp
@@ -0,0 +1,88 @@
+#ifndef _RIVE_DATA_ENUM_VALUE_BASE_HPP_
+#define _RIVE_DATA_ENUM_VALUE_BASE_HPP_
+#include <string>
+#include "rive/core.hpp"
+#include "rive/core/field_types/core_string_type.hpp"
+namespace rive
+{
+class DataEnumValueBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 445;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case DataEnumValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t keyPropertyKey = 578;
+    static const uint16_t valuePropertyKey = 579;
+
+private:
+    std::string m_Key = "";
+    std::string m_Value = "";
+
+public:
+    inline const std::string& key() const { return m_Key; }
+    void key(std::string value)
+    {
+        if (m_Key == value)
+        {
+            return;
+        }
+        m_Key = value;
+        keyChanged();
+    }
+
+    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 DataEnumValueBase& object)
+    {
+        m_Key = object.m_Key;
+        m_Value = object.m_Value;
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case keyPropertyKey:
+                m_Key = CoreStringType::deserialize(reader);
+                return true;
+            case valuePropertyKey:
+                m_Value = CoreStringType::deserialize(reader);
+                return true;
+        }
+        return false;
+    }
+
+protected:
+    virtual void keyChanged() {}
+    virtual void valueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_base.hpp b/include/rive/generated/viewmodel/viewmodel_base.hpp
new file mode 100644
index 0000000..e9f63b2
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_BASE_HPP_
+#define _RIVE_VIEW_MODEL_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/viewmodel/viewmodel_component.hpp"
+namespace rive
+{
+class ViewModelBase : public ViewModelComponent
+{
+protected:
+    typedef ViewModelComponent Super;
+
+public:
+    static const uint16_t typeKey = 435;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelBase::typeKey:
+            case ViewModelComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t defaultInstanceIdPropertyKey = 564;
+
+private:
+    uint32_t m_DefaultInstanceId = -1;
+
+public:
+    inline uint32_t defaultInstanceId() const { return m_DefaultInstanceId; }
+    void defaultInstanceId(uint32_t value)
+    {
+        if (m_DefaultInstanceId == value)
+        {
+            return;
+        }
+        m_DefaultInstanceId = value;
+        defaultInstanceIdChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelBase& object)
+    {
+        m_DefaultInstanceId = object.m_DefaultInstanceId;
+        ViewModelComponent::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case defaultInstanceIdPropertyKey:
+                m_DefaultInstanceId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return ViewModelComponent::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void defaultInstanceIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_component_base.hpp b/include/rive/generated/viewmodel/viewmodel_component_base.hpp
new file mode 100644
index 0000000..611ebb3
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_component_base.hpp
@@ -0,0 +1,67 @@
+#ifndef _RIVE_VIEW_MODEL_COMPONENT_BASE_HPP_
+#define _RIVE_VIEW_MODEL_COMPONENT_BASE_HPP_
+#include <string>
+#include "rive/core.hpp"
+#include "rive/core/field_types/core_string_type.hpp"
+namespace rive
+{
+class ViewModelComponentBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 429;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t namePropertyKey = 557;
+
+private:
+    std::string m_Name = "";
+
+public:
+    inline const std::string& name() const { return m_Name; }
+    void name(std::string value)
+    {
+        if (m_Name == value)
+        {
+            return;
+        }
+        m_Name = value;
+        nameChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelComponentBase& object) { m_Name = object.m_Name; }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case namePropertyKey:
+                m_Name = CoreStringType::deserialize(reader);
+                return true;
+        }
+        return false;
+    }
+
+protected:
+    virtual void nameChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_base.hpp
new file mode 100644
index 0000000..21f95aa
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_BASE_HPP_
+#include "rive/component.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class ViewModelInstanceBase : public Component
+{
+protected:
+    typedef Component Super;
+
+public:
+    static const uint16_t typeKey = 437;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceBase::typeKey:
+            case ComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t viewModelIdPropertyKey = 566;
+
+private:
+    uint32_t m_ViewModelId = 0;
+
+public:
+    inline uint32_t viewModelId() const { return m_ViewModelId; }
+    void viewModelId(uint32_t value)
+    {
+        if (m_ViewModelId == value)
+        {
+            return;
+        }
+        m_ViewModelId = value;
+        viewModelIdChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceBase& object)
+    {
+        m_ViewModelId = object.m_ViewModelId;
+        Component::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case viewModelIdPropertyKey:
+                m_ViewModelId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return Component::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void viewModelIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp
new file mode 100644
index 0000000..873f602
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_color_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_COLOR_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_COLOR_BASE_HPP_
+#include "rive/core/field_types/core_color_type.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceColorBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 426;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceColorBase::typeKey:
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 555;
+
+private:
+    int m_PropertyValue = 0xFF1D1D1D;
+
+public:
+    inline int propertyValue() const { return m_PropertyValue; }
+    void propertyValue(int value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceColorBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        ViewModelInstanceValue::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreColorType::deserialize(reader);
+                return true;
+        }
+        return ViewModelInstanceValue::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp
new file mode 100644
index 0000000..7d489b3
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_enum_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_ENUM_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_ENUM_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceEnumBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 432;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceEnumBase::typeKey:
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 560;
+
+private:
+    uint32_t m_PropertyValue = 0;
+
+public:
+    inline uint32_t propertyValue() const { return m_PropertyValue; }
+    void propertyValue(uint32_t value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceEnumBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        ViewModelInstanceValue::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return ViewModelInstanceValue::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp
new file mode 100644
index 0000000..7a30aeb
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_list_base.hpp
@@ -0,0 +1,36 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_LIST_BASE_HPP_
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceListBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 441;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceListBase::typeKey:
+            case ViewModelInstanceValueBase::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/viewmodel/viewmodel_instance_list_item_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp
new file mode 100644
index 0000000..4fedbf6
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp
@@ -0,0 +1,124 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_BASE_HPP_
+#include "rive/core.hpp"
+#include "rive/core/field_types/core_bool_type.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class ViewModelInstanceListItemBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 427;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceListItemBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t useLinkedArtboardPropertyKey = 547;
+    static const uint16_t viewModelIdPropertyKey = 549;
+    static const uint16_t viewModelInstanceIdPropertyKey = 550;
+    static const uint16_t artboardIdPropertyKey = 551;
+
+private:
+    bool m_UseLinkedArtboard = true;
+    uint32_t m_ViewModelId = -1;
+    uint32_t m_ViewModelInstanceId = -1;
+    uint32_t m_ArtboardId = -1;
+
+public:
+    inline bool useLinkedArtboard() const { return m_UseLinkedArtboard; }
+    void useLinkedArtboard(bool value)
+    {
+        if (m_UseLinkedArtboard == value)
+        {
+            return;
+        }
+        m_UseLinkedArtboard = value;
+        useLinkedArtboardChanged();
+    }
+
+    inline uint32_t viewModelId() const { return m_ViewModelId; }
+    void viewModelId(uint32_t value)
+    {
+        if (m_ViewModelId == value)
+        {
+            return;
+        }
+        m_ViewModelId = value;
+        viewModelIdChanged();
+    }
+
+    inline uint32_t viewModelInstanceId() const { return m_ViewModelInstanceId; }
+    void viewModelInstanceId(uint32_t value)
+    {
+        if (m_ViewModelInstanceId == value)
+        {
+            return;
+        }
+        m_ViewModelInstanceId = value;
+        viewModelInstanceIdChanged();
+    }
+
+    inline uint32_t artboardId() const { return m_ArtboardId; }
+    void artboardId(uint32_t value)
+    {
+        if (m_ArtboardId == value)
+        {
+            return;
+        }
+        m_ArtboardId = value;
+        artboardIdChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceListItemBase& object)
+    {
+        m_UseLinkedArtboard = object.m_UseLinkedArtboard;
+        m_ViewModelId = object.m_ViewModelId;
+        m_ViewModelInstanceId = object.m_ViewModelInstanceId;
+        m_ArtboardId = object.m_ArtboardId;
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case useLinkedArtboardPropertyKey:
+                m_UseLinkedArtboard = CoreBoolType::deserialize(reader);
+                return true;
+            case viewModelIdPropertyKey:
+                m_ViewModelId = CoreUintType::deserialize(reader);
+                return true;
+            case viewModelInstanceIdPropertyKey:
+                m_ViewModelInstanceId = CoreUintType::deserialize(reader);
+                return true;
+            case artboardIdPropertyKey:
+                m_ArtboardId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return false;
+    }
+
+protected:
+    virtual void useLinkedArtboardChanged() {}
+    virtual void viewModelIdChanged() {}
+    virtual void viewModelInstanceIdChanged() {}
+    virtual void artboardIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp
new file mode 100644
index 0000000..6df85d0
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_number_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_NUMBER_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_NUMBER_BASE_HPP_
+#include "rive/core/field_types/core_double_type.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceNumberBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 442;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceNumberBase::typeKey:
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 575;
+
+private:
+    float m_PropertyValue = 0.0f;
+
+public:
+    inline float propertyValue() const { return m_PropertyValue; }
+    void propertyValue(float value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceNumberBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        ViewModelInstanceValue::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreDoubleType::deserialize(reader);
+                return true;
+        }
+        return ViewModelInstanceValue::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp
new file mode 100644
index 0000000..538c833
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_string_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_STRING_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_STRING_BASE_HPP_
+#include <string>
+#include "rive/core/field_types/core_string_type.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceStringBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 433;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceStringBase::typeKey:
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 561;
+
+private:
+    std::string m_PropertyValue = "";
+
+public:
+    inline const std::string& propertyValue() const { return m_PropertyValue; }
+    void propertyValue(std::string value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceStringBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        ViewModelInstanceValue::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreStringType::deserialize(reader);
+                return true;
+        }
+        return ViewModelInstanceValue::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp
new file mode 100644
index 0000000..3bb08bd
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_value_base.hpp
@@ -0,0 +1,68 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_VALUE_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_VALUE_BASE_HPP_
+#include "rive/core.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive
+{
+class ViewModelInstanceValueBase : public Core
+{
+protected:
+    typedef Core Super;
+
+public:
+    static const uint16_t typeKey = 428;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t viewModelPropertyIdPropertyKey = 554;
+
+private:
+    uint32_t m_ViewModelPropertyId = 0;
+
+public:
+    inline uint32_t viewModelPropertyId() const { return m_ViewModelPropertyId; }
+    void viewModelPropertyId(uint32_t value)
+    {
+        if (m_ViewModelPropertyId == value)
+        {
+            return;
+        }
+        m_ViewModelPropertyId = value;
+        viewModelPropertyIdChanged();
+    }
+
+    void copy(const ViewModelInstanceValueBase& object)
+    {
+        m_ViewModelPropertyId = object.m_ViewModelPropertyId;
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case viewModelPropertyIdPropertyKey:
+                m_ViewModelPropertyId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return false;
+    }
+
+protected:
+    virtual void viewModelPropertyIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp b/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp
new file mode 100644
index 0000000..395569a
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp
@@ -0,0 +1,71 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_BASE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+namespace rive
+{
+class ViewModelInstanceViewModelBase : public ViewModelInstanceValue
+{
+protected:
+    typedef ViewModelInstanceValue Super;
+
+public:
+    static const uint16_t typeKey = 444;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelInstanceViewModelBase::typeKey:
+            case ViewModelInstanceValueBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t propertyValuePropertyKey = 577;
+
+private:
+    uint32_t m_PropertyValue = 0;
+
+public:
+    inline uint32_t propertyValue() const { return m_PropertyValue; }
+    void propertyValue(uint32_t value)
+    {
+        if (m_PropertyValue == value)
+        {
+            return;
+        }
+        m_PropertyValue = value;
+        propertyValueChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelInstanceViewModelBase& object)
+    {
+        m_PropertyValue = object.m_PropertyValue;
+        ViewModelInstanceValue::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case propertyValuePropertyKey:
+                m_PropertyValue = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return ViewModelInstanceValue::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void propertyValueChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_property_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_base.hpp
new file mode 100644
index 0000000..fd65087
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_base.hpp
@@ -0,0 +1,36 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_BASE_HPP_
+#include "rive/viewmodel/viewmodel_component.hpp"
+namespace rive
+{
+class ViewModelPropertyBase : public ViewModelComponent
+{
+protected:
+    typedef ViewModelComponent Super;
+
+public:
+    static const uint16_t typeKey = 430;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::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/viewmodel/viewmodel_property_color_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_color_base.hpp
new file mode 100644
index 0000000..a24b20f
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_color_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_COLOR_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_COLOR_BASE_HPP_
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyColorBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 440;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyColorBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::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/viewmodel/viewmodel_property_enum_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_enum_base.hpp
new file mode 100644
index 0000000..63bd198
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_enum_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyEnumBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 439;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyEnumBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t enumIdPropertyKey = 574;
+
+private:
+    uint32_t m_EnumId = -1;
+
+public:
+    inline uint32_t enumId() const { return m_EnumId; }
+    void enumId(uint32_t value)
+    {
+        if (m_EnumId == value)
+        {
+            return;
+        }
+        m_EnumId = value;
+        enumIdChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelPropertyEnumBase& object)
+    {
+        m_EnumId = object.m_EnumId;
+        ViewModelProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case enumIdPropertyKey:
+                m_EnumId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return ViewModelProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void enumIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp
new file mode 100644
index 0000000..0ced54b
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_list_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_LIST_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_LIST_BASE_HPP_
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyListBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 434;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyListBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::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/viewmodel/viewmodel_property_number_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_number_base.hpp
new file mode 100644
index 0000000..6b4055a
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_number_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_NUMBER_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_NUMBER_BASE_HPP_
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyNumberBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 431;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyNumberBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::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/viewmodel/viewmodel_property_string_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_string_base.hpp
new file mode 100644
index 0000000..49bd3aa
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_string_base.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_STRING_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_STRING_BASE_HPP_
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyStringBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 443;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyStringBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::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/viewmodel/viewmodel_property_viewmodel_base.hpp b/include/rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp
new file mode 100644
index 0000000..e79e25a
--- /dev/null
+++ b/include/rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp
@@ -0,0 +1,72 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_BASE_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_BASE_HPP_
+#include "rive/core/field_types/core_uint_type.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+namespace rive
+{
+class ViewModelPropertyViewModelBase : public ViewModelProperty
+{
+protected:
+    typedef ViewModelProperty Super;
+
+public:
+    static const uint16_t typeKey = 436;
+
+    /// Helper to quickly determine if a core object extends another without RTTI
+    /// at runtime.
+    bool isTypeOf(uint16_t typeKey) const override
+    {
+        switch (typeKey)
+        {
+            case ViewModelPropertyViewModelBase::typeKey:
+            case ViewModelPropertyBase::typeKey:
+            case ViewModelComponentBase::typeKey:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    uint16_t coreType() const override { return typeKey; }
+
+    static const uint16_t viewModelReferenceIdPropertyKey = 565;
+
+private:
+    uint32_t m_ViewModelReferenceId = 0;
+
+public:
+    inline uint32_t viewModelReferenceId() const { return m_ViewModelReferenceId; }
+    void viewModelReferenceId(uint32_t value)
+    {
+        if (m_ViewModelReferenceId == value)
+        {
+            return;
+        }
+        m_ViewModelReferenceId = value;
+        viewModelReferenceIdChanged();
+    }
+
+    Core* clone() const override;
+    void copy(const ViewModelPropertyViewModelBase& object)
+    {
+        m_ViewModelReferenceId = object.m_ViewModelReferenceId;
+        ViewModelProperty::copy(object);
+    }
+
+    bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+    {
+        switch (propertyKey)
+        {
+            case viewModelReferenceIdPropertyKey:
+                m_ViewModelReferenceId = CoreUintType::deserialize(reader);
+                return true;
+        }
+        return ViewModelProperty::deserialize(propertyKey, reader);
+    }
+
+protected:
+    virtual void viewModelReferenceIdChanged() {}
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/importers/enum_importer.hpp b/include/rive/importers/enum_importer.hpp
new file mode 100644
index 0000000..a79b1b6
--- /dev/null
+++ b/include/rive/importers/enum_importer.hpp
@@ -0,0 +1,23 @@
+#ifndef _RIVE_ENUM_IMPORTER_HPP_
+#define _RIVE_ENUM_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class Core;
+class DataEnum;
+class DataEnumValue;
+class EnumImporter : public ImportStackObject
+{
+private:
+    DataEnum* m_DataEnum;
+
+public:
+    EnumImporter(DataEnum* dataEnum);
+    void addValue(DataEnumValue* object);
+    StatusCode resolve() override;
+    const DataEnum* dataEnum() const { return m_DataEnum; }
+};
+} // namespace rive
+#endif
diff --git a/include/rive/importers/viewmodel_importer.hpp b/include/rive/importers/viewmodel_importer.hpp
new file mode 100644
index 0000000..8298c26
--- /dev/null
+++ b/include/rive/importers/viewmodel_importer.hpp
@@ -0,0 +1,24 @@
+#ifndef _RIVE_VIEWMODEL_IMPORTER_HPP_
+#define _RIVE_VIEWMODEL_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class ViewModel;
+class ViewModelProperty;
+class ViewModelInstance;
+
+class ViewModelImporter : public ImportStackObject
+{
+private:
+    ViewModel* m_ViewModel;
+
+public:
+    ViewModelImporter(ViewModel* viewModel);
+    void addProperty(ViewModelProperty* property);
+    void addInstance(ViewModelInstance* value);
+    StatusCode resolve() override;
+};
+} // namespace rive
+#endif
diff --git a/include/rive/importers/viewmodel_instance_importer.hpp b/include/rive/importers/viewmodel_instance_importer.hpp
new file mode 100644
index 0000000..d70c858
--- /dev/null
+++ b/include/rive/importers/viewmodel_instance_importer.hpp
@@ -0,0 +1,22 @@
+#ifndef _RIVE_VIEWMODEL_INSTANCE_IMPORTER_HPP_
+#define _RIVE_VIEWMODEL_INSTANCE_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class ViewModelInstance;
+class ViewModelInstanceValue;
+
+class ViewModelInstanceImporter : public ImportStackObject
+{
+private:
+    ViewModelInstance* m_ViewModelInstance;
+
+public:
+    ViewModelInstanceImporter(ViewModelInstance* viewModelInstance);
+    void addValue(ViewModelInstanceValue* value);
+    StatusCode resolve() override;
+};
+} // namespace rive
+#endif
diff --git a/include/rive/importers/viewmodel_instance_list_importer.hpp b/include/rive/importers/viewmodel_instance_list_importer.hpp
new file mode 100644
index 0000000..3833b2e
--- /dev/null
+++ b/include/rive/importers/viewmodel_instance_list_importer.hpp
@@ -0,0 +1,22 @@
+#ifndef _RIVE_VIEWMODEL_INSTANCE_LIST_IMPORTER_HPP_
+#define _RIVE_VIEWMODEL_INSTANCE_LIST_IMPORTER_HPP_
+
+#include "rive/importers/import_stack.hpp"
+
+namespace rive
+{
+class Core;
+class ViewModelInstanceList;
+class ViewModelInstanceListItem;
+class ViewModelInstanceListImporter : public ImportStackObject
+{
+private:
+    ViewModelInstanceList* m_ViewModelInstanceList;
+
+public:
+    ViewModelInstanceListImporter(ViewModelInstanceList* viewModelInstanceList);
+    void addItem(ViewModelInstanceListItem* listItem);
+    StatusCode resolve() override;
+};
+} // namespace rive
+#endif
diff --git a/include/rive/nested_artboard.hpp b/include/rive/nested_artboard.hpp
index 0c2ecd7..9f57ec4 100644
--- a/include/rive/nested_artboard.hpp
+++ b/include/rive/nested_artboard.hpp
@@ -48,6 +48,9 @@
     float m_layoutScaleX = NAN;
     float m_layoutScaleY = NAN;
 
+protected:
+    std::vector<uint32_t> m_DataBindPathIdsBuffer;
+
 public:
     NestedArtboard();
     ~NestedArtboard() override;
@@ -91,6 +94,9 @@
     /// nested within. Returns true when the conversion succeeds, and false
     /// when one is not possible.
     bool worldToLocal(Vec2D world, Vec2D* local);
+    void decodeDataBindPathIds(Span<const uint8_t> value) override;
+    void copyDataBindPathIds(const NestedArtboardBase& object) override;
+    std::vector<uint32_t> dataBindPathIds() { return m_DataBindPathIdsBuffer; };
 };
 } // namespace rive
 
diff --git a/include/rive/viewmodel/data_enum.hpp b/include/rive/viewmodel/data_enum.hpp
new file mode 100644
index 0000000..ed8addb
--- /dev/null
+++ b/include/rive/viewmodel/data_enum.hpp
@@ -0,0 +1,25 @@
+#ifndef _RIVE_DATA_ENUM_HPP_
+#define _RIVE_DATA_ENUM_HPP_
+#include "rive/generated/viewmodel/data_enum_base.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataEnum : public DataEnumBase
+{
+private:
+    std::vector<DataEnumValue*> m_Values;
+
+public:
+    void addValue(DataEnumValue* value);
+    std::vector<DataEnumValue*> values() { return m_Values; };
+    std::string value(std::string name);
+    std::string value(uint32_t index);
+    bool value(std::string name, std::string value);
+    bool value(uint32_t index, std::string value);
+    int valueIndex(std::string name);
+    int valueIndex(uint32_t index);
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/data_enum_value.hpp b/include/rive/viewmodel/data_enum_value.hpp
new file mode 100644
index 0000000..de64216
--- /dev/null
+++ b/include/rive/viewmodel/data_enum_value.hpp
@@ -0,0 +1,14 @@
+#ifndef _RIVE_DATA_ENUM_VALUE_HPP_
+#define _RIVE_DATA_ENUM_VALUE_HPP_
+#include "rive/generated/viewmodel/data_enum_value_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataEnumValue : public DataEnumValueBase
+{
+public:
+    StatusCode import(ImportStack& importStack) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel.hpp b/include/rive/viewmodel/viewmodel.hpp
new file mode 100644
index 0000000..2dbc600
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel.hpp
@@ -0,0 +1,26 @@
+#ifndef _RIVE_VIEW_MODEL_HPP_
+#define _RIVE_VIEW_MODEL_HPP_
+#include "rive/generated/viewmodel/viewmodel_base.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModel : public ViewModelBase
+{
+private:
+    std::vector<ViewModelProperty*> m_Properties;
+    std::vector<ViewModelInstance*> m_Instances;
+
+public:
+    void addProperty(ViewModelProperty* property);
+    ViewModelProperty* property(const std::string& name);
+    ViewModelProperty* property(size_t index);
+    void addInstance(ViewModelInstance* value);
+    ViewModelInstance* instance(size_t index);
+    ViewModelInstance* instance(const std::string& name);
+    ViewModelInstance* defaultInstance();
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_component.hpp b/include/rive/viewmodel/viewmodel_component.hpp
new file mode 100644
index 0000000..28354b4
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_component.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_COMPONENT_HPP_
+#define _RIVE_VIEW_MODEL_COMPONENT_HPP_
+#include "rive/generated/viewmodel/viewmodel_component_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelComponent : public ViewModelComponentBase
+{
+public:
+};
+} // 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
new file mode 100644
index 0000000..3115dc4
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance.hpp
@@ -0,0 +1,32 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/component.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModel;
+class ViewModelInstance : public ViewModelInstanceBase
+{
+private:
+    std::vector<ViewModelInstanceValue*> m_PropertyValues;
+    ViewModel* m_ViewModel;
+
+public:
+    void addValue(ViewModelInstanceValue* value);
+    ViewModelInstanceValue* propertyValue(const uint32_t id);
+    ViewModelInstanceValue* propertyValue(const std::string& name);
+    std::vector<ViewModelInstanceValue*> propertyValues();
+    void viewModel(ViewModel* value);
+    ViewModel* viewModel();
+    void onComponentDirty(Component* component);
+    void setAsRoot();
+    void setRoot(ViewModelInstance* value);
+    Core* clone() const override;
+    StatusCode import(ImportStack& importStack) override;
+    StatusCode onAddedDirty(CoreContext* context) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_color.hpp b/include/rive/viewmodel/viewmodel_instance_color.hpp
new file mode 100644
index 0000000..833ddbb
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_color.hpp
@@ -0,0 +1,14 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_COLOR_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_COLOR_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_color_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceColor : public ViewModelInstanceColorBase
+{
+public:
+    void propertyValueChanged() override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_enum.hpp b/include/rive/viewmodel/viewmodel_instance_enum.hpp
new file mode 100644
index 0000000..6980ae4
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_enum.hpp
@@ -0,0 +1,18 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_ENUM_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_ENUM_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_enum_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceEnum : public ViewModelInstanceEnumBase
+{
+public:
+    bool value(std::string name);
+    bool value(uint32_t index);
+
+protected:
+    void propertyValueChanged() override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_list.hpp b/include/rive/viewmodel/viewmodel_instance_list.hpp
new file mode 100644
index 0000000..8f1b934
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_list.hpp
@@ -0,0 +1,26 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_LIST_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_list_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceList : public ViewModelInstanceListBase
+{
+public:
+    void addItem(ViewModelInstanceListItem* listItem);
+    void insertItem(int index, ViewModelInstanceListItem* listItem);
+    void removeItem(int index);
+    void removeItem(ViewModelInstanceListItem* listItem);
+    std::vector<ViewModelInstanceListItem*> listItems() { return m_ListItems; };
+    ViewModelInstanceListItem* item(uint32_t index);
+    void swap(uint32_t index1, uint32_t index2);
+    Core* clone() const override;
+
+protected:
+    std::vector<ViewModelInstanceListItem*> m_ListItems;
+    void propertyValueChanged();
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_list_item.hpp b/include/rive/viewmodel/viewmodel_instance_list_item.hpp
new file mode 100644
index 0000000..d09ab72
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_list_item.hpp
@@ -0,0 +1,23 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_LIST_ITEM_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceListItem : public ViewModelInstanceListItemBase
+{
+private:
+    ViewModelInstance* m_viewModelInstance;
+    Artboard* m_artboard;
+
+public:
+    void viewModelInstance(ViewModelInstance* value) { m_viewModelInstance = value; };
+    ViewModelInstance* viewModelInstance() { return m_viewModelInstance; }
+    void artboard(Artboard* value) { m_artboard = value; };
+    Artboard* artboard() { return m_artboard; }
+    StatusCode import(ImportStack& importStack) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_number.hpp b/include/rive/viewmodel/viewmodel_instance_number.hpp
new file mode 100644
index 0000000..a5f40e9
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_number.hpp
@@ -0,0 +1,14 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_NUMBER_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_NUMBER_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_number_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceNumber : public ViewModelInstanceNumberBase
+{
+protected:
+    void propertyValueChanged() override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_string.hpp b/include/rive/viewmodel/viewmodel_instance_string.hpp
new file mode 100644
index 0000000..a7234e8
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_string.hpp
@@ -0,0 +1,14 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_STRING_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_STRING_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_string_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceString : public ViewModelInstanceStringBase
+{
+public:
+    void propertyValueChanged() override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_value.hpp b/include/rive/viewmodel/viewmodel_instance_value.hpp
new file mode 100644
index 0000000..7e3d5c7
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_value.hpp
@@ -0,0 +1,31 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_VALUE_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_VALUE_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_value_base.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/dependency_helper.hpp"
+#include "rive/component.hpp"
+#include "rive/component_dirt.hpp"
+#include <stdio.h>
+namespace rive
+{
+class DataBindContext;
+class ViewModelInstance;
+class ViewModelInstanceValue : public ViewModelInstanceValueBase
+{
+private:
+    ViewModelProperty* m_ViewModelProperty;
+
+protected:
+    DependencyHelper<ViewModelInstance, DataBindContext> m_DependencyHelper;
+    void addDirt(ComponentDirt value);
+
+public:
+    StatusCode import(ImportStack& importStack) override;
+    void viewModelProperty(ViewModelProperty* value);
+    ViewModelProperty* viewModelProperty();
+    void addDependent(DataBindContext* value);
+    virtual void setRoot(ViewModelInstance* value);
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp b/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp
new file mode 100644
index 0000000..d2ea9ab
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_instance_viewmodel.hpp
@@ -0,0 +1,23 @@
+#ifndef _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_HPP_
+#define _RIVE_VIEW_MODEL_INSTANCE_VIEW_MODEL_HPP_
+#include "rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelInstanceViewModel : public ViewModelInstanceViewModelBase
+{
+private:
+    ViewModelInstance* m_referenceViewModelInstance;
+
+public:
+    void referenceViewModelInstance(ViewModelInstance* value)
+    {
+        m_referenceViewModelInstance = value;
+    };
+    ViewModelInstance* referenceViewModelInstance() { return m_referenceViewModelInstance; }
+    void setRoot(ViewModelInstance* value) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property.hpp b/include/rive/viewmodel/viewmodel_property.hpp
new file mode 100644
index 0000000..87b3a25
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property.hpp
@@ -0,0 +1,14 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelProperty : public ViewModelPropertyBase
+{
+public:
+    StatusCode import(ImportStack& importStack) override;
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_color.hpp b/include/rive/viewmodel/viewmodel_property_color.hpp
new file mode 100644
index 0000000..ffc1191
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_color.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_COLOR_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_COLOR_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_color_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyColor : public ViewModelPropertyColorBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_enum.hpp b/include/rive/viewmodel/viewmodel_property_enum.hpp
new file mode 100644
index 0000000..41582e4
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_enum.hpp
@@ -0,0 +1,27 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_ENUM_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_ENUM_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_enum_base.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyEnum : public ViewModelPropertyEnumBase
+{
+
+public:
+    std::string value(std::string name);
+    std::string value(uint32_t index);
+    bool value(std::string name, std::string value);
+    bool value(uint32_t index, std::string value);
+    int valueIndex(std::string name);
+    int valueIndex(uint32_t index);
+    void dataEnum(DataEnum* value);
+    DataEnum* dataEnum();
+
+private:
+    DataEnum* m_DataEnum;
+};
+
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_list.hpp b/include/rive/viewmodel/viewmodel_property_list.hpp
new file mode 100644
index 0000000..a4fa054
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_list.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_LIST_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_LIST_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_list_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyList : public ViewModelPropertyListBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_number.hpp b/include/rive/viewmodel/viewmodel_property_number.hpp
new file mode 100644
index 0000000..0ba2468
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_number.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_NUMBER_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_NUMBER_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_number_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyNumber : public ViewModelPropertyNumberBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_string.hpp b/include/rive/viewmodel/viewmodel_property_string.hpp
new file mode 100644
index 0000000..0ff3745
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_string.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_STRING_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_STRING_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_string_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyString : public ViewModelPropertyStringBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/viewmodel/viewmodel_property_viewmodel.hpp b/include/rive/viewmodel/viewmodel_property_viewmodel.hpp
new file mode 100644
index 0000000..32ae213
--- /dev/null
+++ b/include/rive/viewmodel/viewmodel_property_viewmodel.hpp
@@ -0,0 +1,13 @@
+#ifndef _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_HPP_
+#define _RIVE_VIEW_MODEL_PROPERTY_VIEW_MODEL_HPP_
+#include "rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp"
+#include <stdio.h>
+namespace rive
+{
+class ViewModelPropertyViewModel : public ViewModelPropertyViewModelBase
+{
+public:
+};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 6b8e83d..6c0fe6a 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -2,6 +2,9 @@
 #include "rive/backboard.hpp"
 #include "rive/animation/linear_animation_instance.hpp"
 #include "rive/dependency_sorter.hpp"
+#include "rive/data_bind/data_bind.hpp"
+#include "rive/data_bind/data_bind_context.hpp"
+#include "rive/data_bind/data_bind_mode.hpp"
 #include "rive/draw_rules.hpp"
 #include "rive/draw_target.hpp"
 #include "rive/audio_event.hpp"
@@ -168,6 +171,9 @@
             case NestedArtboardBase::typeKey:
                 m_NestedArtboards.push_back(object->as<NestedArtboard>());
                 break;
+            case DataBindContext::typeKey:
+                m_DataBinds.push_back(object->as<DataBind>());
+                break;
 
             case JoystickBase::typeKey:
             {
@@ -468,6 +474,21 @@
     }
 }
 
+void Artboard::updateDataBinds()
+{
+    for (auto dataBind : m_AllDataBinds)
+    {
+        dataBind->updateSourceBinding();
+        auto d = dataBind->m_Dirt;
+        if (d == ComponentDirt::None)
+        {
+            continue;
+        }
+        dataBind->m_Dirt = ComponentDirt::None;
+        dataBind->update(d);
+    }
+}
+
 bool Artboard::updateComponents()
 {
     if (hasDirt(ComponentDirt::Components))
@@ -509,7 +530,7 @@
     return false;
 }
 
-bool Artboard::advance(double elapsedSeconds)
+bool Artboard::advanceInternal(double elapsedSeconds, bool isRoot)
 {
     m_HasChangedDrawOrderInLastUpdate = false;
 #ifdef WITH_RIVE_LAYOUT
@@ -539,7 +560,10 @@
             joystick->apply(this);
         }
     }
-
+    if (isRoot)
+    {
+        updateDataBinds();
+    }
     bool didUpdate = updateComponents();
     if (!m_JoysticksApplyBeforeUpdate)
     {
@@ -547,6 +571,10 @@
         {
             if (!joystick->canApplyBeforeUpdate())
             {
+                if (isRoot)
+                {
+                    updateDataBinds();
+                }
                 if (updateComponents())
                 {
                     didUpdate = true;
@@ -554,6 +582,10 @@
             }
             joystick->apply(this);
         }
+        if (isRoot)
+        {
+            updateDataBinds();
+        }
         if (updateComponents())
         {
             didUpdate = true;
@@ -569,6 +601,8 @@
     return didUpdate;
 }
 
+bool Artboard::advance(double elapsedSeconds) { return advanceInternal(elapsedSeconds, true); }
+
 Core* Artboard::hitTest(HitInfo* hinfo, const Mat2D* xform)
 {
     if (clip())
@@ -900,6 +934,112 @@
     return result;
 }
 
+void Artboard::internalDataContext(DataContext* value, DataContext* parent, bool isRoot)
+{
+    m_DataContext = value;
+    m_DataContext->parent(parent);
+    for (auto nestedArtboard : m_NestedArtboards)
+    {
+        if (nestedArtboard->artboard() == nullptr)
+        {
+            continue;
+        }
+        auto value = m_DataContext->getViewModelInstance(nestedArtboard->dataBindPathIds());
+        if (value != nullptr && value->is<ViewModelInstance>())
+        {
+            nestedArtboard->artboard()->dataContextFromInstance(value, m_DataContext, false);
+        }
+        else
+        {
+            nestedArtboard->artboard()->internalDataContext(m_DataContext,
+                                                            m_DataContext->parent(),
+                                                            false);
+        }
+    }
+    for (auto dataBind : m_DataBinds)
+    {
+        if (dataBind->is<DataBindContext>())
+        {
+            dataBind->as<DataBindContext>()->bindToContext();
+        }
+    }
+    if (isRoot)
+    {
+        std::vector<Component*> dataBinds;
+        populateDataBinds(&dataBinds);
+        buildDataBindDependencies(&dataBinds);
+        sortDataBinds(dataBinds);
+    }
+}
+
+void Artboard::sortDataBinds(std::vector<Component*> dataBinds)
+{
+    DependencySorter sorter;
+    // TODO: @hernan review this. Should not need to push to a component list to sort.
+
+    std::vector<Component*> dbOrder;
+    sorter.sort(dataBinds, dbOrder);
+    for (auto dataBind : dbOrder)
+    {
+        m_AllDataBinds.push_back(dataBind->as<DataBind>());
+    }
+}
+
+void Artboard::buildDataBindDependencies(std::vector<Component*>* dataBinds)
+{
+    // TODO: @hernan review this dependency building
+    // Do we really need this? If a property is bound to a data bind, it can't be bound
+    // to a second data bind object.
+    for (auto component : *dataBinds)
+    {
+        auto dataBind = component->as<DataBind>();
+        auto mode = static_cast<DataBindMode>(dataBind->modeValue());
+        // If the data bind reads from the target, we want to add it as dependent from any other
+        // data bind that writes into that target.
+        if (mode == DataBindMode::oneWayToSource || mode == DataBindMode::twoWay)
+        {
+            for (auto innerComponent : *dataBinds)
+            {
+                auto dataBindParent = innerComponent->as<DataBind>();
+                auto parentMode = static_cast<DataBindMode>(dataBind->modeValue());
+                if (dataBindParent != dataBind && (parentMode != DataBindMode::oneWayToSource) &&
+                    dataBindParent->target() == dataBind->target() &&
+                    dataBindParent->propertyKey() == dataBind->propertyKey())
+                {
+                    dataBindParent->addDependent(dataBind);
+                    break;
+                }
+            }
+        }
+        else
+        {
+            // If the data bind reads from a source we want to add it as dependent
+            // from any other data bind that writes into that source.
+            if (dataBind->is<DataBindContext>())
+            {
+                for (auto innerComponent : *dataBinds)
+                {
+                    auto dataBindChild = innerComponent->as<DataBind>();
+                    if (dataBindChild != dataBind)
+                    {
+                        auto childMode = static_cast<DataBindMode>(dataBind->modeValue());
+                        if (childMode == DataBindMode::oneWayToSource ||
+                            childMode == DataBindMode::twoWay)
+                        {
+                            if (dataBindChild->is<DataBindContext>() &&
+                                dataBindChild->as<DataBindContext>()->source() ==
+                                    dataBind->as<DataBindContext>()->source())
+                            {
+                                dataBind->addDependent(dataBindChild);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 float Artboard::volume() const { return m_volume; }
 void Artboard::volume(float value)
 {
@@ -914,6 +1054,51 @@
     }
 }
 
+void Artboard::populateDataBinds(std::vector<Component*>* dataBinds)
+{
+    for (auto dataBind : m_DataBinds)
+    {
+        dataBinds->push_back(dataBind);
+    }
+    for (auto nestedArtboard : m_NestedArtboards)
+    {
+        if (nestedArtboard->artboard() != nullptr)
+        {
+            nestedArtboard->artboard()->populateDataBinds(dataBinds);
+        }
+    }
+}
+
+void Artboard::dataContext(DataContext* value, DataContext* parent)
+{
+    internalDataContext(value, parent, true);
+}
+
+void Artboard::dataContextFromInstance(ViewModelInstance* viewModelInstance)
+{
+    dataContextFromInstance(viewModelInstance, nullptr, true);
+}
+
+void Artboard::dataContextFromInstance(ViewModelInstance* viewModelInstance, DataContext* parent)
+{
+    dataContextFromInstance(viewModelInstance, parent, true);
+}
+
+void Artboard::dataContextFromInstance(ViewModelInstance* viewModelInstance,
+                                       DataContext* parent,
+                                       bool isRoot)
+{
+    if (viewModelInstance == nullptr)
+    {
+        return;
+    }
+    if (isRoot)
+    {
+        viewModelInstance->setAsRoot();
+    }
+    internalDataContext(new DataContext(viewModelInstance), parent, isRoot);
+}
+
 ////////// ArtboardInstance
 
 #include "rive/animation/linear_animation_instance.hpp"
diff --git a/src/component.cpp b/src/component.cpp
index eaf7003..b7fa038 100644
--- a/src/component.cpp
+++ b/src/component.cpp
@@ -11,6 +11,7 @@
 StatusCode Component::onAddedDirty(CoreContext* context)
 {
     m_Artboard = static_cast<Artboard*>(context);
+    m_DependencyHelper.dependecyRoot(m_Artboard);
     if (this == m_Artboard)
     {
         // We're the artboard, don't parent to ourselves.
@@ -26,15 +27,7 @@
     return StatusCode::Ok;
 }
 
-void Component::addDependent(Component* component)
-{
-    // Make it's not already a dependent.
-    if (std::find(m_Dependents.begin(), m_Dependents.end(), component) != m_Dependents.end())
-    {
-        return;
-    }
-    m_Dependents.push_back(component);
-}
+void Component::addDependent(Component* component) { m_DependencyHelper.addDependent(component); }
 
 bool Component::addDirt(ComponentDirt value, bool recurse)
 {
@@ -49,17 +42,14 @@
 
     onDirty(m_Dirt);
 
-    m_Artboard->onComponentDirty(this);
+    m_DependencyHelper.onComponentDirty(this);
 
     if (!recurse)
     {
         return true;
     }
 
-    for (auto d : m_Dependents)
-    {
-        d->addDirt(value, true);
-    }
+    m_DependencyHelper.addDirt(value);
     return true;
 }
 
@@ -97,7 +87,7 @@
         m_Dirt &= ~ComponentDirt::Collapsed;
     }
     onDirty(m_Dirt);
-    m_Artboard->onComponentDirty(this);
+    m_DependencyHelper.onComponentDirty(this);
     return true;
 }
 
diff --git a/src/data_bind/context/context_value_color.cpp b/src/data_bind/context/context_value_color.cpp
new file mode 100644
index 0000000..18d392f
--- /dev/null
+++ b/src/data_bind/context/context_value_color.cpp
@@ -0,0 +1,26 @@
+#include "rive/data_bind/context/context_value_color.hpp"
+#include "rive/generated/core_registry.hpp"
+
+using namespace rive;
+
+DataBindContextValueColor::DataBindContextValueColor(ViewModelInstanceValue* value)
+{
+    m_Source = value;
+}
+
+void DataBindContextValueColor::apply(Component* target, uint32_t propertyKey)
+{
+    CoreRegistry::setColor(target,
+                           propertyKey,
+                           m_Source->as<ViewModelInstanceColor>()->propertyValue());
+}
+
+void DataBindContextValueColor::applyToSource(Component* target, uint32_t propertyKey)
+{
+    auto value = CoreRegistry::getColor(target, propertyKey);
+    if (m_Value != value)
+    {
+        m_Value = value;
+        m_Source->as<ViewModelInstanceColor>()->propertyValue(value);
+    }
+}
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_enum.cpp b/src/data_bind/context/context_value_enum.cpp
new file mode 100644
index 0000000..8569ce9
--- /dev/null
+++ b/src/data_bind/context/context_value_enum.cpp
@@ -0,0 +1,30 @@
+#include "rive/data_bind/context/context_value_enum.hpp"
+#include "rive/generated/core_registry.hpp"
+
+using namespace rive;
+
+DataBindContextValueEnum::DataBindContextValueEnum(ViewModelInstanceValue* value)
+{
+    m_Source = value;
+}
+
+void DataBindContextValueEnum::apply(Component* target, uint32_t propertyKey)
+{
+    auto enumSource = m_Source->as<ViewModelInstanceEnum>();
+    auto enumProperty = enumSource->viewModelProperty()->as<ViewModelPropertyEnum>();
+    auto enumValue = enumProperty->value(m_Source->as<ViewModelInstanceEnum>()->propertyValue());
+    CoreRegistry::setString(target, propertyKey, enumValue);
+}
+
+void DataBindContextValueEnum::applyToSource(Component* target, uint32_t propertyKey)
+{
+    auto value = CoreRegistry::getString(target, propertyKey);
+    auto enumSource = m_Source->as<ViewModelInstanceEnum>();
+    auto enumProperty = enumSource->viewModelProperty()->as<ViewModelPropertyEnum>();
+    auto valueIndex = enumProperty->valueIndex(value);
+    if (valueIndex != -1 && m_Value != valueIndex)
+    {
+        m_Value = valueIndex;
+        m_Source->as<ViewModelInstanceEnum>()->value(static_cast<uint32_t>(valueIndex));
+    }
+}
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_list.cpp b/src/data_bind/context/context_value_list.cpp
new file mode 100644
index 0000000..59f0f55
--- /dev/null
+++ b/src/data_bind/context/context_value_list.cpp
@@ -0,0 +1,133 @@
+#include "rive/data_bind/context/context_value_list.hpp"
+#include "rive/data_bind/context/context_value_list_item.hpp"
+#include "rive/generated/core_registry.hpp"
+#include "rive/node.hpp"
+
+using namespace rive;
+
+DataBindContextValueList::DataBindContextValueList(ViewModelInstanceValue* value)
+{
+    m_Source = value;
+}
+
+std::unique_ptr<ArtboardInstance> DataBindContextValueList::createArtboard(
+    Component* target,
+    Artboard* artboard,
+    ViewModelInstanceListItem* listItem) const
+{
+    if (artboard != nullptr)
+    {
+
+        auto mainArtboard = target->artboard();
+        auto dataContext = mainArtboard->dataContext();
+        auto artboardCopy = artboard->instance();
+        artboardCopy->advanceInternal(0.0f, false);
+        artboardCopy->dataContextFromInstance(listItem->viewModelInstance(), dataContext, false);
+        return artboardCopy;
+    }
+    return nullptr;
+}
+
+std::unique_ptr<StateMachineInstance> DataBindContextValueList::createStateMachineInstance(
+    ArtboardInstance* artboard)
+{
+    if (artboard != nullptr)
+    {
+        auto stateMachineInstance = artboard->stateMachineAt(0);
+        stateMachineInstance->advance(0.0f);
+        return stateMachineInstance;
+    }
+    return nullptr;
+}
+
+void DataBindContextValueList::insertItem(Component* target,
+                                          ViewModelInstanceListItem* listItem,
+                                          int index)
+{
+    auto artboard = listItem->artboard();
+    auto artboardCopy = createArtboard(target, artboard, listItem);
+    auto stateMachineInstance = createStateMachineInstance(artboardCopy.get());
+    std::unique_ptr<DataBindContextValueListItem> cacheListItem =
+        rivestd::make_unique<DataBindContextValueListItem>(std::move(artboardCopy),
+                                                           std::move(stateMachineInstance),
+                                                           listItem);
+    if (index == -1)
+    {
+        m_ListItemsCache.push_back(std::move(cacheListItem));
+    }
+    else
+    {
+        m_ListItemsCache.insert(m_ListItemsCache.begin() + index, std::move(cacheListItem));
+    }
+}
+
+void DataBindContextValueList::swapItems(Component* target, int index1, int index2)
+{
+    std::iter_swap(m_ListItemsCache.begin() + index1, m_ListItemsCache.begin() + index2);
+}
+
+void DataBindContextValueList::popItem(Component* target) { m_ListItemsCache.pop_back(); }
+
+void DataBindContextValueList::update(Component* target)
+{
+    if (target != nullptr)
+    {
+        auto sourceList = m_Source->as<ViewModelInstanceList>();
+        auto listItems = sourceList->listItems();
+
+        int listIndex = 0;
+        while (listIndex < listItems.size())
+        {
+            auto listItem = listItems[listIndex];
+            if (listIndex < m_ListItemsCache.size())
+            {
+                if (m_ListItemsCache[listIndex]->listItem() == listItem)
+                {
+                    // Same item in same position: do nothing
+                }
+                else
+                {
+                    int cacheIndex = listIndex + 1;
+                    bool found = false;
+                    while (cacheIndex < m_ListItemsCache.size())
+                    {
+                        if (m_ListItemsCache[cacheIndex]->listItem() == listItem)
+                        {
+                            // swap cache position with new item
+                            swapItems(target, listIndex, cacheIndex);
+                            found = true;
+                            break;
+                        }
+                        cacheIndex++;
+                    }
+                    if (!found)
+                    {
+                        // create new element and insert it in listIndex
+                        insertItem(target, listItem, listIndex);
+                    }
+                }
+            }
+            else
+            {
+                // create new element and cache the listItem in listIndex
+                insertItem(target, listItem, -1);
+            }
+
+            listIndex++;
+        }
+        // remove remaining cached elements backwars to pop from the vector.
+        listIndex = m_ListItemsCache.size() - 1;
+        while (listIndex >= listItems.size())
+        {
+            popItem(target);
+            listIndex--;
+        }
+    }
+}
+
+void DataBindContextValueList::apply(Component* target, uint32_t propertyKey) {}
+
+void DataBindContextValueList::applyToSource(Component* target, uint32_t propertyKey)
+{
+    // TODO: @hernan does applyToSource make sense? Should we block it somehow?
+}
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_list_item.cpp b/src/data_bind/context/context_value_list_item.cpp
new file mode 100644
index 0000000..07f1a0f
--- /dev/null
+++ b/src/data_bind/context/context_value_list_item.cpp
@@ -0,0 +1,11 @@
+#include "rive/data_bind/context/context_value_list_item.hpp"
+
+using namespace rive;
+
+DataBindContextValueListItem::DataBindContextValueListItem(
+    std::unique_ptr<ArtboardInstance> artboard,
+    std::unique_ptr<StateMachineInstance> stateMachine,
+    ViewModelInstanceListItem* listItem) :
+    m_Artboard(std::move(artboard)),
+    m_StateMachine(std::move(stateMachine)),
+    m_ListItem(listItem){};
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_number.cpp b/src/data_bind/context/context_value_number.cpp
new file mode 100644
index 0000000..ecc5b7f
--- /dev/null
+++ b/src/data_bind/context/context_value_number.cpp
@@ -0,0 +1,26 @@
+#include "rive/data_bind/context/context_value_number.hpp"
+#include "rive/generated/core_registry.hpp"
+
+using namespace rive;
+
+DataBindContextValueNumber::DataBindContextValueNumber(ViewModelInstanceValue* value)
+{
+    m_Source = value;
+}
+
+void DataBindContextValueNumber::apply(Component* target, uint32_t propertyKey)
+{
+    CoreRegistry::setDouble(target,
+                            propertyKey,
+                            m_Source->as<ViewModelInstanceNumber>()->propertyValue());
+}
+
+void DataBindContextValueNumber::applyToSource(Component* target, uint32_t propertyKey)
+{
+    auto value = CoreRegistry::getDouble(target, propertyKey);
+    if (m_Value != value)
+    {
+        m_Value = value;
+        m_Source->as<ViewModelInstanceNumber>()->propertyValue(value);
+    }
+}
\ No newline at end of file
diff --git a/src/data_bind/context/context_value_string.cpp b/src/data_bind/context/context_value_string.cpp
new file mode 100644
index 0000000..6a62e75
--- /dev/null
+++ b/src/data_bind/context/context_value_string.cpp
@@ -0,0 +1,26 @@
+#include "rive/data_bind/context/context_value_string.hpp"
+#include "rive/generated/core_registry.hpp"
+
+using namespace rive;
+
+DataBindContextValueString::DataBindContextValueString(ViewModelInstanceValue* value)
+{
+    m_Source = value;
+}
+
+void DataBindContextValueString::apply(Component* target, uint32_t propertyKey)
+{
+    CoreRegistry::setString(target,
+                            propertyKey,
+                            m_Source->as<ViewModelInstanceString>()->propertyValue());
+}
+
+void DataBindContextValueString::applyToSource(Component* target, uint32_t propertyKey)
+{
+    auto value = CoreRegistry::getString(target, propertyKey);
+    if (m_Value != value)
+    {
+        m_Value = value;
+        m_Source->as<ViewModelInstanceString>()->propertyValue(value);
+    }
+}
\ No newline at end of file
diff --git a/src/data_bind/data_bind.cpp b/src/data_bind/data_bind.cpp
new file mode 100644
index 0000000..4f59d89
--- /dev/null
+++ b/src/data_bind/data_bind.cpp
@@ -0,0 +1,43 @@
+#include "rive/data_bind/data_bind.hpp"
+#include "rive/data_bind/data_bind_mode.hpp"
+#include "rive/artboard.hpp"
+#include "rive/generated/core_registry.hpp"
+
+using namespace rive;
+
+// StatusCode DataBind::onAddedClean(CoreContext* context)
+// {
+//     return Super::onAddedClean(context);
+// }
+
+StatusCode DataBind::onAddedDirty(CoreContext* context)
+{
+    StatusCode code = Super::onAddedDirty(context);
+    if (code != StatusCode::Ok)
+    {
+        return code;
+    }
+    auto coreObject = context->resolve(targetId());
+    if (coreObject == nullptr || !coreObject->is<Component>())
+    {
+        return StatusCode::MissingObject;
+    }
+
+    m_target = static_cast<Component*>(coreObject);
+
+    return StatusCode::Ok;
+}
+
+StatusCode DataBind::import(ImportStack& importStack) { return Super::import(importStack); }
+
+void DataBind::buildDependencies()
+{
+    Super::buildDependencies();
+    auto mode = static_cast<DataBindMode>(modeValue());
+    if (mode == DataBindMode::oneWayToSource || mode == DataBindMode::twoWay)
+    {
+        m_target->addDependent(this);
+    }
+}
+
+void DataBind::updateSourceBinding() {}
\ No newline at end of file
diff --git a/src/data_bind/data_bind_context.cpp b/src/data_bind/data_bind_context.cpp
new file mode 100644
index 0000000..77194d4
--- /dev/null
+++ b/src/data_bind/data_bind_context.cpp
@@ -0,0 +1,100 @@
+#include "rive/data_bind/data_bind_context.hpp"
+#include "rive/data_bind/data_bind_mode.hpp"
+#include "rive/data_bind/context/context_value_number.hpp"
+#include "rive/data_bind/context/context_value_string.hpp"
+#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/artboard.hpp"
+#include "rive/generated/core_registry.hpp"
+#include <iostream>
+
+using namespace rive;
+
+void DataBindContext::decodeSourcePathIds(Span<const uint8_t> value)
+{
+    BinaryReader reader(value);
+    while (!reader.reachedEnd())
+    {
+        auto val = reader.readVarUintAs<uint32_t>();
+        m_SourcePathIdsBuffer.push_back(val);
+    }
+}
+
+void DataBindContext::copySourcePathIds(const DataBindContextBase& object)
+{
+    m_SourcePathIdsBuffer = object.as<DataBindContext>()->m_SourcePathIdsBuffer;
+}
+
+void DataBindContext::bindToContext()
+{
+    auto dataContext = artboard()->dataContext();
+    if (dataContext != nullptr)
+    {
+        auto value = dataContext->getViewModelProperty(m_SourcePathIdsBuffer);
+        if (value != nullptr)
+        {
+            value->addDependent(this);
+            m_Source = value;
+            if (m_Source->is<ViewModelInstanceNumber>())
+            {
+                m_ContextValue = rivestd::make_unique<DataBindContextValueNumber>(m_Source);
+            }
+            else if (m_Source->is<ViewModelInstanceString>())
+            {
+                m_ContextValue = rivestd::make_unique<DataBindContextValueString>(m_Source);
+            }
+            else if (m_Source->is<ViewModelInstanceEnum>())
+            {
+                m_ContextValue = rivestd::make_unique<DataBindContextValueEnum>(m_Source);
+            }
+            else if (m_Source->is<ViewModelInstanceList>())
+            {
+                m_ContextValue = rivestd::make_unique<DataBindContextValueList>(m_Source);
+                // TODO: @hernan decide the best place to initialize this
+                m_ContextValue->update(m_target);
+            }
+            else if (m_Source->is<ViewModelInstanceColor>())
+            {
+                m_ContextValue = rivestd::make_unique<DataBindContextValueColor>(m_Source);
+            }
+        }
+    }
+}
+
+void DataBindContext::update(ComponentDirt value)
+{
+    if (m_Source != nullptr && m_ContextValue != nullptr)
+    {
+
+        // Use the ComponentDirt::Components flag to indicate the viewmodel has added or removed
+        // an element to a list.
+        if ((value & ComponentDirt::Components) == ComponentDirt::Components)
+        {
+            m_ContextValue->update(m_target);
+        }
+        if ((value & ComponentDirt::Bindings) == ComponentDirt::Bindings)
+        {
+            // TODO: @hernan review how dirt and mode work together. If dirt is not set for
+            // certain modes, we might be able to skip the mode validation.
+            auto mode = static_cast<DataBindMode>(modeValue());
+            if (mode == DataBindMode::oneWay || mode == DataBindMode::twoWay)
+            {
+                m_ContextValue->apply(m_target, propertyKey());
+            }
+        }
+    }
+    Super::update(value);
+}
+
+void DataBindContext::updateSourceBinding()
+{
+    auto mode = static_cast<DataBindMode>(modeValue());
+    if (mode == DataBindMode::oneWayToSource || mode == DataBindMode::twoWay)
+    {
+        if (m_ContextValue != nullptr)
+        {
+            m_ContextValue->applyToSource(m_target, propertyKey());
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/data_bind/data_context.cpp b/src/data_bind/data_context.cpp
new file mode 100644
index 0000000..a8b3f30
--- /dev/null
+++ b/src/data_bind/data_context.cpp
@@ -0,0 +1,90 @@
+#include "rive/data_bind/data_context.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+
+using namespace rive;
+
+DataContext::DataContext(ViewModelInstance* viewModelInstance) :
+    m_ViewModelInstance(viewModelInstance)
+{}
+
+DataContext::DataContext() : m_ViewModelInstances({}) {}
+
+DataContext::~DataContext() {}
+
+void DataContext::addViewModelInstance(ViewModelInstance* value)
+{
+    m_ViewModelInstances.push_back(value);
+}
+
+void DataContext::viewModelInstance(ViewModelInstance* value) { m_ViewModelInstance = value; }
+
+ViewModelInstanceValue* DataContext::getViewModelProperty(const std::vector<uint32_t> path) const
+{
+    std::vector<uint32_t>::const_iterator it;
+    if (path.size() == 0)
+    {
+        return nullptr;
+    }
+    // TODO: @hernan review. We should probably remove the std::vector and only keep the instance
+    for (auto viewModel : m_ViewModelInstances)
+    {
+        if (viewModel->viewModelId() == path[0])
+        {
+            ViewModelInstance* instance = viewModel;
+            for (it = path.begin() + 1; it != path.end() - 1; it++)
+            {
+                instance = instance->propertyValue(*it)
+                               ->as<ViewModelInstanceViewModel>()
+                               ->referenceViewModelInstance();
+            }
+            ViewModelInstanceValue* value = instance->propertyValue(*it++);
+            return value;
+        }
+    }
+    if (m_ViewModelInstance != nullptr && m_ViewModelInstance->viewModelId() == path[0])
+    {
+        ViewModelInstance* instance = m_ViewModelInstance;
+        for (it = path.begin() + 1; it != path.end() - 1; it++)
+        {
+            instance = instance->propertyValue(*it)
+                           ->as<ViewModelInstanceViewModel>()
+                           ->referenceViewModelInstance();
+        }
+        ViewModelInstanceValue* value = instance->propertyValue(*it++);
+        return value;
+    }
+    if (m_Parent != nullptr)
+    {
+        return m_Parent->getViewModelProperty(path);
+    }
+    return nullptr;
+}
+
+ViewModelInstance* DataContext::getViewModelInstance(const std::vector<uint32_t> path) const
+{
+    std::vector<uint32_t>::const_iterator it;
+    if (path.size() == 0)
+    {
+        return nullptr;
+    }
+    if (m_ViewModelInstance != nullptr && m_ViewModelInstance->viewModelId() == path[0])
+    {
+        ViewModelInstance* instance = m_ViewModelInstance;
+        for (it = path.begin() + 1; it != path.end(); it++)
+        {
+            instance = instance->propertyValue(*it)
+                           ->as<ViewModelInstanceViewModel>()
+                           ->referenceViewModelInstance();
+            if (instance == nullptr)
+            {
+                return instance;
+            }
+        }
+        return instance;
+    }
+    if (m_Parent != nullptr)
+    {
+        return m_Parent->getViewModelInstance(path);
+    }
+    return nullptr;
+}
\ No newline at end of file
diff --git a/src/dependency_sorter.cpp b/src/dependency_sorter.cpp
index 1bf9f44..dcfa266 100644
--- a/src/dependency_sorter.cpp
+++ b/src/dependency_sorter.cpp
@@ -9,6 +9,15 @@
     visit(root, order);
 }
 
+void DependencySorter::sort(std::vector<Component*> roots, std::vector<Component*>& order)
+{
+    order.clear();
+    for (auto root : roots)
+    {
+        visit(root, order);
+    }
+}
+
 bool DependencySorter::visit(Component* component, std::vector<Component*>& order)
 {
     if (m_Perm.find(component) != m_Perm.end())
diff --git a/src/file.cpp b/src/file.cpp
index 1fc3fbb..93bdf04 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -8,6 +8,7 @@
 #include "rive/generated/core_registry.hpp"
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/importers/backboard_importer.hpp"
+#include "rive/importers/enum_importer.hpp"
 #include "rive/importers/file_asset_importer.hpp"
 #include "rive/importers/import_stack.hpp"
 #include "rive/importers/keyed_object_importer.hpp"
@@ -19,6 +20,9 @@
 #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/viewmodel_importer.hpp"
+#include "rive/importers/viewmodel_instance_importer.hpp"
+#include "rive/importers/viewmodel_instance_list_importer.hpp"
 #include "rive/animation/blend_state_transition.hpp"
 #include "rive/animation/any_state.hpp"
 #include "rive/animation/entry_state.hpp"
@@ -29,6 +33,18 @@
 #include "rive/assets/file_asset.hpp"
 #include "rive/assets/audio_asset.hpp"
 #include "rive/assets/file_asset_contents.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_instance_number.hpp"
+#include "rive/viewmodel/viewmodel_instance_string.hpp"
+#include "rive/viewmodel/viewmodel_property_viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_property_string.hpp"
+#include "rive/viewmodel/viewmodel_property_number.hpp"
+#include "rive/viewmodel/viewmodel_property_enum.hpp"
+#include "rive/viewmodel/viewmodel_property_list.hpp"
 
 // Default namespace for Rive Cpp code
 using namespace rive;
@@ -218,6 +234,24 @@
                     m_fileAssets.push_back(fa);
                 }
                 break;
+                case ViewModel::typeKey:
+                {
+                    auto vmc = object->as<ViewModel>();
+                    m_ViewModels.push_back(vmc);
+                    break;
+                }
+                case DataEnum::typeKey:
+                {
+                    auto de = object->as<DataEnum>();
+                    m_Enums.push_back(de);
+                    break;
+                }
+                case ViewModelPropertyEnum::typeKey:
+                {
+                    auto vme = object->as<ViewModelPropertyEnum>();
+                    vme->dataEnum(m_Enums[vme->enumId()]);
+                }
+                break;
             }
         }
         else
@@ -237,6 +271,9 @@
             case Artboard::typeKey:
                 stackObject = rivestd::make_unique<ArtboardImporter>(object->as<Artboard>());
                 break;
+            case DataEnum::typeKey:
+                stackObject = rivestd::make_unique<EnumImporter>(object->as<DataEnum>());
+                break;
             case LinearAnimation::typeKey:
                 stackObject =
                     rivestd::make_unique<LinearAnimationImporter>(object->as<LinearAnimation>());
@@ -302,6 +339,20 @@
                                                                       m_factory);
                 stackType = FileAsset::typeKey;
                 break;
+            case ViewModel::typeKey:
+                stackObject = rivestd::make_unique<ViewModelImporter>(object->as<ViewModel>());
+                stackType = ViewModel::typeKey;
+                break;
+            case ViewModelInstance::typeKey:
+                stackObject = rivestd::make_unique<ViewModelInstanceImporter>(
+                    object->as<ViewModelInstance>());
+                stackType = ViewModelInstance::typeKey;
+                break;
+            case ViewModelInstanceList::typeKey:
+                stackObject = rivestd::make_unique<ViewModelInstanceListImporter>(
+                    object->as<ViewModelInstanceList>());
+                stackType = ViewModelInstanceList::typeKey;
+                break;
         }
         if (importStack.makeLatest(stackType, std::move(stackObject)) != StatusCode::Ok)
         {
@@ -375,6 +426,148 @@
     return ab ? ab->instance() : nullptr;
 }
 
+void File::completeViewModelInstance(ViewModelInstance* viewModelInstance)
+{
+    auto viewModel = m_ViewModels[viewModelInstance->viewModelId()];
+    auto propertyValues = viewModelInstance->propertyValues();
+    for (auto value : propertyValues)
+    {
+        if (value->is<ViewModelInstanceViewModel>())
+        {
+            auto property = viewModel->property(value->viewModelPropertyId());
+            if (property->is<ViewModelPropertyViewModel>())
+            {
+                auto valueViewModel = value->as<ViewModelInstanceViewModel>();
+                auto propertViewModel = property->as<ViewModelPropertyViewModel>();
+                auto viewModelReference = m_ViewModels[propertViewModel->viewModelReferenceId()];
+                auto viewModelInstance =
+                    viewModelReference->instance(valueViewModel->propertyValue());
+                if (viewModelInstance != nullptr)
+                {
+                    valueViewModel->referenceViewModelInstance(
+                        copyViewModelInstance(viewModelInstance));
+                }
+            }
+        }
+        else if (value->is<ViewModelInstanceList>())
+        {
+            auto viewModelList = value->as<ViewModelInstanceList>();
+            for (auto listItem : viewModelList->listItems())
+            {
+                auto viewModel = m_ViewModels[listItem->viewModelId()];
+                auto viewModelInstance = viewModel->instance(listItem->viewModelInstanceId());
+                listItem->viewModelInstance(copyViewModelInstance(viewModelInstance));
+                if (listItem->artboardId() < m_artboards.size())
+                {
+                    listItem->artboard(m_artboards[listItem->artboardId()]);
+                }
+            }
+        }
+        value->viewModelProperty(viewModel->property(value->viewModelPropertyId()));
+    }
+}
+
+ViewModelInstance* File::copyViewModelInstance(ViewModelInstance* viewModelInstance)
+{
+    auto copy = viewModelInstance->clone()->as<ViewModelInstance>();
+    completeViewModelInstance(copy);
+    return copy;
+}
+
+ViewModelInstance* File::createViewModelInstance(std::string name)
+{
+    for (auto viewModel : m_ViewModels)
+    {
+        if (viewModel->is<ViewModel>())
+        {
+            if (viewModel->name() == name)
+            {
+                return createViewModelInstance(viewModel);
+            }
+        }
+    }
+    return nullptr;
+}
+
+ViewModelInstance* File::createViewModelInstance(std::string name, std::string instanceName)
+{
+    for (auto viewModel : m_ViewModels)
+    {
+        if (viewModel->is<ViewModel>())
+        {
+            if (viewModel->name() == name)
+            {
+                auto instance = viewModel->instance(instanceName);
+                if (instance != nullptr)
+                {
+                    return copyViewModelInstance(instance);
+                }
+            }
+        }
+    }
+    return nullptr;
+}
+
+ViewModelInstance* File::createViewModelInstance(ViewModel* viewModel)
+{
+    if (viewModel != nullptr)
+    {
+        auto viewModelInstance = viewModel->defaultInstance();
+        return copyViewModelInstance(viewModelInstance);
+    }
+    return nullptr;
+}
+
+ViewModelInstance* File::createViewModelInstance(Artboard* artboard)
+{
+    if ((size_t)artboard->viewModelId() < m_ViewModels.size())
+    {
+        auto viewModel = m_ViewModels[artboard->viewModelId()];
+        if (viewModel != nullptr)
+        {
+            return createViewModelInstance(viewModel);
+        }
+    }
+    return nullptr;
+}
+
+ViewModelInstanceListItem* File::viewModelInstanceListItem(ViewModelInstance* viewModelInstance)
+{
+    // Search for an implicit artboard linked to the viewModel.
+    // It will return the first one it finds, but there could be more.
+    // We should decide if we want to be more restrictive and only return
+    // an artboard if one and only one is found.
+    for (auto artboard : m_artboards)
+    {
+        if (artboard->viewModelId() == viewModelInstance->viewModelId())
+        {
+            return viewModelInstanceListItem(viewModelInstance, artboard);
+        }
+    }
+    return nullptr;
+}
+
+ViewModelInstanceListItem* File::viewModelInstanceListItem(ViewModelInstance* viewModelInstance,
+                                                           Artboard* artboard)
+{
+    auto viewModelInstanceListItem = new ViewModelInstanceListItem();
+    viewModelInstanceListItem->viewModelInstance(viewModelInstance);
+    viewModelInstanceListItem->artboard(artboard);
+    return viewModelInstanceListItem;
+}
+
+ViewModel* File::viewModel(std::string name)
+{
+    for (auto viewModel : m_ViewModels)
+    {
+        if (viewModel->name() == name)
+        {
+            return viewModel;
+        }
+    }
+    return nullptr;
+}
+
 const std::vector<FileAsset*>& File::assets() const { return m_fileAssets; }
 
 #ifdef WITH_RIVE_TOOLS
diff --git a/src/generated/data_bind/data_bind_base.cpp b/src/generated/data_bind/data_bind_base.cpp
new file mode 100644
index 0000000..cc993f8
--- /dev/null
+++ b/src/generated/data_bind/data_bind_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/data_bind_base.hpp"
+#include "rive/data_bind/data_bind.hpp"
+
+using namespace rive;
+
+Core* DataBindBase::clone() const
+{
+    auto cloned = new DataBind();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/data_bind/data_bind_context_base.cpp b/src/generated/data_bind/data_bind_context_base.cpp
new file mode 100644
index 0000000..4691f4c
--- /dev/null
+++ b/src/generated/data_bind/data_bind_context_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/data_bind/data_bind_context_base.hpp"
+#include "rive/data_bind/data_bind_context.hpp"
+
+using namespace rive;
+
+Core* DataBindContextBase::clone() const
+{
+    auto cloned = new DataBindContext();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/data_enum_base.cpp b/src/generated/viewmodel/data_enum_base.cpp
new file mode 100644
index 0000000..9ac0ef0
--- /dev/null
+++ b/src/generated/viewmodel/data_enum_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/data_enum_base.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+
+using namespace rive;
+
+Core* DataEnumBase::clone() const
+{
+    auto cloned = new DataEnum();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/data_enum_value_base.cpp b/src/generated/viewmodel/data_enum_value_base.cpp
new file mode 100644
index 0000000..f695edc
--- /dev/null
+++ b/src/generated/viewmodel/data_enum_value_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/data_enum_value_base.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+
+using namespace rive;
+
+Core* DataEnumValueBase::clone() const
+{
+    auto cloned = new DataEnumValue();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_base.cpp b/src/generated/viewmodel/viewmodel_base.cpp
new file mode 100644
index 0000000..87e7f7a
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_base.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+
+using namespace rive;
+
+Core* ViewModelBase::clone() const
+{
+    auto cloned = new ViewModel();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_component_base.cpp b/src/generated/viewmodel/viewmodel_component_base.cpp
new file mode 100644
index 0000000..706138b
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_component_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_component_base.hpp"
+#include "rive/viewmodel/viewmodel_component.hpp"
+
+using namespace rive;
+
+Core* ViewModelComponentBase::clone() const
+{
+    auto cloned = new ViewModelComponent();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_base.cpp b/src/generated/viewmodel/viewmodel_instance_base.cpp
new file mode 100644
index 0000000..892eba0
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_base.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceBase::clone() const
+{
+    auto cloned = new ViewModelInstance();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_color_base.cpp b/src/generated/viewmodel/viewmodel_instance_color_base.cpp
new file mode 100644
index 0000000..599a25d
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_color_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_color_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_color.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceColorBase::clone() const
+{
+    auto cloned = new ViewModelInstanceColor();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_enum_base.cpp b/src/generated/viewmodel/viewmodel_instance_enum_base.cpp
new file mode 100644
index 0000000..3937d48
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_enum_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_enum_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_enum.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceEnumBase::clone() const
+{
+    auto cloned = new ViewModelInstanceEnum();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_list_base.cpp b/src/generated/viewmodel/viewmodel_instance_list_base.cpp
new file mode 100644
index 0000000..b73c5a6
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_list_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_list_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceListBase::clone() const
+{
+    auto cloned = new ViewModelInstanceList();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_list_item_base.cpp b/src/generated/viewmodel/viewmodel_instance_list_item_base.cpp
new file mode 100644
index 0000000..b327aad
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_list_item_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_list_item_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceListItemBase::clone() const
+{
+    auto cloned = new ViewModelInstanceListItem();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_number_base.cpp b/src/generated/viewmodel/viewmodel_instance_number_base.cpp
new file mode 100644
index 0000000..6ac41a5
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_number_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_number_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_number.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceNumberBase::clone() const
+{
+    auto cloned = new ViewModelInstanceNumber();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_string_base.cpp b/src/generated/viewmodel/viewmodel_instance_string_base.cpp
new file mode 100644
index 0000000..ce48839
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_string_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_string_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_string.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceStringBase::clone() const
+{
+    auto cloned = new ViewModelInstanceString();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp b/src/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp
new file mode 100644
index 0000000..b0854a0
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_instance_viewmodel_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp"
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+
+using namespace rive;
+
+Core* ViewModelInstanceViewModelBase::clone() const
+{
+    auto cloned = new ViewModelInstanceViewModel();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_base.cpp b/src/generated/viewmodel/viewmodel_property_base.cpp
new file mode 100644
index 0000000..333ffa8
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_base.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyBase::clone() const
+{
+    auto cloned = new ViewModelProperty();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_color_base.cpp b/src/generated/viewmodel/viewmodel_property_color_base.cpp
new file mode 100644
index 0000000..6f3bf82
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_color_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_color_base.hpp"
+#include "rive/viewmodel/viewmodel_property_color.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyColorBase::clone() const
+{
+    auto cloned = new ViewModelPropertyColor();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_enum_base.cpp b/src/generated/viewmodel/viewmodel_property_enum_base.cpp
new file mode 100644
index 0000000..5f05b71
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_enum_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_enum_base.hpp"
+#include "rive/viewmodel/viewmodel_property_enum.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyEnumBase::clone() const
+{
+    auto cloned = new ViewModelPropertyEnum();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_list_base.cpp b/src/generated/viewmodel/viewmodel_property_list_base.cpp
new file mode 100644
index 0000000..d6a7e79
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_list_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_list_base.hpp"
+#include "rive/viewmodel/viewmodel_property_list.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyListBase::clone() const
+{
+    auto cloned = new ViewModelPropertyList();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_number_base.cpp b/src/generated/viewmodel/viewmodel_property_number_base.cpp
new file mode 100644
index 0000000..bf38820
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_number_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_number_base.hpp"
+#include "rive/viewmodel/viewmodel_property_number.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyNumberBase::clone() const
+{
+    auto cloned = new ViewModelPropertyNumber();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_string_base.cpp b/src/generated/viewmodel/viewmodel_property_string_base.cpp
new file mode 100644
index 0000000..5deac13
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_string_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_string_base.hpp"
+#include "rive/viewmodel/viewmodel_property_string.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyStringBase::clone() const
+{
+    auto cloned = new ViewModelPropertyString();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/viewmodel/viewmodel_property_viewmodel_base.cpp b/src/generated/viewmodel/viewmodel_property_viewmodel_base.cpp
new file mode 100644
index 0000000..5b57217
--- /dev/null
+++ b/src/generated/viewmodel/viewmodel_property_viewmodel_base.cpp
@@ -0,0 +1,11 @@
+#include "rive/generated/viewmodel/viewmodel_property_viewmodel_base.hpp"
+#include "rive/viewmodel/viewmodel_property_viewmodel.hpp"
+
+using namespace rive;
+
+Core* ViewModelPropertyViewModelBase::clone() const
+{
+    auto cloned = new ViewModelPropertyViewModel();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/importers/backboard_importer.cpp b/src/importers/backboard_importer.cpp
index 19eb762..286f133 100644
--- a/src/importers/backboard_importer.cpp
+++ b/src/importers/backboard_importer.cpp
@@ -1,8 +1,12 @@
 
 #include "rive/importers/backboard_importer.hpp"
+#include "rive/artboard.hpp"
 #include "rive/nested_artboard.hpp"
+#include "rive/backboard.hpp"
 #include "rive/assets/file_asset_referencer.hpp"
 #include "rive/assets/file_asset.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
 #include <unordered_set>
 
 using namespace rive;
@@ -59,7 +63,6 @@
 
 StatusCode BackboardImporter::resolve()
 {
-
     for (auto nestedArtboard : m_NestedArtboards)
     {
         auto itr = m_ArtboardLookup.find(nestedArtboard->artboardId());
@@ -84,4 +87,4 @@
     }
 
     return StatusCode::Ok;
-}
+}
\ No newline at end of file
diff --git a/src/importers/enum_importer.cpp b/src/importers/enum_importer.cpp
new file mode 100644
index 0000000..65d616a
--- /dev/null
+++ b/src/importers/enum_importer.cpp
@@ -0,0 +1,11 @@
+#include "rive/importers/enum_importer.hpp"
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+
+using namespace rive;
+
+EnumImporter::EnumImporter(DataEnum* dataEnum) : m_DataEnum(dataEnum) {}
+
+void EnumImporter::addValue(DataEnumValue* value) { m_DataEnum->addValue(value); }
+
+StatusCode EnumImporter::resolve() { return StatusCode::Ok; }
\ No newline at end of file
diff --git a/src/importers/viewmodel_importer.cpp b/src/importers/viewmodel_importer.cpp
new file mode 100644
index 0000000..d868d05
--- /dev/null
+++ b/src/importers/viewmodel_importer.cpp
@@ -0,0 +1,15 @@
+#include "rive/importers/viewmodel_importer.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+
+using namespace rive;
+
+ViewModelImporter::ViewModelImporter(ViewModel* viewModel) : m_ViewModel(viewModel) {}
+void ViewModelImporter::addProperty(ViewModelProperty* property)
+{
+    m_ViewModel->addProperty(property);
+}
+void ViewModelImporter::addInstance(ViewModelInstance* value) { m_ViewModel->addInstance(value); }
+
+StatusCode ViewModelImporter::resolve() { return StatusCode::Ok; }
\ No newline at end of file
diff --git a/src/importers/viewmodel_instance_importer.cpp b/src/importers/viewmodel_instance_importer.cpp
new file mode 100644
index 0000000..c4642fc
--- /dev/null
+++ b/src/importers/viewmodel_instance_importer.cpp
@@ -0,0 +1,15 @@
+#include "rive/importers/viewmodel_instance_importer.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+
+using namespace rive;
+
+ViewModelInstanceImporter::ViewModelInstanceImporter(ViewModelInstance* viewModelInstance) :
+    m_ViewModelInstance(viewModelInstance)
+{}
+void ViewModelInstanceImporter::addValue(ViewModelInstanceValue* value)
+{
+    m_ViewModelInstance->addValue(value);
+}
+
+StatusCode ViewModelInstanceImporter::resolve() { return StatusCode::Ok; }
\ No newline at end of file
diff --git a/src/importers/viewmodel_instance_list_importer.cpp b/src/importers/viewmodel_instance_list_importer.cpp
new file mode 100644
index 0000000..2edf062
--- /dev/null
+++ b/src/importers/viewmodel_instance_list_importer.cpp
@@ -0,0 +1,16 @@
+#include "rive/importers/viewmodel_instance_list_importer.hpp"
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+
+using namespace rive;
+
+ViewModelInstanceListImporter::ViewModelInstanceListImporter(
+    ViewModelInstanceList* viewModelInstanceList) :
+    m_ViewModelInstanceList(viewModelInstanceList)
+{}
+void ViewModelInstanceListImporter::addItem(ViewModelInstanceListItem* listItem)
+{
+    m_ViewModelInstanceList->addItem(listItem);
+}
+
+StatusCode ViewModelInstanceListImporter::resolve() { return StatusCode::Ok; }
\ No newline at end of file
diff --git a/src/nested_artboard.cpp b/src/nested_artboard.cpp
index e59b9e9..6ef8cf3 100644
--- a/src/nested_artboard.cpp
+++ b/src/nested_artboard.cpp
@@ -45,7 +45,7 @@
     {
         m_Instance.reset(static_cast<ArtboardInstance*>(artboard)); // take ownership
     }
-    m_Artboard->advance(0.0f);
+    m_Artboard->advanceInternal(0.0f, false);
 }
 
 static Mat2D makeTranslate(const Artboard* artboard)
@@ -139,7 +139,7 @@
     {
         keepGoing = animation->advance(elapsedSeconds) || keepGoing;
     }
-    return m_Artboard->advance(elapsedSeconds) || keepGoing;
+    return m_Artboard->advanceInternal(elapsedSeconds, false) || keepGoing;
 }
 
 void NestedArtboard::update(ComponentDirt value)
@@ -258,4 +258,19 @@
         scaleY(newScaleY);
         addDirt(ComponentDirt::WorldTransform, false);
     }
+}
+
+void NestedArtboard::decodeDataBindPathIds(Span<const uint8_t> value)
+{
+    BinaryReader reader(value);
+    while (!reader.reachedEnd())
+    {
+        auto val = reader.readVarUintAs<uint32_t>();
+        m_DataBindPathIdsBuffer.push_back(val);
+    }
+}
+
+void NestedArtboard::copyDataBindPathIds(const NestedArtboardBase& object)
+{
+    m_DataBindPathIdsBuffer = object.as<NestedArtboard>()->m_DataBindPathIdsBuffer;
 }
\ No newline at end of file
diff --git a/src/viewmodel/data_enum.cpp b/src/viewmodel/data_enum.cpp
new file mode 100644
index 0000000..a1780cb
--- /dev/null
+++ b/src/viewmodel/data_enum.cpp
@@ -0,0 +1,80 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/backboard.hpp"
+#include "rive/importers/backboard_importer.hpp"
+
+using namespace rive;
+
+void DataEnum::addValue(DataEnumValue* value) { m_Values.push_back(value); }
+
+std::string DataEnum::value(std::string key)
+{
+    for (auto enumValue : m_Values)
+    {
+        if (enumValue->key() == key)
+        {
+            return enumValue->value();
+        };
+    }
+    return "";
+}
+
+std::string DataEnum::value(uint32_t index)
+{
+    if (index < m_Values.size())
+    {
+        return m_Values[index]->value();
+    }
+    return "";
+}
+
+bool DataEnum::value(std::string key, std::string value)
+{
+    for (auto enumValue : m_Values)
+    {
+        if (enumValue->key() == key)
+        {
+            enumValue->value(value);
+            return true;
+        };
+    }
+    return false;
+}
+
+bool DataEnum::value(uint32_t index, std::string value)
+{
+    if (index < m_Values.size())
+    {
+        m_Values[index]->value(value);
+        return true;
+    }
+    return false;
+}
+
+int DataEnum::valueIndex(std::string key)
+{
+    int index = 0;
+    for (auto enumValue : m_Values)
+    {
+        if (enumValue->key() == key)
+        {
+            return index;
+        };
+        index++;
+    }
+    return -1;
+}
+
+int DataEnum::valueIndex(uint32_t index)
+{
+    if (index < m_Values.size())
+    {
+        return index;
+    }
+    return -1;
+}
\ No newline at end of file
diff --git a/src/viewmodel/data_enum_value.cpp b/src/viewmodel/data_enum_value.cpp
new file mode 100644
index 0000000..e5a2e90
--- /dev/null
+++ b/src/viewmodel/data_enum_value.cpp
@@ -0,0 +1,21 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/data_enum.hpp"
+#include "rive/viewmodel/data_enum_value.hpp"
+#include "rive/importers/enum_importer.hpp"
+
+using namespace rive;
+
+StatusCode DataEnumValue::import(ImportStack& importStack)
+{
+    auto enumImporter = importStack.latest<EnumImporter>(DataEnum::typeKey);
+    if (enumImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+
+    enumImporter->addValue(this);
+    return Super::import(importStack);
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel.cpp b/src/viewmodel/viewmodel.cpp
new file mode 100644
index 0000000..7e764b9
--- /dev/null
+++ b/src/viewmodel/viewmodel.cpp
@@ -0,0 +1,58 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/backboard.hpp"
+#include "rive/importers/backboard_importer.hpp"
+
+using namespace rive;
+
+void ViewModel::addProperty(ViewModelProperty* property) { m_Properties.push_back(property); }
+
+ViewModelProperty* ViewModel::property(size_t index)
+{
+    if (index < m_Properties.size())
+    {
+        return m_Properties[index];
+    }
+    return nullptr;
+}
+
+ViewModelProperty* ViewModel::property(const std::string& name)
+{
+    for (auto property : m_Properties)
+    {
+        if (property->name() == name)
+        {
+            return property;
+        }
+    }
+    return nullptr;
+}
+
+void ViewModel::addInstance(ViewModelInstance* value) { m_Instances.push_back(value); }
+
+ViewModelInstance* ViewModel::defaultInstance() { return m_Instances[defaultInstanceId()]; }
+
+ViewModelInstance* ViewModel::instance(size_t index)
+{
+    if (index < m_Instances.size())
+    {
+        return m_Instances[index];
+    }
+    return nullptr;
+}
+
+ViewModelInstance* ViewModel::instance(const std::string& name)
+{
+    for (auto instance : m_Instances)
+    {
+        if (instance->name() == name)
+        {
+            return instance;
+        }
+    }
+    return nullptr;
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance.cpp b/src/viewmodel/viewmodel_instance.cpp
new file mode 100644
index 0000000..bac6882
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance.cpp
@@ -0,0 +1,105 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/importers/viewmodel_importer.hpp"
+#include "rive/core_context.hpp"
+
+using namespace rive;
+
+void ViewModelInstance::addValue(ViewModelInstanceValue* value)
+{
+    m_PropertyValues.push_back(value);
+}
+
+StatusCode ViewModelInstance::onAddedDirty(CoreContext* context)
+{
+    StatusCode result = Super::onAddedDirty(context);
+    if (result != StatusCode::Ok)
+    {
+        return result;
+    }
+    auto coreObject = context->resolve(viewModelId());
+    if (coreObject != nullptr && coreObject->is<ViewModel>())
+    {
+        m_ViewModel = static_cast<ViewModel*>(coreObject);
+    }
+
+    return StatusCode::Ok;
+}
+
+ViewModelInstanceValue* ViewModelInstance::propertyValue(const uint32_t id)
+{
+    for (auto value : m_PropertyValues)
+    {
+        if (value->viewModelPropertyId() == id)
+        {
+            return value;
+        }
+    }
+    return nullptr;
+}
+
+ViewModelInstanceValue* ViewModelInstance::propertyValue(const std::string& name)
+{
+    auto viewModelProperty = viewModel()->property(name);
+    if (viewModelProperty != nullptr)
+    {
+        for (auto value : m_PropertyValues)
+        {
+            if (value->viewModelProperty() == viewModelProperty)
+            {
+                return value;
+            }
+        }
+    }
+    return nullptr;
+}
+
+void ViewModelInstance::viewModel(ViewModel* value) { m_ViewModel = value; }
+
+ViewModel* ViewModelInstance::viewModel() { return m_ViewModel; }
+
+void ViewModelInstance::onComponentDirty(Component* component) {}
+
+void ViewModelInstance::setAsRoot() { setRoot(this); }
+
+void ViewModelInstance::setRoot(ViewModelInstance* value)
+{
+    for (auto propertyValue : m_PropertyValues)
+    {
+        propertyValue->setRoot(value);
+    }
+}
+
+std::vector<ViewModelInstanceValue*> ViewModelInstance::propertyValues()
+{
+    return m_PropertyValues;
+}
+
+Core* ViewModelInstance::clone() const
+{
+    auto cloned = new ViewModelInstance();
+    cloned->copy(*this);
+    for (auto propertyValue : m_PropertyValues)
+    {
+        auto clonedValue = propertyValue->clone()->as<ViewModelInstanceValue>();
+        cloned->addValue(clonedValue);
+    }
+    return cloned;
+}
+
+StatusCode ViewModelInstance::import(ImportStack& importStack)
+{
+    auto viewModelImporter = importStack.latest<ViewModelImporter>(ViewModel::typeKey);
+    if (viewModelImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+
+    viewModelImporter->addInstance(this);
+    return StatusCode::Ok;
+}
diff --git a/src/viewmodel/viewmodel_instance_color.cpp b/src/viewmodel/viewmodel_instance_color.cpp
new file mode 100644
index 0000000..9cd82bd
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_color.cpp
@@ -0,0 +1,10 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_color.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceColor::propertyValueChanged() { addDirt(ComponentDirt::Bindings); }
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_enum.cpp b/src/viewmodel/viewmodel_instance_enum.cpp
new file mode 100644
index 0000000..0cdbc60
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_enum.cpp
@@ -0,0 +1,34 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_enum.hpp"
+#include "rive/viewmodel/viewmodel_property_enum.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceEnum::propertyValueChanged() { addDirt(ComponentDirt::Components); }
+
+bool ViewModelInstanceEnum::value(std::string name)
+{
+    auto enumProperty = viewModelProperty()->as<ViewModelPropertyEnum>();
+    int index = enumProperty->valueIndex(name);
+    if (index != -1)
+    {
+        propertyValue(index);
+        return true;
+    }
+    return false;
+}
+
+bool ViewModelInstanceEnum::value(uint32_t index)
+{
+    auto enumProperty = viewModelProperty()->as<ViewModelPropertyEnum>();
+    if (enumProperty->valueIndex(index) != -1)
+    {
+        propertyValue(index);
+        return true;
+    }
+    return false;
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_list.cpp b/src/viewmodel/viewmodel_instance_list.cpp
new file mode 100644
index 0000000..0ac9f5a
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_list.cpp
@@ -0,0 +1,74 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceList::propertyValueChanged() { addDirt(ComponentDirt::Components); }
+
+void ViewModelInstanceList::addItem(ViewModelInstanceListItem* item)
+{
+    m_ListItems.push_back(item);
+    propertyValueChanged();
+}
+
+void ViewModelInstanceList::insertItem(int index, ViewModelInstanceListItem* item)
+{
+    // TODO: @hernan decide if we want to return a boolean
+    if (index < m_ListItems.size())
+    {
+        m_ListItems.insert(m_ListItems.begin() + index, item);
+        propertyValueChanged();
+    }
+}
+
+void ViewModelInstanceList::removeItem(int index)
+{
+    // TODO: @hernan decide if we want to return a boolean
+    if (index < m_ListItems.size())
+    {
+        m_ListItems.erase(m_ListItems.begin() + index);
+        propertyValueChanged();
+    }
+}
+
+void ViewModelInstanceList::removeItem(ViewModelInstanceListItem* listItem)
+{
+    auto noSpaceEnd = std::remove(m_ListItems.begin(), m_ListItems.end(), listItem);
+    m_ListItems.erase(noSpaceEnd, m_ListItems.end());
+    propertyValueChanged();
+}
+
+ViewModelInstanceListItem* ViewModelInstanceList::item(uint32_t index)
+{
+    if (index < m_ListItems.size())
+    {
+        return m_ListItems[index];
+    }
+    return nullptr;
+}
+
+void ViewModelInstanceList::swap(uint32_t index1, uint32_t index2)
+{
+    if (index1 < m_ListItems.size() && index2 < m_ListItems.size())
+    {
+        std::iter_swap(m_ListItems.begin() + index1, m_ListItems.begin() + index2);
+        propertyValueChanged();
+    }
+}
+
+Core* ViewModelInstanceList::clone() const
+{
+    auto cloned = new ViewModelInstanceList();
+    cloned->copy(*this);
+    for (auto property : m_ListItems)
+    {
+        auto clonedValue = property->clone()->as<ViewModelInstanceListItem>();
+        cloned->addItem(clonedValue);
+    }
+    return cloned;
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_list_item.cpp b/src/viewmodel/viewmodel_instance_list_item.cpp
new file mode 100644
index 0000000..a723c6c
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_list_item.cpp
@@ -0,0 +1,22 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_list.hpp"
+#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
+#include "rive/importers/viewmodel_instance_list_importer.hpp"
+
+using namespace rive;
+
+StatusCode ViewModelInstanceListItem::import(ImportStack& importStack)
+{
+    auto viewModelInstanceList =
+        importStack.latest<ViewModelInstanceListImporter>(ViewModelInstanceList::typeKey);
+    if (viewModelInstanceList == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    viewModelInstanceList->addItem(this);
+
+    return Super::import(importStack);
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_number.cpp b/src/viewmodel/viewmodel_instance_number.cpp
new file mode 100644
index 0000000..6e2620a
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_number.cpp
@@ -0,0 +1,10 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_number.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceNumber::propertyValueChanged() { addDirt(ComponentDirt::Bindings); }
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_string.cpp b/src/viewmodel/viewmodel_instance_string.cpp
new file mode 100644
index 0000000..6c60d4b
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_string.cpp
@@ -0,0 +1,10 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_string.hpp"
+#include "rive/component_dirt.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceString::propertyValueChanged() { addDirt(ComponentDirt::Bindings); }
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_value.cpp b/src/viewmodel/viewmodel_instance_value.cpp
new file mode 100644
index 0000000..2e4fac2
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_value.cpp
@@ -0,0 +1,41 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance.hpp"
+#include "rive/viewmodel/viewmodel_instance_value.hpp"
+#include "rive/importers/viewmodel_instance_importer.hpp"
+#include "rive/data_bind/data_bind_context.hpp"
+
+using namespace rive;
+
+StatusCode ViewModelInstanceValue::import(ImportStack& importStack)
+{
+    auto viewModelInstanceImporter =
+        importStack.latest<ViewModelInstanceImporter>(ViewModelInstance::typeKey);
+    if (viewModelInstanceImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+    viewModelInstanceImporter->addValue(this);
+
+    return Super::import(importStack);
+}
+
+void ViewModelInstanceValue::viewModelProperty(ViewModelProperty* value)
+{
+    m_ViewModelProperty = value;
+}
+ViewModelProperty* ViewModelInstanceValue::viewModelProperty() { return m_ViewModelProperty; }
+
+void ViewModelInstanceValue::addDependent(DataBindContext* value)
+{
+    m_DependencyHelper.addDependent(value);
+}
+
+void ViewModelInstanceValue::addDirt(ComponentDirt value) { m_DependencyHelper.addDirt(value); }
+
+void ViewModelInstanceValue::setRoot(ViewModelInstance* viewModelInstance)
+{
+    m_DependencyHelper.dependecyRoot(viewModelInstance);
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_instance_viewmodel.cpp b/src/viewmodel/viewmodel_instance_viewmodel.cpp
new file mode 100644
index 0000000..7630112
--- /dev/null
+++ b/src/viewmodel/viewmodel_instance_viewmodel.cpp
@@ -0,0 +1,13 @@
+#include <sstream>
+#include <iomanip>
+#include <array>
+
+#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
+
+using namespace rive;
+
+void ViewModelInstanceViewModel::setRoot(ViewModelInstance* value)
+{
+    Super::setRoot(value);
+    referenceViewModelInstance()->setRoot(value);
+}
\ No newline at end of file
diff --git a/src/viewmodel/viewmodel_property.cpp b/src/viewmodel/viewmodel_property.cpp
new file mode 100644
index 0000000..4450bc1
--- /dev/null
+++ b/src/viewmodel/viewmodel_property.cpp
@@ -0,0 +1,17 @@
+#include "rive/viewmodel/viewmodel_property.hpp"
+#include "rive/importers/viewmodel_importer.hpp"
+#include "rive/viewmodel/viewmodel.hpp"
+
+using namespace rive;
+
+StatusCode ViewModelProperty::import(ImportStack& importStack)
+{
+    auto viewModelImporter = importStack.latest<ViewModelImporter>(ViewModel::typeKey);
+    if (viewModelImporter == nullptr)
+    {
+        return StatusCode::MissingObject;
+    }
+
+    viewModelImporter->addProperty(this);
+    return Super::import(importStack);
+}
diff --git a/src/viewmodel/viewmodel_property_enum.cpp b/src/viewmodel/viewmodel_property_enum.cpp
new file mode 100644
index 0000000..ef5e12f
--- /dev/null
+++ b/src/viewmodel/viewmodel_property_enum.cpp
@@ -0,0 +1,61 @@
+#include "rive/viewmodel/viewmodel_property_enum.hpp"
+
+using namespace rive;
+
+void ViewModelPropertyEnum::dataEnum(DataEnum* value) { m_DataEnum = value; }
+
+DataEnum* ViewModelPropertyEnum::dataEnum() { return m_DataEnum; }
+
+std::string ViewModelPropertyEnum::value(std::string name)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->value(name);
+    }
+    return "";
+}
+
+std::string ViewModelPropertyEnum::value(uint32_t index)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->value(index);
+    }
+    return "";
+}
+
+bool ViewModelPropertyEnum::value(std::string name, std::string value)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->value(name, value);
+    }
+    return false;
+}
+
+bool ViewModelPropertyEnum::value(uint32_t index, std::string value)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->value(index, value);
+    }
+    return false;
+}
+
+int ViewModelPropertyEnum::valueIndex(std::string name)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->valueIndex(name);
+    }
+    return -1;
+}
+
+int ViewModelPropertyEnum::valueIndex(uint32_t index)
+{
+    if (dataEnum() != nullptr)
+    {
+        return dataEnum()->valueIndex(index);
+    }
+    return -1;
+}
diff --git a/viewer/src/viewer_content/scene_content.cpp b/viewer/src/viewer_content/scene_content.cpp
index e847adb..ee43e2e 100644
--- a/viewer/src/viewer_content/scene_content.cpp
+++ b/viewer/src/viewer_content/scene_content.cpp
@@ -13,6 +13,7 @@
 #include "rive/layout.hpp"
 #include "rive/math/aabb.hpp"
 #include "rive/assets/image_asset.hpp"
+#include "rive/viewmodel/viewmodel_instance.hpp"
 #include "viewer/viewer_content.hpp"
 #include "rive/relative_local_asset_loader.hpp"
 
@@ -68,6 +69,7 @@
 
     std::unique_ptr<rive::ArtboardInstance> m_ArtboardInstance;
     std::unique_ptr<rive::Scene> m_CurrentScene;
+    rive::ViewModelInstance* m_ViewModelInstance;
     int m_ArtboardIndex = 0;
     int m_AnimationIndex = 0;
     int m_StateMachineIndex = -1;
@@ -84,6 +86,9 @@
 
         m_ArtboardIndex = (index == REQUEST_DEFAULT_SCENE) ? 0 : index;
         m_ArtboardInstance = m_File->artboardAt(m_ArtboardIndex);
+        // m_ViewModelInstance = m_File->viewModelInstanceNamed("vm-3");
+        m_ViewModelInstance = m_File->createViewModelInstance(m_ArtboardInstance.get());
+        m_ArtboardInstance->dataContextFromInstance(m_ViewModelInstance);
 
         m_ArtboardInstance->advance(0.0f);
         loadNames(m_ArtboardInstance.get());