diff --git a/src/raytracer/main.c b/src/raytracer/main.c
index 5405521..0e305ad 100644
--- a/src/raytracer/main.c
+++ b/src/raytracer/main.c
@@ -46,10 +46,21 @@ typedef struct {
   f32 t2;
 } solutions_t;
 
-solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
-                                  sphere_t sphere);
+typedef struct {
+  f32 closest_t;
+  sphere_t *closest_sphere;
+} intersection_t;
+
 colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
                    const scene_t *scene, colour_t default_colour);
+intersection_t find_closest_intersection(vec3f_t origin, vec3f_t direction,
+                                         f32 t_min, f32 t_max,
+                                         const scene_t *scene);
+f32 calculate_lighting_for_intersection(vec3f_t origin, vec3f_t direction,
+                                        intersection_t intersection,
+                                        const scene_t *scene);
+solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
+                                  sphere_t sphere);
 f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
                      vec3f_t view_vector, f32 specular_exponent,
                      const scene_t *scene);
@@ -167,28 +178,37 @@ i32 main(i32 argc, char *argv[]) {
   return EXIT_SUCCESS;
 }
 
-solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
-                                  sphere_t sphere) {
-  f32 r = sphere.radius;
-  vec3f_t CO = vec_sub(vec3f_t, origin, sphere.centre);
-
-  f32 a = vec_dot(vec3f_t, direction, direction);
-  f32 b = 2.0f * vec_dot(vec3f_t, CO, direction);
-  f32 c = vec_dot(vec3f_t, CO, CO) - r * r;
-
-  f32 discriminant = b * b - 4 * a * c;
-  if (discriminant < 0) {
-    return (solutions_t){INFINITY, INFINITY};
-  }
-
-  f32 t1 = (-b + sqrtf(discriminant)) / (2 * a);
-  f32 t2 = (-b - sqrtf(discriminant)) / (2 * a);
-
-  return (solutions_t){t1, t2};
-}
-
 colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
                    const scene_t *scene, colour_t default_colour) {
+
+  intersection_t intersection =
+      find_closest_intersection(origin, direction, t_min, t_max, scene);
+
+  if (!intersection.closest_sphere) {
+    return default_colour;
+  }
+
+  f32 light = calculate_lighting_for_intersection(origin, direction,
+                                                  intersection, scene);
+
+  f32 r = (f32)(intersection.closest_sphere->colour.rgba.r) * light;
+  r = clamp(r, 0.0f, (f32)UINT8_MAX);
+  f32 g = (f32)(intersection.closest_sphere->colour.rgba.g) * light;
+  g = clamp(g, 0.0f, (f32)UINT8_MAX);
+  f32 b = (f32)(intersection.closest_sphere->colour.rgba.b) * light;
+  b = clamp(b, 0.0f, (f32)UINT8_MAX);
+
+  return (colour_t){
+      .rgba.r = (u8)r,
+      .rgba.g = (u8)g,
+      .rgba.b = (u8)b,
+      .rgba.a = intersection.closest_sphere->colour.rgba.a,
+  };
+}
+
+intersection_t find_closest_intersection(vec3f_t origin, vec3f_t direction,
+                                         f32 t_min, f32 t_max,
+                                         const scene_t *scene) {
   f32 closest_t = INFINITY;
   sphere_t *closest_sphere = NULL;
 
@@ -209,35 +229,44 @@ colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
     }
   }
 
-  if (!closest_sphere) {
-    return default_colour;
-  }
+  return (intersection_t){closest_t, closest_sphere};
+}
 
-  vec3f_t position =
-      vec_add(vec3f_t, origin, vec_mul_num(vec3f_t, direction, closest_t));
+f32 calculate_lighting_for_intersection(vec3f_t origin, vec3f_t direction,
+                                        intersection_t intersection,
+                                        const scene_t *scene) {
+  vec3f_t position = vec_add(
+      vec3f_t, origin, vec_mul_num(vec3f_t, direction, intersection.closest_t));
 
-  vec3f_t surface_normal = vec_sub(vec3f_t, position, closest_sphere->centre);
+  vec3f_t surface_normal =
+      vec_sub(vec3f_t, position, intersection.closest_sphere->centre);
   surface_normal = vec_div_num(vec3f_t, surface_normal,
                                vec_magnitude(vec3f_t, surface_normal));
 
   vec3f_t view_vector = vec_mul_num(vec3f_t, direction, -1.0f);
 
-  f32 light = compute_lighting(position, surface_normal, view_vector,
-                               closest_sphere->specular, scene);
+  return compute_lighting(position, surface_normal, view_vector,
+                          intersection.closest_sphere->specular, scene);
+}
 
-  f32 r = (f32)(closest_sphere->colour.rgba.r) * light;
-  r = clamp(r, 0.0f, (f32)UINT8_MAX);
-  f32 g = (f32)(closest_sphere->colour.rgba.g) * light;
-  g = clamp(g, 0.0f, (f32)UINT8_MAX);
-  f32 b = (f32)(closest_sphere->colour.rgba.b) * light;
-  b = clamp(b, 0.0f, (f32)UINT8_MAX);
+solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
+                                  sphere_t sphere) {
+  f32 r = sphere.radius;
+  vec3f_t CO = vec_sub(vec3f_t, origin, sphere.centre);
 
-  return (colour_t){
-      .rgba.r = (u8)r,
-      .rgba.g = (u8)g,
-      .rgba.b = (u8)b,
-      .rgba.a = closest_sphere->colour.rgba.a,
-  };
+  f32 a = vec_dot(vec3f_t, direction, direction);
+  f32 b = 2.0f * vec_dot(vec3f_t, CO, direction);
+  f32 c = vec_dot(vec3f_t, CO, CO) - r * r;
+
+  f32 discriminant = b * b - 4 * a * c;
+  if (discriminant < 0) {
+    return (solutions_t){INFINITY, INFINITY};
+  }
+
+  f32 t1 = (-b + sqrtf(discriminant)) / (2 * a);
+  f32 t2 = (-b - sqrtf(discriminant)) / (2 * a);
+
+  return (solutions_t){t1, t2};
 }
 
 f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,