Simplify Vec2D
diff --git a/include/rive/bones/bone.hpp b/include/rive/bones/bone.hpp
index 357b855..74a4028 100644
--- a/include/rive/bones/bone.hpp
+++ b/include/rive/bones/bone.hpp
@@ -20,7 +20,7 @@
         inline const std::vector<Bone*> childBones() { return m_ChildBones; }
 
         void addChildBone(Bone* bone);
-        void tipWorldTranslation(Vec2D& result);
+        Vec2D tipWorldTranslation() const;
         void addPeerConstraint(Constraint* peer);
         const std::vector<Constraint*>& peerConstraints() const { return m_PeerConstraints; }
 
diff --git a/include/rive/bones/weight.hpp b/include/rive/bones/weight.hpp
index e7a1979..7145d59 100644
--- a/include/rive/bones/weight.hpp
+++ b/include/rive/bones/weight.hpp
@@ -14,13 +14,11 @@
 
         StatusCode onAddedDirty(CoreContext* context) override;
 
-        static void deform(float x,
-                           float y,
-                           unsigned int indices,
-                           unsigned int weights,
-                           const Mat2D& world,
-                           const float* boneTransforms,
-                           Vec2D& result);
+        static Vec2D deform(Vec2D inPoint,
+                            unsigned int indices,
+                            unsigned int weights,
+                            const Mat2D& world,
+                            const float* boneTransforms);
     };
 } // namespace rive
 
diff --git a/include/rive/command_path.hpp b/include/rive/command_path.hpp
index f22d4a2..9c61674 100644
--- a/include/rive/command_path.hpp
+++ b/include/rive/command_path.hpp
@@ -32,10 +32,10 @@
             close();
         }
 
-        void move(Vec2D v) { this->moveTo(v.x(), v.y()); }
-        void line(Vec2D v) { this->lineTo(v.x(), v.y()); }
+        void move(Vec2D v) { this->moveTo(v.x, v.y); }
+        void line(Vec2D v) { this->lineTo(v.x, v.y); }
         void cubic(Vec2D a, Vec2D b, Vec2D c) {
-            this->cubicTo(a.x(), a.y(), b.x(), b.y(), c.x(), c.y());
+            this->cubicTo(a.x, a.y, b.x, b.y, c.x, c.y);
         }
     };
 } // namespace rive
diff --git a/include/rive/math/mat2d.hpp b/include/rive/math/mat2d.hpp
index 0e492ab..f14e269 100644
--- a/include/rive/math/mat2d.hpp
+++ b/include/rive/math/mat2d.hpp
@@ -55,6 +55,8 @@
         float tx() const { return m_Buffer[4]; }
         float ty() const { return m_Buffer[5]; }
 
+        Vec2D translation() const { return {m_Buffer[4], m_Buffer[5]}; }
+
         void xx(float value) { m_Buffer[0] = value; }
         void xy(float value) { m_Buffer[1] = value; }
         void yx(float value) { m_Buffer[2] = value; }
@@ -65,8 +67,8 @@
 
     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],
+            m[0] * v.x + m[2] * v.y + m[4],
+            m[1] * v.x + m[3] * v.y + m[5],
         };
     }
 
diff --git a/include/rive/math/vec2d.hpp b/include/rive/math/vec2d.hpp
index 1e462d8..21dcdd4 100644
--- a/include/rive/math/vec2d.hpp
+++ b/include/rive/math/vec2d.hpp
@@ -6,44 +6,50 @@
 namespace rive {
     class Mat2D;
     class Vec2D {
-    private:
-        float m_Buffer[2];
-
     public:
-        constexpr Vec2D() : m_Buffer{0.0f, 0.0f} {}
-        constexpr Vec2D(float x, float y) : m_Buffer{x, y} {}
+        float x, y;
+
+        constexpr Vec2D() : x(0), y(0) {}
+        constexpr Vec2D(float x, float y) : x(x), y(y) {}
         constexpr Vec2D(const Vec2D&) = default;
 
-        float x() const { return m_Buffer[0]; }
-        float y() const { return m_Buffer[1]; }
-        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]; }
-
-        float lengthSquared() const { return x() * x() + y() * y(); }
+        float lengthSquared() const { return x * x + y * y; }
         float length() const;
         Vec2D normalized() const;
 
