Add support for optional clipping to artboard.
diff --git a/dev/defs/artboard.json b/dev/defs/artboard.json
index 25e825d..05782ba 100644
--- a/dev/defs/artboard.json
+++ b/dev/defs/artboard.json
@@ -4,8 +4,17 @@
     "int": 1,
     "string": "artboard"
   },
-  "extends": "container_component.json",
+  "extends": "world_transform_component.json",
   "properties": {
+    "clip": {
+      "type": "bool",
+      "initialValue": "true",
+      "key": {
+        "int": 196,
+        "string": "clip"
+      },
+      "description": "True when the artboard bounds clip its contents."
+    },
     "width": {
       "type": "double",
       "initialValue": "0",
diff --git a/dev/defs/backboard.json b/dev/defs/backboard.json
index d2b1519..ea19b83 100644
--- a/dev/defs/backboard.json
+++ b/dev/defs/backboard.json
@@ -23,7 +23,7 @@
         "int": 44,
         "string": "mainArtboardId"
       },
-      "description": "Identifier used to track the  main artboard (this is the default one that shows up in runtimes unless specified).",
+      "description": "Identifier used to track the main artboard (this is the default one that shows up in runtimes unless specified).",
       "runtime": false
     },
     "colorValue": {
diff --git a/dev/defs/transform_component.json b/dev/defs/transform_component.json
index 2e1ef05..084705f 100644
--- a/dev/defs/transform_component.json
+++ b/dev/defs/transform_component.json
@@ -5,7 +5,7 @@
     "string": "transformcomponent"
   },
   "abstract": true,
-  "extends": "container_component.json",
+  "extends": "world_transform_component.json",
   "properties": {
     "rotation": {
       "type": "double",
@@ -35,15 +35,6 @@
         "int": 17,
         "string": "sy"
       }
-    },
-    "opacity": {
-      "type": "double",
-      "initialValue": "1",
-      "animates": true,
-      "key": {
-        "int": 18,
-        "string": "opacity"
-      }
     }
   }
 }
