Refactor Mat2D
diff --git a/include/rive/math/mat2d.hpp b/include/rive/math/mat2d.hpp
index 051c5f0..81884a6 100644
--- a/include/rive/math/mat2d.hpp
+++ b/include/rive/math/mat2d.hpp
@@ -1,43 +1,43 @@
 #ifndef _RIVE_MAT2D_HPP_
 #define _RIVE_MAT2D_HPP_
 
+#include "rive/math/vec2d.hpp"
 #include <cstddef>
 
 namespace rive {
-    class Vec2D;
     class TransformComponents;
     class Mat2D {
     private:
         float m_Buffer[6];
 
     public:
-        Mat2D();
-        Mat2D(const Mat2D& copy);
-        Mat2D(float x1, float y1, float x2, float y2, float tx, float ty);
+        Mat2D() : m_Buffer{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f} {}
+        Mat2D(const Mat2D& copy) = default;
+        Mat2D(float x1, float y1, float x2, float y2, float tx, float ty)
+            : m_Buffer{x1, y1, x2, y2, tx, ty}
+        {}
 
         inline const float* values() const { return m_Buffer; }
 
         float& operator[](std::size_t idx) { return m_Buffer[idx]; }
         const float& operator[](std::size_t idx) const { return m_Buffer[idx]; }
 
-        static void identity(Mat2D& result) {
-            result[0] = 1.0f;
-            result[1] = 0.0f;
-            result[2] = 0.0f;
-            result[3] = 1.0f;
-            result[4] = 0.0f;
-            result[5] = 0.0f;
+        static Mat2D fromRotation(float rad);
+        static Mat2D fromScale(float sx, float sy) {
+            return {sx, 0, 0, sy, 0, 0};
+        }
+        static Mat2D fromTranslate(float tx, float ty) {
+            return {1, 0, 0, 1, tx, ty};
         }
 
-        static void fromRotation(Mat2D& result, float rad);
-        static void scale(Mat2D& result, const Mat2D& mat, const Vec2D& vec);
-        static void multiply(Mat2D& result, const Mat2D& a, const Mat2D& b);
+        void scaleByValues(float sx, float sy);
+
+        static Mat2D scale(const Mat2D& mat, const Vec2D& vec);
+        static Mat2D multiply(const Mat2D& a, const Mat2D& b);
         static bool invert(Mat2D& result, const Mat2D& a);
-        static void copy(Mat2D& result, const Mat2D& a);
         static void decompose(TransformComponents& result, const Mat2D& m);
         static void compose(Mat2D& result,
                             const TransformComponents& components);
-        static void scaleByValues(Mat2D& result, float sx, float sy);
 
         float xx() const { return m_Buffer[0]; }
         float xy() const { return m_Buffer[1]; }
@@ -54,10 +54,15 @@
         void ty(float value) { m_Buffer[5] = value; }
     };
 
+    inline Vec2D operator*(const Mat2D& m, Vec2D v) {
+        return {
+            m[0] * v.x() + m[2] * v.y() + m[4],
+            m[1] * v.x() + m[3] * v.y() + m[5],
+        };
+    }
+
     inline Mat2D operator*(const Mat2D& a, const Mat2D& b) {
-        Mat2D result;
-        Mat2D::multiply(result, a, b);
-        return result;
+        return Mat2D::multiply(a, b);
     }
 
     inline bool operator==(const Mat2D& a, const Mat2D& b) {
@@ -65,4 +70,4 @@
                a[4] == b[4] && a[5] == b[5];
     }
 } // namespace rive
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/math/vec2d.hpp b/include/rive/math/vec2d.hpp
index 1289f26..073ddcc 100644
--- a/include/rive/math/vec2d.hpp
+++ b/include/rive/math/vec2d.hpp
@@ -11,7 +11,7 @@
 
     public:
         Vec2D() : m_Buffer{0.0f, 0.0f} {}
-        Vec2D(const Vec2D& copy) : m_Buffer{copy.m_Buffer[0], copy.m_Buffer[1]} {}
+        Vec2D(const Vec2D&) = default;
         Vec2D(float x, float y) : m_Buffer{x, y} {}
 
         float x() const { return m_Buffer[0]; }
@@ -33,20 +33,29 @@
             m_Buffer[0] *= s;
             m_Buffer[1] *= s;
         }