-        Vec2D operator-() const { return {-x(), -y()}; }
+        // Normalize this Vec, and return its previous length
+        float normalizeLength() {
+            const float len = this->length();
+            x /= len;
+            y /= len;
+            return len;
+        }
+
+        Vec2D operator-() const { return {-x, -y}; }
 
         void operator*=(float s) {
-            m_Buffer[0] *= s;
-            m_Buffer[1] *= s;
+            x *= s;
+            y *= s;
+        }
+
+        void operator/=(float s) {
+            x /= s;
+            y /= s;
         }
 
         friend inline Vec2D operator-(const Vec2D& a, const Vec2D& b) {
-            return {a[0] - b[0], a[1] - b[1]};
+            return {a.x - b.x, a.y - b.y};
         }
 
-        static Vec2D lerp(const Vec2D& a, const Vec2D& b, float f);
+        static inline Vec2D lerp(Vec2D a, 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 float dot(Vec2D a, Vec2D b) { return a.x * b.x + a.y * b.y; }
         static Vec2D scaleAndAdd(Vec2D a, Vec2D b, float scale) {
             return {
-                a[0] + b[0] * scale,
-                a[1] + b[1] * scale,
+                a.x + b.x * scale,
+                a.y + b.y * scale,
             };
         }
         static float distance(const Vec2D& a, const Vec2D& b) { return (a - b).length(); }
@@ -52,24 +58,29 @@
         }
 
         Vec2D& operator+=(Vec2D v) {
-            m_Buffer[0] += v[0];
-            m_Buffer[1] += v[1];
+            x += v.x;
+            y += v.y;
             return *this;
         }
         Vec2D& operator-=(Vec2D v) {
-            m_Buffer[0] -= v[0];
-            m_Buffer[1] -= v[1];
+            x -= v.x;
+            y -= v.y;
             return *this;
         }
     };
 
-    inline Vec2D operator*(const Vec2D& v, float s) { return {v[0] * s, v[1] * s}; }
-    inline Vec2D operator*(float s, const Vec2D& v) { return {v[0] * s, v[1] * s}; }
-    inline Vec2D operator/(const Vec2D& v, float s) { return {v[0] / s, v[1] / s}; }
+    inline Vec2D operator*(const Vec2D& v, float s) { return {v.x * s, v.y * s}; }
+    inline Vec2D operator*(float s, const Vec2D& v) { return {v.x * s, v.y * s}; }
+    inline Vec2D operator/(const Vec2D& v, float s) { return {v.x / s, v.y / s}; }
 
-    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.x + b.x, a.y + b.y}; }
 
-    inline bool operator==(const Vec2D& a, const Vec2D& b) { return a[0] == b[0] && a[1] == b[1]; }
-    inline bool operator!=(const Vec2D& a, const Vec2D& b) { return a[0] != b[0] || a[1] != b[1]; }
+    inline bool operator==(const Vec2D& a, const Vec2D& b) { return a.x == b.x && a.y == b.y; }
+    inline bool operator!=(const Vec2D& a, const Vec2D& b) { return a.x != b.x || a.y != b.y; }
+
+    Vec2D Vec2D::lerp(Vec2D a, Vec2D b, float t) {
+        return a + (b - a) * t;
+    }
+
 } // namespace rive
 #endif
diff --git a/include/rive/world_transform_component.hpp b/include/rive/world_transform_component.hpp
index 320ba86..b7769b1 100644
--- a/include/rive/world_transform_component.hpp
+++ b/include/rive/world_transform_component.hpp
@@ -16,7 +16,7 @@
         virtual float childOpacity();
         Mat2D& mutableWorldTransform();
         const Mat2D& worldTransform() const;
-        void worldTranslation(Vec2D& result) const;
+        Vec2D worldTranslation() const { return m_WorldTransform.translation(); }
         void opacityChanged() override;
     };
 } // namespace rive
diff --git a/skia/renderer/include/to_skia.hpp b/skia/renderer/include/to_skia.hpp
index a80848a..e92649c 100644
--- a/skia/renderer/include/to_skia.hpp
+++ b/skia/renderer/include/to_skia.hpp
@@ -24,8 +24,8 @@
             return SkMatrix::MakeAll(m[0], m[2], m[4], m[1], m[3], m[5], 0, 0, 1);
         }
 
