Support for align action.
diff --git a/dev/defs/animation/listener_action.json b/dev/defs/animation/listener_action.json
new file mode 100644
index 0000000..a1f0b1c
--- /dev/null
+++ b/dev/defs/animation/listener_action.json
@@ -0,0 +1,33 @@
+{
+  "name": "ListenerAction",
+  "key": {
+    "int": 125,
+    "string": "listener_action"
+  },
+  "abstract": true,
+  "properties": {
+    "listenerId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 226,
+        "string": "listenerId"
+      },
+      "description": "Identifier used to track the StateMachineListener this result belongs to.",
+      "runtime": false
+    },
+    "order": {
+      "type": "FractionalIndex",
+      "initialValue": "FractionalIndex.invalid",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 230,
+        "string": "order"
+      },
+      "description": "Order value for condition in a transition.",
+      "runtime": false
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/listener_align_target.json b/dev/defs/animation/listener_align_target.json
new file mode 100644
index 0000000..b34168f
--- /dev/null
+++ b/dev/defs/animation/listener_align_target.json
@@ -0,0 +1,21 @@
+{
+  "name": "ListenerAlignTarget",
+  "key": {
+    "int": 126,
+    "string": "listeneraligntarget"
+  },
+  "extends": "animation/listener_action.json",
+  "properties": {
+    "targetId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "0",
+      "key": {
+        "int": 240,
+        "string": "targetid"
+      },
+      "description": "Identifier used to track the object use as a target fo this listener action."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/listener_input_change.json b/dev/defs/animation/listener_input_change.json
index df4cd3b..445b3e4 100644
--- a/dev/defs/animation/listener_input_change.json
+++ b/dev/defs/animation/listener_input_change.json
@@ -5,19 +5,8 @@
     "string": "listener_input_change"
   },
   "abstract": true,
+  "extends": "animation/listener_action.json",
   "properties": {
-    "listenerId": {
-      "type": "Id",
-      "typeRuntime": "uint",
-      "initialValue": "Core.missingId",
-      "initialValueRuntime": "0",
-      "key": {
-        "int": 226,
-        "string": "listenerId"
-      },
-      "description": "Identifier used to track the StateMachineListener this result belongs to.",
-      "runtime": false
-    },
     "inputId": {
       "type": "Id",
       "typeRuntime": "uint",
@@ -28,17 +17,6 @@
         "string": "inputid"
       },
       "description": "Id of the StateMachineInput referenced."
-    },
-    "order": {
-      "type": "FractionalIndex",
-      "initialValue": "FractionalIndex.invalid",
-      "initialValueRuntime": "0",
-      "key": {
-        "int": 230,
-        "string": "order"
-      },
-      "description": "Order value for condition in a transition.",
-      "runtime": false
     }
   }
 }
