Starting to load events and tests.
diff --git a/include/rive/animation/event_bool_change.hpp b/include/rive/animation/event_bool_change.hpp
new file mode 100644
index 0000000..79d3933
--- /dev/null
+++ b/include/rive/animation/event_bool_change.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_EVENT_BOOL_CHANGE_HPP_
+#define _RIVE_EVENT_BOOL_CHANGE_HPP_
+#include "rive/generated/animation/event_bool_change_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class EventBoolChange : public EventBoolChangeBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/event_input_change.hpp b/include/rive/animation/event_input_change.hpp
new file mode 100644
index 0000000..93e3796
--- /dev/null
+++ b/include/rive/animation/event_input_change.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_EVENT_INPUT_CHANGE_HPP_
+#define _RIVE_EVENT_INPUT_CHANGE_HPP_
+#include "rive/generated/animation/event_input_change_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class EventInputChange : public EventInputChangeBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/event_number_change.hpp b/include/rive/animation/event_number_change.hpp
new file mode 100644
index 0000000..27ac05f
--- /dev/null
+++ b/include/rive/animation/event_number_change.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_EVENT_NUMBER_CHANGE_HPP_
+#define _RIVE_EVENT_NUMBER_CHANGE_HPP_
+#include "rive/generated/animation/event_number_change_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class EventNumberChange : public EventNumberChangeBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/event_trigger_change.hpp b/include/rive/animation/event_trigger_change.hpp
new file mode 100644
index 0000000..b6245af
--- /dev/null
+++ b/include/rive/animation/event_trigger_change.hpp
@@ -0,0 +1,11 @@
+#ifndef _RIVE_EVENT_TRIGGER_CHANGE_HPP_
+#define _RIVE_EVENT_TRIGGER_CHANGE_HPP_
+#include "rive/generated/animation/event_trigger_change_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class EventTriggerChange : public EventTriggerChangeBase {
+    public:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/animation/state_machine.hpp b/include/rive/animation/state_machine.hpp
index 8f659ea..526dd4c 100644
--- a/include/rive/animation/state_machine.hpp
+++ b/include/rive/animation/state_machine.hpp
@@ -7,6 +7,7 @@
 namespace rive {
     class StateMachineLayer;
     class StateMachineInput;
+    class StateMachineEvent;
     class StateMachineImporter;
     class StateMachine : public StateMachineBase {
         friend class StateMachineImporter;
@@ -14,9 +15,11 @@
     private:
         std::vector<StateMachineLayer*> m_Layers;
         std::vector<StateMachineInput*> m_Inputs;
+        std::vector<StateMachineEvent*> m_Events;
 
         void addLayer(StateMachineLayer* layer);
         void addInput(StateMachineInput* input);
+        void addEvent(StateMachineEvent* event);
 
     public:
         ~StateMachine();
@@ -24,11 +27,13 @@
 
         size_t layerCount() const { return m_Layers.size(); }
         size_t inputCount() const { return m_Inputs.size(); }
+        size_t eventCount() const { return m_Events.size(); }
 
         const StateMachineInput* input(std::string name) const;
         const StateMachineInput* input(size_t index) const;
         const StateMachineLayer* layer(std::string name) const;
         const StateMachineLayer* layer(size_t index) const;
+        const StateMachineEvent* event(size_t index) const;
 
         StatusCode onAddedDirty(CoreContext* context) override;
         StatusCode onAddedClean(CoreContext* context) override;
diff --git a/include/rive/animation/state_machine_event.hpp b/include/rive/animation/state_machine_event.hpp
new file mode 100644
index 0000000..55a2644
--- /dev/null
+++ b/include/rive/animation/state_machine_event.hpp
@@ -0,0 +1,12 @@
+#ifndef _RIVE_STATE_MACHINE_EVENT_HPP_
+#define _RIVE_STATE_MACHINE_EVENT_HPP_
+#include "rive/generated/animation/state_machine_event_base.hpp"
+#include <stdio.h>
+namespace rive {
+    class StateMachineEvent : public StateMachineEventBase {
+    public:
+        StatusCode import(ImportStack& importStack) override;
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/event_bool_change_base.hpp b/include/rive/generated/animation/event_bool_change_base.hpp
new file mode 100644
index 0000000..13d95ad
--- /dev/null
+++ b/include/rive/generated/animation/event_bool_change_base.hpp
@@ -0,0 +1,62 @@
+#ifndef _RIVE_EVENT_BOOL_CHANGE_BASE_HPP_
+#define _RIVE_EVENT_BOOL_CHANGE_BASE_HPP_
+#include "rive/animation/event_input_change.hpp"
+#include "rive/core/field_types/core_bool_type.hpp"
+namespace rive {
+    class EventBoolChangeBase : public EventInputChange {
+    protected:
+        typedef EventInputChange Super;
+
+    public:
+        static const uint16_t typeKey = 117;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case EventBoolChangeBase::typeKey:
+                case EventInputChangeBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t valuePropertyKey = 228;
+
+    private:
+        bool m_Value = true;
+
+    public:
+        inline bool value() const { return m_Value; }
+        void value(bool value) {
+            if (m_Value == value) {
+                return;
+            }
+            m_Value = value;
+            valueChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const EventBoolChangeBase& object) {
+            m_Value = object.m_Value;
+            EventInputChange::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case valuePropertyKey:
+                    m_Value = CoreBoolType::deserialize(reader);
+                    return true;
+            }
+            return EventInputChange::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void valueChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/event_input_change_base.hpp b/include/rive/generated/animation/event_input_change_base.hpp
new file mode 100644
index 0000000..61f30d1
--- /dev/null
+++ b/include/rive/generated/animation/event_input_change_base.hpp
@@ -0,0 +1,57 @@
+#ifndef _RIVE_EVENT_INPUT_CHANGE_BASE_HPP_
+#define _RIVE_EVENT_INPUT_CHANGE_BASE_HPP_
+#include "rive/core.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive {
+    class EventInputChangeBase : public Core {
+    protected:
+        typedef Core Super;
+
+    public:
+        static const uint16_t typeKey = 116;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case EventInputChangeBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t inputIdPropertyKey = 227;
+
+    private:
+        int m_InputId = -1;
+
+    public:
+        inline int inputId() const { return m_InputId; }
+        void inputId(int value) {
+            if (m_InputId == value) {
+                return;
+            }
+            m_InputId = value;
+            inputIdChanged();
+        }
+
+        void copy(const EventInputChangeBase& object) { m_InputId = object.m_InputId; }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case inputIdPropertyKey:
+                    m_InputId = CoreUintType::deserialize(reader);
+                    return true;
+            }
+            return false;
+        }
+
+    protected:
+        virtual void inputIdChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/event_number_change_base.hpp b/include/rive/generated/animation/event_number_change_base.hpp
new file mode 100644
index 0000000..4c647ed
--- /dev/null
+++ b/include/rive/generated/animation/event_number_change_base.hpp
@@ -0,0 +1,62 @@
+#ifndef _RIVE_EVENT_NUMBER_CHANGE_BASE_HPP_
+#define _RIVE_EVENT_NUMBER_CHANGE_BASE_HPP_
+#include "rive/animation/event_input_change.hpp"
+#include "rive/core/field_types/core_double_type.hpp"
+namespace rive {
+    class EventNumberChangeBase : public EventInputChange {
+    protected:
+        typedef EventInputChange Super;
+
+    public:
+        static const uint16_t typeKey = 118;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case EventNumberChangeBase::typeKey:
+                case EventInputChangeBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t valuePropertyKey = 229;
+
+    private:
+        float m_Value = 0.0f;
+
+    public:
+        inline float value() const { return m_Value; }
+        void value(float value) {
+            if (m_Value == value) {
+                return;
+            }
+            m_Value = value;
+            valueChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const EventNumberChangeBase& object) {
+            m_Value = object.m_Value;
+            EventInputChange::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case valuePropertyKey:
+                    m_Value = CoreDoubleType::deserialize(reader);
+                    return true;
+            }
+            return EventInputChange::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void valueChanged() {}
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/event_trigger_change_base.hpp b/include/rive/generated/animation/event_trigger_change_base.hpp
new file mode 100644
index 0000000..7232825
--- /dev/null
+++ b/include/rive/generated/animation/event_trigger_change_base.hpp
@@ -0,0 +1,32 @@
+#ifndef _RIVE_EVENT_TRIGGER_CHANGE_BASE_HPP_
+#define _RIVE_EVENT_TRIGGER_CHANGE_BASE_HPP_
+#include "rive/animation/event_input_change.hpp"
+namespace rive {
+    class EventTriggerChangeBase : public EventInputChange {
+    protected:
+        typedef EventInputChange Super;
+
+    public:
+        static const uint16_t typeKey = 115;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case EventTriggerChangeBase::typeKey:
+                case EventInputChangeBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        Core* clone() const override;
+
+    protected:
+    };
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/generated/animation/state_machine_event_base.hpp b/include/rive/generated/animation/state_machine_event_base.hpp
new file mode 100644
index 0000000..2aa9f01
--- /dev/null
+++ b/include/rive/generated/animation/state_machine_event_base.hpp
@@ -0,0 +1,78 @@
+#ifndef _RIVE_STATE_MACHINE_EVENT_BASE_HPP_
+#define _RIVE_STATE_MACHINE_EVENT_BASE_HPP_
+#include "rive/animation/state_machine_component.hpp"
+#include "rive/core/field_types/core_uint_type.hpp"
+namespace rive {
+    class StateMachineEventBase : public StateMachineComponent {
+    protected:
+        typedef StateMachineComponent Super;
+
+    public:
+        static const uint16_t typeKey = 114;
+
+        /// Helper to quickly determine if a core object extends another without RTTI
+        /// at runtime.
+        bool isTypeOf(uint16_t typeKey) const override {
+            switch (typeKey) {
+                case StateMachineEventBase::typeKey:
+                case StateMachineComponentBase::typeKey:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
+        uint16_t coreType() const override { return typeKey; }
+
+        static const uint16_t targetIdPropertyKey = 224;
+        static const uint16_t eventTypeValuePropertyKey = 225;
+
+    private:
+        int m_TargetId = 0;
+        int m_EventTypeValue = 0;
+
+    public:
+        inline int targetId() const { return m_TargetId; }
+        void targetId(int value) {
+            if (m_TargetId == value) {
+                return;
+            }
+            m_TargetId = value;
+            targetIdChanged();
+        }
+
+        inline int eventTypeValue() const { return m_EventTypeValue; }
+        void eventTypeValue(int value) {
+            if (m_EventTypeValue == value) {
+                return;
+            }
+            m_EventTypeValue = value;
+            eventTypeValueChanged();
+        }
+
+        Core* clone() const override;
+        void copy(const StateMachineEventBase& object) {
+            m_TargetId = object.m_TargetId;
+            m_EventTypeValue = object.m_EventTypeValue;
+            StateMachineComponent::copy(object);
+        }
+
+        bool deserialize(uint16_t propertyKey, BinaryReader& reader) override {
+            switch (propertyKey) {
+                case targetIdPropertyKey:
+                    m_TargetId = CoreUintType::deserialize(reader);
+                    return true;
+                case eventTypeValuePropertyKey:
+                    m_EventTypeValue = CoreUintType::deserialize(reader);
+                    return true;
+            }
+            return StateMachineComponent::deserialize(propertyKey, reader);
+        }
+
+    protected:
+        virtual void targetIdChanged() {}
+        virtual void eventTypeValueChanged() {}
+    };
+} // 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 7c78ec2..54f9bc5 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -12,6 +12,10 @@
 #include "rive/animation/blend_state_transition.hpp"
 #include "rive/animation/cubic_interpolator.hpp"
 #include "rive/animation/entry_state.hpp"
+#include "rive/animation/event_bool_change.hpp"
+#include "rive/animation/event_input_change.hpp"
+#include "rive/animation/event_number_change.hpp"
+#include "rive/animation/event_trigger_change.hpp"
 #include "rive/animation/exit_state.hpp"
 #include "rive/animation/keyed_object.hpp"
 #include "rive/animation/keyed_property.hpp"
@@ -29,6 +33,7 @@
 #include "rive/animation/state_machine.hpp"
 #include "rive/animation/state_machine_bool.hpp"
 #include "rive/animation/state_machine_component.hpp"
+#include "rive/animation/state_machine_event.hpp"
 #include "rive/animation/state_machine_input.hpp"
 #include "rive/animation/state_machine_layer.hpp"
 #include "rive/animation/state_machine_layer_component.hpp"
@@ -128,10 +133,14 @@
                     return new Node();
                 case NestedArtboardBase::typeKey:
                     return new NestedArtboard();
+                case EventNumberChangeBase::typeKey:
+                    return new EventNumberChange();
                 case NestedSimpleAnimationBase::typeKey:
                     return new NestedSimpleAnimation();
                 case AnimationStateBase::typeKey:
                     return new AnimationState();
+                case StateMachineEventBase::typeKey:
+                    return new StateMachineEvent();
                 case KeyedObjectBase::typeKey:
                     return new KeyedObject();
                 case BlendAnimationDirectBase::typeKey:
@@ -148,8 +157,12 @@
                     return new KeyFrameBool();
                 case TransitionNumberConditionBase::typeKey:
                     return new TransitionNumberCondition();
+                case EventBoolChangeBase::typeKey:
+                    return new EventBoolChange();
                 case AnyStateBase::typeKey:
                     return new AnyState();
+                case EventTriggerChangeBase::typeKey:
+                    return new EventTriggerChange();
                 case StateMachineLayerBase::typeKey:
                     return new StateMachineLayer();
                 case AnimationBase::typeKey:
@@ -318,9 +331,18 @@
                 case NestedAnimationBase::animationIdPropertyKey:
                     object->as<NestedAnimationBase>()->animationId(value);
                     break;
+                case EventInputChangeBase::inputIdPropertyKey:
+                    object->as<EventInputChangeBase>()->inputId(value);
+                    break;
                 case AnimationStateBase::animationIdPropertyKey:
                     object->as<AnimationStateBase>()->animationId(value);
                     break;
+                case StateMachineEventBase::targetIdPropertyKey:
+                    object->as<StateMachineEventBase>()->targetId(value);
+                    break;
+                case StateMachineEventBase::eventTypeValuePropertyKey:
+                    object->as<StateMachineEventBase>()->eventTypeValue(value);
+                    break;
                 case KeyedObjectBase::objectIdPropertyKey:
                     object->as<KeyedObjectBase>()->objectId(value);
                     break;
@@ -484,6 +506,9 @@
                 case NodeBase::yPropertyKey:
                     object->as<NodeBase>()->y(value);
                     break;
+                case EventNumberChangeBase::valuePropertyKey:
+                    object->as<EventNumberChangeBase>()->value(value);
+                    break;
                 case NestedLinearAnimationBase::mixPropertyKey:
                     object->as<NestedLinearAnimationBase>()->mix(value);
                     break;
@@ -725,6 +750,9 @@
                 case KeyFrameBoolBase::valuePropertyKey:
                     object->as<KeyFrameBoolBase>()->value(value);
                     break;
+                case EventBoolChangeBase::valuePropertyKey:
+                    object->as<EventBoolChangeBase>()->value(value);
+                    break;
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                     object->as<LinearAnimationBase>()->enableWorkArea(value);
                     break;
@@ -805,8 +833,14 @@
                     return object->as<NestedArtboardBase>()->artboardId();
                 case NestedAnimationBase::animationIdPropertyKey:
                     return object->as<NestedAnimationBase>()->animationId();
+                case EventInputChangeBase::inputIdPropertyKey:
+                    return object->as<EventInputChangeBase>()->inputId();
                 case AnimationStateBase::animationIdPropertyKey:
                     return object->as<AnimationStateBase>()->animationId();
+                case StateMachineEventBase::targetIdPropertyKey:
+                    return object->as<StateMachineEventBase>()->targetId();
+                case StateMachineEventBase::eventTypeValuePropertyKey:
+                    return object->as<StateMachineEventBase>()->eventTypeValue();
                 case KeyedObjectBase::objectIdPropertyKey:
                     return object->as<KeyedObjectBase>()->objectId();
                 case BlendAnimationBase::animationIdPropertyKey:
@@ -918,6 +952,8 @@
                     return object->as<NodeBase>()->x();
                 case NodeBase::yPropertyKey:
                     return object->as<NodeBase>()->y();
+                case EventNumberChangeBase::valuePropertyKey:
+                    return object->as<EventNumberChangeBase>()->value();
                 case NestedLinearAnimationBase::mixPropertyKey:
                     return object->as<NestedLinearAnimationBase>()->mix();
                 case NestedSimpleAnimationBase::speedPropertyKey:
@@ -1081,6 +1117,8 @@
                     return object->as<NestedSimpleAnimationBase>()->isPlaying();
                 case KeyFrameBoolBase::valuePropertyKey:
                     return object->as<KeyFrameBoolBase>()->value();
+                case EventBoolChangeBase::valuePropertyKey:
+                    return object->as<EventBoolChangeBase>()->value();
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                     return object->as<LinearAnimationBase>()->enableWorkArea();
                 case StateMachineBoolBase::valuePropertyKey:
@@ -1131,7 +1169,10 @@
                 case DrawableBase::drawableFlagsPropertyKey:
                 case NestedArtboardBase::artboardIdPropertyKey:
                 case NestedAnimationBase::animationIdPropertyKey:
+                case EventInputChangeBase::inputIdPropertyKey:
                 case AnimationStateBase::animationIdPropertyKey:
+                case StateMachineEventBase::targetIdPropertyKey:
+                case StateMachineEventBase::eventTypeValuePropertyKey:
                 case KeyedObjectBase::objectIdPropertyKey:
                 case BlendAnimationBase::animationIdPropertyKey:
                 case BlendAnimationDirectBase::inputIdPropertyKey:
@@ -1186,6 +1227,7 @@
                 case TransformComponentBase::scaleYPropertyKey:
                 case NodeBase::xPropertyKey:
                 case NodeBase::yPropertyKey:
+                case EventNumberChangeBase::valuePropertyKey:
                 case NestedLinearAnimationBase::mixPropertyKey:
                 case NestedSimpleAnimationBase::speedPropertyKey:
                 case StateMachineNumberBase::valuePropertyKey:
@@ -1266,6 +1308,7 @@
                 case IKConstraintBase::invertDirectionPropertyKey:
                 case NestedSimpleAnimationBase::isPlayingPropertyKey:
                 case KeyFrameBoolBase::valuePropertyKey:
+                case EventBoolChangeBase::valuePropertyKey:
                 case LinearAnimationBase::enableWorkAreaPropertyKey:
                 case StateMachineBoolBase::valuePropertyKey:
                 case ShapePaintBase::isVisiblePropertyKey:
diff --git a/include/rive/importers/state_machine_importer.hpp b/include/rive/importers/state_machine_importer.hpp
index 963223c..cbfabfe 100644
--- a/include/rive/importers/state_machine_importer.hpp
+++ b/include/rive/importers/state_machine_importer.hpp
@@ -6,6 +6,7 @@
 namespace rive {
     class StateMachineInput;
     class StateMachineLayer;
+    class StateMachineEvent;
     class StateMachine;
     class StateMachineImporter : public ImportStackObject {
     private:
@@ -16,6 +17,7 @@
         const StateMachine* stateMachine() const { return m_StateMachine; }
         void addLayer(StateMachineLayer* layer);
         void addInput(StateMachineInput* input);
+        void addEvent(StateMachineEvent* event);
         StatusCode resolve() override;
         bool readNullObject() override;
     };
diff --git a/src/animation/state_machine.cpp b/src/animation/state_machine.cpp
index 8a5ef31..a767143 100644
--- a/src/animation/state_machine.cpp
+++ b/src/animation/state_machine.cpp
@@ -3,6 +3,7 @@
 #include "rive/importers/artboard_importer.hpp"
 #include "rive/animation/state_machine_layer.hpp"
 #include "rive/animation/state_machine_input.hpp"
+#include "rive/animation/state_machine_event.hpp"
 
 using namespace rive;
 
@@ -13,6 +14,9 @@
     for (auto object : m_Layers) {
         delete object;
     }
+    for (auto object : m_Events) {
+        delete object;
+    }
 }
 
 StatusCode StateMachine::onAddedDirty(CoreContext* context) {
@@ -27,6 +31,11 @@
             return code;
         }
     }
+    for (auto object : m_Events) {
+        if ((code = object->onAddedDirty(context)) != StatusCode::Ok) {
+            return code;
+        }
+    }
     return StatusCode::Ok;
 }
 
@@ -42,6 +51,11 @@
             return code;
         }
     }
+    for (auto object : m_Events) {
+        if ((code = object->onAddedClean(context)) != StatusCode::Ok) {
+            return code;
+        }
+    }
     return StatusCode::Ok;
 }
 
@@ -57,6 +71,7 @@
 void StateMachine::addLayer(StateMachineLayer* layer) { m_Layers.push_back(layer); }
 
 void StateMachine::addInput(StateMachineInput* input) { m_Inputs.push_back(input); }
+void StateMachine::addEvent(StateMachineEvent* event) { m_Events.push_back(event); }
 
 const StateMachineInput* StateMachine::input(std::string name) const {
     for (auto input : m_Inputs) {
@@ -88,4 +103,11 @@
         return m_Layers[index];
     }
     return nullptr;
+}
+
+const StateMachineEvent* StateMachine::event(size_t index) const {
+    if (index >= 0 && index < m_Events.size()) {
+        return m_Events[index];
+    }
+    return nullptr;
 }
\ No newline at end of file
diff --git a/src/animation/state_machine_event.cpp b/src/animation/state_machine_event.cpp
new file mode 100644
index 0000000..d14c0ab
--- /dev/null
+++ b/src/animation/state_machine_event.cpp
@@ -0,0 +1,15 @@
+#include "rive/animation/state_machine_event.hpp"
+#include "rive/importers/import_stack.hpp"
+#include "rive/importers/state_machine_importer.hpp"
+#include "rive/generated/animation/state_machine_base.hpp"
+
+using namespace rive;
+
+StatusCode StateMachineEvent::import(ImportStack& importStack) {
+    auto stateMachineImporter = importStack.latest<StateMachineImporter>(StateMachineBase::typeKey);
+    if (stateMachineImporter == nullptr) {
+        return StatusCode::MissingObject;
+    }
+    stateMachineImporter->addEvent(this);
+    return Super::import(importStack);
+}
diff --git a/src/generated/animation/event_bool_change_base.cpp b/src/generated/animation/event_bool_change_base.cpp
new file mode 100644
index 0000000..722a754
--- /dev/null
+++ b/src/generated/animation/event_bool_change_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/event_bool_change_base.hpp"
+#include "rive/animation/event_bool_change.hpp"
+
+using namespace rive;
+
+Core* EventBoolChangeBase::clone() const {
+    auto cloned = new EventBoolChange();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/event_number_change_base.cpp b/src/generated/animation/event_number_change_base.cpp
new file mode 100644
index 0000000..64eb85a
--- /dev/null
+++ b/src/generated/animation/event_number_change_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/event_number_change_base.hpp"
+#include "rive/animation/event_number_change.hpp"
+
+using namespace rive;
+
+Core* EventNumberChangeBase::clone() const {
+    auto cloned = new EventNumberChange();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/event_trigger_change_base.cpp b/src/generated/animation/event_trigger_change_base.cpp
new file mode 100644
index 0000000..4a78dfe
--- /dev/null
+++ b/src/generated/animation/event_trigger_change_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/event_trigger_change_base.hpp"
+#include "rive/animation/event_trigger_change.hpp"
+
+using namespace rive;
+
+Core* EventTriggerChangeBase::clone() const {
+    auto cloned = new EventTriggerChange();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/generated/animation/state_machine_event_base.cpp b/src/generated/animation/state_machine_event_base.cpp
new file mode 100644
index 0000000..0ba8a2b
--- /dev/null
+++ b/src/generated/animation/state_machine_event_base.cpp
@@ -0,0 +1,10 @@
+#include "rive/generated/animation/state_machine_event_base.hpp"
+#include "rive/animation/state_machine_event.hpp"
+
+using namespace rive;
+
+Core* StateMachineEventBase::clone() const {
+    auto cloned = new StateMachineEvent();
+    cloned->copy(*this);
+    return cloned;
+}
diff --git a/src/importers/state_machine_importer.cpp b/src/importers/state_machine_importer.cpp
index 6acd11d..c223e6a 100644
--- a/src/importers/state_machine_importer.cpp
+++ b/src/importers/state_machine_importer.cpp
@@ -9,6 +9,8 @@
 
 void StateMachineImporter::addInput(StateMachineInput* input) { m_StateMachine->addInput(input); }
 
+void StateMachineImporter::addEvent(StateMachineEvent* event) { m_StateMachine->addEvent(event); }
+
 bool StateMachineImporter::readNullObject() {
     // Hard assumption that we won't add new layer types...
     m_StateMachine->addInput(nullptr);
diff --git a/test/assets/bullet_man.riv b/test/assets/bullet_man.riv
new file mode 100644
index 0000000..63e2a15
--- /dev/null
+++ b/test/assets/bullet_man.riv
Binary files differ
diff --git a/test/state_machine_event_test.cpp b/test/state_machine_event_test.cpp
new file mode 100644
index 0000000..4e5389c
--- /dev/null
+++ b/test/state_machine_event_test.cpp
@@ -0,0 +1,30 @@
+#include <rive/core/binary_reader.hpp>
+#include <rive/file.hpp>
+#include <rive/animation/state_machine_bool.hpp>
+#include <rive/animation/state_machine_layer.hpp>
+#include <rive/animation/animation_state.hpp>
+#include <rive/animation/entry_state.hpp>
+#include <rive/animation/state_transition.hpp>
+#include <rive/animation/state_machine_instance.hpp>
+#include <rive/animation/state_machine_input_instance.hpp>
+#include <rive/animation/blend_state_1d.hpp>
+#include <rive/animation/blend_animation_1d.hpp>
+#include <rive/animation/blend_state_direct.hpp>
+#include <rive/animation/blend_state_transition.hpp>
+#include "catch.hpp"
+#include "rive_file_reader.hpp"
+#include <cstdio>
+
+TEST_CASE("file with state machine events be read", "[file]") {
+    RiveFileReader reader("../../test/assets/bullet_man.riv");
+
+    auto artboard = reader.file()->artboard("Bullet Man");
+    REQUIRE(artboard != nullptr);
+    REQUIRE(artboard->stateMachineCount() == 1);
+
+    auto stateMachine = artboard->stateMachine(0);
+    REQUIRE(stateMachine != nullptr);
+
+    REQUIRE(stateMachine->eventCount() == 3);
+    REQUIRE(stateMachine->inputCount() == 4);
+}