-    
-        static Vec2D transform(const Vec2D& a, const Mat2D& m);
-        static Vec2D transformDir(const Vec2D& a, const Mat2D& m);
-        static float distance(const Vec2D& a, const Vec2D& b);
-        static float distanceSquared(const Vec2D& a, const Vec2D& b);
-        static void copy(Vec2D& result, const Vec2D& a);
-        static float dot(const Vec2D& a, const Vec2D& b);
+
+        friend inline Vec2D operator-(const Vec2D& a, const Vec2D& b) {
+            return {a[0] - b[0], a[1] - b[1]};
+        }
+
         static Vec2D lerp(const Vec2D& a, const Vec2D& b, float f);
+        static Vec2D transformDir(const Vec2D& a, const Mat2D& m);
+
+        static float dot(Vec2D a, Vec2D b) {
+            return a[0] * b[0] + a[1] * b[1];
+        }
         static Vec2D scaleAndAdd(Vec2D a, Vec2D b, float scale) {
             return {
                 a[0] + b[0] * scale,
                 a[1] + b[1] * scale,
             };
         }
+        static float distance(const Vec2D& a, const Vec2D& b) {
+            return (a - b).length();
+        }
+        static float distanceSquared(const Vec2D& a, const Vec2D& b) {
+            return (a - b).lengthSquared();
+        }
     };
 
     inline Vec2D operator*(const Vec2D& v, float s) {
@@ -59,14 +68,6 @@
         return { v[0] / s, v[1] / s };
     }
 
-    inline Vec2D operator*(const Mat2D& a, const Vec2D& b) {
-        return Vec2D::transform(b, a);
-    }
-
-    inline Vec2D operator-(const Vec2D& a, const Vec2D& b) {
-        return {a[0] - b[0], a[1] - b[1]};
-    }
-
     inline Vec2D operator+(const Vec2D& a, const Vec2D& b) {
         return {a[0] + b[0], a[1] + b[1]};
     }
