diff --git a/include/math/math_utils.h b/include/math/math_utils.h
index 4d34e5f..d00f19d 100644
--- a/include/math/math_utils.h
+++ b/include/math/math_utils.h
@@ -2,6 +2,9 @@
 #define MATH_UTILS_H
 
 #include "c_cpp_aliases/aliases.h"
+#include <math.h>
+
+#define RADIANS(DEG) (DEG * (f32)M_PI / 180.0f)
 
 f32 clamp(f32 value, f32 min, f32 max);
 
diff --git a/include/vector/vec.h b/include/vector/vec.h
index f9a2e26..dfae2fe 100644
--- a/include/vector/vec.h
+++ b/include/vector/vec.h
@@ -69,5 +69,6 @@ vec3f_t vec_div_num_vec3f_t(vec3f_t v1, f32 num);
 f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2);
 f32 vec_magnitude_vec3f_t(vec3f_t v);
 vec3f_t vec_unit_vec3f_t(vec3f_t v);
+vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation);
 
 #endif // !VEC_H
diff --git a/src/raytracer/main.c b/src/raytracer/main.c
index 0723064..81725eb 100644
--- a/src/raytracer/main.c
+++ b/src/raytracer/main.c
@@ -3,6 +3,7 @@
 #include "vector/vec.h"
 #include "window/window.h"
 #include <SDL2/SDL_events.h>
+#include <SDL2/SDL_keycode.h>
 #include <math.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -10,10 +11,18 @@
 #define ARR_LEN(ARR) sizeof(ARR) / sizeof(ARR[0])
 #define RECURSION_DEPTH 3
 
+typedef struct {
+  vec3f_t position;
+  vec3f_t rotation;
+} camera_t;
+
 i32 main(i32 argc, char *argv[]) {
   colour_t bg =
       (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
-  vec3f_t camera = {.x = 0.0f, .y = 0.0f, .z = 0.0f};
+  camera_t camera = {
+      .position = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
+      .rotation = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
+  };
   vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f};
 
   window_t window = {0};
@@ -107,8 +116,9 @@ i32 main(i32 argc, char *argv[]) {
     for (i32 y = h_min; y < h_max; ++y) {
       for (i32 x = w_min; x < w_max; ++x) {
         vec3f_t direction = window_to_viewport(&window, x, y, viewport);
-        colour_t colour = trace_ray(camera, direction, 1, INFINITY, &scene, bg,
-                                    RECURSION_DEPTH);
+        vec3f_t rotated = vec_rotate_vec3f_t(direction, camera.rotation);
+        colour_t colour = trace_ray(camera.position, rotated, 1, INFINITY,
+                                    &scene, bg, RECURSION_DEPTH);
         set_pixel(&window, x, y, colour);
       }
     }
diff --git a/src/vector/vec.c b/src/vector/vec.c
index 8145339..04969e0 100644
--- a/src/vector/vec.c
+++ b/src/vector/vec.c
@@ -1,6 +1,13 @@
 #include "vector/vec.h"
+#include "math/math_utils.h"
 #include <math.h>
 
+typedef struct {
+  vec3f_t row0;
+  vec3f_t row1;
+  vec3f_t row2;
+} mat3x3f_t;
+
 vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2) {
   return (vec2i_t){.x = v1.x + v2.x, .y = v1.y + v2.y};
 }
@@ -136,3 +143,44 @@ vec3f_t vec_unit_vec3f_t(vec3f_t v) {
   f32 magnitude = vec_magnitude_vec3f_t(v);
   return (vec3f_t){v.x / magnitude, v.y / magnitude, v.z / magnitude};
 }
+
+vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) {
+  f32 x_rad = RADIANS(rotation.x);
+  f32 y_rad = RADIANS(rotation.y);
+  f32 z_rad = RADIANS(rotation.z);
+
+  f32 cos_x = cosf(x_rad);
+  f32 sin_x = sinf(x_rad);
+
+  f32 cos_y = cosf(y_rad);
+  f32 sin_y = sinf(y_rad);
+
+  f32 cos_z = cosf(z_rad);
+  f32 sin_z = sinf(z_rad);
+
+  f32 row0_col0 = cos_z * cos_y;
+  f32 row0_col1 = cos_z * sin_y * sin_x - sin_z * cos_x;
+  f32 row0_col2 = cos_z * sin_y * cos_x + sin_z * sin_x;
+
+  f32 row1_col0 = sin_z * cos_y;
+  f32 row1_col1 = sin_z * sin_y * sin_x + cos_z * cos_x;
+  f32 row1_col2 = sin_z * sin_y * cos_x - cos_z * sin_x;
+
+  f32 row2_col0 = -sin_y;
+  f32 row2_col1 = cos_y * sin_x;
+  f32 row2_col2 = cos_y * cos_x;
+
+  mat3x3f_t matrix = {
+      .row0 = {row0_col0, row0_col1, row0_col2},
+      .row1 = {row1_col0, row1_col1, row1_col2},
+      .row2 = {row2_col0, row2_col1, row2_col2},
+  };
+
+  // clang-format off
+	return (vec3f_t){
+		.x = matrix.row0.x * original.x + matrix.row0.y * original.y + matrix.row0.z * original.z,
+		.y = matrix.row1.x * original.x + matrix.row1.y * original.y + matrix.row1.z * original.z,
+		.z = matrix.row2.x * original.x + matrix.row2.y * original.y + matrix.row2.z * original.z,
+	};
+  // clang-format on
+}