Repository: software-mansion/TypeGPU
Pull request #1319 (2025-06-02 10:35:41)

feat: Add matrix rotate and scale

github-actions[bot]: **pkg.pr.new**

*packages*
```
pnpm i https://pkg.pr.new/software-mansion/TypeGPU/typegpu@1319
pnpm i https://pkg.pr.new/software-mansion/TypeGPU/typegpu@d56aa240c9bd6b0ef6907f797250a085029888d7
```

*benchmark*
[view benchmark](https://docs.swmansion.com/TypeGPU/benchmark?p=npm-latest_pr-1319)

*commit*
[view commit](https://github.com/software-mansion/TypeGPU/commit/d56aa240c9bd6b0ef6907f797250a085029888d7)

Patch:
diff --git a/apps/typegpu-docs/src/content/examples/rendering/3d-fish/render.ts b/apps/typegpu-docs/src/content/examples/rendering/3d-fish/render.ts
index c00fa021..9c55aeca 100644
--- a/apps/typegpu-docs/src/content/examples/rendering/3d-fish/render.ts
+++ b/apps/typegpu-docs/src/content/examples/rendering/3d-fish/render.ts
@@ -19,8 +19,7 @@ export const vertexShader = tgpu['~unstable']
     // https://simple.wikipedia.org/wiki/Pitch,_yaw,_and_roll
     const currentModelData = layout.$.modelData[input.instanceIndex];
 
-    // apply sin wave
-
+    // apply sin wave to imitate swimming motion
     let wavedVertex = PosAndNormal({
       position: input.modelPosition,
       normal: input.modelNormal,
@@ -37,43 +36,37 @@ export const vertexShader = tgpu['~unstable']
     }
 
     // rotate model
-
     const direction = std.normalize(currentModelData.direction);
+    const yaw = -std.atan2(direction.z, direction.x) + Math.PI;
+    const pitch = std.asin(-direction.y);
 
-    const yaw = std.atan2(direction.z, direction.x) + Math.PI;
-    // deno-fmt-ignore
-    const yawMatrix = d.mat3x3f(
-      std.cos(yaw),  0, std.sin(yaw),
-      0,             1, 0,           
-      -std.sin(yaw), 0, std.cos(yaw),
-    );
-
-    const pitch = -std.asin(-direction.y);
-    // deno-fmt-ignore
-    const pitchMatrix = d.mat3x3f(
-      std.cos(pitch), -std.sin(pitch), 0,
-      std.sin(pitch), std.cos(pitch),  0,
-      0,              0,               1,
-    );
+    const scaleMatrix = d.mat4x4f.scaling(d.vec3f(currentModelData.scale));
+    const pitchMatrix = d.mat4x4f.rotationZ(pitch);
+    const yawMatrix = d.mat4x4f.rotationY(yaw);
+    const translationMatrix = d.mat4x4f.translation(currentModelData.position);
 
-    const worldPosition = std.add(
+    const worldPosition = std.mul(
+      translationMatrix,
       std.mul(
         yawMatrix,
         std.mul(
           pitchMatrix,
-          std.mul(currentModelData.scale, wavedVertex.position),
+          std.mul(
+            scaleMatrix,
+            d.vec4f(wavedVertex.position, 1),
+          ),
         ),
       ),
-      currentModelData.position,
     );
 
     // calculate where the normal vector points to
     const worldNormal = std.normalize(
-      std.mul(pitchMatrix, std.mul(yawMatrix, wavedVertex.normal)),
+      std.mul(yawMatrix, std.mul(pitchMatrix, d.vec4f(wavedVertex.normal, 1)))
+        .xyz,
     );
 
     // project the world position into the camera
-    const worldPositionUniform = d.vec4f(worldPosition.xyz, 1);
+    const worldPositionUniform = worldPosition;
     const canvasPosition = std.mul(
       layout.$.camera.projection,
       std.mul(layout.$.camera.view, worldPositionUniform),
@@ -83,7 +76,7 @@ export const vertexShader = tgpu['~unstable']
       canvasPosition: canvasPosition,
       textureUV: input.textureUV,
       worldNormal: worldNormal,
-      worldPosition: worldPosition,
+      worldPosition: worldPosition.xyz,
       applySeaFog: currentModelData.applySeaFog,
       applySeaDesaturation: currentModelData.applySeaDesaturation,
       variant: currentModelData.variant,
diff --git a/packages/typegpu/src/data/matrix.ts b/packages/typegpu/src/data/matrix.ts
index f378fa65..16e4cd74 100644
--- a/packages/typegpu/src/data/matrix.ts
+++ b/packages/typegpu/src/data/matrix.ts
@@ -1,5 +1,5 @@
-import { setName } from '../shared/meta.ts';
 import { createDualImpl } from '../shared/generators.ts';
+import { setName } from '../shared/meta.ts';
 import { $repr } from '../shared/repr.ts';
 import { $internal } from '../shared/symbols.ts';
 import type { SelfResolvable } from '../types.ts';
@@ -57,7 +57,11 @@ function createMatSchema<
     [$repr]: undefined as unknown as ValueType,
     type: options.type,
     identity: identityFunctions[options.columns],
-    translation: options.columns === 4 ? translation4x4 : undefined,
+    translation: options.columns === 4 ? translation4 : undefined,
+    scaling: options.columns === 4 ? scaling4 : undefined,
+    rotationX: options.columns === 4 ? rotationX4 : undefined,
+    rotationY: options.columns === 4 ? rotationY4 : undefined,
+    rotationZ: options.columns === 4 ? rotationZ4 : undefined,
   } as unknown as AnyWgslData;
   setName(MatSchema, options.type);
 
@@ -169,81 +173,7 @@ abstract class mat2x2Impl<TColumn extends v2f>
     })`;
   }
 }
-export const identity4x4 = createDualImpl(
-  // CPU implementation
-  () => mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1),
-  // GPU implementation
-  () => ({
-    value: `mat4x4f(
-      1.0, 0.0, 0.0, 0.0,
-      0.0, 1.0, 0.0, 0.0,
-      0.0, 0.0, 1.0, 0.0,
-      0.0, 0.0, 0.0, 1.0
-    )`,
-    dataType: mat4x4f,
-  }),
-);
-
-export const identity3x3 = createDualImpl(
-  // CPU implementation
-  () => mat3x3f(1, 0, 0, 0, 1, 0, 0, 0, 1),
-  // GPU implementation
-  () => ({
-    value: `mat4x4f(
-      1.0, 0.0, 0.0,
-      0.0, 1.0, 0.0,
-      0.0, 0.0, 1.0,
-    )`,
-    dataType: mat3x3f,
-  }),
-);
-
-export const identity2x2 = createDualImpl(
-  // CPU implementation
-  () => mat2x2f(1, 0, 0, 1),
-  // GPU implementation
-  () => ({
-    value: `mat4x4f(
-      1.0, 0.0,
-      0.0, 1.0
-    )`,
-    dataType: mat2x2f,
-  }),
-);
-const identityFunctions = {
-  2: identity2x2,
-  3: identity3x3,
-  4: identity4x4,
-};
 
-export const translation4x4 = createDualImpl(
-  // CPU implementation
-  (vector: v3f) =>
-    mat4x4f(
-      1,
-      0,
-      0,
-      0,
-      0,
-      1,
-      0,
-      0,
-      0,
-      0,
-      1,
-      0,
-      vector.x,
-      vector.y,
-      vector.z,
-      1,
-    ),
-  // GPU implementation
-  (vector) => ({
-    value:
-      `mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, ${vector.value}.x, ${vector.value}.y, ${vector.value}.z, 1)`,
-    dataType: mat4x4f,
-  }),
-);
 class mat2x2fImpl extends mat2x2Impl<v2f> implements m2x2f {
   public readonly kind = 'mat2x2f';
 
@@ -583,6 +513,208 @@ class mat4x4fImpl extends mat4x4Impl<v4f> implements m4x4f {
   }
 }
 
+// ----------
+// Matrix ops
+// ----------
+
+/**
+ * Returns a 2-by-2 identity matrix.
+ * @returns {m2x2f} The result matrix.
+ */
+export const identity2 = createDualImpl(
+  // CPU implementation
+  () => mat2x2f(1, 0, 0, 1),
+  // GPU implementation
+  () => ({
+    value: `mat4x4f(
+      1.0, 0.0,
+      0.0, 1.0
+    )`,
+    dataType: mat2x2f,
+  }),
+);
+
+/**
+ * Returns a 3-by-3 identity matrix.
+ * @returns {m3x3f} The result matrix.
+ */
+export const identity3 = createDualImpl(
+  // CPU implementation
+  () => mat3x3f(1, 0, 0, 0, 1, 0, 0, 0, 1),
+  // GPU implementation
+  () => ({
+    value: `mat4x4f(
+      1.0, 0.0, 0.0,
+      0.0, 1.0, 0.0,
+      0.0, 0.0, 1.0,
+    )`,
+    dataType: mat3x3f,
+  }),
+);
+
+/**
+ * Returns a 4-by-4 identity matrix.
+ * @returns {m4x4f} The result matrix.
+ */
+export const identity4 = createDualImpl(
+  // CPU implementation
+  () => mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1),
+  // GPU implementation
+  () => ({
+    value: `mat4x4f(
+      1.0, 0.0, 0.0, 0.0,
+      0.0, 1.0, 0.0, 0.0,
+      0.0, 0.0, 1.0, 0.0,
+      0.0, 0.0, 0.0, 1.0
+    )`,
+    dataType: mat4x4f,
+  }),
+);
+
+const identityFunctions = {
+  2: identity2,
+  3: identity3,
+  4: identity4,
+};
+
+/**
+ * Creates a 4-by-4 matrix which translates by the given vector v.
+ * @param {v3f} vector - The vector by which to translate.
+ * @returns {m4x4f} The translation matrix.
+ */
+export const translation4 = createDualImpl(
+  // CPU implementation
+  (vector: v3f) =>
+    // deno-fmt-ignore
+    mat4x4f(
+      1, 0, 0, 0,
+      0, 1, 0, 0,
+      0, 0, 1, 0,
+      vector.x, vector.y, vector.z, 1,
+    ),
+  // GPU implementation
+  (vector) => ({
+    value: `mat4x4f(
+        1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0, 
+        ${vector.value}.x, ${vector.value}.y, ${vector.value}.z, 1
+      )`,
+    dataType: mat4x4f,
+  }),
+);
+
+/**
+ * Creates a 4-by-4 matrix which scales in each dimension by an amount given by the corresponding entry in the given vector.
+ * @param {v3f} vector - A vector of three entries specifying the factor by which to scale in each dimension.
+ * @returns {m4x4f} The scaling matrix.
+ */
+export const scaling4 = createDualImpl(
+  // CPU implementation
+  (vector: v3f) =>
+    // deno-fmt-ignore
+    mat4x4f(
+      vector.x, 0, 0, 0,
+      0, vector.y, 0, 0,
+      0, 0, vector.z, 0,
+      0, 0, 0, 1,
+    ),
+  // GPU implementation
+  (vector) => ({
+    value: `mat4x4f(
+        ${vector.value}.x, 0, 0, 0,
+        0, ${vector.value}.y, 0, 0,
+        0, 0, ${vector.value}.z, 0, 
+        0, 0, 0, 1
+      )`,
+    dataType: mat4x4f,
+  }),
+);
+
+/**
+ * Creates a 4-by-4 matrix which rotates around the x-axis by the given angle.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotation matrix.
+ */
+export const rotationX4 = createDualImpl(
+  // CPU implementation
+  (a: number) =>
+    // deno-fmt-ignore
+    mat4x4f(
+      1, 0, 0, 0,
+      0, Math.cos(a), Math.sin(a), 0,
+      0, -Math.sin(a), Math.cos(a), 0,
+      0, 0, 0, 1,
+    ),
+  // GPU implementation
+  (a) =>
+    snip(
+      `mat4x4f(
+        1, 0, 0, 0,
+        0, cos(${a.value}), sin(${a.value}), 0,
+        0, -sin(${a.value}), cos(${a.value}), 0,
+        0, 0, 0, 1
+      )`,
+      mat4x4f,
+    ),
+);
+
+/**
+ * Creates a 4-by-4 matrix which rotates around the y-axis by the given angle.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotation matrix.
+ */
+export const rotationY4 = createDualImpl(
+  // CPU implementation
+  (a: number) =>
+    // deno-fmt-ignore
+    mat4x4f(
+      Math.cos(a), 0, -Math.sin(a), 0,
+      0, 1, 0, 0,
+      Math.sin(a), 0, Math.cos(a), 0,
+      0, 0, 0, 1,
+    ),
+  // GPU implementation
+  (a) =>
+    snip(
+      `mat4x4f(
+        cos(${a.value}), 0, -sin(${a.value}), 0,
+        0, 1, 0, 0,
+        sin(${a.value}), 0, cos(${a.value}), 0,
+        0, 0, 0, 1
+      )`,
+      mat4x4f,
+    ),
+);
+
+/**
+ * Creates a 4-by-4 matrix which rotates around the z-axis by the given angle.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotation matrix.
+ */
+export const rotationZ4 = createDualImpl(
+  // CPU implementation
+  (a: number) =>
+    // deno-fmt-ignore
+    mat4x4f(
+      Math.cos(a), Math.sin(a), 0, 0,
+      -Math.sin(a), Math.cos(a), 0, 0,
+      0, 0, 1, 0,
+      0, 0, 0, 1,
+    ),
+  // GPU implementation
+  (a) =>
+    snip(
+      `mat4x4f(
+        cos(${a.value}), sin(${a.value}), 0, 0,
+        -sin(${a.value}), cos(${a.value}), 0, 0,
+        0, 0, 1, 0,
+        0, 0, 0, 1
+      )`,
+      mat4x4f,
+    ),
+);
+
 // ----------
 // Public API
 // ----------
diff --git a/packages/typegpu/src/data/wgslTypes.ts b/packages/typegpu/src/data/wgslTypes.ts
index 0e3a0842..b0b6b574 100644
--- a/packages/typegpu/src/data/wgslTypes.ts
+++ b/packages/typegpu/src/data/wgslTypes.ts
@@ -1042,6 +1042,10 @@ export interface Mat4x4f {
   (): m4x4f;
   identity(): m4x4f;
   translation(vec: v3f): m4x4f;
+  scaling(vec: v3f): m4x4f;
+  rotationX(angle: number): m4x4f;
+  rotationY(angle: number): m4x4f;
+  rotationZ(angle: number): m4x4f;
 }
 
 /**
diff --git a/packages/typegpu/src/std/index.ts b/packages/typegpu/src/std/index.ts
index 12ae6062..0d869b2c 100644
--- a/packages/typegpu/src/std/index.ts
+++ b/packages/typegpu/src/std/index.ts
@@ -35,10 +35,24 @@ export {
   sign,
   sin,
   sqrt,
-  translate4x4,
   tanh
 } from './numeric.ts';
 
+// deno-fmt-ingore
+export { rotateX4, rotateY4, rotateZ4, scale4, translate4 } from './matrix.ts';
+
+// deno-fmt-ingore
+export {
+  identity2,
+  identity3,
+  identity4,
+  rotationX4,
+  rotationY4,
+  rotationZ4,
+  scaling4,
+  translation4,
+} from '../data/matrix.ts';
+
 // deno-fmt-ignore
 export {
   // comparison
diff --git a/packages/typegpu/src/std/matrix.ts b/packages/typegpu/src/std/matrix.ts
new file mode 100644
index 00000000..aae24d91
--- /dev/null
+++ b/packages/typegpu/src/std/matrix.ts
@@ -0,0 +1,110 @@
+import type { Snippet } from '../data/dataTypes.ts';
+import { mat4x4f } from '../data/matrix.ts';
+import type { m4x4f, v3f } from '../data/wgslTypes.ts';
+import { createDualImpl } from '../shared/generators.ts';
+import { mul } from './numeric.ts';
+
+/**
+ * Translates the given 4-by-4 matrix by the given vector.
+ * @param {m4x4f} matrix - The matrix to be modified.
+ * @param {v3f} vector - The vector by which to translate the matrix.
+ * @returns {m4x4f} The translated matrix.
+ */
+export const translate4 = createDualImpl(
+  // CPU implementation
+  (matrix: m4x4f, vector: v3f) => {
+    return mul(mat4x4f.translation(vector), matrix);
+  },
+  // GPU implementation
+  (matrix, vector) => ({
+    value: `(${
+      (mat4x4f.translation(vector as unknown as v3f) as unknown as Snippet)
+        .value
+    } * ${matrix.value})`,
+    dataType: matrix.dataType,
+  }),
+);
+
+/**
+ * Scales the given 4-by-4 matrix in each dimension by an amount given by the corresponding entry in the given vector.
+ * @param {m4x4f} matrix - The matrix to be modified.
+ * @param {v3f} vector - A vector of three entries specifying the factor by which to scale in each dimension.
+ * @returns {m4x4f} The scaled matrix.
+ */
+export const scale4 = createDualImpl(
+  // CPU implementation
+  (matrix: m4x4f, vector: v3f) => {
+    return mul(mat4x4f.scaling(vector), matrix);
+  },
+  // GPU implementation
+  (matrix, vector) => ({
+    value: `(${
+      (mat4x4f.scaling(vector as unknown as v3f) as unknown as Snippet)
+        .value
+    } * ${matrix.value})`,
+    dataType: matrix.dataType,
+  }),
+);
+
+/**
+ * Rotates the given 4-by-4 matrix around the x-axis by the given angle.
+ * @param {m4x4f} matrix - The matrix to be modified.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotated matrix.
+ */
+export const rotateX4 = createDualImpl(
+  // CPU implementation
+  (matrix: m4x4f, angle: number) => {
+    return mul(mat4x4f.rotationX(angle), matrix);
+  },
+  // GPU implementation
+  (matrix, angle) => ({
+    value: `(${
+      (mat4x4f.rotationX(angle as unknown as number) as unknown as Snippet)
+        .value
+    } * ${matrix.value})`,
+    dataType: matrix.dataType,
+  }),
+);
+
+/**
+ * Rotates the given 4-by-4 matrix around the y-axis by the given angle.
+ * @param {m4x4f} matrix - The matrix to be modified.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotated matrix.
+ */
+export const rotateY4 = createDualImpl(
+  // CPU implementation
+  (matrix: m4x4f, angle: number) => {
+    return mul(mat4x4f.rotationY(angle), matrix);
+  },
+  // GPU implementation
+  (matrix, angle) => ({
+    value: `(${
+      (mat4x4f.rotationY(angle as unknown as number) as unknown as Snippet)
+        .value
+    } * ${matrix.value})`,
+    dataType: matrix.dataType,
+  }),
+);
+
+/**
+ * Rotates the given 4-by-4 matrix around the z-axis by the given angle.
+ * @param {m4x4f} matrix - The matrix to be modified.
+ * @param {number} angle - The angle by which to rotate (in radians).
+ * @returns {m4x4f} The rotated matrix.
+ */
+export const rotateZ4 = createDualImpl(
+  // CPU implementation
+  (matrix: m4x4f, angle: number) => {
+    return mul(mat4x4f.rotationZ(angle), matrix);
+  },
+  // GPU implementation
+  (matrix, angle) => ({
+    value: `(${
+      (mat4x4f.rotationZ(angle as unknown as number) as unknown as Snippet)
+        .value
+    } * ${matrix.value})`,
+    dataType: matrix.dataType,
+  }),
+);
diff --git a/packages/typegpu/src/std/numeric.ts b/packages/typegpu/src/std/numeric.ts
index 7a42b089..1ddabeaf 100644
--- a/packages/typegpu/src/std/numeric.ts
+++ b/packages/typegpu/src/std/numeric.ts
@@ -1,4 +1,3 @@
-import { mat4x4f } from '../data/matrix.ts';
 import { type AnyData, snip, type Snippet } from '../data/dataTypes.ts';
 import { f32 } from '../data/numeric.ts';
 import { VectorOps } from '../data/vectorOps.ts';
@@ -14,7 +13,6 @@ import {
   isFloat32VecInstance,
   isMatInstance,
   isVecInstance,
-  type m4x4f,
   type mBaseForVec,
   type U32,
   type v2f,
@@ -648,28 +646,6 @@ export const sqrt = createDualImpl(
   (value) => snip(`sqrt(${value.value})`, value.dataType),
 );
 
-/**
- * Translates a matrix by a given vector.
- * @param {m4x4f} matrix - The matrix to be translated.
- * @param {v3f} vector - The vector by which to translate the matrix.
- * @returns {m4x4f} - The translated matrix.
- */
-export const translate4x4 = createDualImpl(
-  // CPU implementation
-  (matrix: m4x4f, vector: v3f) => {
-    return mul(matrix, mat4x4f.translation(vector));
-  },
-  // GPU implementation
-  (matrix, vector) => ({
-    value: `(${matrix.value} * ${
-      (mat4x4f.translation(
-        vector as unknown as v3f,
-      ) as unknown as Snippet).value
-    })`,
-    dataType: matrix.dataType,
-  }),
-);
-
 export const tanh = createDualImpl(
   // CPU implementation
   <T extends AnyFloatVecInstance | number>(value: T): T => {


Test patch:
diff --git a/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/index.ts b/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/index.ts
index 4b3ffe37..028de708 100644
--- a/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/index.ts
+++ b/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/index.ts
@@ -1,6 +1,7 @@
 import tgpu from 'typegpu';
 import * as d from 'typegpu/data';
 import { logicalExpressionTests } from './logical-expressions.ts';
+import { matrixOpsTests } from './matrix-ops.ts';
 
 const root = await tgpu.init();
 const result = root['~unstable'].createMutable(d.i32, 0);
@@ -9,6 +10,7 @@ const computeRunTests = tgpu['~unstable']
   .computeFn({ workgroupSize: [1] })(() => {
     let s = true;
     s = s && logicalExpressionTests();
+    s = s && matrixOpsTests();
 
     if (s) {
       result.value = 1;
diff --git a/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/matrix-ops.ts b/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/matrix-ops.ts
new file mode 100644
index 00000000..bdd00613
--- /dev/null
+++ b/apps/typegpu-docs/src/content/examples/tests/tgsl-parsing-test/matrix-ops.ts
@@ -0,0 +1,146 @@
+import tgpu from 'typegpu';
+import * as d from 'typegpu/data';
+import * as std from 'typegpu/std';
+
+// TODO: replace `s = s &&` with `s &&=` when implemented
+export const matrixOpsTests = tgpu['~unstable']
+  .fn([], d.bool)(() => {
+    let s = true;
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(d.mat4x4f.translation(d.vec3f(-1, 0, 1)), d.vec4f(1, 2, 3, 1)),
+        d.vec4f(0, 2, 4, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(d.mat4x4f.scaling(d.vec3f(-1, 0, 1)), d.vec4f(1, 2, 3, 1)),
+        d.vec4f(-1, 0, 3, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(d.mat4x4f.rotationX(Math.PI / 2), d.vec4f(1, 2, 3, 1)),
+        d.vec4f(1, -3, 2, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(d.mat4x4f.rotationY(Math.PI / 2), d.vec4f(1, 2, 3, 1)),
+        d.vec4f(3, 2, -1, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(d.mat4x4f.rotationZ(Math.PI / 2), d.vec4f(1, 2, 3, 1)),
+        d.vec4f(-2, 1, 3, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.translate4(d.mat4x4f.identity(), d.vec3f(-1, 0, 1)),
+          d.vec4f(1, 2, 3, 1),
+        ),
+        d.vec4f(0, 2, 4, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.scale4(d.mat4x4f.identity(), d.vec3f(-1, 0, 1)),
+          d.vec4f(1, 2, 3, 1),
+        ),
+        d.vec4f(-1, 0, 3, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateX4(d.mat4x4f.identity(), Math.PI / 2),
+          d.vec4f(1, 2, 3, 1),
+        ),
+        d.vec4f(1, -3, 2, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateY4(d.mat4x4f.identity(), Math.PI / 2),
+          d.vec4f(1, 2, 3, 1),
+        ),
+        d.vec4f(3, 2, -1, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateZ4(d.mat4x4f.identity(), Math.PI / 2),
+          d.vec4f(1, 2, 3, 1),
+        ),
+        d.vec4f(-2, 1, 3, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateZ4(
+            std.rotateX4(d.mat4x4f.identity(), Math.PI / 2),
+            Math.PI / 2,
+          ),
+          d.vec4f(1, 0, 0, 1),
+        ),
+        d.vec4f(0, 1, 0, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateX4(
+            std.rotateZ4(d.mat4x4f.identity(), Math.PI / 2),
+            Math.PI / 2,
+          ),
+          d.vec4f(1, 0, 0, 1),
+        ),
+        d.vec4f(0, 0, 1, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.translate4(
+            std.scale4(d.mat4x4f.identity(), d.vec3f(2, 3, 4)),
+            d.vec3f(0, 1, 0),
+          ),
+          d.vec4f(1, 0, 0, 1),
+        ),
+        d.vec4f(2, 1, 0, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.scale4(
+            std.translate4(d.mat4x4f.identity(), d.vec3f(0, 1, 0)),
+            d.vec3f(2, 3, 4),
+          ),
+          d.vec4f(0, 0, 0, 1),
+        ),
+        d.vec4f(0, 3, 0, 1),
+      );
+
+    s = s &&
+      std.isCloseTo(
+        std.mul(
+          std.rotateZ4(
+            std.rotateY4(d.mat4x4f.identity(), Math.PI / 2),
+            Math.PI / 2,
+          ),
+          d.vec4f(0, 1, 0, 1),
+        ),
+        d.vec4f(-1, 0, 0, 1),
+      );
+
+    return s;
+  });
diff --git a/packages/typegpu/tests/matrix.test.ts b/packages/typegpu/tests/matrix.test.ts
index 9a5b0f09..a223bfed 100644
--- a/packages/typegpu/tests/matrix.test.ts
+++ b/packages/typegpu/tests/matrix.test.ts
@@ -4,6 +4,7 @@ import * as d from '../src/data/index.ts';
 import tgpu from '../src/index.ts';
 
 import { readData, writeData } from '../src/data/dataIO.ts';
+import { isCloseTo } from '../src/std/index.ts';
 
 describe('mat2x2f', () => {
   it('creates a 2x2 matrix with zeros', () => {
@@ -394,10 +395,16 @@ describe('mat4x4f', () => {
   });
 });
 
-describe('identity matrix', () => {
-  it('returns identity matrix of size 4x4', () => {
-    expect(d.mat4x4f.identity()).toStrictEqual(
-      d.mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1),
+describe('different matrix constructors', () => {
+  it('returns identity matrix of size 2x2', () => {
+    expect(d.mat2x2f.identity()).toStrictEqual(
+      d.mat2x2f(d.vec2f(1, 0), d.vec2f(0, 1)),
+    );
+  });
+
+  it('returns identity matrix of size 3x3', () => {
+    expect(d.mat3x3f.identity()).toStrictEqual(
+      d.mat3x3f(d.vec3f(1, 0, 0), d.vec3f(0, 1, 0), d.vec3f(0, 0, 1)),
     );
   });
 
@@ -412,22 +419,49 @@ describe('identity matrix', () => {
     );
   });
 
-  it('returns identity matrix of size 3x3', () => {
-    expect(d.mat3x3f.identity()).toStrictEqual(
-      d.mat3x3f(1, 0, 0, 0, 1, 0, 0, 0, 1),
+  it('returns translation matrix', () => {
+    expect(d.mat4x4f.translation(d.vec3f(3, 4, 5))).toStrictEqual(
+      d.mat4x4f(
+        d.vec4f(1, 0, 0, 0),
+        d.vec4f(0, 1, 0, 0),
+        d.vec4f(0, 0, 1, 0),
+        d.vec4f(3, 4, 5, 1),
+      ),
     );
   });
-  it('returns identity matrix of size 3x3', () => {
-    expect(d.mat3x3f.identity()).toStrictEqual(
-      d.mat3x3f(d.vec3f(1, 0, 0), d.vec3f(0, 1, 0), d.vec3f(0, 0, 1)),
+
+  it('returns scaling matrix', () => {
+    expect(d.mat4x4f.scaling(d.vec3f(3, 4, 5))).toStrictEqual(
+      d.mat4x4f(
+        d.vec4f(3, 0, 0, 0),
+        d.vec4f(0, 4, 0, 0),
+        d.vec4f(0, 0, 5, 0),
+        d.vec4f(0, 0, 0, 1),
+      ),
     );
   });
-  it('returns identity matrix of size 2x2', () => {
-    expect(d.mat2x2f.identity()).toStrictEqual(d.mat2x2f(1, 0, 0, 1));
+
+  it('returns rotationX matrix', () => {
+    const result = d.mat4x4f.rotationX(Math.PI / 2);
+    expect(isCloseTo(result.columns[0], d.vec4f(1, 0, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[1], d.vec4f(0, 0, 1, 0))).toBe(true);
+    expect(isCloseTo(result.columns[2], d.vec4f(0, -1, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[3], d.vec4f(0, 0, 0, 1))).toBe(true);
   });
-  it('returns identity matrix of size 2x2', () => {
-    expect(d.mat2x2f.identity()).toStrictEqual(
-      d.mat2x2f(d.vec2f(1, 0), d.vec2f(0, 1)),
-    );
+
+  it('returns rotationY matrix', () => {
+    const result = d.mat4x4f.rotationY(Math.PI / 2);
+    expect(isCloseTo(result.columns[0], d.vec4f(0, 0, -1, 0))).toBe(true);
+    expect(isCloseTo(result.columns[1], d.vec4f(0, 1, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[2], d.vec4f(1, 0, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[3], d.vec4f(0, 0, 0, 1))).toBe(true);
+  });
+
+  it('returns rotationZ matrix', () => {
+    const result = d.mat4x4f.rotationZ(Math.PI / 2);
+    expect(isCloseTo(result.columns[0], d.vec4f(0, 1, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[1], d.vec4f(-1, 0, 0, 0))).toBe(true);
+    expect(isCloseTo(result.columns[2], d.vec4f(0, 0, 1, 0))).toBe(true);
+    expect(isCloseTo(result.columns[3], d.vec4f(0, 0, 0, 1))).toBe(true);
   });
 });
diff --git a/packages/typegpu/tests/std/matrix/rotate.test.ts b/packages/typegpu/tests/std/matrix/rotate.test.ts
new file mode 100644
index 00000000..12575219
--- /dev/null
+++ b/packages/typegpu/tests/std/matrix/rotate.test.ts
@@ -0,0 +1,129 @@
+import { describe, expect, it } from 'vitest';
+import { mat4x4f, vec4f } from '../../../src/data/index.ts';
+import tgpu from '../../../src/index.ts';
+import { isCloseTo, mul } from '../../../src/std/index.ts';
+import { rotateX4, rotateY4, rotateZ4 } from '../../../src/std/matrix.ts';
+import { parse, parseResolved } from '../../utils/parseResolved.ts';
+
+describe('rotate', () => {
+  it('generates correct WGSL for rotateX4 with custom matrix', () => {
+    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
+
+    const rotateFn = tgpu['~unstable']
+      .fn([])(() => {
+        const angle = 4;
+        const resultExpression = rotateX4(M, angle);
+      }).$name('rotateX4');
+
+    expect(parseResolved({ rotateFn })).toBe(
+      parse(
+        `fn rotateX4() {
+          var angle = 4;
+          var resultExpression = (
+            mat4x4f(1, 0, 0, 0, 0, cos(angle), sin(angle), 0, 0, -sin(angle), cos(angle), 0, 0, 0, 0, 1) *
+            mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1)
+          );
+        }`,
+      ),
+    );
+  });
+
+  it('generates correct WGSL for rotateY4 with custom matrix', () => {
+    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
+
+    const rotateFn = tgpu['~unstable']
+      .fn([])(() => {
+        const angle = 4;
+        const resultExpression = rotateY4(M, angle);
+      }).$name('rotateY4');
+
+    expect(parseResolved({ rotateFn })).toBe(
+      parse(
+        `fn rotateY4() {
+          var angle = 4;
+          var resultExpression = (
+            mat4x4f(cos(angle), 0, -sin(angle), 0, 0, 1, 0, 0, sin(angle), 0, cos(angle), 0, 0, 0, 0, 1) *
+            mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1)
+          );
+        }`,
+      ),
+    );
+  });
+
+  it('generates correct WGSL for rotateZ4 with custom matrix', () => {
+    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
+
+    const rotateFn = tgpu['~unstable']
+      .fn([])(() => {
+        const angle = 4;
+        const resultExpression = rotateZ4(M, angle);
+      }).$name('rotateZ4');
+
+    expect(parseResolved({ rotateFn })).toBe(
+      parse(
+        `fn rotateZ4() {
+          var angle = 4;
+          var resultExpression = (
+            mat4x4f(cos(angle), sin(angle), 0, 0, -sin(angle), cos(angle), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) *
+            mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1)
+          );
+        }`,
+      ),
+    );
+  });
+
+  it('rotates around X correctly', () => {
+    expect(
+      isCloseTo(
+        mul(rotateX4(mat4x4f.identity(), Math.PI / 2), vec4f(1, 2, 3, 1)),
+        vec4f(1, -3, 2, 1),
+      ),
+    )
+      .toBe(true);
+  });
+
+  it('rotates around Y correctly', () => {
+    expect(
+      isCloseTo(
+        mul(rotateY4(mat4x4f.identity(), Math.PI / 2), vec4f(1, 2, 3, 1)),
+        vec4f(3, 2, -1, 1),
+      ),
+    )
+      .toBe(true);
+  });
+
+  it('rotates around Z correctly', () => {
+    expect(
+      isCloseTo(
+        mul(rotateZ4(mat4x4f.identity(), Math.PI / 2), vec4f(1, 2, 3, 1)),
+        vec4f(-2, 1, 3, 1),
+      ),
+    )
+      .toBe(true);
+  });
+
+  it('applies order correctly', () => {
+    let transformation1 = mat4x4f.identity();
+    transformation1 = rotateX4(transformation1, Math.PI / 2);
+    transformation1 = rotateZ4(transformation1, Math.PI / 2);
+    expect(
+      isCloseTo(mul(transformation1, vec4f(1, 0, 0, 1)), vec4f(0, 1, 0, 1)),
+    ).toBe(true);
+
+    let transformation2 = mat4x4f.identity();
+    transformation2 = rotateZ4(transformation2, Math.PI / 2);
+    transformation2 = rotateX4(transformation2, Math.PI / 2);
+    expect(
+      isCloseTo(mul(transformation2, vec4f(1, 0, 0, 1)), vec4f(0, 0, 1, 1)),
+    ).toBe(true);
+  });
+
+  it('applies order correctly', () => {
+    let transformation1 = mat4x4f.identity();
+    transformation1 = rotateY4(transformation1, Math.PI / 2);
+    transformation1 = rotateZ4(transformation1, Math.PI / 2);
+    expect(
+      isCloseTo(mul(transformation1, vec4f(0, 1, 0, 1)), vec4f(-1, 0, 0, 1)),
+    ).toBe(true);
+  });
+});
diff --git a/packages/typegpu/tests/std/matrix/scale.test.ts b/packages/typegpu/tests/std/matrix/scale.test.ts
new file mode 100644
index 00000000..133ba890
--- /dev/null
+++ b/packages/typegpu/tests/std/matrix/scale.test.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it } from 'vitest';
+import { mat4x4f, vec3f, vec4f } from '../../../src/data/index.ts';
+import tgpu from '../../../src/index.ts';
+import { isCloseTo, mul, scale4, translate4 } from '../../../src/std/index.ts';
+import { parse, parseResolved } from '../../utils/parseResolved.ts';
+
+describe('scale', () => {
+  it('scales a matrix by a vec3f vector', () => {
+    const M = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+    const T = vec3f(2, 3, 4);
+    const result = scale4(M, T);
+    expect(result).toEqual(
+      mat4x4f(2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1),
+    );
+  });
+
+  it('generates correct WGSL for scale4 with custom matrix', () => {
+    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
+    const T = vec3f(2, 2, 4);
+
+    const scaleFn = tgpu['~unstable']
+      .fn([])(() => {
+        const resultExpression = scale4(M, T);
+      }).$name('scale4');
+
+    expect(parseResolved({ scaleFn })).toBe(
+      parse(
+        `fn scale4() { 
+          var resultExpression = (
+            mat4x4f(vec3f(2, 2, 4).x, 0, 0, 0, 0, vec3f(2, 2, 4).y, 0, 0, 0, 0, vec3f(2, 2, 4).z, 0, 0, 0, 0, 1) *
+            mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1)
+          ); 
+        }`,
+      ),
+    );
+  });
+
+  it('scales correctly', () => {
+    const result = scale4(mat4x4f.identity(), vec3f(3, 4, 5));
+    expect(isCloseTo(mul(result, vec4f(1, 2, 3, 1)), vec4f(3, 8, 15, 1))).toBe(
+      true,
+    );
+  });
+
+  it('applies order correctly', () => {
+    let transformation = mat4x4f.identity();
+    transformation = translate4(transformation, vec3f(0, 1, 0));
+    transformation = scale4(transformation, vec3f(2, 3, 4));
+    expect(
+      isCloseTo(mul(transformation, vec4f(0, 0, 0, 1)), vec4f(0, 3, 0, 1)),
+    ).toBe(true);
+  });
+});
diff --git a/packages/typegpu/tests/std/matrix/translate.test.ts b/packages/typegpu/tests/std/matrix/translate.test.ts
new file mode 100644
index 00000000..8f25b551
--- /dev/null
+++ b/packages/typegpu/tests/std/matrix/translate.test.ts
@@ -0,0 +1,53 @@
+import { describe, expect, it } from 'vitest';
+import { mat4x4f, vec3f, vec4f } from '../../../src/data/index.ts';
+import tgpu from '../../../src/index.ts';
+import { isCloseTo, mul, scale4, translate4 } from '../../../src/std/index.ts';
+import { parse, parseResolved } from '../../utils/parseResolved.ts';
+
+describe('translate', () => {
+  it('translates a matrix by a vec3f vector', () => {
+    const M = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
+    const T = vec3f(2, 3, 4);
+    const result = translate4(M, T);
+    expect(result).toEqual(
+      mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 2, 3, 4, 1),
+    );
+  });
+
+  it('generates correct WGSL for translate4 with custom matrix', () => {
+    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
+    const T = vec3f(2, 2, 4);
+
+    const translateFn = tgpu['~unstable']
+      .fn([])(() => {
+        const resultExpression = translate4(M, T);
+      }).$name('translate4');
+
+    expect(parseResolved({ translateFn })).toBe(
+      parse(
+        `fn translate4() { 
+          var resultExpression = (
+            mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(2, 2, 4).x, vec3f(2, 2, 4).y, vec3f(2, 2, 4).z, 1) *
+            mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1)
+          ); 
+        }`,
+      ),
+    );
+  });
+
+  it('translates correctly', () => {
+    const result = translate4(mat4x4f.identity(), vec3f(3, 4, 5));
+    expect(isCloseTo(mul(result, vec4f(1, 2, 3, 1)), vec4f(4, 6, 8, 1))).toBe(
+      true,
+    );
+  });
+
+  it('applies order correctly', () => {
+    let transformation = mat4x4f.identity();
+    transformation = scale4(transformation, vec3f(2, 3, 4));
+    transformation = translate4(transformation, vec3f(0, 1, 0));
+    expect(
+      isCloseTo(mul(transformation, vec4f(1, 0, 0, 1)), vec4f(2, 1, 0, 1)),
+    ).toBe(true);
+  });
+});
diff --git a/packages/typegpu/tests/std/numeric/translate4x4.test.ts b/packages/typegpu/tests/std/numeric/translate4x4.test.ts
deleted file mode 100644
index 86e63183..00000000
--- a/packages/typegpu/tests/std/numeric/translate4x4.test.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { describe, expect, it } from 'vitest';
-import { mul, translate4x4 } from '../../../src/std/index.ts';
-import { mat4x4f, vec3f } from '../../../src/data/index.ts';
-import { parse, parseResolved } from '../../utils/parseResolved.ts';
-import tgpu from '../../../src/index.ts';
-
-describe('translate', () => {
-  it('translates a matrix by a vec3f vector', () => {
-    const M = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
-    const T = vec3f(1, 2, 3);
-    const result = translate4x4(M, T);
-    expect(result).toEqual(
-      mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1),
-    );
-  });
-
-  it('translates a matrix by a vec3f vector', () => {
-    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
-    const T = vec3f(2, 2, 4);
-    const result = translate4x4(M, T);
-    expect(result).toEqual(
-      mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 6, 3, 4, 3),
-    );
-  });
-
-  it('generates correct WGSL for translate4x4 with custom matrix', () => {
-    const M = mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1);
-    const T = vec3f(2, 2, 4);
-
-    const translateFn = tgpu['~unstable']
-      .fn([])(() => {
-        const resultExpression = translate4x4(M, T);
-      }).$name('translate4x4');
-
-    expect(parseResolved({ translateFn })).toBe(
-      parse(
-        `fn translate4x4() { 
-          var resultExpression = (mat4x4f(1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1) * mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(2, 2, 4).x, vec3f(2, 2, 4).y, vec3f(2, 2, 4).z, 1)); 
-        }`,
-      ),
-    );
-  });
-
-  it('generates correct WGSL for translate4x4 with negative translation values', () => {
-    const M = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
-    const T = vec3f(-2.5, -3.75, -10);
-
-    const translateFn = tgpu['~unstable']
-      .fn([])(() => {
-        const resultExpression = translate4x4(M, T);
-      }).$name('translateNegative');
-
-    expect(parseResolved({ translateFn })).toBe(
-      parse(
-        `fn translateNegative() { 
-          var resultExpression = (mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) * mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(-2.5, -3.75, -10).x, vec3f(-2.5, -3.75, -10).y, vec3f(-2.5, -3.75, -10).z, 1)); 
-        }`,
-      ),
-    );
-  });
-
-  it('generates correct WGSL for translate4x4 with zero translation (identity case)', () => {
-    const M = mat4x4f(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 5, 5, 5, 1);
-    const T = vec3f(0, 0, 0);
-
-    const translateFn = tgpu['~unstable']
-      .fn([])(() => {
-        const resultExpression = translate4x4(M, T);
-      }).$name('translateZero');
-
-    expect(parseResolved({ translateFn })).toBe(
-      parse(
-        `fn translateZero() { 
-          var resultExpression = (mat4x4f(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 5, 5, 5, 1) * mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(0, 0, 0).x, vec3f(0, 0, 0).y, vec3f(0, 0, 0).z, 1)); 
-        }`,
-      ),
-    );
-  });
-
-  it('generates correct WGSL for translate4x4 with large numbers', () => {
-    const M = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 10, 10, 1);
-    const T = vec3f(999.99, 8888.88, 77777.77);
-
-    const translateFn = tgpu['~unstable']
-      .fn([])(() => {
-        const resultExpression = translate4x4(M, T);
-      }).$name('translateLarge');
-
-    expect(parseResolved({ translateFn })).toBe(
-      parse(
-        `fn translateLarge() { 
-          var resultExpression = (mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 10, 10, 1) * mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(999.99, 8888.88, 77777.77).x, vec3f(999.99, 8888.88, 77777.77).y, vec3f(999.99, 8888.88, 77777.77).z, 1)); 
-        }`,
-      ),
-    );
-  });
-
-  it('generates correct WGSL for nested translate4x4 within multiplication', () => {
-    const M1 = mat4x4f(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1);
-    const M2 = mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 5, 5, 1);
-    const T = vec3f(1, 2, 3);
-
-    const translateFn = tgpu['~unstable']
-      .fn([])(() => {
-        const resultExpression = mul(M1, translate4x4(M2, T));
-      }).$name('nestedTranslate');
-
-    expect(parseResolved({ translateFn })).toBe(
-      parse(
-        `fn nestedTranslate() { 
-          var resultExpression =(mat4x4f(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1) * (mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 5, 5, 5, 1) * mat4x4f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, vec3f(1, 2, 3).x, vec3f(1, 2, 3).y, vec3f(1, 2, 3).z, 1))); 
-        }`,
-      ),
-    );
-  });
-});