diff --git a/src/bones/bone.cpp b/src/bones/bone.cpp
index 2759e84..35d0c51 100644
--- a/src/bones/bone.cpp
+++ b/src/bones/bone.cpp
@@ -26,7 +26,7 @@
 float Bone::y() const { return 0.0f; }
 
 void Bone::tipWorldTranslation(Vec2D& result) {
-    result = Vec2D::transform({length(), 0}, worldTransform());
+    result = worldTransform() * Vec2D(length(), 0);
 }
 
 void Bone::addPeerConstraint(Constraint* peer) {
diff --git a/src/bones/skin.cpp b/src/bones/skin.cpp
index 1e38a25..7ecf216 100644
--- a/src/bones/skin.cpp
+++ b/src/bones/skin.cpp
@@ -29,10 +29,8 @@
 
 void Skin::update(ComponentDirt value) {
     int bidx = 6;
-    Mat2D world;
     for (auto tendon : m_Tendons) {
-        Mat2D::multiply(
-            world, tendon->bone()->worldTransform(), tendon->inverseBind());
+        auto world = tendon->bone()->worldTransform() * tendon->inverseBind();
         m_BoneTransforms[bidx++] = world[0];
         m_BoneTransforms[bidx++] = world[1];
         m_BoneTransforms[bidx++] = world[2];
@@ -72,4 +70,4 @@
 }
 void Skin::addTendon(Tendon* tendon) { m_Tendons.push_back(tendon); }
 
-void Skin::onDirty(ComponentDirt dirt) { m_Skinnable->markSkinDirty(); }
\ No newline at end of file
+void Skin::onDirty(ComponentDirt dirt) { m_Skinnable->markSkinDirty(); }
diff --git a/src/constraints/ik_constraint.cpp b/src/constraints/ik_constraint.cpp
index 964110e..9348d12 100644
--- a/src/constraints/ik_constraint.cpp
+++ b/src/constraints/ik_constraint.cpp
@@ -104,10 +104,10 @@
     b2->tipWorldTranslation(pB);
     Vec2D pBT(worldTargetTranslation);
 
-    pA  = Vec2D::transform(pA, iworld);
-    pC  = Vec2D::transform(pC, iworld);
-    pB  = Vec2D::transform(pB, iworld);
-    pBT = Vec2D::transform(pBT, iworld);
+    pA  = iworld * pA;
+    pC  = iworld * pC;
+    pB  = iworld * pB;
+    pBT = iworld * pBT;
 
     // http://mathworld.wolfram.com/LawofCosines.html
     Vec2D av = pB  - pC,
@@ -153,9 +153,7 @@
     constrainRotation(*firstChild, r2);
     if (firstChild != fk2) {
         Bone* bone = fk2->bone;
-        Mat2D::multiply(bone->mutableWorldTransform(),
-                        getParentWorld(*bone),
-                        bone->transform());
+        bone->mutableWorldTransform() = getParentWorld(*bone) * bone->transform();
     }
 
     // Simple storage, need this for interpolation.
@@ -169,11 +167,7 @@
     Mat2D& transform = bone->mutableTransform();
     TransformComponents& c = fk.transformComponents;
 
-    if (rotation == 0.0f) {
-        Mat2D::identity(transform);
-    } else {
-        Mat2D::fromRotation(transform, rotation);
-    }
+    transform = Mat2D::fromRotation(rotation);
 
     // Translate
     transform[4] = c.x();
@@ -193,7 +187,7 @@
         transform[3] = transform[1] * skew + transform[3];
     }
 
-    Mat2D::multiply(bone->mutableWorldTransform(), parentWorld, transform);
+    bone->mutableWorldTransform() = parentWorld * transform;
 }
 
 void IKConstraint::constrain(TransformComponent* component) {
@@ -211,8 +205,7 @@
         Mat2D::invert(item.parentWorldInverse, parentWorld);
 
         Mat2D& boneTransform = bone->mutableTransform();
-        Mat2D::multiply(
-            boneTransform, item.parentWorldInverse, bone->worldTransform());
+        boneTransform = item.parentWorldInverse * bone->worldTransform();
         Mat2D::decompose(item.transformComponents, boneTransform);
     }
 
diff --git a/src/constraints/rotation_constraint.cpp b/src/constraints/rotation_constraint.cpp
index 08fc61c..1738243 100644
--- a/src/constraints/rotation_constraint.cpp
+++ b/src/constraints/rotation_constraint.cpp
@@ -10,17 +10,17 @@
     Mat2D transformB;
     Mat2D::decompose(m_ComponentsA, transformA);
     if (m_Target == nullptr) {
-        Mat2D::copy(transformB, transformA);
+        transformB = transformA;
         TransformComponents::copy(m_ComponentsB, m_ComponentsA);
     } else {
-        Mat2D::copy(transformB, m_Target->worldTransform());
+        transformB = m_Target->worldTransform();
         if (sourceSpace() == TransformSpace::local) {
             Mat2D inverse;
 
             if (!Mat2D::invert(inverse, getParentWorld(*m_Target))) {
                 return;
             }
-            Mat2D::multiply(transformB, inverse, transformB);
+            transformB = inverse * transformB;
         }
 
         Mat2D::decompose(m_ComponentsB, transformB);
@@ -43,7 +43,7 @@
             // the world for interpolation.
 
             Mat2D::compose(transformB, m_ComponentsB);
-            Mat2D::multiply(transformB, getParentWorld(*component), transformB);
+            transformB = getParentWorld(*component) * transformB;
             Mat2D::decompose(m_ComponentsB, transformB);
         }
     }
@@ -56,7 +56,7 @@
         if (!Mat2D::invert(inverse, getParentWorld(*component))) {
             return;
         }