-        static SkPoint convert(const rive::Vec2D& point) {
-            return SkPoint::Make(point[0], point[1]);
+        static SkPoint convert(rive::Vec2D point) {
+            return SkPoint::Make(point.x, point.y);
         }
 
         // clang-format off
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp
index 69fbf73..e6d2a60 100644
--- a/src/animation/state_machine_instance.cpp
+++ b/src/animation/state_machine_instance.cpp
@@ -240,11 +240,11 @@
     position -= Vec2D(m_ArtboardInstance->originX() * m_ArtboardInstance->width(),
                       m_ArtboardInstance->originY() * m_ArtboardInstance->height());
 
-    const int hitRadius = 2;
-    auto hitArea = AABB(position.x() - hitRadius,
-                        position.y() - hitRadius,
-                        position.x() + hitRadius,
-                        position.y() + hitRadius)
+    const float hitRadius = 2;
+    auto hitArea = AABB(position.x - hitRadius,
+                        position.y - hitRadius,
+                        position.x + hitRadius,
+                        position.y + hitRadius)
                        .round();
 
     for (const auto& hitShape : m_HitShapes) {
diff --git a/src/bones/bone.cpp b/src/bones/bone.cpp
index ec72eb9..f5e7a4b 100644
--- a/src/bones/bone.cpp
+++ b/src/bones/bone.cpp
@@ -25,7 +25,9 @@
 
 float Bone::y() const { return 0.0f; }
 
-void Bone::tipWorldTranslation(Vec2D& result) { result = worldTransform() * Vec2D(length(), 0); }
+Vec2D Bone::tipWorldTranslation() const {
+    return worldTransform() * Vec2D(length(), 0);
+}
 
 void Bone::addPeerConstraint(Constraint* peer) {
     assert(std::find(m_PeerConstraints.begin(), m_PeerConstraints.end(), peer) ==
diff --git a/src/bones/weight.cpp b/src/bones/weight.cpp
index 287972d..9f00714 100644
--- a/src/bones/weight.cpp
+++ b/src/bones/weight.cpp
@@ -22,16 +22,12 @@
     return (data >> (index * 8)) & 0xFF;
 }
 
-void Weight::deform(float x,
-                    float y,
+Vec2D Weight::deform(Vec2D inPoint,
                     unsigned int indices,
                     unsigned int weights,
                     const Mat2D& world,
-                    const float* boneTransforms,
-                    Vec2D& result) {
+                    const float* boneTransforms) {
     float xx = 0, xy = 0, yx = 0, yy = 0, tx = 0, ty = 0;
-    float rx = world[0] * x + world[2] * y + world[4];
-    float ry = world[1] * x + world[3] * y + world[5];
     for (int i = 0; i < 4; i++) {
         int weight = encodedWeightValue(i, weights);
         if (weight == 0) {
@@ -48,6 +44,6 @@
         tx += boneTransforms[startBoneTransformIndex++] * normalizedWeight;
         ty += boneTransforms[startBoneTransformIndex++] * normalizedWeight;
     }
-    result[0] = xx * rx + yx * ry + tx;
-    result[1] = xy * rx + yy * ry + ty;
-}
\ No newline at end of file
+
+    return Mat2D(xx, xy, yx, yy, tx, ty) * (world * inPoint);
+}
diff --git a/src/constraints/distance_constraint.cpp b/src/constraints/distance_constraint.cpp
index 0df5022..6f79f93 100644
--- a/src/constraints/distance_constraint.cpp
+++ b/src/constraints/distance_constraint.cpp
@@ -12,14 +12,12 @@
         return;
     }
 
-    Vec2D targetTranslation;
-    m_Target->worldTranslation(targetTranslation);
-
-    Vec2D ourTranslation;
-    component->worldTranslation(ourTranslation);
-
+    const Vec2D targetTranslation = m_Target->worldTranslation();
+    const Vec2D ourTranslation = component->worldTranslation();
+    
     Vec2D toTarget = ourTranslation - targetTranslation;
     float currentDistance = toTarget.length();
+
     switch (static_cast<Mode>(modeValue())) {
         case Mode::Closer:
             if (currentDistance < distance()) {
@@ -43,6 +41,6 @@
     Mat2D& world = component->mutableWorldTransform();
     Vec2D position = targetTranslation + toTarget;
     position = Vec2D::lerp(ourTranslation, position, strength());
-    world[4] = position[0];
-    world[5] = position[1];
+    world[4] = position.x;
+    world[5] = position.y;
 }
diff --git a/src/constraints/ik_constraint.cpp b/src/constraints/ik_constraint.cpp
index 7985526..bb07b3a 100644
--- a/src/constraints/ik_constraint.cpp
+++ b/src/constraints/ik_constraint.cpp
@@ -7,7 +7,7 @@
 using namespace rive;
 
 static float atan2(Vec2D v) {
-    return std::atan2(v.y(), v.x());
+    return std::atan2(v.y, v.x);
 }
 
 void IKConstraint::buildDependencies() {
@@ -87,8 +87,7 @@
 
 void IKConstraint::solve1(BoneChainLink* fk1, const Vec2D& worldTargetTranslation) {
     Mat2D iworld = fk1->parentWorldInverse;
-    Vec2D pA;
-    fk1->bone->worldTranslation(pA);
+    Vec2D pA = fk1->bone->worldTranslation();
     Vec2D pBT(worldTargetTranslation);
 
     // To target in worldspace
@@ -111,10 +110,9 @@
 
     const Mat2D& iworld = fk1->parentWorldInverse;
 
-    Vec2D pA, pC, pB;
-    b1->worldTranslation(pA);
-    firstChild->bone->worldTranslation(pC);
-    b2->tipWorldTranslation(pB);
+    Vec2D pA = b1->worldTranslation();
+    Vec2D pC = firstChild->bone->worldTranslation();
+    Vec2D pB = b2->tipWorldTranslation();
     Vec2D pBT(worldTargetTranslation);
 
     pA = iworld * pA;
@@ -135,8 +133,8 @@
 
         const Mat2D& secondChildWorldInverse = secondChild.parentWorldInverse;
 
-        firstChild->bone->worldTranslation(pC);
-        b2->tipWorldTranslation(pB);
+        pC = firstChild->bone->worldTranslation();
+        pB = b2->tipWorldTranslation();
 
         Vec2D avLocal = Vec2D::transformDir(pB - pC, secondChildWorldInverse);
         float angleCorrection = -atan2(avLocal);
@@ -202,8 +200,7 @@
         return;
     }
 
-    Vec2D worldTargetTranslation;
-    m_Target->worldTranslation(worldTargetTranslation);
+    Vec2D worldTargetTranslation = m_Target->worldTranslation();
 
     // Decompose the chain.
     for (BoneChainLink& item : m_FkChain) {
diff --git a/src/constraints/translation_constraint.cpp b/src/constraints/translation_constraint.cpp
index 4ade22b..7bc56b5 100644
--- a/src/constraints/translation_constraint.cpp
+++ b/src/constraints/translation_constraint.cpp
@@ -23,25 +23,24 @@
             }
             transformB = inverse * transformB;
         }
-        translationB[0] = transformB[4];
-        translationB[1] = transformB[5];
+        translationB = transformB.translation();
 
         if (!doesCopy()) {
-            translationB[0] = destSpace() == TransformSpace::local ? 0.0f : translationA[0];
+            translationB.x = destSpace() == TransformSpace::local ? 0.0f : translationA.x;
         } else {
-            translationB[0] *= copyFactor();
+            translationB.x *= copyFactor();
             if (offset()) {
-                translationB[0] += component->x();
+                translationB.x += component->x();
             }
         }
 
         if (!doesCopyY()) {
-            translationB[1] = destSpace() == TransformSpace::local ? 0.0f : translationA[1];
+            translationB.y = destSpace() == TransformSpace::local ? 0.0f : translationA.y;
         } else {
-            translationB[1] *= copyFactorY();
+            translationB.y *= copyFactorY();
 
             if (offset()) {
-                translationB[1] += component->y();
+                translationB.y += component->y();
             }
         }
 
@@ -62,17 +61,17 @@
         // Get our target world coordinates in parent local.
         translationB = inverse * translationB;
     }
-    if (max() && translationB[0] > maxValue()) {
-        translationB[0] = maxValue();
+    if (max() && translationB.x > maxValue()) {
+        translationB.x = maxValue();
     }
-    if (min() && translationB[0] < minValue()) {
-        translationB[0] = minValue();
+    if (min() && translationB.x < minValue()) {
+        translationB.x = minValue();
     }
-    if (maxY() && translationB[1] > maxValueY()) {
-        translationB[1] = maxValueY();
+    if (maxY() && translationB.y > maxValueY()) {
+        translationB.y = maxValueY();
     }
-    if (minY() && translationB[1] < minValueY()) {
-        translationB[1] = minValueY();
+    if (minY() && translationB.y < minValueY()) {
+        translationB.y = minValueY();
     }
     if (clampLocal) {
         // Transform back to world.
@@ -83,6 +82,6 @@
     float ti = 1.0f - t;
 
     // Just interpolate world translation
-    transformA[4] = translationA[0] * ti + translationB[0] * t;
-    transformA[5] = translationA[1] * ti + translationB[1] * t;
+    transformA[4] = translationA.x * ti + translationB.x * t;
+    transformA[5] = translationA.y * ti + translationB.y * t;
 }
diff --git a/src/math/aabb.cpp b/src/math/aabb.cpp
index 028e213..f4ae193 100644
--- a/src/math/aabb.cpp
+++ b/src/math/aabb.cpp
@@ -10,13 +10,13 @@
         return;
     }
 
-    float L = pts[0].x(), R = L, T = pts[0].y(), B = T;
+    float L = pts[0].x, R = L, T = pts[0].y, B = T;
 
     for (size_t i = 1; i < pts.size(); ++i) {
-        L = std::min(L, pts[i].x());
-        R = std::max(R, pts[i].x());
-        T = std::min(T, pts[i].y());
-        B = std::max(B, pts[i].y());
+        L = std::min(L, pts[i].x);
+        R = std::max(R, pts[i].x);
+        T = std::min(T, pts[i].y);
+        B = std::max(B, pts[i].y);
     }
     minX = L;
     maxX = R;
diff --git a/src/math/hit_test.cpp b/src/math/hit_test.cpp
index 0e4d142..7b4c7f5 100644
--- a/src/math/hit_test.cpp
+++ b/src/math/hit_test.cpp
@@ -22,7 +22,7 @@
 
     Point() {}
     Point(float xx, float yy) : x(xx), y(yy) {}
-    Point(const Vec2D& src) : x(src.x()), y(src.y()) {}
+    Point(const Vec2D& src) : x(src.x), y(src.y) {}
 
     Point operator+(Point v) const { return {x + v.x, y + v.y}; }
     Point operator-(Point v) const { return {x - v.x, y - v.y}; }
@@ -317,7 +317,7 @@
 /////////////////////////
 
 static bool cross_lt(Vec2D a, Vec2D b) {
-    return a.x() * b.y() < a.y() * b.x();
+    return a.x * b.y < a.y * b.x;
 }
 
 bool HitTester::testMesh(Vec2D pt, Span<Vec2D> verts, Span<uint16_t> indices) {
@@ -330,8 +330,8 @@
     if (CULL_BOUNDS) {
         const auto bounds = AABB(verts);
 
-        if (bounds.bottom() < pt.y() || pt.y() < bounds.top() ||
-            bounds.right()  < pt.x() || pt.x() < bounds.left()) {
+        if (bounds.bottom() < pt.y || pt.y < bounds.top() ||
+            bounds.right()  < pt.x || pt.x < bounds.left()) {
             return false;
         }
     }
diff --git a/src/math/mat2d.cpp b/src/math/mat2d.cpp
index eb9b8ec..601dd6c 100644
--- a/src/math/mat2d.cpp
+++ b/src/math/mat2d.cpp
@@ -16,10 +16,10 @@
 
 Mat2D Mat2D::scale(Vec2D vec) const {
     return {
-        m_Buffer[0] * vec.x(),
-        m_Buffer[1] * vec.x(),
-        m_Buffer[2] * vec.y(),
-        m_Buffer[3] * vec.y(),
+        m_Buffer[0] * vec.x,
+        m_Buffer[1] * vec.x,
+        m_Buffer[2] * vec.y,
+        m_Buffer[3] * vec.y,
         m_Buffer[4],
         m_Buffer[5],
     };
diff --git a/src/math/raw_path.cpp b/src/math/raw_path.cpp
index 651eb79..2461c3d 100644
--- a/src/math/raw_path.cpp
+++ b/src/math/raw_path.cpp
@@ -13,11 +13,11 @@
     }
 
     float l, t, r, b;
-    l = r = m_Points[0].x();
-    t = b = m_Points[0].y();
+    l = r = m_Points[0].x;
+    t = b = m_Points[0].y;
     for (size_t i = 1; i < m_Points.size(); ++i) {
-        const float x = m_Points[i].x();
-        const float y = m_Points[i].y();
+        const float x = m_Points[i].x;
+        const float y = m_Points[i].y;
         l = std::min(l, x);
         r = std::max(r, x);
         t = std::min(t, y);
@@ -68,24 +68,14 @@
 
     path.m_Points.resize(m_Points.size());
     for (size_t i = 0; i < m_Points.size(); ++i) {
-        const float x = m_Points[i].x();
-        const float y = m_Points[i].y();
-        path.m_Points[i] = {
-            m[0] * x + m[2] * y + m[4],
-            m[1] * x + m[3] * y + m[5],
-        };
+        path.m_Points[i] = m * m_Points[i];
     }
     return path;
 }
 
 void RawPath::transformInPlace(const Mat2D& m) {
     for (auto& p : m_Points) {
-        const float x = p.x();
-        const float y = p.y();
-        p = {
-            m[0] * x + m[2] * y + m[4],
-            m[1] * x + m[3] * y + m[5],
-        };
+        p = m * p;
     }
 }
 
@@ -131,13 +121,13 @@
     };
 
     const auto center = r.center();
-    const float dx = center.x();
-    const float dy = center.y();
+    const float dx = center.x;
+    const float dy = center.y;
     const float sx = r.width() * 0.5f;
     const float sy = r.height() * 0.5f;
 
     auto map = [dx, dy, sx, sy](rive::Vec2D p) {
-        return rive::Vec2D(p.x() * sx + dx, p.y() * sy + dy);
+        return rive::Vec2D(p.x * sx + dx, p.y * sy + dy);
     };
 
     m_Points.reserve(13);
diff --git a/src/math/vec2d.cpp b/src/math/vec2d.cpp
index 52b27a8..f8b2f90 100644
--- a/src/math/vec2d.cpp
+++ b/src/math/vec2d.cpp
@@ -6,8 +6,8 @@
 
 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(),
+        m[0] * a.x + m[2] * a.y,
+        m[1] * a.x + m[3] * a.y,
     };
 }
 float Vec2D::length() const { return std::sqrt(lengthSquared()); }
@@ -17,10 +17,3 @@
     auto scale = len2 > 0 ? (1 / std::sqrt(len2)) : 1;
     return *this * scale;
 }
-
-Vec2D Vec2D::lerp(const Vec2D& a, const Vec2D& b, float f) {
-    return {
-        a.x() + f * (b[0] - a.x()),
-        a.y() + f * (b[1] - a.y()),
-    };
-}
diff --git a/src/shapes/cubic_vertex.cpp b/src/shapes/cubic_vertex.cpp
index c359f01..5964ede 100644
--- a/src/shapes/cubic_vertex.cpp
+++ b/src/shapes/cubic_vertex.cpp
@@ -58,21 +58,15 @@
 
     auto cubicWeight = weight<CubicWeight>();
 
-    auto inp = inPoint();
-    Weight::deform(inp[0],
-                   inp[1],
-                   cubicWeight->inIndices(),
-                   cubicWeight->inValues(),
-                   worldTransform,
-                   boneTransforms,
-                   cubicWeight->inTranslation());
+    cubicWeight->inTranslation() = Weight::deform(inPoint(),
+                                                  cubicWeight->inIndices(),
+                                                  cubicWeight->inValues(),
+                                                  worldTransform,
+                                                  boneTransforms);
 
-    auto outp = outPoint();
-    Weight::deform(outp[0],
-                   outp[1],
-                   cubicWeight->outIndices(),
-                   cubicWeight->outValues(),
-                   worldTransform,
-                   boneTransforms,
-                   cubicWeight->outTranslation());
+    cubicWeight->outTranslation() = Weight::deform(outPoint(),
+                                                   cubicWeight->outIndices(),
+                                                   cubicWeight->outValues(),
+                                                   worldTransform,
+                                                   boneTransforms);
 }
diff --git a/src/shapes/mesh.cpp b/src/shapes/mesh.cpp
index e98d853..baac40a 100644
--- a/src/shapes/mesh.cpp
+++ b/src/shapes/mesh.cpp
@@ -113,8 +113,8 @@
         std::size_t index = 0;
         for (auto vertex : m_Vertices) {
             auto translation = vertex->renderTranslation();
-            vertices[index++] = translation[0];
-            vertices[index++] = translation[1];
+            vertices[index++] = translation.x;
+            vertices[index++] = translation.y;
         }
 
         auto factory = artboard()->factory();
diff --git a/src/shapes/metrics_path.cpp b/src/shapes/metrics_path.cpp
index 0190008..86754f6 100644
--- a/src/shapes/metrics_path.cpp
+++ b/src/shapes/metrics_path.cpp
@@ -70,7 +70,8 @@
 static const float distTooFar = 1.0f;
 
 static bool tooFar(const Vec2D& a, const Vec2D& b) {
-    return std::max(std::abs(a[0] - b[0]), std::abs(a[1] - b[1])) > distTooFar;
+    auto diff = a - b;
+    return std::max(std::abs(diff.x), std::abs(diff.y)) > distTooFar;
 }
 
 static bool
diff --git a/src/shapes/paint/linear_gradient.cpp b/src/shapes/paint/linear_gradient.cpp
index 06a7a3b..5071b8d 100644
--- a/src/shapes/paint/linear_gradient.cpp
+++ b/src/shapes/paint/linear_gradient.cpp
@@ -100,7 +100,7 @@
     Vec2D start, Vec2D end, const ColorInt colors[], const float stops[], size_t count) {
     auto factory = artboard()->factory();
     renderPaint()->shader(factory->makeLinearGradient(
-        start[0], start[1], end[0], end[1], colors, stops, count, RenderTileMode::clamp));
+        start.x, start.y, end.x, end.y, colors, stops, count, RenderTileMode::clamp));
 }
 
 void LinearGradient::markGradientDirty() { addDirt(ComponentDirt::Paint); }