\ No newline at end of file
diff --git a/dev/defs/animation/nested_bool.json b/dev/defs/animation/nested_bool.json
new file mode 100644
index 0000000..b55c59a
--- /dev/null
+++ b/dev/defs/animation/nested_bool.json
@@ -0,0 +1,19 @@
+{
+  "name": "NestedBool",
+  "key": {
+    "int": 123,
+    "string": "nestedBool"
+  },
+  "extends": "animation/nested_input.json",
+  "properties": {
+    "nestedValue": {
+      "type": "bool",
+      "initialValue": "false",
+      "animates": true,
+      "key": {
+        "int": 238,
+        "string": "value"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/nested_input.json b/dev/defs/animation/nested_input.json
new file mode 100644
index 0000000..4fd8fe1
--- /dev/null
+++ b/dev/defs/animation/nested_input.json
@@ -0,0 +1,22 @@
+{
+  "name": "NestedInput",
+  "key": {
+    "int": 121,
+    "string": "nestedinput"
+  },
+  "abstract": true,
+  "extends": "component.json",
+  "properties": {
+    "inputId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 237,
+        "string": "inputid"
+      },
+      "description": "Identifier used to track the actual backing state machine input."
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/nested_number.json b/dev/defs/animation/nested_number.json
new file mode 100644
index 0000000..7315cf1
--- /dev/null
+++ b/dev/defs/animation/nested_number.json
@@ -0,0 +1,19 @@
+{
+  "name": "NestedNumber",
+  "key": {
+    "int": 124,
+    "string": "nestedNumber"
+  },
+  "extends": "animation/nested_input.json",
+  "properties": {
+    "nestedValue": {
+      "type": "double",
+      "initialValue": "0",
+      "animates": true,
+      "key": {
+        "int": 239,
+        "string": "nestedValue"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/dev/defs/animation/nested_trigger.json b/dev/defs/animation/nested_trigger.json
new file mode 100644
index 0000000..ea7f077
--- /dev/null
+++ b/dev/defs/animation/nested_trigger.json
@@ -0,0 +1,8 @@
+{
+  "name": "NestedTrigger",
+  "key": {
+    "int": 122,
+    "string": "nestedTrigger"
+  },
+  "extends": "animation/nested_input.json"
+}
\ No newline at end of file
diff --git a/dev/defs/assets/layered_asset.json b/dev/defs/assets/layered_asset.json
index 042381f..09a1713 100644
--- a/dev/defs/assets/layered_asset.json
+++ b/dev/defs/assets/layered_asset.json
@@ -4,6 +4,6 @@
     "int": 119,
     "string": "layeredasset"
   },
-  "runtime": false,
-  "extends": "assets/drawable_asset.json"
+  "extends": "assets/drawable_asset.json",
+  "runtime": false
 }
\ No newline at end of file
diff --git a/dev/defs/nested_animation.json b/dev/defs/nested_animation.json
index 2d89627..db6cbfb 100644
--- a/dev/defs/nested_animation.json
+++ b/dev/defs/nested_animation.json
@@ -5,7 +5,7 @@
     "string": "nestedanimation"
   },
   "abstract": true,
-  "extends": "component.json",
+  "extends": "container_component.json",
   "properties": {
     "animationId": {
       "type": "Id",
diff --git a/include/rive/animation/listener_action.hpp b/include/rive/animation/listener_action.hpp
new file mode 100644
index 0000000..1b78659
--- /dev/null
+++ b/include/rive/animation/listener_action.hpp
@@ -0,0 +1,15 @@
+#ifndef _RIVE_LISTENER_ACTION_HPP_
+#define _RIVE_LISTENER_ACTION_HPP_
+#include "rive/generated/animation/listener_action_base.hpp"
+#include "rive/math/vec2d.hpp"
+
+namespace rive {
+    class StateMachineInstance;
+    class ListenerAction : public ListenerActionBase {
+    public:
+        StatusCode import(ImportStack& importStack) override;
+        virtual void perform(StateMachineInstance* stateMachineInstance, Vec2D position) const = 0;
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/listener_align_target.hpp b/include/rive/animation/listener_align_target.hpp
new file mode 100644
index 0000000..aec3c89
--- /dev/null
+++ b/include/rive/animation/listener_align_target.hpp
@@ -0,0 +1,12 @@
+#ifndef _RIVE_LISTENER_ALIGN_TARGET_HPP_
+#define _RIVE_LISTENER_ALIGN_TARGET_HPP_
+#include "rive/generated/animation/listener_align_target_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class ListenerAlignTarget : public ListenerAlignTargetBase {
+    public:
+        void perform(StateMachineInstance* stateMachineInstance, Vec2D position) const override;
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/listener_bool_change.hpp b/include/rive/animation/listener_bool_change.hpp
index 2bc6efb..d821ae1 100644
--- a/include/rive/animation/listener_bool_change.hpp
+++ b/include/rive/animation/listener_bool_change.hpp
@@ -6,7 +6,7 @@
     class ListenerBoolChange : public ListenerBoolChangeBase {
     public:
         bool validateInputType(const StateMachineInput* input) const override;
-        void perform(StateMachineInstance* stateMachineInstance) const override;
+        void perform(StateMachineInstance* stateMachineInstance, Vec2D position) const override;
     };
 } // namespace rive
 
diff --git a/include/rive/animation/listener_input_change.hpp b/include/rive/animation/listener_input_change.hpp
index c7ccc04..c71047f 100644
--- a/include/rive/animation/listener_input_change.hpp
+++ b/include/rive/animation/listener_input_change.hpp
@@ -3,12 +3,10 @@
 #include "rive/generated/animation/listener_input_change_base.hpp"
 
 namespace rive {
-    class StateMachineInstance;
     class StateMachineInput;
     class ListenerInputChange : public ListenerInputChangeBase {
     public:
         StatusCode import(ImportStack& importStack) override;
-        virtual void perform(StateMachineInstance* stateMachineInstance) const = 0;
         virtual bool validateInputType(const StateMachineInput* input) const { return true; }
     };
 } // namespace rive
diff --git a/include/rive/animation/listener_number_change.hpp b/include/rive/animation/listener_number_change.hpp
index a20c911..9f933d9 100644
--- a/include/rive/animation/listener_number_change.hpp
+++ b/include/rive/animation/listener_number_change.hpp
@@ -6,7 +6,7 @@
     class ListenerNumberChange : public ListenerNumberChangeBase {
     public:
         bool validateInputType(const StateMachineInput* input) const override;
-        void perform(StateMachineInstance* stateMachineInstance) const override;
+        void perform(StateMachineInstance* stateMachineInstance, Vec2D position) const override;
     };
 } // namespace rive
 
diff --git a/include/rive/animation/listener_trigger_change.hpp b/include/rive/animation/listener_trigger_change.hpp
index ab89e1f..cc98376 100644
--- a/include/rive/animation/listener_trigger_change.hpp
+++ b/include/rive/animation/listener_trigger_change.hpp
@@ -6,7 +6,7 @@
     class ListenerTriggerChange : public ListenerTriggerChangeBase {
     public:
         bool validateInputType(const StateMachineInput* input) const override;
-        void perform(StateMachineInstance* stateMachineInstance) const override;
+        void perform(StateMachineInstance* stateMachineInstance, Vec2D position) const override;
     };
 } // namespace rive
 
diff --git a/include/rive/animation/nested_bool.hpp b/include/rive/animation/nested_bool.hpp
new file mode 100644
index 0000000..6b084ae
--- /dev/null
+++ b/include/rive/animation/nested_bool.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_NESTED_BOOL_HPP_
+#define _RIVE_NESTED_BOOL_HPP_
+#include "rive/generated/animation/nested_bool_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class NestedBool : public NestedBoolBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/nested_input.hpp b/include/rive/animation/nested_input.hpp
new file mode 100644
index 0000000..94c2b69
--- /dev/null
+++ b/include/rive/animation/nested_input.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_NESTED_INPUT_HPP_
+#define _RIVE_NESTED_INPUT_HPP_
+#include "rive/generated/animation/nested_input_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class NestedInput : public NestedInputBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/nested_number.hpp b/include/rive/animation/nested_number.hpp
new file mode 100644
index 0000000..f4c2f12
--- /dev/null
+++ b/include/rive/animation/nested_number.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_NESTED_NUMBER_HPP_
+#define _RIVE_NESTED_NUMBER_HPP_
+#include "rive/generated/animation/nested_number_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class NestedNumber : public NestedNumberBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/nested_trigger.hpp b/include/rive/animation/nested_trigger.hpp
new file mode 100644
index 0000000..2fc040b
--- /dev/null
+++ b/include/rive/animation/nested_trigger.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_NESTED_TRIGGER_HPP_
+#define _RIVE_NESTED_TRIGGER_HPP_
+#include "rive/generated/animation/nested_trigger_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class NestedTrigger : public NestedTriggerBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp
index fa8fe6f..c189b81 100644
--- a/include/rive/animation/state_machine_instance.hpp
+++ b/include/rive/animation/state_machine_instance.hpp
@@ -39,7 +39,7 @@
 
         /// Provide a hitListener if you want to process a down or an up for the pointer position
         /// too.
-        void updateListeners(Vec2D position, ListenerType hitListener = ListenerType::updateHover);
+        void updateListeners(Vec2D position, ListenerType hitListener);
 
         template <typename SMType, typename InstType>
         InstType* getNamedInput(const std::string& name) const;
@@ -85,6 +85,10 @@
         float durationSeconds() const override { return -1; }
         Loop loop() const override { return Loop::oneShot; }
         bool isTranslucent() const override { return true; }
+
+        /// Allow anything referencing a concrete StateMachineInstace access to
+        /// the backing artboard (explicitly not allowed on Scenes).
+        Artboard* artboard() { return m_ArtboardInstance; }
     };
 } // namespace rive
 #endif
diff --git a/include/rive/animation/state_machine_listener.hpp b/include/rive/animation/state_machine_listener.hpp
index 14bd60b..bea2763 100644
--- a/include/rive/animation/state_machine_listener.hpp
+++ b/include/rive/animation/state_machine_listener.hpp
@@ -2,29 +2,31 @@
 #define _RIVE_STATE_MACHINE_LISTENER_HPP_
 #include "rive/generated/animation/state_machine_listener_base.hpp"
 #include "rive/listener_type.hpp"
+#include "rive/math/vec2d.hpp"
 
 namespace rive {
     class Shape;
     class StateMachineListenerImporter;
-    class ListenerInputChange;
+    class ListenerAction;
     class StateMachineInstance;
     class StateMachineListener : public StateMachineListenerBase {
         friend class StateMachineListenerImporter;
 
     private:
         std::vector<uint32_t> m_HitShapesIds;
-        std::vector<ListenerInputChange*> m_InputChanges;
-        void addInputChange(ListenerInputChange* inputChange);
+        std::vector<ListenerAction*> m_Actions;
+        void addAction(ListenerAction* action);
 
     public:
         ListenerType listenerType() const { return (ListenerType)listenerTypeValue(); }
-        size_t inputChangeCount() const { return m_InputChanges.size(); }
-        const ListenerInputChange* inputChange(size_t index) const;
+        size_t actionCount() const { return m_Actions.size(); }
+
+        const ListenerAction* action(size_t index) const;
         StatusCode import(ImportStack& importStack) override;
         StatusCode onAddedClean(CoreContext* context) override;
 
         const std::vector<uint32_t>& hitShapeIds() const { return m_HitShapesIds; }
-        void performChanges(StateMachineInstance* stateMachineInstance) const;
+        void performChanges(StateMachineInstance* stateMachineInstance, Vec2D position) const;
     };
 } // namespace rive
 
diff --git a/include/rive/generated/animation/listener_action_base.hpp b/include/rive/generated/animation/listener_action_base.hpp
new file mode 100644
index 0000000..e73cb1c
--- /dev/null
+++ b/include/rive/generated/animation/listener_action_base.hpp
@@ -0,0 +1,33 @@
+#ifndef _RIVE_LISTENER_ACTION_BASE_HPP_
+#define _RIVE_LISTENER_ACTION_BASE_HPP_
+#include "rive/core.hpp"
+namespace rive {
+    class ListenerActionBase : public Core {
+    protected:
+        typedef Core Super;
+
+    public:
+        static const uint16_t typeKey = 125;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case ListenerActionBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        void copy(const ListenerActionBase& object) {}
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override { return false; }
+
+    protected:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/listener_align_target_base.hpp b/include/rive/generated/animation/listener_align_target_base.hpp
new file mode 100644
index 0000000..d7e8c86
--- /dev/null
+++ b/include/rive/generated/animation/listener_align_target_base.hpp
@@ -0,0 +1,62 @@
+#ifndef _RIVE_LISTENER_ALIGN_TARGET_BASE_HPP_
+#define _RIVE_LISTENER_ALIGN_TARGET_BASE_HPP_
+#include "rive/animation/listener_action.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive {
+    class ListenerAlignTargetBase : public ListenerAction {
+    protected:
+        typedef ListenerAction Super;
+
+    public:
+        static const uint16_t typeKey = 126;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case ListenerAlignTargetBase::typeKey:
+                case ListenerActionBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t targetIdPropertyKey = 240;
+
+    private:
+        uint32_t m_TargetId = 0;
+
+    public:
+        inline uint32_t targetId() const { return m_TargetId; }
+        void targetId(uint32_t value) {
+            if (m_TargetId == value) {
+                return;
+            }
+            m_TargetId = value;
+            targetIdChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const ListenerAlignTargetBase& object) {
+            m_TargetId = object.m_TargetId;
+            ListenerAction::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case targetIdPropertyKey:
+                    m_TargetId = CoreUintType::deserialize(reader);
+                    return true;
+            }
+            return ListenerAction::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void targetIdChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/listener_bool_change_base.hpp b/include/rive/generated/animation/listener_bool_change_base.hpp
index e4e667b..c7d87c8 100644
--- a/include/rive/generated/animation/listener_bool_change_base.hpp
+++ b/include/rive/generated/animation/listener_bool_change_base.hpp
@@ -16,6 +16,7 @@
             switch (typeKey) {
                 case ListenerBoolChangeBase::typeKey:
                 case ListenerInputChangeBase::typeKey:
+                case ListenerActionBase::typeKey:
                     return true;
                 default:
                     return false;
diff --git a/include/rive/generated/animation/listener_input_change_base.hpp b/include/rive/generated/animation/listener_input_change_base.hpp
index f4dca8a..ef82552 100644
--- a/include/rive/generated/animation/listener_input_change_base.hpp
+++ b/include/rive/generated/animation/listener_input_change_base.hpp
@@ -1,11 +1,11 @@
 #ifndef _RIVE_LISTENER_INPUT_CHANGE_BASE_HPP_
 #define _RIVE_LISTENER_INPUT_CHANGE_BASE_HPP_
-#include "rive/core.hpp"
+#include "rive/animation/listener_action.hpp"
 #include "rive/core/field_types/core_uint_type.hpp"
 namespace rive {
-    class ListenerInputChangeBase : public Core {
+    class ListenerInputChangeBase : public ListenerAction {
     protected:
-        typedef Core Super;
+        typedef ListenerAction Super;
 
     public:
         static const uint16_t typeKey = 116;
@@ -15,6 +15,7 @@
         bool isTypeOf(uint16_t typeKey) const override {
             switch (typeKey) {
                 case ListenerInputChangeBase::typeKey:
+                case ListenerActionBase::typeKey:
                     return true;
                 default:
                     return false;
@@ -38,7 +39,10 @@
             inputIdChanged();
         }
 
-        void copy(const ListenerInputChangeBase& object) { m_InputId = object.m_InputId; }
+        void copy(const ListenerInputChangeBase& object) {
+            m_InputId = object.m_InputId;
+            ListenerAction::copy(object);
+        }
 
         bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
             switch (propertyKey) {
@@ -46,7 +50,7 @@
                     m_InputId = CoreUintType::deserialize(reader);
                     return true;
             }
-            return false;
+            return ListenerAction::deserialize(propertyKey, reader);
         }
 
     protected:
diff --git a/include/rive/generated/animation/listener_number_change_base.hpp b/include/rive/generated/animation/listener_number_change_base.hpp
index 54a7209..8106d29 100644
--- a/include/rive/generated/animation/listener_number_change_base.hpp
+++ b/include/rive/generated/animation/listener_number_change_base.hpp
@@ -16,6 +16,7 @@
             switch (typeKey) {
                 case ListenerNumberChangeBase::typeKey:
                 case ListenerInputChangeBase::typeKey:
+                case ListenerActionBase::typeKey:
                     return true;
                 default:
                     return false;
diff --git a/include/rive/generated/animation/listener_trigger_change_base.hpp b/include/rive/generated/animation/listener_trigger_change_base.hpp
index 14985b3..7e82832 100644
--- a/include/rive/generated/animation/listener_trigger_change_base.hpp
+++ b/include/rive/generated/animation/listener_trigger_change_base.hpp
@@ -15,6 +15,7 @@
             switch (typeKey) {
                 case ListenerTriggerChangeBase::typeKey:
                 case ListenerInputChangeBase::typeKey:
+                case ListenerActionBase::typeKey:
                     return true;
                 default:
                     return false;
diff --git a/include/rive/generated/animation/nested_bool_base.hpp b/include/rive/generated/animation/nested_bool_base.hpp
new file mode 100644
index 0000000..781fcfc
--- /dev/null
+++ b/include/rive/generated/animation/nested_bool_base.hpp
@@ -0,0 +1,63 @@
+#ifndef _RIVE_NESTED_BOOL_BASE_HPP_
+#define _RIVE_NESTED_BOOL_BASE_HPP_
+#include "rive/animation/nested_input.hpp"
+#include "rive/core/field_types/core_bool_type.hpp"
+namespace rive {
+    class NestedBoolBase : public NestedInput {
+    protected:
+        typedef NestedInput Super;
+
+    public:
+        static const uint16_t typeKey = 123;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case NestedBoolBase::typeKey:
+                case NestedInputBase::typeKey:
+                case ComponentBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t nestedValuePropertyKey = 238;
+
+    private:
+        bool m_NestedValue = false;
+
+    public:
+        inline bool nestedValue() const { return m_NestedValue; }
+        void nestedValue(bool value) {
+            if (m_NestedValue == value) {
+                return;
+            }
+            m_NestedValue = value;
+            nestedValueChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const NestedBoolBase& object) {
+            m_NestedValue = object.m_NestedValue;
+            NestedInput::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case nestedValuePropertyKey:
+                    m_NestedValue = CoreBoolType::deserialize(reader);
+                    return true;
+            }
+            return NestedInput::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void nestedValueChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/nested_input_base.hpp b/include/rive/generated/animation/nested_input_base.hpp
new file mode 100644
index 0000000..df1fa05
--- /dev/null
+++ b/include/rive/generated/animation/nested_input_base.hpp
@@ -0,0 +1,61 @@
+#ifndef _RIVE_NESTED_INPUT_BASE_HPP_
+#define _RIVE_NESTED_INPUT_BASE_HPP_
+#include "rive/component.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive {
+    class NestedInputBase : public Component {
+    protected:
+        typedef Component Super;
+
+    public:
+        static const uint16_t typeKey = 121;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case NestedInputBase::typeKey:
+                case ComponentBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t inputIdPropertyKey = 237;
+
+    private:
+        uint32_t m_InputId = -1;
+
+    public:
+        inline uint32_t inputId() const { return m_InputId; }
+        void inputId(uint32_t value) {
+            if (m_InputId == value) {
+                return;
+            }
+            m_InputId = value;
+            inputIdChanged();
+        }
+
+        void copy(const NestedInputBase& object) {
+            m_InputId = object.m_InputId;
+            Component::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case inputIdPropertyKey:
+                    m_InputId = CoreUintType::deserialize(reader);
+                    return true;
+            }
+            return Component::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void inputIdChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/nested_linear_animation_base.hpp b/include/rive/generated/animation/nested_linear_animation_base.hpp
index 766a335..a749818 100644
--- a/include/rive/generated/animation/nested_linear_animation_base.hpp
+++ b/include/rive/generated/animation/nested_linear_animation_base.hpp
@@ -16,6 +16,7 @@
             switch (typeKey) {
                 case NestedLinearAnimationBase::typeKey:
                 case NestedAnimationBase::typeKey:
+                case ContainerComponentBase::typeKey:
                 case ComponentBase::typeKey:
                     return true;
                 default:
diff --git a/include/rive/generated/animation/nested_number_base.hpp b/include/rive/generated/animation/nested_number_base.hpp
new file mode 100644
index 0000000..3847b20
--- /dev/null
+++ b/include/rive/generated/animation/nested_number_base.hpp
@@ -0,0 +1,63 @@
+#ifndef _RIVE_NESTED_NUMBER_BASE_HPP_
+#define _RIVE_NESTED_NUMBER_BASE_HPP_
+#include "rive/animation/nested_input.hpp"
+#include "rive/core/field_types/core_double_type.hpp"
+namespace rive {
+    class NestedNumberBase : public NestedInput {
+    protected:
+        typedef NestedInput Super;
+
+    public:
+        static const uint16_t typeKey = 124;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case NestedNumberBase::typeKey:
+                case NestedInputBase::typeKey:
+                case ComponentBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t nestedValuePropertyKey = 239;
+
+    private:
+        float m_NestedValue = 0.0f;
+
+    public:
+        inline float nestedValue() const { return m_NestedValue; }
+        void nestedValue(float value) {
+            if (m_NestedValue == value) {
+                return;
+            }
+            m_NestedValue = value;
+            nestedValueChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const NestedNumberBase& object) {
+            m_NestedValue = object.m_NestedValue;
+            NestedInput::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case nestedValuePropertyKey:
+                    m_NestedValue = CoreDoubleType::deserialize(reader);
+                    return true;
+            }
+            return NestedInput::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void nestedValueChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/nested_remap_animation_base.hpp b/include/rive/generated/animation/nested_remap_animation_base.hpp
index f8eadcb..a743a90 100644
--- a/include/rive/generated/animation/nested_remap_animation_base.hpp
+++ b/include/rive/generated/animation/nested_remap_animation_base.hpp
@@ -17,6 +17,7 @@
                 case NestedRemapAnimationBase::typeKey:
                 case NestedLinearAnimationBase::typeKey:
                 case NestedAnimationBase::typeKey:
+                case ContainerComponentBase::typeKey:
                 case ComponentBase::typeKey:
                     return true;
                 default:
diff --git a/include/rive/generated/animation/nested_simple_animation_base.hpp b/include/rive/generated/animation/nested_simple_animation_base.hpp
index 9c6e357..d51e941 100644
--- a/include/rive/generated/animation/nested_simple_animation_base.hpp
+++ b/include/rive/generated/animation/nested_simple_animation_base.hpp
@@ -18,6 +18,7 @@
                 case NestedSimpleAnimationBase::typeKey:
                 case NestedLinearAnimationBase::typeKey:
                 case NestedAnimationBase::typeKey:
+                case ContainerComponentBase::typeKey:
                 case ComponentBase::typeKey:
                     return true;
                 default:
diff --git a/include/rive/generated/animation/nested_state_machine_base.hpp b/include/rive/generated/animation/nested_state_machine_base.hpp
index b6708a5..407de9d 100644
--- a/include/rive/generated/animation/nested_state_machine_base.hpp
+++ b/include/rive/generated/animation/nested_state_machine_base.hpp
@@ -15,6 +15,7 @@
             switch (typeKey) {
                 case NestedStateMachineBase::typeKey:
                 case NestedAnimationBase::typeKey:
+                case ContainerComponentBase::typeKey:
                 case ComponentBase::typeKey:
                     return true;
                 default:
diff --git a/include/rive/generated/animation/nested_trigger_base.hpp b/include/rive/generated/animation/nested_trigger_base.hpp
new file mode 100644
index 0000000..61a9c32
--- /dev/null
+++ b/include/rive/generated/animation/nested_trigger_base.hpp
@@ -0,0 +1,33 @@
+#ifndef _RIVE_NESTED_TRIGGER_BASE_HPP_
+#define _RIVE_NESTED_TRIGGER_BASE_HPP_
+#include "rive/animation/nested_input.hpp"
+namespace rive {
+    class NestedTriggerBase : public NestedInput {
+    protected:
+        typedef NestedInput Super;
+
+    public:
+        static const uint16_t typeKey = 122;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case NestedTriggerBase::typeKey:
+                case NestedInputBase::typeKey:
+                case ComponentBase::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/core_registry.hpp b/include/rive/generated/core_registry.hpp
index ed1a0f7..ad48ce9 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -22,14 +22,20 @@
 #include "rive/animation/keyframe_id.hpp"
 #include "rive/animation/layer_state.hpp"
 #include "rive/animation/linear_animation.hpp"
+#include "rive/animation/listener_action.hpp"
+#include "rive/animation/listener_align_target.hpp"
 #include "rive/animation/listener_bool_change.hpp"
 #include "rive/animation/listener_input_change.hpp"
 #include "rive/animation/listener_number_change.hpp"
 #include "rive/animation/listener_trigger_change.hpp"
+#include "rive/animation/nested_bool.hpp"
+#include "rive/animation/nested_input.hpp"
 #include "rive/animation/nested_linear_animation.hpp"
+#include "rive/animation/nested_number.hpp"
 #include "rive/animation/nested_remap_animation.hpp"
 #include "rive/animation/nested_simple_animation.hpp"
 #include "rive/animation/nested_state_machine.hpp"
+#include "rive/animation/nested_trigger.hpp"
 #include "rive/animation/state_machine.hpp"
 #include "rive/animation/state_machine_bool.hpp"
 #include "rive/animation/state_machine_component.hpp"
@@ -137,6 +143,8 @@
                     return new NestedSimpleAnimation();
                 case AnimationStateBase::typeKey:
                     return new AnimationState();
+                case NestedTriggerBase::typeKey:
+                    return new NestedTrigger();
                 case KeyedObjectBase::typeKey:
                     return new KeyedObject();
                 case BlendAnimationDirectBase::typeKey:
@@ -155,6 +163,8 @@
                     return new KeyFrameBool();
                 case ListenerBoolChangeBase::typeKey:
                     return new ListenerBoolChange();
+                case ListenerAlignTargetBase::typeKey:
+                    return new ListenerAlignTarget();
                 case TransitionNumberConditionBase::typeKey:
                     return new TransitionNumberCondition();
                 case AnyStateBase::typeKey:
@@ -169,6 +179,8 @@
                     return new CubicInterpolator();
                 case StateTransitionBase::typeKey:
                     return new StateTransition();
+                case NestedBoolBase::typeKey:
+                    return new NestedBool();
                 case KeyFrameDoubleBase::typeKey:
                     return new KeyFrameDouble();
                 case KeyFrameColorBase::typeKey:
@@ -189,6 +201,8 @@
                     return new NestedStateMachine();
                 case ExitStateBase::typeKey:
                     return new ExitState();
+                case NestedNumberBase::typeKey:
+                    return new NestedNumber();
                 case BlendState1DBase::typeKey:
                     return new BlendState1D();
                 case NestedRemapAnimationBase::typeKey:
@@ -337,6 +351,9 @@
                 case AnimationStateBase::animationIdPropertyKey:
                     object->as<AnimationStateBase>()->animationId(value);
                     break;
+                case NestedInputBase::inputIdPropertyKey:
+                    object->as<NestedInputBase>()->inputId(value);
+                    break;
                 case KeyedObjectBase::objectIdPropertyKey:
                     object->as<KeyedObjectBase>()->objectId(value);
                     break;
@@ -373,6 +390,9 @@
                 case ListenerBoolChangeBase::valuePropertyKey:
                     object->as<ListenerBoolChangeBase>()->value(value);
                     break;
+                case ListenerAlignTargetBase::targetIdPropertyKey:
+                    object->as<ListenerAlignTargetBase>()->targetId(value);
+                    break;
                 case TransitionValueConditionBase::opValuePropertyKey:
                     object->as<TransitionValueConditionBase>()->opValue(value);
                     break;
@@ -545,6 +565,9 @@
                 case LinearAnimationBase::speedPropertyKey:
                     object->as<LinearAnimationBase>()->speed(value);
                     break;
+                case NestedNumberBase::nestedValuePropertyKey:
+                    object->as<NestedNumberBase>()->nestedValue(value);
+                    break;
                 case NestedRemapAnimationBase::timePropertyKey:
                     object->as<NestedRemapAnimationBase>()->time(value);
                     break;
@@ -756,6 +779,9 @@
                 case KeyFrameBoolBase::valuePropertyKey:
                     object->as<KeyFrameBoolBase>()->value(value);
                     break;
+                case NestedBoolBase::nestedValuePropertyKey:
+                    object->as<NestedBoolBase>()->nestedValue(value);
+                    break;
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                     object->as<LinearAnimationBase>()->enableWorkArea(value);
                     break;
@@ -840,6 +866,8 @@
                     return object->as<ListenerInputChangeBase>()->inputId();
                 case AnimationStateBase::animationIdPropertyKey:
                     return object->as<AnimationStateBase>()->animationId();
+                case NestedInputBase::inputIdPropertyKey:
+                    return object->as<NestedInputBase>()->inputId();
                 case KeyedObjectBase::objectIdPropertyKey:
                     return object->as<KeyedObjectBase>()->objectId();
                 case BlendAnimationBase::animationIdPropertyKey:
@@ -864,6 +892,8 @@
                     return object->as<KeyFrameIdBase>()->value();
                 case ListenerBoolChangeBase::valuePropertyKey:
                     return object->as<ListenerBoolChangeBase>()->value();
+                case ListenerAlignTargetBase::targetIdPropertyKey:
+                    return object->as<ListenerAlignTargetBase>()->targetId();
                 case TransitionValueConditionBase::opValuePropertyKey:
                     return object->as<TransitionValueConditionBase>()->opValue();
                 case StateTransitionBase::stateToIdPropertyKey:
@@ -981,6 +1011,8 @@
                     return object->as<KeyFrameDoubleBase>()->value();
                 case LinearAnimationBase::speedPropertyKey:
                     return object->as<LinearAnimationBase>()->speed();
+                case NestedNumberBase::nestedValuePropertyKey:
+                    return object->as<NestedNumberBase>()->nestedValue();
                 case NestedRemapAnimationBase::timePropertyKey:
                     return object->as<NestedRemapAnimationBase>()->time();
                 case BlendAnimation1DBase::valuePropertyKey:
@@ -1124,6 +1156,8 @@
                     return object->as<NestedSimpleAnimationBase>()->isPlaying();
                 case KeyFrameBoolBase::valuePropertyKey:
                     return object->as<KeyFrameBoolBase>()->value();
+                case NestedBoolBase::nestedValuePropertyKey:
+                    return object->as<NestedBoolBase>()->nestedValue();
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                     return object->as<LinearAnimationBase>()->enableWorkArea();
                 case StateMachineBoolBase::valuePropertyKey:
@@ -1176,6 +1210,7 @@
                 case NestedAnimationBase::animationIdPropertyKey:
                 case ListenerInputChangeBase::inputIdPropertyKey:
                 case AnimationStateBase::animationIdPropertyKey:
+                case NestedInputBase::inputIdPropertyKey:
                 case KeyedObjectBase::objectIdPropertyKey:
                 case BlendAnimationBase::animationIdPropertyKey:
                 case BlendAnimationDirectBase::inputIdPropertyKey:
@@ -1188,6 +1223,7 @@
                 case KeyFrameBase::interpolatorIdPropertyKey:
                 case KeyFrameIdBase::valuePropertyKey:
                 case ListenerBoolChangeBase::valuePropertyKey:
+                case ListenerAlignTargetBase::targetIdPropertyKey:
                 case TransitionValueConditionBase::opValuePropertyKey:
                 case StateTransitionBase::stateToIdPropertyKey:
                 case StateTransitionBase::flagsPropertyKey:
@@ -1245,6 +1281,7 @@
                 case CubicInterpolatorBase::y2PropertyKey:
                 case KeyFrameDoubleBase::valuePropertyKey:
                 case LinearAnimationBase::speedPropertyKey:
+                case NestedNumberBase::nestedValuePropertyKey:
                 case NestedRemapAnimationBase::timePropertyKey:
                 case BlendAnimation1DBase::valuePropertyKey:
                 case LinearGradientBase::startXPropertyKey:
@@ -1315,6 +1352,7 @@
                 case IKConstraintBase::invertDirectionPropertyKey:
                 case NestedSimpleAnimationBase::isPlayingPropertyKey:
                 case KeyFrameBoolBase::valuePropertyKey:
+                case NestedBoolBase::nestedValuePropertyKey:
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                 case StateMachineBoolBase::valuePropertyKey:
                 case ShapePaintBase::isVisiblePropertyKey:
diff --git a/include/rive/generated/nested_animation_base.hpp b/include/rive/generated/nested_animation_base.hpp
index cb31c68..6d33c29 100644
--- a/include/rive/generated/nested_animation_base.hpp
+++ b/include/rive/generated/nested_animation_base.hpp
@@ -1,11 +1,11 @@
 #ifndef _RIVE_NESTED_ANIMATION_BASE_HPP_
 #define _RIVE_NESTED_ANIMATION_BASE_HPP_
-#include "rive/component.hpp"
+#include "rive/container_component.hpp"
 #include "rive/core/field_types/core_uint_type.hpp"
 namespace rive {
-    class NestedAnimationBase : public Component {
+    class NestedAnimationBase : public ContainerComponent {
     protected:
-        typedef Component Super;
+        typedef ContainerComponent Super;
 
     public:
         static const uint16_t typeKey = 93;
@@ -15,6 +15,7 @@
         bool isTypeOf(uint16_t typeKey) const override {
             switch (typeKey) {
                 case NestedAnimationBase::typeKey:
+                case ContainerComponentBase::typeKey:
                 case ComponentBase::typeKey:
                     return true;
                 default:
@@ -41,7 +42,7 @@
 
         void copy(const NestedAnimationBase& object) {
             m_AnimationId = object.m_AnimationId;
-            Component::copy(object);
+            ContainerComponent::copy(object);
         }
 
         bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
@@ -50,7 +51,7 @@
                     m_AnimationId = CoreUintType::deserialize(reader);
                     return true;
             }
-            return Component::deserialize(propertyKey, reader);
+            return ContainerComponent::deserialize(propertyKey, reader);
         }
 
     protected:
diff --git a/include/rive/importers/state_machine_listener_importer.hpp b/include/rive/importers/state_machine_listener_importer.hpp
index 6702e44..d936ea5 100644
--- a/include/rive/importers/state_machine_listener_importer.hpp
+++ b/include/rive/importers/state_machine_listener_importer.hpp
@@ -6,7 +6,7 @@
 namespace rive {
     class StateMachineListener;
     class StateMachine;
-    class ListenerInputChange;
+    class ListenerAction;
     class StateMachineListenerImporter : public ImportStackObject {
     private:
         StateMachineListener* m_StateMachineListener;
@@ -14,7 +14,7 @@
     public:
         StateMachineListenerImporter(StateMachineListener* listener);
         const StateMachineListener* stateMachineListener() const { return m_StateMachineListener; }
-        void addInputChange(ListenerInputChange* change);
+        void addAction(ListenerAction* action);
         StatusCode resolve() override;
     };
 } // namespace rive
diff --git a/include/rive/listener_type.hpp b/include/rive/listener_type.hpp
index a2c8471..8617e4f 100644
--- a/include/rive/listener_type.hpp
+++ b/include/rive/listener_type.hpp
@@ -2,11 +2,11 @@
 #define _RIVE_LISTENER_TYPE_HPP_
 namespace rive {
     enum class ListenerType : int {
-        updateHover = -1,
         enter = 0,
         exit = 1,
         down = 2,
         up = 3,
+        move = 4,
     };
 }
 #endif
\ No newline at end of file
diff --git a/src/animation/listener_action.cpp b/src/animation/listener_action.cpp
new file mode 100644
index 0000000..46b2ab0
--- /dev/null
+++ b/src/animation/listener_action.cpp
@@ -0,0 +1,19 @@
+#include "rive/animation/state_machine_listener.hpp"
+#include "rive/importers/import_stack.hpp"
+#include "rive/importers/state_machine_listener_importer.hpp"
+#include "rive/importers/state_machine_importer.hpp"
+#include "rive/animation/listener_input_change.hpp"
+#include "rive/animation/state_machine.hpp"
+
+using namespace rive;
+
+StatusCode ListenerAction::import(ImportStack& importStack) {
+    auto stateMachineListenerImporter =
+        importStack.latest<StateMachineListenerImporter>(StateMachineListenerBase::typeKey);
+    if (stateMachineListenerImporter == nullptr) {
+        return StatusCode::MissingObject;
+    }
+
+    stateMachineListenerImporter->addAction(this);
+    return Super::import(importStack);
+}
diff --git a/src/animation/listener_align_target.cpp b/src/animation/listener_align_target.cpp
new file mode 100644
index 0000000..f2f90d0
--- /dev/null
+++ b/src/animation/listener_align_target.cpp
@@ -0,0 +1,26 @@
+#include "rive/animation/listener_align_target.hpp"
+#include "rive/animation/state_machine_instance.hpp"
+// #include "rive/animation/state_machine_number.hpp"
+// #include "rive/animation/state_machine_input_instance.hpp"
+#include "rive/node.hpp"
+#include "rive/constraints/constraint.hpp"
+
+using namespace rive;
+
+void ListenerAlignTarget::perform(StateMachineInstance* stateMachineInstance,
+                                  Vec2D position) const {
+    auto coreTarget = stateMachineInstance->artboard()->resolve(targetId());
+    if (coreTarget == nullptr || !coreTarget->is<Node>()) {
+        return;
+    }
+    auto target = coreTarget->as<Node>();
+    Mat2D targetParentWorld = getParentWorld(*target);
+    Mat2D inverse;
+    if (!targetParentWorld.invert(&inverse)) {
+        return;
+    }
+
+    auto localPosition = inverse * position;
+    target->x(localPosition.x);
+    target->y(localPosition.y);
+}
diff --git a/src/animation/listener_bool_change.cpp b/src/animation/listener_bool_change.cpp
index a930b28..0745b6b 100644
--- a/src/animation/listener_bool_change.cpp
+++ b/src/animation/listener_bool_change.cpp
@@ -11,7 +11,7 @@
     return input == nullptr || input->is<StateMachineBool>();
 }
 
-void ListenerBoolChange::perform(StateMachineInstance* stateMachineInstance) const {
+void ListenerBoolChange::perform(StateMachineInstance* stateMachineInstance, Vec2D position) const {
     auto inputInstance = stateMachineInstance->input(inputId());
     if (inputInstance == nullptr) {
         return;
diff --git a/src/animation/listener_input_change.cpp b/src/animation/listener_input_change.cpp
index a3e3e54..79c0489 100644
--- a/src/animation/listener_input_change.cpp
+++ b/src/animation/listener_input_change.cpp
@@ -13,15 +13,8 @@
         return StatusCode::MissingObject;
     }
 
-    auto stateMachineListenerImporter =
-        importStack.latest<StateMachineListenerImporter>(StateMachineListenerBase::typeKey);
-    if (stateMachineListenerImporter == nullptr) {
-        return StatusCode::MissingObject;
-    }
-
     if (!validateInputType(stateMachineImporter->stateMachine()->input((size_t)inputId()))) {
         return StatusCode::InvalidObject;
     }
-    stateMachineListenerImporter->addInputChange(this);
     return Super::import(importStack);
 }
diff --git a/src/animation/listener_number_change.cpp b/src/animation/listener_number_change.cpp
index 33c8316..91d9268 100644
--- a/src/animation/listener_number_change.cpp
+++ b/src/animation/listener_number_change.cpp
@@ -12,7 +12,8 @@
     return input == nullptr || input->is<StateMachineNumber>();
 }
 
-void ListenerNumberChange::perform(StateMachineInstance* stateMachineInstance) const {
+void ListenerNumberChange::perform(StateMachineInstance* stateMachineInstance,
+                                   Vec2D position) const {
     auto inputInstance = stateMachineInstance->input(inputId());
     if (inputInstance == nullptr) {
         return;
diff --git a/src/animation/listener_trigger_change.cpp b/src/animation/listener_trigger_change.cpp
index f1939e0..b601f04 100644
--- a/src/animation/listener_trigger_change.cpp
+++ b/src/animation/listener_trigger_change.cpp
@@ -12,7 +12,8 @@
     return input == nullptr || input->is<StateMachineTrigger>();
 }
 
-void ListenerTriggerChange::perform(StateMachineInstance* stateMachineInstance) const {
+void ListenerTriggerChange::perform(StateMachineInstance* stateMachineInstance,
+                                    Vec2D position) const {
     auto inputInstance = stateMachineInstance->input(inputId());
     if (inputInstance == nullptr) {
         return;
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp
index d7bbe98..20625a1 100644
--- a/src/animation/state_machine_instance.cpp
+++ b/src/animation/state_machine_instance.cpp
@@ -267,15 +267,15 @@
             // we're trying to trigger.
             if (hoverChange) {
                 if (isOver && listener->listenerType() == ListenerType::enter) {
-                    listener->performChanges(this);
+                    listener->performChanges(this, position);
                     markNeedsAdvance();
                 } else if (!isOver && listener->listenerType() == ListenerType::exit) {
-                    listener->performChanges(this);
+                    listener->performChanges(this, position);
                     markNeedsAdvance();
                 }
             }
             if (isOver && hitType == listener->listenerType()) {
-                listener->performChanges(this);
+                listener->performChanges(this, position);
                 markNeedsAdvance();
             }
         }
@@ -302,7 +302,7 @@
                     case ListenerType::up:
                         nestedStateMachine->pointerUp(nestedPosition);
                         break;
-                    case ListenerType::updateHover:
+                    case ListenerType::move:
                         nestedStateMachine->pointerMove(nestedPosition);
                         break;
                     default:
@@ -314,7 +314,7 @@
 }
 
 void StateMachineInstance::pointerMove(Vec2D position) {
-    updateListeners(position, ListenerType::updateHover);
+    updateListeners(position, ListenerType::move);
 }
 void StateMachineInstance::pointerDown(Vec2D position) {
     updateListeners(position, ListenerType::down);
diff --git a/src/animation/state_machine_listenable.cpp b/src/animation/state_machine_listener.cpp
similarity index 81%
rename from src/animation/state_machine_listenable.cpp
rename to src/animation/state_machine_listener.cpp
index 36e54b5..294143d 100644
--- a/src/animation/state_machine_listenable.cpp
+++ b/src/animation/state_machine_listener.cpp
@@ -9,9 +9,7 @@
 
 using namespace rive;
 
-void StateMachineListener::addInputChange(ListenerInputChange* inputChange) {
-    m_InputChanges.push_back(inputChange);
-}
+void StateMachineListener::addAction(ListenerAction* action) { m_Actions.push_back(action); }
 
 StatusCode StateMachineListener::import(ImportStack& importStack) {
     auto stateMachineImporter = importStack.latest<StateMachineImporter>(StateMachineBase::typeKey);
@@ -23,9 +21,9 @@
     return Super::import(importStack);
 }
 
-const ListenerInputChange* StateMachineListener::inputChange(size_t index) const {
-    if (index < m_InputChanges.size()) {
-        return m_InputChanges[index];
+const ListenerAction* StateMachineListener::action(size_t index) const {
+    if (index < m_Actions.size()) {
+        return m_Actions[index];
     }
     return nullptr;
 }
@@ -59,8 +57,9 @@
     return Super::onAddedClean(context);
 }
 
-void StateMachineListener::performChanges(StateMachineInstance* stateMachineInstance) const {
-    for (auto inputChange : m_InputChanges) {
-        inputChange->perform(stateMachineInstance);
+void StateMachineListener::performChanges(StateMachineInstance* stateMachineInstance,
+                                          Vec2D position) const {
+    for (auto action : m_Actions) {
+        action->perform(stateMachineInstance, position);
     }
 }
\ No newline at end of file
diff --git a/src/generated/animation/listener_align_target_base.cpp b/src/generated/animation/listener_align_target_base.cpp
new file mode 100644
index 0000000..9da8b5b
--- /dev/null
+++ b/src/generated/animation/listener_align_target_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/listener_align_target_base.hpp"
+#include "rive/animation/listener_align_target.hpp"
+
+using namespace rive;
+
+Core* ListenerAlignTargetBase::clone() const {
+    auto cloned = new ListenerAlignTarget();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/nested_bool_base.cpp b/src/generated/animation/nested_bool_base.cpp
new file mode 100644
index 0000000..315ebbd
--- /dev/null
+++ b/src/generated/animation/nested_bool_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/nested_bool_base.hpp"
+#include "rive/animation/nested_bool.hpp"
+
+using namespace rive;
+
+Core* NestedBoolBase::clone() const {
+    auto cloned = new NestedBool();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/nested_number_base.cpp b/src/generated/animation/nested_number_base.cpp
new file mode 100644
index 0000000..4a7fa1d
--- /dev/null
+++ b/src/generated/animation/nested_number_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/nested_number_base.hpp"
+#include "rive/animation/nested_number.hpp"
+
+using namespace rive;
+
+Core* NestedNumberBase::clone() const {
+    auto cloned = new NestedNumber();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/nested_trigger_base.cpp b/src/generated/animation/nested_trigger_base.cpp
new file mode 100644
index 0000000..44bb423
--- /dev/null
+++ b/src/generated/animation/nested_trigger_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/nested_trigger_base.hpp"
+#include "rive/animation/nested_trigger.hpp"
+
+using namespace rive;
+
+Core* NestedTriggerBase::clone() const {
+    auto cloned = new NestedTrigger();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/importers/state_machine_listener_importer.cpp b/src/importers/state_machine_listener_importer.cpp
index bf403af..e8ac8fc 100644
--- a/src/importers/state_machine_listener_importer.cpp
+++ b/src/importers/state_machine_listener_importer.cpp
@@ -6,8 +6,8 @@
 StateMachineListenerImporter::StateMachineListenerImporter(StateMachineListener* listener) :
     m_StateMachineListener(listener) {}
 
-void StateMachineListenerImporter::addInputChange(ListenerInputChange* change) {
-    m_StateMachineListener->addInputChange(change);
+void StateMachineListenerImporter::addAction(ListenerAction* action) {
+    m_StateMachineListener->addAction(action);
 }
 
 StatusCode StateMachineListenerImporter::resolve() { return StatusCode::Ok; }
\ No newline at end of file
diff --git a/test/state_machine_event_test.cpp b/test/state_machine_event_test.cpp
index 5e9b462..01e77ae 100644
--- a/test/state_machine_event_test.cpp
+++ b/test/state_machine_event_test.cpp
@@ -36,28 +36,31 @@
     auto target1 = artboard->resolve(listener1->targetId());
     REQUIRE(target1->is<rive::Node>());
     REQUIRE(target1->as<rive::Node>()->name() == "HandWickHit");
-    REQUIRE(listener1->inputChangeCount() == 1);
-    auto inputChange1 = listener1->inputChange(0);
+    REQUIRE(listener1->actionCount() == 1);
+    auto inputChange1 = listener1->action(0);
     REQUIRE(inputChange1 != nullptr);
-    REQUIRE(inputChange1->inputId() == 0);
+    REQUIRE(inputChange1->is<rive::ListenerInputChange>());
+    REQUIRE(inputChange1->as<rive::ListenerInputChange>()->inputId() == 0);
 
     auto listener2 = stateMachine->listener(1);
     auto target2 = artboard->resolve(listener2->targetId());
     REQUIRE(target2->is<rive::Node>());
     REQUIRE(target2->as<rive::Node>()->name() == "HandCannonHit");
-    REQUIRE(listener2->inputChangeCount() == 1);
-    auto inputChange2 = listener2->inputChange(0);
+    REQUIRE(listener2->actionCount() == 1);
+    auto inputChange2 = listener2->action(0);
     REQUIRE(inputChange2 != nullptr);
-    REQUIRE(inputChange2->inputId() == 1);
+    REQUIRE(inputChange2->is<rive::ListenerInputChange>());
+    REQUIRE(inputChange2->as<rive::ListenerInputChange>()->inputId() == 1);
 
     auto listener3 = stateMachine->listener(2);
     auto target3 = artboard->resolve(listener3->targetId());
     REQUIRE(target3->is<rive::Node>());
     REQUIRE(target3->as<rive::Node>()->name() == "HandHelmetHit");
-    REQUIRE(listener3->inputChangeCount() == 1);
-    auto inputChange3 = listener3->inputChange(0);
+    REQUIRE(listener3->actionCount() == 1);
+    auto inputChange3 = listener3->action(0);
     REQUIRE(inputChange3 != nullptr);
-    REQUIRE(inputChange3->inputId() == 2);
+    REQUIRE(inputChange3->is<rive::ListenerInputChange>());
+    REQUIRE(inputChange3->as<rive::ListenerInputChange>()->inputId() == 2);
 }
 
 TEST_CASE("hit testing via a state machine works", "[file]") {