-        Mat2D::multiply(transformB, inverse, transformB);
+        transformB = inverse * transformB;
         Mat2D::decompose(m_ComponentsB, transformB);
     }
     if (max() && m_ComponentsB.rotation() > maxValue()) {
@@ -68,7 +68,7 @@
     if (clampLocal) {
         // Transform back to world.
         Mat2D::compose(transformB, m_ComponentsB);
-        Mat2D::multiply(transformB, getParentWorld(*component), transformB);
+        transformB = getParentWorld(*component) * transformB;
         Mat2D::decompose(m_ComponentsB, transformB);
     }
 
diff --git a/src/constraints/scale_constraint.cpp b/src/constraints/scale_constraint.cpp
index 87208a0..301e5f3 100644
--- a/src/constraints/scale_constraint.cpp
+++ b/src/constraints/scale_constraint.cpp
@@ -10,16 +10,16 @@
     Mat2D transformB;
     Mat2D::decompose(m_ComponentsA, transformA);
     if (m_Target == nullptr) {
-        Mat2D::copy(transformB, transformA);
+        transformB = transformA;
         TransformComponents::copy(m_ComponentsB, m_ComponentsA);
     } else {
-        Mat2D::copy(transformB, m_Target->worldTransform());
+        transformB = m_Target->worldTransform();
         if (sourceSpace() == TransformSpace::local) {
             Mat2D inverse;
             if (!Mat2D::invert(inverse, getParentWorld(*m_Target))) {
                 return;
             }
-            Mat2D::multiply(transformB, inverse, transformB);
+            transformB = inverse * transformB;
         }
         Mat2D::decompose(m_ComponentsB, transformB);
 
@@ -53,7 +53,7 @@
             // the world for interpolation.
 
             Mat2D::compose(transformB, m_ComponentsB);
-            Mat2D::multiply(transformB, getParentWorld(*component), transformB);
+            transformB = getParentWorld(*component) * transformB;
             Mat2D::decompose(m_ComponentsB, transformB);
         }
     }
@@ -67,7 +67,7 @@
         if (!Mat2D::invert(inverse, getParentWorld(*component))) {
             return;
         }
-        Mat2D::multiply(transformB, inverse, transformB);
+        transformB = inverse * transformB;
         Mat2D::decompose(m_ComponentsB, transformB);
     }
     if (max() && m_ComponentsB.scaleX() > maxValue()) {
@@ -85,7 +85,7 @@
     if (clamplocal) {
         // Transform back to world.
         Mat2D::compose(transformB, m_ComponentsB);
-        Mat2D::multiply(transformB, getParentWorld(*component), transformB);
+        transformB = getParentWorld(*component) * transformB;
         Mat2D::decompose(m_ComponentsB, transformB);
     }
 
diff --git a/src/constraints/transform_constraint.cpp b/src/constraints/transform_constraint.cpp
index 0e9df72..0459dec 100644
--- a/src/constraints/transform_constraint.cpp
+++ b/src/constraints/transform_constraint.cpp
@@ -19,11 +19,11 @@
         if (!Mat2D::invert(inverse, targetParentWorld)) {
             return;
         }
-        Mat2D::multiply(transformB, inverse, transformB);
+        transformB = inverse * transformB;
     }
     if (destSpace() == TransformSpace::local) {
         const Mat2D& targetParentWorld = getParentWorld(*component);
-        Mat2D::multiply(transformB, targetParentWorld, transformB);
+        transformB = targetParentWorld * transformB;
     }
 
     Mat2D::decompose(m_ComponentsA, transformA);