diff --git a/src/shapes/paint/radial_gradient.cpp b/src/shapes/paint/radial_gradient.cpp
index 6c6b481..92e3b28 100644
--- a/src/shapes/paint/radial_gradient.cpp
+++ b/src/shapes/paint/radial_gradient.cpp
@@ -7,8 +7,8 @@
 void RadialGradient::makeGradient(
     Vec2D start, Vec2D end, const ColorInt colors[], const float stops[], size_t count) {
     auto factory = artboard()->factory();
-    renderPaint()->shader(factory->makeRadialGradient(start[0],
-                                                      start[1],
+    renderPaint()->shader(factory->makeRadialGradient(start.x,
+                                                      start.y,
                                                       Vec2D::distance(start, end),
                                                       colors,
                                                       stops,
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp
index 0b11b30..28efb10 100644
--- a/src/shapes/path.cpp
+++ b/src/shapes/path.cpp
@@ -80,18 +80,14 @@
                                                     : prev->renderTranslation()) -
                            pos;
 
-            auto toPrevLength = toPrev.length();
-            toPrev[0] /= toPrevLength;
-            toPrev[1] /= toPrevLength;
+            auto toPrevLength = toPrev.normalizeLength();
 
             auto next = vertices[1];
 
             Vec2D toNext = (next->is<CubicVertex>() ? next->as<CubicVertex>()->renderIn()
                                                     : next->renderTranslation()) -
                            pos;
-            auto toNextLength = toNext.length();
-            toNext[0] /= toNextLength;
-            toNext[1] /= toNextLength;
+            auto toNextLength = toNext.normalizeLength();
 
             float renderRadius = std::min(toPrevLength, std::min(toNextLength, radius));
 
@@ -127,18 +123,14 @@
 
             if (auto radius = point.radius(); radius > 0.0f) {
                 Vec2D toPrev = out - pos;
-                auto toPrevLength = toPrev.length();
-                toPrev[0] /= toPrevLength;
-                toPrev[1] /= toPrevLength;
+                auto toPrevLength = toPrev.normalizeLength();
 
                 auto next = vertices[(i + 1) % length];
 
                 Vec2D toNext = (next->is<CubicVertex>() ? next->as<CubicVertex>()->renderIn()
                                                         : next->renderTranslation()) -
                                pos;
-                auto toNextLength = toNext.length();
-                toNext[0] /= toNextLength;
-                toNext[1] /= toNextLength;
+                auto toNextLength = toNext.normalizeLength();
 
                 float renderRadius = std::min(toPrevLength, std::min(toNextLength, radius));
 
@@ -219,8 +211,8 @@
         m_OutPoint = out;
         m_InValid = true;
         m_OutValid = true;
-        x(translation[0]);
-        y(translation[1]);
+        x(translation.x);
+        y(translation.y);
     }
 
     void computeIn() override {}
@@ -263,14 +255,10 @@
                     Vec2D pos = point.renderTranslation();
 
                     Vec2D toPrev = prevPoint - pos;
-                    auto toPrevLength = toPrev.length();
-                    toPrev[0] /= toPrevLength;
-                    toPrev[1] /= toPrevLength;
+                    auto toPrevLength = toPrev.normalizeLength();
 
                     Vec2D toNext = nextPoint - pos;
-                    auto toNextLength = toNext.length();
-                    toNext[0] /= toNextLength;
-                    toNext[1] /= toNextLength;
+                    auto toNextLength = toNext.normalizeLength();
 
                     auto renderRadius =
                         std::min(toPrevLength, std::min(toNextLength, point.radius()));
@@ -330,8 +318,8 @@
     } else {
         auto point = new PathVertex();
         Vec2D translation = transform * vertex->renderTranslation();
-        point->x(translation[0]);
-        point->y(translation[1]);
+        point->x(translation.x);
+        point->y(translation.y);
         m_Vertices.push_back(point);
     }
 }
diff --git a/src/shapes/vertex.cpp b/src/shapes/vertex.cpp
index 4375555..a7c6890 100644
--- a/src/shapes/vertex.cpp
+++ b/src/shapes/vertex.cpp
@@ -13,11 +13,9 @@
 void Vertex::yChanged() { markGeometryDirty(); }
 
 void Vertex::deform(const Mat2D& worldTransform, const float* boneTransforms) {
-    Weight::deform(x(),
-                   y(),
-                   m_Weight->indices(),
-                   m_Weight->values(),
-                   worldTransform,
-                   boneTransforms,
-                   m_Weight->translation());
+    m_Weight->translation() = Weight::deform(Vec2D(x(), y()),
+                                             m_Weight->indices(),
+                                             m_Weight->values(),
+                                             worldTransform,
+                                             boneTransforms);
 }
\ No newline at end of file
diff --git a/src/world_transform_component.cpp b/src/world_transform_component.cpp
index d4e19dc..0a0ea78 100644
--- a/src/world_transform_component.cpp
+++ b/src/world_transform_component.cpp
@@ -16,8 +16,3 @@
 Mat2D& WorldTransformComponent::mutableWorldTransform() { return m_WorldTransform; }
 
 void WorldTransformComponent::opacityChanged() { addDirt(ComponentDirt::RenderOpacity, true); }
-
-void WorldTransformComponent::worldTranslation(Vec2D& result) const {
-    result[0] = m_WorldTransform[4];
-    result[1] = m_WorldTransform[5];
-}
diff --git a/test/distance_constraint_test.cpp b/test/distance_constraint_test.cpp
index dfb7b26..ece41f0 100644
--- a/test/distance_constraint_test.cpp
+++ b/test/distance_constraint_test.cpp
@@ -28,8 +28,7 @@
     b->y(137.87f);
     artboard->advance(0.0f);
 
-    rive::Vec2D at;
-    a->worldTranslation(at);
-    rive::Vec2D expectedTranslation(259.2808837890625, 62.87000274658203);
+    rive::Vec2D at = a->worldTranslation();
+    rive::Vec2D expectedTranslation(259.2808837890625f, 62.87000274658203f);
     REQUIRE(rive::Vec2D::distance(at, expectedTranslation) < 0.001f);
 }