\ No newline at end of file
diff --git a/dev/defs/world_transform_component.json b/dev/defs/world_transform_component.json
new file mode 100644
index 0000000..249706b
--- /dev/null
+++ b/dev/defs/world_transform_component.json
@@ -0,0 +1,20 @@
+{
+  "name": "WorldTransformComponent",
+  "key": {
+    "int": 91,
+    "string": "worldtransformcomponent"
+  },
+  "abstract": true,
+  "extends": "container_component.json",
+  "properties": {
+    "opacity": {
+      "type": "double",
+      "initialValue": "1",
+      "animates": true,
+      "key": {
+        "int": 18,
+        "string": "opacity"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/include/rive/generated/artboard_base.hpp b/include/rive/generated/artboard_base.hpp
index e6229bb..87b4e2f 100644
--- a/include/rive/generated/artboard_base.hpp
+++ b/include/rive/generated/artboard_base.hpp
@@ -1,13 +1,14 @@
 #ifndef _RIVE_ARTBOARD_BASE_HPP_
 #define _RIVE_ARTBOARD_BASE_HPP_
-#include "rive/container_component.hpp"
+#include "rive/core/field_types/core_bool_type.hpp"
 #include "rive/core/field_types/core_double_type.hpp"
+#include "rive/world_transform_component.hpp"
 namespace rive
 {
-	class ArtboardBase : public ContainerComponent
+	class ArtboardBase : public WorldTransformComponent
 	{
 	protected:
-		typedef ContainerComponent Super;
+		typedef WorldTransformComponent Super;
 
 	public:
 		static const uint16_t typeKey = 1;
@@ -19,6 +20,7 @@
 			switch (typeKey)
 			{
 				case ArtboardBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
@@ -29,6 +31,7 @@
 
 		uint16_t coreType() const override { return typeKey; }
 
+		static const uint16_t clipPropertyKey = 196;
 		static const uint16_t widthPropertyKey = 7;
 		static const uint16_t heightPropertyKey = 8;
 		static const uint16_t xPropertyKey = 9;
@@ -37,6 +40,7 @@
 		static const uint16_t originYPropertyKey = 12;
 
 	private:
+		bool m_Clip = true;
 		float m_Width = 0.0f;
 		float m_Height = 0.0f;
 		float m_X = 0.0f;
@@ -44,6 +48,17 @@
 		float m_OriginX = 0.0f;
 		float m_OriginY = 0.0f;
 	public:
+		inline bool clip() const { return m_Clip; }
+		void clip(bool value)
+		{
+			if (m_Clip == value)
+			{
+				return;
+			}
+			m_Clip = value;
+			clipChanged();
+		}
+
 		inline float width() const { return m_Width; }
 		void width(float value)
 		{
@@ -113,19 +128,23 @@
 		Core* clone() const override;
 		void copy(const ArtboardBase& object)
 		{
+			m_Clip = object.m_Clip;
 			m_Width = object.m_Width;
 			m_Height = object.m_Height;
 			m_X = object.m_X;
 			m_Y = object.m_Y;
 			m_OriginX = object.m_OriginX;
 			m_OriginY = object.m_OriginY;
-			ContainerComponent::copy(object);
+			WorldTransformComponent::copy(object);
 		}
 
 		bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
 		{
 			switch (propertyKey)
 			{
+				case clipPropertyKey:
+					m_Clip = CoreBoolType::deserialize(reader);
+					return true;
 				case widthPropertyKey:
 					m_Width = CoreDoubleType::deserialize(reader);
 					return true;
@@ -145,10 +164,11 @@
 					m_OriginY = CoreDoubleType::deserialize(reader);
 					return true;
 			}
-			return ContainerComponent::deserialize(propertyKey, reader);
+			return WorldTransformComponent::deserialize(propertyKey, reader);
 		}
 
 	protected:
+		virtual void clipChanged() {}
 		virtual void widthChanged() {}
 		virtual void heightChanged() {}
 		virtual void xChanged() {}
diff --git a/include/rive/generated/bones/bone_base.hpp b/include/rive/generated/bones/bone_base.hpp
index e6df26e..b4ce7a5 100644
--- a/include/rive/generated/bones/bone_base.hpp
+++ b/include/rive/generated/bones/bone_base.hpp
@@ -21,6 +21,7 @@
 				case BoneBase::typeKey:
 				case SkeletalComponentBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/bones/root_bone_base.hpp b/include/rive/generated/bones/root_bone_base.hpp
index 8c869ef..a7aa313 100644
--- a/include/rive/generated/bones/root_bone_base.hpp
+++ b/include/rive/generated/bones/root_bone_base.hpp
@@ -22,6 +22,7 @@
 				case BoneBase::typeKey:
 				case SkeletalComponentBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/bones/skeletal_component_base.hpp b/include/rive/generated/bones/skeletal_component_base.hpp
index f31fe37..73b7ec8 100644
--- a/include/rive/generated/bones/skeletal_component_base.hpp
+++ b/include/rive/generated/bones/skeletal_component_base.hpp
@@ -19,6 +19,7 @@
 			{
 				case SkeletalComponentBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp
index dde79f7..8c6d1a4 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -87,6 +87,7 @@
 #include "rive/shapes/straight_vertex.hpp"
 #include "rive/shapes/triangle.hpp"
 #include "rive/transform_component.hpp"
+#include "rive/world_transform_component.hpp"
 namespace rive
 {
 	class CoreRegistry
@@ -489,6 +490,9 @@
 				case TrimPathBase::offsetPropertyKey:
 					object->as<TrimPathBase>()->offset(value);
 					break;
+				case WorldTransformComponentBase::opacityPropertyKey:
+					object->as<WorldTransformComponentBase>()->opacity(value);
+					break;
 				case TransformComponentBase::rotationPropertyKey:
 					object->as<TransformComponentBase>()->rotation(value);
 					break;
@@ -498,9 +502,6 @@
 				case TransformComponentBase::scaleYPropertyKey:
 					object->as<TransformComponentBase>()->scaleY(value);
 					break;
-				case TransformComponentBase::opacityPropertyKey:
-					object->as<TransformComponentBase>()->opacity(value);
-					break;
 				case NodeBase::xPropertyKey:
 					object->as<NodeBase>()->x(value);
 					break;
@@ -695,6 +696,9 @@
 				case ClippingShapeBase::isVisiblePropertyKey:
 					object->as<ClippingShapeBase>()->isVisible(value);
 					break;
+				case ArtboardBase::clipPropertyKey:
+					object->as<ArtboardBase>()->clip(value);
+					break;
 			}
 		}
 		static void setColor(Core* object, int propertyKey, int value)
@@ -900,14 +904,14 @@
 					return object->as<TrimPathBase>()->end();
 				case TrimPathBase::offsetPropertyKey:
 					return object->as<TrimPathBase>()->offset();
+				case WorldTransformComponentBase::opacityPropertyKey:
+					return object->as<WorldTransformComponentBase>()->opacity();
 				case TransformComponentBase::rotationPropertyKey:
 					return object->as<TransformComponentBase>()->rotation();
 				case TransformComponentBase::scaleXPropertyKey:
 					return object->as<TransformComponentBase>()->scaleX();
 				case TransformComponentBase::scaleYPropertyKey:
 					return object->as<TransformComponentBase>()->scaleY();
-				case TransformComponentBase::opacityPropertyKey:
-					return object->as<TransformComponentBase>()->opacity();
 				case NodeBase::xPropertyKey:
 					return object->as<NodeBase>()->x();
 				case NodeBase::yPropertyKey:
@@ -1046,6 +1050,8 @@
 					return object->as<RectangleBase>()->linkCornerRadius();
 				case ClippingShapeBase::isVisiblePropertyKey:
 					return object->as<ClippingShapeBase>()->isVisible();
+				case ArtboardBase::clipPropertyKey:
+					return object->as<ArtboardBase>()->clip();
 			}
 			return false;
 		}
@@ -1148,10 +1154,10 @@
 				case TrimPathBase::startPropertyKey:
 				case TrimPathBase::endPropertyKey:
 				case TrimPathBase::offsetPropertyKey:
+				case WorldTransformComponentBase::opacityPropertyKey:
 				case TransformComponentBase::rotationPropertyKey:
 				case TransformComponentBase::scaleXPropertyKey:
 				case TransformComponentBase::scaleYPropertyKey:
-				case TransformComponentBase::opacityPropertyKey:
 				case NodeBase::xPropertyKey:
 				case NodeBase::yPropertyKey:
 				case PathVertexBase::xPropertyKey:
@@ -1214,6 +1220,7 @@
 				case PointsPathBase::isClosedPropertyKey:
 				case RectangleBase::linkCornerRadiusPropertyKey:
 				case ClippingShapeBase::isVisiblePropertyKey:
+				case ArtboardBase::clipPropertyKey:
 					return CoreBoolType::id;
 				case KeyFrameColorBase::valuePropertyKey:
 				case SolidColorBase::colorValuePropertyKey:
diff --git a/include/rive/generated/drawable_base.hpp b/include/rive/generated/drawable_base.hpp
index c545f1f..b3ee959 100644
--- a/include/rive/generated/drawable_base.hpp
+++ b/include/rive/generated/drawable_base.hpp
@@ -21,6 +21,7 @@
 				case DrawableBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/node_base.hpp b/include/rive/generated/node_base.hpp
index 1bcbb43..fbd26c3 100644
--- a/include/rive/generated/node_base.hpp
+++ b/include/rive/generated/node_base.hpp
@@ -20,6 +20,7 @@
 			{
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/ellipse_base.hpp b/include/rive/generated/shapes/ellipse_base.hpp
index ad90986..29d3b0f 100644
--- a/include/rive/generated/shapes/ellipse_base.hpp
+++ b/include/rive/generated/shapes/ellipse_base.hpp
@@ -22,6 +22,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/parametric_path_base.hpp b/include/rive/generated/shapes/parametric_path_base.hpp
index 1c4ef80..80a84f2 100644
--- a/include/rive/generated/shapes/parametric_path_base.hpp
+++ b/include/rive/generated/shapes/parametric_path_base.hpp
@@ -22,6 +22,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/path_base.hpp b/include/rive/generated/shapes/path_base.hpp
index 6138190..12aa10f 100644
--- a/include/rive/generated/shapes/path_base.hpp
+++ b/include/rive/generated/shapes/path_base.hpp
@@ -21,6 +21,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/points_path_base.hpp b/include/rive/generated/shapes/points_path_base.hpp
index 5bf78d8..dfa8692 100644
--- a/include/rive/generated/shapes/points_path_base.hpp
+++ b/include/rive/generated/shapes/points_path_base.hpp
@@ -22,6 +22,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/polygon_base.hpp b/include/rive/generated/shapes/polygon_base.hpp
index dfb3f84..899f0c9 100644
--- a/include/rive/generated/shapes/polygon_base.hpp
+++ b/include/rive/generated/shapes/polygon_base.hpp
@@ -24,6 +24,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/rectangle_base.hpp b/include/rive/generated/shapes/rectangle_base.hpp
index 697f2ed..d37bbaa 100644
--- a/include/rive/generated/shapes/rectangle_base.hpp
+++ b/include/rive/generated/shapes/rectangle_base.hpp
@@ -24,6 +24,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/shape_base.hpp b/include/rive/generated/shapes/shape_base.hpp
index a705749..7efb26f 100644
--- a/include/rive/generated/shapes/shape_base.hpp
+++ b/include/rive/generated/shapes/shape_base.hpp
@@ -21,6 +21,7 @@
 				case DrawableBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/star_base.hpp b/include/rive/generated/shapes/star_base.hpp
index ae0d615..c72ff49 100644
--- a/include/rive/generated/shapes/star_base.hpp
+++ b/include/rive/generated/shapes/star_base.hpp
@@ -24,6 +24,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/shapes/triangle_base.hpp b/include/rive/generated/shapes/triangle_base.hpp
index 1078889..437387d 100644
--- a/include/rive/generated/shapes/triangle_base.hpp
+++ b/include/rive/generated/shapes/triangle_base.hpp
@@ -22,6 +22,7 @@
 				case PathBase::typeKey:
 				case NodeBase::typeKey:
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
diff --git a/include/rive/generated/transform_component_base.hpp b/include/rive/generated/transform_component_base.hpp
index b85a64f..8ecae51 100644
--- a/include/rive/generated/transform_component_base.hpp
+++ b/include/rive/generated/transform_component_base.hpp
@@ -1,13 +1,13 @@
 #ifndef _RIVE_TRANSFORM_COMPONENT_BASE_HPP_
 #define _RIVE_TRANSFORM_COMPONENT_BASE_HPP_
-#include "rive/container_component.hpp"
 #include "rive/core/field_types/core_double_type.hpp"
+#include "rive/world_transform_component.hpp"
 namespace rive
 {
-	class TransformComponentBase : public ContainerComponent
+	class TransformComponentBase : public WorldTransformComponent
 	{
 	protected:
-		typedef ContainerComponent Super;
+		typedef WorldTransformComponent Super;
 
 	public:
 		static const uint16_t typeKey = 38;
@@ -19,6 +19,7 @@
 			switch (typeKey)
 			{
 				case TransformComponentBase::typeKey:
+				case WorldTransformComponentBase::typeKey:
 				case ContainerComponentBase::typeKey:
 				case ComponentBase::typeKey:
 					return true;
@@ -32,13 +33,11 @@
 		static const uint16_t rotationPropertyKey = 15;
 		static const uint16_t scaleXPropertyKey = 16;
 		static const uint16_t scaleYPropertyKey = 17;
-		static const uint16_t opacityPropertyKey = 18;
 
 	private:
 		float m_Rotation = 0.0f;
 		float m_ScaleX = 1.0f;
 		float m_ScaleY = 1.0f;
-		float m_Opacity = 1.0f;
 	public:
 		inline float rotation() const { return m_Rotation; }
 		void rotation(float value)
@@ -73,24 +72,12 @@
 			scaleYChanged();
 		}
 
-		inline float opacity() const { return m_Opacity; }
-		void opacity(float value)
-		{
-			if (m_Opacity == value)
-			{
-				return;
-			}
-			m_Opacity = value;
-			opacityChanged();
-		}
-
 		void copy(const TransformComponentBase& object)
 		{
 			m_Rotation = object.m_Rotation;
 			m_ScaleX = object.m_ScaleX;
 			m_ScaleY = object.m_ScaleY;
-			m_Opacity = object.m_Opacity;
-			ContainerComponent::copy(object);
+			WorldTransformComponent::copy(object);
 		}
 
 		bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
@@ -106,18 +93,14 @@
 				case scaleYPropertyKey:
 					m_ScaleY = CoreDoubleType::deserialize(reader);
 					return true;
-				case opacityPropertyKey:
-					m_Opacity = CoreDoubleType::deserialize(reader);
-					return true;
 			}
-			return ContainerComponent::deserialize(propertyKey, reader);
+			return WorldTransformComponent::deserialize(propertyKey, reader);
 		}
 
 	protected:
 		virtual void rotationChanged() {}
 		virtual void scaleXChanged() {}
 		virtual void scaleYChanged() {}
-		virtual void opacityChanged() {}
 	};
 } // namespace rive
 
diff --git a/include/rive/generated/world_transform_component_base.hpp b/include/rive/generated/world_transform_component_base.hpp
new file mode 100644
index 0000000..0580642
--- /dev/null
+++ b/include/rive/generated/world_transform_component_base.hpp
@@ -0,0 +1,70 @@
+#ifndef _RIVE_WORLD_TRANSFORM_COMPONENT_BASE_HPP_
+#define _RIVE_WORLD_TRANSFORM_COMPONENT_BASE_HPP_
+#include "rive/container_component.hpp"
+#include "rive/core/field_types/core_double_type.hpp"
+namespace rive
+{
+	class WorldTransformComponentBase : public ContainerComponent
+	{
+	protected:
+		typedef ContainerComponent Super;
+
+	public:
+		static const uint16_t typeKey = 91;
+
+		/// Helper to quickly determine if a core object extends another without
+		/// RTTI at runtime.
+		bool isTypeOf(uint16_t typeKey) const override
+		{
+			switch (typeKey)
+			{
+				case WorldTransformComponentBase::typeKey:
+				case ContainerComponentBase::typeKey:
+				case ComponentBase::typeKey:
+					return true;
+				default:
+					return false;
+			}
+		}
+
+		uint16_t coreType() const override { return typeKey; }
+
+		static const uint16_t opacityPropertyKey = 18;
+
+	private:
+		float m_Opacity = 1.0f;
+	public:
+		inline float opacity() const { return m_Opacity; }
+		void opacity(float value)
+		{
+			if (m_Opacity == value)
+			{
+				return;
+			}
+			m_Opacity = value;
+			opacityChanged();
+		}
+
+		void copy(const WorldTransformComponentBase& object)
+		{
+			m_Opacity = object.m_Opacity;
+			ContainerComponent::copy(object);
+		}
+
+		bool deserialize(uint16_t propertyKey, BinaryReader& reader) override
+		{
+			switch (propertyKey)
+			{
+				case opacityPropertyKey:
+					m_Opacity = CoreDoubleType::deserialize(reader);
+					return true;
+			}
+			return ContainerComponent::deserialize(propertyKey, reader);
+		}
+
+	protected:
+		virtual void opacityChanged() {}
+	};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/include/rive/transform_component.hpp b/include/rive/transform_component.hpp
index 80dcf57..4260b24 100644
--- a/include/rive/transform_component.hpp
+++ b/include/rive/transform_component.hpp
@@ -6,13 +6,13 @@
 namespace rive
 {
 	class Constraint;
+	class WorldTransformComponent;
 	class TransformComponent : public TransformComponentBase
 	{
 	private:
 		Mat2D m_Transform;
-		Mat2D m_WorldTransform;
 		float m_RenderOpacity = 0.0f;
-		TransformComponent* m_ParentTransformComponent = nullptr;
+		WorldTransformComponent* m_ParentTransformComponent = nullptr;
 		std::vector<Constraint*> m_Constraints;
 
 	public:
@@ -28,21 +28,17 @@
 		void updateTransform();
 		void updateWorldTransform();
 		void markTransformDirty();
-		void markWorldTransformDirty();
-		void worldTranslation(Vec2D& result) const;
 
 		/// Opacity inherited by any child of this transform component. This'll
 		/// later get overridden by effect layers.
-		virtual float childOpacity() { return m_RenderOpacity; }
+		float childOpacity() override { return m_RenderOpacity; }
 		float renderOpacity() const { return m_RenderOpacity; }
 
 		const Mat2D& transform() const;
-		const Mat2D& worldTransform() const;
 
 		/// Explicitly dangerous. Use transform/worldTransform when you don't
 		/// need to transform things outside of their hierarchy.
 		Mat2D& mutableTransform();
-		Mat2D& mutableWorldTransform();
 
 		virtual float x() const = 0;
 		virtual float y() const = 0;
@@ -50,7 +46,6 @@
 		void rotationChanged() override;
 		void scaleXChanged() override;
 		void scaleYChanged() override;
-		void opacityChanged() override;
 
 		void addConstraint(Constraint* constraint);
 	};
diff --git a/include/rive/world_transform_component.hpp b/include/rive/world_transform_component.hpp
new file mode 100644
index 0000000..c7ab8df
--- /dev/null
+++ b/include/rive/world_transform_component.hpp
@@ -0,0 +1,26 @@
+#ifndef _RIVE_WORLD_TRANSFORM_COMPONENT_HPP_
+#define _RIVE_WORLD_TRANSFORM_COMPONENT_HPP_
+#include "rive/generated/world_transform_component_base.hpp"
+#include "rive/math/mat2d.hpp"
+
+namespace rive
+{
+	class TransformComponent;
+	class WorldTransformComponent : public WorldTransformComponentBase
+	{
+		friend class TransformComponent;
+
+	protected:
+		Mat2D m_WorldTransform;
+
+	public:
+		void markWorldTransformDirty();
+		virtual float childOpacity();
+		Mat2D& mutableWorldTransform();
+		const Mat2D& worldTransform() const;
+		void worldTranslation(Vec2D& result) const;
+		void opacityChanged() override;
+	};
+} // namespace rive
+
+#endif
\ No newline at end of file
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 78b8844..8840a03 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -423,7 +423,10 @@
 void Artboard::draw(Renderer* renderer)
 {
 	renderer->save();
-	renderer->clipPath(m_ClipPath->renderPath());
+	if (clip())
+	{
+		renderer->clipPath(m_ClipPath->renderPath());
+	}
 
 	Mat2D artboardTransform;
 	artboardTransform[4] = width() * originX();