diff --git a/src/constraints/translation_constraint.cpp b/src/constraints/translation_constraint.cpp
index de5d976..4ab34ef 100644
--- a/src/constraints/translation_constraint.cpp
+++ b/src/constraints/translation_constraint.cpp
@@ -11,7 +11,7 @@
     Vec2D translationA(transformA[4], transformA[5]);
     Vec2D translationB;
     if (m_Target == nullptr) {
-        Vec2D::copy(translationB, translationA);
+        translationB = translationA;
     } else {
         Mat2D transformB(m_Target->worldTransform());
         if (sourceSpace() == TransformSpace::local) {
@@ -21,7 +21,7 @@
             if (!Mat2D::invert(inverse, targetParentWorld)) {
                 return;
             }
-            Mat2D::multiply(transformB, inverse, transformB);
+            transformB = inverse * transformB;
         }
         translationB[0] = transformB[4];
         translationB[1] = transformB[5];
@@ -49,7 +49,7 @@
 
         if (destSpace() == TransformSpace::local) {
             // Destination space is in parent transform coordinates.
-            translationB = Vec2D::transform(translationB, getParentWorld(*component));
+            translationB = getParentWorld(*component) * translationB;
         }
     }
 
@@ -62,7 +62,7 @@
             return;
         }
         // Get our target world coordinates in parent local.
-        translationB = Vec2D::transform(translationB, invert);
+        translationB = invert * translationB;
     }
     if (max() && translationB[0] > maxValue()) {
         translationB[0] = maxValue();
@@ -78,7 +78,7 @@
     }
     if (clampLocal) {
         // Transform back to world.
-        translationB = Vec2D::transform(translationB, getParentWorld(*component));
+        translationB = getParentWorld(*component) * translationB;
     }
 
     float t = strength();
