diff --git a/src/camera.c b/src/camera.c
index 3c3089b..5e0dfe3 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -5,16 +5,37 @@ Camera g_camera;
 
 void camera_init() {
     g_camera.centre = ZeroVector;
-    g_camera.width = 1;
+    g_camera.width = 10;
 }
 
-SDL_FRect render_calculate_unit_rect() {
-    // If the camera's width is 1, this rectangle should fill the width of the screen.
-    // If the camera's width is 2, this rectangle should fill half the width of the screen.
+static inline
+float _camera_height(Camera* self) {
+    return self->width * ((float)g_render_resolution.y / (float)g_render_resolution.x);
+}
+
+static inline
+float _one() {
+    return g_render_resolution.x / g_camera.width;
+}
+
+SDL_FRect camera_world_to_screen_space(Camera* self, SDL_FRect* world_space) {
+    float unit = _one();
     return (SDL_FRect) {
-        .x = -g_camera.centre.x * g_render_resolution.x,
-        .y = -g_camera.centre.y * g_render_resolution.x,
-        .w = g_render_resolution.x / g_camera.width,
-        .h = g_render_resolution.x / g_camera.width
+        .x = (world_space->x - g_camera.centre.x + g_camera.width/2.0) * unit,
+        .y = (world_space->y - g_camera.centre.y + _camera_height(&g_camera)/2.0) * unit,
+        .w = world_space->w * unit,
+        .h = world_space->h * unit
+    };
+}
+
+SDL_FRect camera_calculate_unit_rect() {
+    // If the camera's width is 1, this rectangle should fill the width of the screen.
+    // If the camera's width is 2, this rectangle should fill half the width of the screen.
+    float unit = _one();
+    return (SDL_FRect) {
+        .x = (-g_camera.centre.x + g_camera.width/2) * unit,
+        .y = (-g_camera.centre.y + _camera_height(&g_camera)/2) * unit,
+        .w = unit,
+        .h = unit
     };
 }
diff --git a/src/camera.h b/src/camera.h
index 5bd9f4e..b03e035 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -18,7 +18,7 @@ extern void camera_init();
 // generate a screen-space rectangle that is exactly 1x1 in world units.
 // With it's centre on the world origin.
 extern SDL_FRect camera_calculate_world_unit_rect(Camera* self);
-extern SDL_FRect camera_to_world_space(Camera* self, SDL_FRect* camera_space);
-extern SDL_FRect camera_world_to_camera_space(Camera* self, SDL_FRect* world_space);
+extern SDL_FRect camera_screen_to_world_space(Camera* self, SDL_FRect* camera_space);
+extern SDL_FRect camera_world_to_screen_space(Camera* self, SDL_FRect* world_space);
 
 #endif // !_fencer_camera_h
diff --git a/src/program.c b/src/program.c
index 4cf1be6..96640fb 100644
--- a/src/program.c
+++ b/src/program.c
@@ -1,7 +1,8 @@
 #include "program.h"
+#include "tilemap.h"
+#include "camera.h"
 #include <SDL2/SDL_video.h>
 #include <SDL2/SDL_image.h>
-#include "tilemap.h"
 
 SDL_Window* g_window;
 double g_delta_time;
@@ -22,6 +23,7 @@ int program_run(const struct ProgramSettings* settings) {
         SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE);
 
     render_init(g_window, settings);
+    camera_init();
 
     struct Tilemap map = tilemap_load("resources/box.tilemap.xml");
     struct Tileset set = {
diff --git a/src/tilemap.c b/src/tilemap.c
index 496af9b..8c6deec 100644
--- a/src/tilemap.c
+++ b/src/tilemap.c
@@ -171,14 +171,16 @@ void tilemap_render(struct Tilemap* self) {
     size_t num_tiles = self->dimensions.x * self->dimensions.y;
 
     SDL_Rect source_rect = {0, 0, self->tileset.tile_size.x, self->tileset.tile_size.y};
-    SDL_FRect dest_rect = { .w = 1, .h = 1 };
+    SDL_FRect world_dest_rect = { .w = 1, .h = 1 };
 
     for(int i = 0; i < num_tiles; ++i) {
         source_rect = tileset_index_to_rect(&self->tileset, self->tiles[i]);
 
-        dest_rect.x = (i % self->dimensions.x) * dest_rect.w;
-        dest_rect.y = (float)floor((float)i / self->dimensions.y) * dest_rect.h;
+        world_dest_rect.x = (i % self->dimensions.x) * world_dest_rect.w;
+        world_dest_rect.y = (float)floor((float)i / self->dimensions.y) * world_dest_rect.h;
 
-        SDL_RenderCopyF(g_renderer, self->tileset.texture, &source_rect, &dest_rect);
+        SDL_FRect camera_dest_rect = camera_world_to_screen_space(&g_camera, &world_dest_rect);
+
+        SDL_RenderCopyF(g_renderer, self->tileset.texture, &source_rect, &camera_dest_rect);
     }
 }
\ No newline at end of file