diff --git a/src/math/aabb.cpp b/src/math/aabb.cpp
index be7bc31..ac448c4 100644
--- a/src/math/aabb.cpp
+++ b/src/math/aabb.cpp
@@ -76,10 +76,10 @@
 }
 
 void AABB::transform(AABB& out, const AABB& a, const Mat2D& matrix) {
-    const auto p1 = Vec2D::transform({a[0], a[1]}, matrix);
-    const auto p2 = Vec2D::transform({a[2], a[1]}, matrix);
-    const auto p3 = Vec2D::transform({a[2], a[3]}, matrix);
-    const auto p4 = Vec2D::transform({a[0], a[3]}, matrix);
+    const auto p1 = matrix * Vec2D(a[0], a[1]);
+    const auto p2 = matrix * Vec2D(a[2], a[1]);
+    const auto p3 = matrix * Vec2D(a[2], a[3]);
+    const auto p4 = matrix * Vec2D(a[0], a[3]);
 
     out[0] = std::fmin(p1[0], std::fmin(p2[0], std::fmin(p3[0], p4[0])));
     out[1] = std::fmin(p1[1], std::fmin(p2[1], std::fmin(p3[1], p4[1])));
diff --git a/src/math/mat2d.cpp b/src/math/mat2d.cpp
index 8e46cad..4b91ae4 100644
--- a/src/math/mat2d.cpp
+++ b/src/math/mat2d.cpp
@@ -5,44 +5,35 @@
 
 using namespace rive;
 
-Mat2D::Mat2D() : m_Buffer{1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f} {}
-
-Mat2D::Mat2D(const Mat2D& copy) :
-    m_Buffer{copy[0], copy[1], copy[2], copy[3], copy[4], copy[5]} {}
-
-Mat2D::Mat2D(float x1, float y1, float x2, float y2, float tx, float ty) :
-    m_Buffer{x1, y1, x2, y2, tx, ty} {}
-
-void Mat2D::fromRotation(Mat2D& result, float rad) {
-    float s = sin(rad);
-    float c = cos(rad);
-    result[0] = c;
-    result[1] = s;
-    result[2] = -s;
-    result[3] = c;
-    result[4] = 0;
-    result[5] = 0;
+Mat2D Mat2D::fromRotation(float rad) {
+    float s = 0,
+          c = 1;
+    if (rad != 0) {
+        s = sin(rad);
+        c = cos(rad);
+    }
+    return {c, s, -s, c, 0, 0};
 }
 
-void Mat2D::scale(Mat2D& result, const Mat2D& mat, const Vec2D& vec) {
-    float v0 = vec[0], v1 = vec[1];
-    result[0] = mat[0] * v0;
-    result[1] = mat[1] * v0;
-    result[2] = mat[2] * v1;
-    result[3] = mat[3] * v1;
-    result[4] = mat[4];
-    result[5] = mat[5];
+Mat2D Mat2D::scale(const Mat2D& mat, const Vec2D& vec) {
+    const float v0 = vec[0],
+                v1 = vec[1];
+    return {
+        mat[0] * v0, mat[1] * v0, mat[2] * v1, mat[3] * v1, mat[4], mat[5],
+    };
 }
 
-void Mat2D::multiply(Mat2D& result, const Mat2D& a, const Mat2D& b) {
+Mat2D Mat2D::multiply(const Mat2D& a, const Mat2D& b) {
     float a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
           b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
-    result[0] = a0 * b0 + a2 * b1;
-    result[1] = a1 * b0 + a3 * b1;
-    result[2] = a0 * b2 + a2 * b3;
-    result[3] = a1 * b2 + a3 * b3;
-    result[4] = a0 * b4 + a2 * b5 + a4;
-    result[5] = a1 * b4 + a3 * b5 + a5;
+    return {
+        a0 * b0 + a2 * b1,
+        a1 * b0 + a3 * b1,
+        a0 * b2 + a2 * b3,
+        a1 * b2 + a3 * b3,
+        a0 * b4 + a2 * b5 + a4,
+        a1 * b4 + a3 * b5 + a5,
+    };
 }
 
 bool Mat2D::invert(Mat2D& result, const Mat2D& a) {
@@ -63,15 +54,6 @@
     return true;
 }
 
-void Mat2D::copy(Mat2D& result, const Mat2D& a) {
-    result[0] = a[0];
-    result[1] = a[1];
-    result[2] = a[2];
-    result[3] = a[3];
-    result[4] = a[4];
-    result[5] = a[5];
-}
-
 void Mat2D::decompose(TransformComponents& result, const Mat2D& m) {
     float m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
 
@@ -90,18 +72,12 @@
 }
 
 void Mat2D::compose(Mat2D& result, const TransformComponents& components) {
-    float r = components.rotation();
-
-    if (r != 0.0f) {
-        Mat2D::fromRotation(result, r);
-    } else {
-        Mat2D::identity(result);
-    }
+    result = Mat2D::fromRotation(components.rotation());
     result[4] = components.x();
     result[5] = components.y();
     Vec2D scale;
     components.scale(scale);
-    Mat2D::scale(result, result, scale);
+    result = Mat2D::scale(result, scale);
 
     float sk = components.skew();
     if (sk != 0.0f) {
@@ -110,9 +86,9 @@
     }
 }
 
-void Mat2D::scaleByValues(Mat2D& result, float sx, float sy) {
-    result[0] *= sx;
-    result[1] *= sx;
-    result[2] *= sy;
-    result[3] *= sy;
-}
\ No newline at end of file
+void Mat2D::scaleByValues(float sx, float sy) {
+    m_Buffer[0] *= sx;
+    m_Buffer[1] *= sx;
+    m_Buffer[2] *= sy;
+    m_Buffer[3] *= sy;
+}
diff --git a/src/math/vec2d.cpp b/src/math/vec2d.cpp
index f0b8ebb..45d19c4 100644
--- a/src/math/vec2d.cpp
+++ b/src/math/vec2d.cpp
@@ -4,35 +4,12 @@
 
 using namespace rive;
 
-Vec2D Vec2D::transform(const Vec2D& a, const Mat2D& m) {
-    return {
-        m[0] * a.x() + m[2] * a.y() + m[4],
-        m[1] * a.x() + m[3] * a.y() + m[5],
-    };
-}
-
 Vec2D Vec2D::transformDir(const Vec2D& a, const Mat2D& m) {
     return {
         m[0] * a.x() + m[2] * a.y(),
         m[1] * a.x() + m[3] * a.y(),
     };
 }
-
-float Vec2D::distance(const Vec2D& a, const Vec2D& b) {
-    return std::sqrt(distanceSquared(a, b));
-}
-
-float Vec2D::distanceSquared(const Vec2D& a, const Vec2D& b) {
-    float x = b[0] - a[0];
-    float y = b[1] - a[1];
-    return x * x + y * y;
-}
-
-void Vec2D::copy(Vec2D& result, const Vec2D& a) {
-    result[0] = a[0];
-    result[1] = a[1];
-}
-
 float Vec2D::length() const {
     return std::sqrt(lengthSquared());
 }
@@ -43,10 +20,6 @@
     return *this * scale;
 }
 
-float Vec2D::dot(const Vec2D& a, const Vec2D& b) {
-    return a[0] * b[0] + a[1] * b[1];
-}
-
 Vec2D Vec2D::lerp(const Vec2D& a, const Vec2D& b, float f) {
     return {
         a.x() + f * (b[0] - a.x()),
diff --git a/src/renderer.cpp b/src/renderer.cpp
index 7153488..16c01a0 100644
--- a/src/renderer.cpp
+++ b/src/renderer.cpp
@@ -77,16 +77,8 @@
                    (alignment.x() * frame.width() / 2.0);
     translation[5] = frame[1] + frame.height() / 2.0 +
                    (alignment.y() * frame.height() / 2.0);
-    Mat2D scale;
-    scale[0] = scaleX;
-    scale[3] = scaleY;
 
-    Mat2D translateBack;
-    translateBack[4] = x;
-    translateBack[5] = y;
-
-    Mat2D::multiply(result, translation, scale);
-    Mat2D::multiply(result, result, translateBack);
+    result = translation * Mat2D::fromScale(scaleX, scaleY) * Mat2D::fromTranslate(x, y);
 }
 
 void Renderer::align(Fit fit,
diff --git a/src/shapes/cubic_vertex.cpp b/src/shapes/cubic_vertex.cpp
index bd06c68..baeb1a6 100644
--- a/src/shapes/cubic_vertex.cpp
+++ b/src/shapes/cubic_vertex.cpp
@@ -35,12 +35,12 @@
 }
 
 void CubicVertex::outPoint(const Vec2D& value) {
-    Vec2D::copy(m_OutPoint, value);
+    m_OutPoint = value;
     m_OutValid = true;
 }
 
 void CubicVertex::inPoint(const Vec2D& value) {
-    Vec2D::copy(m_InPoint, value);
+    m_InPoint = value;
     m_InValid = true;
 }
 
@@ -75,4 +75,4 @@
                    worldTransform,
                    boneTransforms,
                    cubicWeight->outTranslation());
-}
\ No newline at end of file
+}
diff --git a/src/shapes/metrics_path.cpp b/src/shapes/metrics_path.cpp
index e24df3d..6d80319 100644
--- a/src/shapes/metrics_path.cpp
+++ b/src/shapes/metrics_path.cpp
@@ -130,7 +130,7 @@
     // another transform).
     m_TransformedPoints.resize(m_Points.size());
     for (size_t i = 0, l = m_Points.size(); i < l; i++) {
-        m_TransformedPoints[i] = Vec2D::transform(m_Points[i], transform);
+        m_TransformedPoints[i] = transform * m_Points[i];
     }
 
     // Should never have subPaths with more subPaths (Skia allows this but for
diff --git a/src/shapes/paint/linear_gradient.cpp b/src/shapes/paint/linear_gradient.cpp
index 2ab64f4..1bc5f5e 100644
--- a/src/shapes/paint/linear_gradient.cpp
+++ b/src/shapes/paint/linear_gradient.cpp
@@ -75,9 +75,7 @@
             // Get the start and end of the gradient in world coordinates (world
             // transform of the shape).
             const Mat2D& world = m_ShapePaintContainer->worldTransform();
-            Vec2D worldStart = Vec2D::transform(start, world);
-            Vec2D worldEnd = Vec2D::transform(end, world);
-            makeGradient(worldStart, worldEnd);
+            makeGradient(world * start, world * end);
         } else {
             makeGradient(start, end);
         }
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp
index fb7a3bd..0e20a37 100644
--- a/src/shapes/path.cpp
+++ b/src/shapes/path.cpp
@@ -284,9 +284,9 @@
         auto world = parent()->as<TransformComponent>()->worldTransform();
         Mat2D inverseWorld;
         if (!Mat2D::invert(inverseWorld, world)) {
-            Mat2D::identity(inverseWorld);
+            inverseWorld = Mat2D();
         }
-        Mat2D::multiply(transform, inverseWorld, transform);
+        transform = inverseWorld * transform;
     }
 
     FlattenedPath* flat = new FlattenedPath();
@@ -374,15 +374,15 @@
 
         // Cubics need to be transformed so we create a Display version which
         // has set in/out values.
-        const auto in = Vec2D::transform(cubic->renderIn(), transform);
-        const auto out = Vec2D::transform(cubic->renderOut(), transform);
-        const auto translation = Vec2D::transform(cubic->renderTranslation(), transform);
+        const auto in = transform * cubic->renderIn();
+        const auto out = transform * cubic->renderOut();
+        const auto translation = transform * cubic->renderTranslation();
 
         auto displayCubic = new DisplayCubicVertex(in, out, translation);
         m_Vertices.push_back(displayCubic);
     } else {
         auto point = new PathVertex();
-        Vec2D translation = Vec2D::transform(vertex->renderTranslation(), transform);
+        Vec2D translation = transform * vertex->renderTranslation();
         point->x(translation[0]);
         point->y(translation[1]);
         m_Vertices.push_back(point);
diff --git a/src/shapes/path_composer.cpp b/src/shapes/path_composer.cpp
index a6483c5..fbfdf28 100644
--- a/src/shapes/path_composer.cpp
+++ b/src/shapes/path_composer.cpp
@@ -34,13 +34,11 @@
             auto world = m_Shape->worldTransform();
             Mat2D inverseWorld;
             if (!Mat2D::invert(inverseWorld, world)) {
-                Mat2D::identity(inverseWorld);
+                inverseWorld = Mat2D();
             }
             // Get all the paths into local shape space.
             for (auto path : m_Shape->paths()) {
-                Mat2D localTransform;
-                const Mat2D& transform = path->pathTransform();
-                Mat2D::multiply(localTransform, inverseWorld, transform);
+                const auto localTransform = inverseWorld * path->pathTransform();
                 m_LocalPath->addPath(path->commandPath(), localTransform);
             }
         }
@@ -56,4 +54,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/transform_component.cpp b/src/transform_component.cpp
index aa7b296..7f58894 100644
--- a/src/transform_component.cpp
+++ b/src/transform_component.cpp
@@ -28,23 +28,18 @@
 }
 
 void TransformComponent::updateTransform() {
-    if (rotation() != 0) {
-        Mat2D::fromRotation(m_Transform, rotation());
-    } else {
-        Mat2D::identity(m_Transform);
-    }
+    m_Transform = Mat2D::fromRotation(rotation());
     m_Transform[4] = x();
     m_Transform[5] = y();
-    Mat2D::scaleByValues(m_Transform, scaleX(), scaleY());
+    m_Transform.scaleByValues(scaleX(), scaleY());
 }
 
 void TransformComponent::updateWorldTransform() {
     if (m_ParentTransformComponent != nullptr) {
-        Mat2D::multiply(m_WorldTransform,
-                        m_ParentTransformComponent->m_WorldTransform,
-                        m_Transform);
+        m_WorldTransform = m_ParentTransformComponent->m_WorldTransform
+                         * m_Transform;
     } else {
-        Mat2D::copy(m_WorldTransform, m_Transform);
+        m_WorldTransform = m_Transform;
     }
 
     for (auto constraint : m_Constraints) {
@@ -77,4 +72,4 @@
 
 void TransformComponent::addConstraint(Constraint* constraint) {
     m_Constraints.push_back(constraint);
-}
\ No newline at end of file
+}