diff --git a/.gitignore b/.gitignore
index 40b878db5b1c97fc77049537a71bb2e249abe5dc..04c01ba7ba0830ccdc49fce1c7257114ed81e68b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-node_modules/
\ No newline at end of file
+node_modules/
+dist/
\ No newline at end of file
diff --git a/assets/tilemap.ase b/assets/tilemap.ase
new file mode 100644
index 0000000000000000000000000000000000000000..c559a196e2b36890b647307e6d650a7a7e491979
Binary files /dev/null and b/assets/tilemap.ase differ
diff --git a/dist/game.js b/dist/game.js
index 635d3ef3f17e5bdc03b412d8afec59d01ba4648e..494c9c9c366570cf13418ad7e75126cff6914199 100644
--- a/dist/game.js
+++ b/dist/game.js
@@ -1,8 +1,12 @@
 (() => {
   // src/js/config.js
   var GAME_TITLE = "Untitled JS13K23 Game.";
-  var WIDTH = 256;
-  var HEIGHT = 256;
+  var WIDTH = 160;
+  var HEIGHT = 144;
+
+  // src/js/utils.js
+  var pi = Math.PI;
+  var convertTileToScreen = (x, y) => ({x: x << 4, y: y << 4});
 
   // src/js/canvas.js
   var Canvas = class {
@@ -10,35 +14,41 @@
       this.canvas = document.getElementById(id);
       this.canvas.width = w;
       this.canvas.height = h;
-      this.context = this.canvas.getContext("2d");
-      this.context.imageSmoothingEnabled = false;
-      this.context.textBaseline = "top";
+      this.ctx = this.canvas.getContext("2d");
+      this.ctx.imageSmoothingEnabled = false;
+      this.ctx.textBaseline = "top";
       this.width = this.canvas.width;
       this.height = this.canvas.height;
+      this.cX = 0;
+      this.cY = 0;
     }
     fill(c = "black") {
-      this.context.fillStyle = c;
-      this.context.fillRect(0, 0, this.width, this.height);
+      this.ctx.fillStyle = c;
+      this.ctx.fillRect(0, 0, this.width, this.height);
     }
     drawImage(image, x, y, width = image.width, height = image.height) {
       console.debug("drawImage", image, x, y, width, height);
-      this.context.drawImage(image, x, y, width, height);
+      this.ctx.drawImage(image, x - this.cX, y - this.cY, width, height);
     }
-    sliceImage(image, sx, sy, sw, sh, dx, dy, dw = sw, dh = sh) {
-      this.context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
+    sliceImage(img, x, y, w, h, cropX, cropY, cropW, cropH, direction = 0) {
+      this.ctx.save();
+      this.ctx.translate(x + w / 2 - this.cX, y + h / 2 - this.cY);
+      this.ctx.rotate(direction * pi / 180);
+      this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w / 2, -h / 2, w, h);
+      this.ctx.restore();
     }
     drawText(text2, x, y, c = "white", size = 16, font = "monospace") {
-      this.context.fillStyle = c;
-      this.context.font = `${size}px ${font}`;
-      this.context.fillText(text2, x, y);
+      this.ctx.fillStyle = c;
+      this.ctx.font = `${size}px ${font}`;
+      this.ctx.fillText(text2, x, y);
     }
     drawLine(x1, y1, x2, y2, c = "white", w = 1) {
-      this.context.strokeStyle = c;
-      this.context.lineWidth = w;
-      this.context.beginPath();
-      this.context.moveTo(x1, y1);
-      this.context.lineTo(x2, y2);
-      this.context.stroke();
+      this.ctx.strokeStyle = c;
+      this.ctx.lineWidth = w;
+      this.ctx.beginPath();
+      this.ctx.moveTo(x1 - this.cX, y1 - this.cY);
+      this.ctx.lineTo(x2 - this.cX, y2 - this.cY);
+      this.ctx.stroke();
     }
   };
 
@@ -48,13 +58,15 @@
       this.fontimg = fontimg;
       this.fontWidth = 7;
       this.fontHeight = 7;
-      this.fontChars = "abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~";
+      this.fontChars = "abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~>";
       this.canvas = canvas2;
     }
-    drawLetter(letter, x, y) {
+    drawLetter(letter, x, y, substituteOK = 0) {
       let index = this.fontChars.indexOf(letter.toLowerCase());
       if (index == -1) {
-        return;
+        if (!substituteOK)
+          return;
+        this.canvas.drawText(letter, x, y, "#ffffff", 7, "monospace");
       }
       let sx = index * this.fontWidth;
       let sy = 0;
@@ -62,7 +74,7 @@
       if (letter == ",") {
         yOffset = -1;
       }
-      this.canvas.sliceImage(this.fontimg, sx, sy, this.fontWidth, this.fontHeight, x, y - yOffset, this.fontWidth, this.fontHeight);
+      this.canvas.sliceImage(this.fontimg, x, y + yOffset, this.fontWidth, this.fontHeight, sx, sy, this.fontWidth, this.fontHeight);
     }
     render(text2, x, y) {
       let heightOffset = 0;
@@ -92,9 +104,10 @@
     }
   };
   var Room = class extends Object2 {
-    constructor() {
+    constructor(name = "") {
       super();
       this.objects = [];
+      this.name = name;
     }
     draw() {
       for (let i = 0; i < this.objects.length; i++) {
@@ -103,6 +116,10 @@
     }
     drawGUI() {
     }
+    keyDown(key) {
+    }
+    keyUp(key) {
+    }
     step() {
       for (let i = 0; i < this.objects.length; i++) {
         this.objects[i].step();
@@ -112,28 +129,49 @@
 
   // src/js/keyboard.js
   var KEYS = {};
+  var _isKeyDown = (code) => KEYS[code] || 0;
   var _releaseKey = (code) => delete KEYS[code];
   addEventListener("keydown", (e) => {
+    e.preventDefault();
     if (!e.repeat) {
       KEYS[e.code] = performance.now();
     }
   });
   addEventListener("keyup", (e) => _releaseKey(e.code));
+  var whichKeyDown = () => Object.keys(KEYS).filter((code) => _isKeyDown(code));
 
   // src/js/game.js
+  console.debug(convertTileToScreen(1, 1));
   var assets = {
     images: {
       splash: "../img/splash1.webp",
-      splash2: "../img/splash2.webp",
-      font: "../img/hampsterfont.webp"
+      font: "../img/hampsterfont.webp",
+      tiles: "../img/t.webp"
+    },
+    spritesheets: {
+      player: [
+        {x: 0},
+        {x: 16},
+        {x: 32},
+        {x: 48}
+      ]
+    },
+    tilesets: {
+      castle: [
+        {x: 0, y: 0},
+        {x: 16, y: 0}
+      ]
     }
   };
+  var running = 1;
   var currentFrame = 0;
   var targetFrames = 60;
   var lastFrameTime = performance.now();
   var rooms = [];
+  var debugStatuses = [];
   var canvas = new Canvas("c", WIDTH, HEIGHT);
   var text;
+  var pressedLastFrame = [];
   canvas.fill("#222034");
   var splash = new Image();
   splash.src = assets.images.splash;
@@ -145,20 +183,23 @@
       console.log("font loaded");
       text = new TextRenderer(canvas, font);
       window.onerror = (e) => {
+        running = 0;
         text.throwPanic(e);
       };
     };
   };
-  var DebugEntity = class extends Object2 {
-    constructor() {
-      super();
-      this.x = 0;
-      this.y = 0;
-    }
-    draw() {
-      canvas.context.fillStyle = "red";
-      canvas.context.fillRect(this.x, this.y, 10, 10);
+  var roomIndex = 0;
+  var currentRoom = rooms[roomIndex];
+  var searchForRoom = (name) => {
+    for (let i = 0; i < rooms.length; i++) {
+      if (rooms[i].name == name)
+        return i;
     }
+    throw new Error("Room not found:" + name);
+  };
+  var changeRoom = (index) => {
+    currentRoom = rooms[index];
+    roomIndex = index;
   };
   var loadingRoom = new Room("loading");
   loadingRoom.updateStatus = (status) => {
@@ -169,33 +210,109 @@
   };
   var debugRoom = new Room("debug");
   debugRoom.draw = () => {
-    canvas.fill("#222034");
-    canvas;
-    for (let i = 0; i < debugRoom.objects.length; i++) {
-      debugRoom.objects[i].draw();
-    }
+    canvas.fill("black");
   };
   debugRoom.drawGUI = () => {
-    text.render("Welcome to the Debug Room,\nwe've got fun and games", 0, canvas.height - 14);
-    text.render("Current Frame:" + currentFrame + `(~${Math.floor(currentFrame / targetFrames * 100) / 100}sec)`, 0, canvas.height - 21);
+    debugStatuses.push("Current Frame:" + currentFrame + `(~${Math.round(currentFrame / targetFrames * 100) / 100} sec)`);
+  };
+  debugRoom.keyDown = (key) => {
+    if (key == "Escape")
+      changeRoom(searchForRoom("menu"));
+  };
+  var menuRoom = new Room("menu");
+  var menuOptions = [
+    {label: "Start Game", action: (_) => {
+      changeRoom(searchForRoom("game"));
+    }},
+    {label: "Debug Room", action: (_) => changeRoom(searchForRoom("debug"))},
+    {label: "Reload", action: (_) => {
+      running = 0;
+      location.reload();
+    }}
+  ];
+  var menuIndex = 0;
+  menuRoom.draw = () => {
+    canvas.fill("black");
+  };
+  menuRoom.drawGUI = () => {
+    text.render(GAME_TITLE, 8, 7 * 4);
+    for (let i = 0; i < menuOptions.length; i++) {
+      if (i == menuIndex) {
+        text.render(">", 8, 7 * (i + 5));
+      }
+      text.render(menuOptions[i].label, 16, 7 * (i + 5));
+    }
+  };
+  menuRoom.keyDown = (key) => {
+    if (pressedLastFrame.includes(key))
+      return;
+    switch (key) {
+      case "ArrowUp":
+        menuIndex--;
+        break;
+      case "ArrowDown":
+        menuIndex++;
+        break;
+      case "Enter":
+        menuOptions[menuIndex].action();
+        break;
+    }
+    if (menuIndex >= menuOptions.length)
+      menuIndex = 0;
+    if (menuIndex < 0)
+      menuIndex = menuOptions.length - 1;
+  };
+  var currentLevelData = {
+    tiles: [
+      {id: 1, x: 1, y: 1},
+      {id: 123, x: 2, y: 2}
+    ]
+  };
+  var gameRoom = new Room("game");
+  gameRoom.draw = () => {
+    canvas.fill("black");
+    for (let i = 0; i < currentLevelData.tiles.length; i++) {
+      let tile = currentLevelData.tiles[i];
+      if (tile.id > currentLevelData.length)
+        tile.id = 0;
+      let tileLocation = convertTileToScreen(tile.x, tile.y);
+      canvas.sliceImage(assets.images.tiles, tileLocation.x, tileLocation.y, 16, 16, tile.id * 16, 0, 16, 16);
+    }
   };
-  var testObject = new DebugEntity(0, 0);
-  debugRoom.objects.push(testObject);
   rooms.push(loadingRoom);
+  rooms.push(menuRoom);
+  rooms.push(gameRoom);
   rooms.push(debugRoom);
-  var roomIndex = 0;
-  var currentRoom = rooms[roomIndex];
+  currentRoom = rooms[roomIndex];
   var main = () => {
+    if (!running)
+      return;
     requestAnimationFrame(main);
     let now = performance.now();
     let delta = now - lastFrameTime;
     if (delta < 1e3 / targetFrames)
       return;
     currentFrame++;
+    debugStatuses = [];
     currentRoom.draw();
     currentRoom.drawGUI();
-    lastFrameTime = now;
+    let currentKeys = whichKeyDown();
+    for (let i = 0; i < currentKeys.length; i++) {
+      debugStatuses.push(currentKeys[i]);
+      currentRoom.keyDown(currentKeys[i]);
+    }
+    pressedLastFrame = currentKeys;
     text.render("FPS:" + Math.round(1e3 / delta), 0, 0);
+    text.render(currentRoom.name, canvas.width - 8 * currentRoom.name.length, 0);
+    if (currentFrame <= 60 * 5) {
+      debugStatuses.push("Debug mode.");
+      debugStatuses.push("Dimensions:" + canvas.width + "x" + canvas.height);
+      debugStatuses.push("Have fun!");
+    }
+    for (let i = 0; i < debugStatuses.length; i++) {
+      text.render(debugStatuses[i], 0, canvas.height - 7 * (debugStatuses.length - i));
+    }
+    lastFrameTime = now;
   };
   var init = () => {
     currentRoom.updateStatus("Loading images...");
@@ -207,6 +324,8 @@
         assets.images[image] = img;
       };
     }
+    console.log(assets.images);
+    console.log("Images loaded.");
     currentRoom.updateStatus("Loading complete!");
     canvas.fill("#222034");
     canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);
@@ -216,12 +335,8 @@
     }, 1e3);
   };
   window.onload = () => {
-    try {
-      document.title = GAME_TITLE;
-      init();
-    } catch (e) {
-      text.throwPanic(e);
-    }
+    document.title = GAME_TITLE;
+    init();
   };
 })();
 //# sourceMappingURL=game.js.map
diff --git a/dist/game.js.map b/dist/game.js.map
index 0fb77d1487b8e559afd409c45661dd3e3c46b266..831429a02de40f78951b4c5bc29b243057397ba7 100644
--- a/dist/game.js.map
+++ b/dist/game.js.map
@@ -1,7 +1,7 @@
 {
   "version": 3,
-  "sources": ["../src/js/config.js", "../src/js/canvas.js", "../src/js/text.js", "../src/js/objects.js", "../src/js/keyboard.js", "../src/js/game.js"],
-  "sourcesContent": ["// Holds all the config for your game.\r\n\r\nconst GAME_TITLE = \"Untitled JS13K23 Game.\"\r\n\r\nconst WIDTH = 256; // pixels\r\nconst HEIGHT = 256; // pixels\r\n\r\nexport { GAME_TITLE, WIDTH, HEIGHT };\r\n", "\r\n// Holds canvas, context and adds endpoints for graphics\r\n\r\nconst floor = function (...args) {\r\n    return Math.floor(...args);\r\n}\r\n\r\nclass Canvas {\r\n    constructor(id=\"c\", w=128, h=128) {\r\n        this.canvas = document.getElementById(id);\r\n        this.canvas.width = w;\r\n        this.canvas.height = h;\r\n\r\n        this.context = this.canvas.getContext(\"2d\");\r\n        this.context.imageSmoothingEnabled = false;\r\n        this.context.textBaseline = \"top\";\r\n\r\n        this.width = this.canvas.width;\r\n        this.height = this.canvas.height;\r\n    }\r\n\r\n    fill(c=\"black\") {\r\n        this.context.fillStyle = c;\r\n        this.context.fillRect(0, 0, this.width, this.height);\r\n    }\r\n    \r\n    drawImage(image, x, y, width = image.width, height = image.height) {\r\n        console.debug(\"drawImage\", image, x, y, width, height);\r\n        this.context.drawImage(image, x, y, width, height);\r\n    }\r\n\r\n    sliceImage(image, sx, sy, sw, sh, dx, dy, dw = sw, dh = sh) {\r\n        this.context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);\r\n    }\r\n\r\n    drawText(text, x, y, c=\"white\", size=16, font=\"monospace\") {\r\n        this.context.fillStyle = c;\r\n        this.context.font = `${size}px ${font}`;\r\n        this.context.fillText(text, x, y);\r\n    }\r\n\r\n    drawLine(x1, y1, x2, y2, c=\"white\", w=1) {\r\n        this.context.strokeStyle = c;\r\n        this.context.lineWidth = w;\r\n        this.context.beginPath();\r\n        this.context.moveTo(x1, y1);\r\n        this.context.lineTo(x2, y2);\r\n        this.context.stroke();\r\n    }\r\n}\r\n\r\nexport { Canvas };\r\n", "// draws text to the screen by splicing a font sheet.\r\n\r\nclass TextRenderer {\r\n    constructor(canvas, fontimg) {\r\n        this.fontimg = fontimg; // MUST BE AN IMAGE OBJECT\r\n        this.fontWidth = 7;\r\n        this.fontHeight = 7;\r\n        this.fontChars = \"abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~\";\r\n        this.canvas = canvas;\r\n    }\r\n\r\n    drawLetter(letter, x, y) {\r\n        let index = this.fontChars.indexOf(letter.toLowerCase());\r\n        if (index == -1) {\r\n            return;\r\n        }\r\n        let sx = index * this.fontWidth;\r\n        let sy = 0;\r\n        // draw image to context\r\n        let yOffset = 0;\r\n        // if the letter is \",\", offset it by -1\r\n        if (letter == \",\") {\r\n            yOffset = -1;\r\n        }\r\n        this.canvas.sliceImage(this.fontimg, sx, sy, this.fontWidth, this.fontHeight, x, y-yOffset, this.fontWidth, this.fontHeight);\r\n    }\r\n\r\n    render(text, x, y) {\r\n        let heightOffset = 0;\r\n        let xOffset = 0;\r\n        for (let i = 0; i < text.length; i++) {\r\n            if (text[i] == \"\\n\") {\r\n                heightOffset++;\r\n                xOffset = 0;\r\n                continue;\r\n            }\r\n            this.drawLetter(text[i], x + (xOffset * this.fontWidth), y + (heightOffset * this.fontHeight));\r\n            xOffset++;\r\n        }\r\n    }\r\n\r\n    throwPanic = (err) => {\r\n        // This function is called when an error is caught but unhandled.\r\n        // It'll show the error on-screen.\r\n    \r\n        this.canvas.fill(\"#00000080\") // 50% black\r\n        this.render(err, 0, 0);\r\n        throw err;\r\n    }\r\n}\r\n\r\nexport { TextRenderer };", "class Object {\r\n    draw() {}\r\n    step() {}\r\n}\r\n\r\nclass Room extends Object {\r\n    constructor() {\r\n        super();\r\n        this.objects = [];\r\n    }\r\n\r\n    draw() {\r\n        for (let i = 0; i < this.objects.length; i++) {\r\n            this.objects[i].draw();\r\n        }\r\n    }\r\n\r\n    drawGUI() {\r\n\r\n    }\r\n\r\n    step() {\r\n        for (let i = 0; i < this.objects.length; i++) {\r\n            this.objects[i].step();\r\n        }\r\n    }\r\n}\r\n\r\n\r\n\r\nexport { Object, Room };", "// Manages keyboard inputs. Code may have been stolen from herebefrogs/gamejam-boilerplate, under MIT license.\r\n\r\n/** Keyboard input\r\n * Record time at which each key gets pressed\r\n * and provide utilities to queries which keys are pressed or released\r\n *\r\n * Note: importing any public function of this module\r\n * will install the keyboard event listeners\r\n */\r\n\r\n/* private */\r\n\r\n// time at which each key was pressed\r\n// key = KeyboardEvent.code\r\n// value = time in ms at which keyboard event was first emitted (repeats are filtered out)\r\nconst KEYS = {};\r\n\r\nconst _isKeyDown = code => KEYS[code] || 0;\r\n\r\nconst _releaseKey = code => delete KEYS[code];\r\n\r\naddEventListener('keydown', e => {\r\n  // prevent itch.io from scrolling the page up/down\r\n  // e.preventDefault();\r\n\r\n  if (!e.repeat) {\r\n    KEYS[e.code] = performance.now();\r\n  }\r\n});\r\n\r\naddEventListener('keyup', e => _releaseKey(e.code));\r\n\r\n\r\n\r\n\r\n/* public API */\r\n\r\n// returns the most recent key pressed amongst the array passed as argument (or 0 if none were)\r\nexport const isKeyDown = (...codes) => Math.max(...codes.map(code => _isKeyDown(code)))\r\n\r\n// retuns the list of keys currently pressed\r\nexport const whichKeyDown = () => Object.keys(KEYS).filter(code => _isKeyDown(code));\r\n\r\n// returns if any key is currently pressed\r\nexport const anyKeyDown = () => whichKeyDown().length;\r\n\r\n// return true if a key can be released (must be currently pressed) or false if it can't\r\n// note: this \"consumes\" the key pressed by releasing it (only if it was pressed)\r\nexport const isKeyUp = code => _isKeyDown(code) ? _releaseKey(code) : false;", "\r\nimport { WIDTH, HEIGHT, GAME_TITLE } from \"./config.js\";\r\nimport { Canvas } from \"./canvas.js\";\r\nimport { TextRenderer } from \"./text.js\";\r\nimport { Room, Object } from \"./objects.js\";\r\nimport { isKeyDown } from \"./keyboard.js\";\r\n\r\nlet assets = {\r\n    images: {\r\n        splash: \"../img/splash1.webp\",\r\n        splash2: \"../img/splash2.webp\",\r\n        font: \"../img/hampsterfont.webp\"\r\n    }\r\n}\r\n\r\nlet currentFrame = 0;\r\nlet targetFrames = 60;\r\n\r\nlet lastFrameTime = performance.now();\r\nlet startFrameTime = lastFrameTime;\r\n\r\nlet rooms = [];\r\nlet canvas = new Canvas(\"c\", WIDTH, HEIGHT);\r\nlet text;\r\ncanvas.fill(\"#222034\");\r\n\r\nlet splash = new Image();\r\nsplash.src = assets.images.splash;\r\nsplash.onload = () => {\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    let font = new Image();\r\n    font.src = assets.images.font;\r\n    font.onload = () => {\r\n        console.log(\"font loaded\")\r\n        text = new TextRenderer(canvas, font);\r\n        window.onerror = (e) => {\r\n            text.throwPanic(e);\r\n        }\r\n    }\r\n}\r\n\r\nclass DebugEntity extends Object {\r\n    constructor() {\r\n        super();\r\n        this.x = 0;\r\n        this.y = 0;\r\n    }\r\n\r\n    draw() {\r\n        canvas.context.fillStyle = \"red\";\r\n        canvas.context.fillRect(this.x, this.y, 10, 10);\r\n    }\r\n}\r\n\r\n// Create all the game rooms\r\n\r\nlet loadingRoom = new Room(\"loading\");\r\nloadingRoom.updateStatus = (status) => {\r\n    console.log(status);\r\n    canvas.fill(\"#222034\");\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    text.render(status, 0, 0);\r\n}\r\n\r\nlet debugRoom = new Room(\"debug\");\r\ndebugRoom.draw = () => {\r\n    canvas.fill(\"#222034\");\r\n    canvas\r\n    for (let i = 0; i < debugRoom.objects.length; i++) {\r\n        debugRoom.objects[i].draw();\r\n    }\r\n}\r\ndebugRoom.drawGUI = () => {\r\n    text.render(\"Welcome to the Debug Room,\\nwe've got fun and games\", 0, canvas.height-14);\r\n    text.render(\"Current Frame:\" + currentFrame + `(~${Math.floor((currentFrame/targetFrames)*100)/100}sec)`, 0, canvas.height-21);\r\n}\r\nlet testObject = new DebugEntity(0, 0);\r\ndebugRoom.objects.push(testObject);\r\n\r\nrooms.push(loadingRoom);\r\nrooms.push(debugRoom);\r\n\r\nlet roomIndex = 0;\r\nlet currentRoom = rooms[roomIndex];\r\n\r\nlet main = () => { // main game loop\r\n    requestAnimationFrame(main);\r\n\r\n    let now = performance.now();\r\n    let delta = now - lastFrameTime;\r\n\r\n    if (delta < 1000 / targetFrames) return;\r\n\r\n    currentFrame++;\r\n    \r\n    currentRoom.draw();\r\n    currentRoom.drawGUI();\r\n\r\n    lastFrameTime = now;\r\n\r\n    text.render(\"FPS:\" + Math.round(1000 / delta), 0, 0);\r\n}\r\n\r\nlet init = () => {\r\n    // begin loading all the assets.\r\n    currentRoom.updateStatus(\"Loading images...\");\r\n    for (let image in assets.images) {\r\n        currentRoom.updateStatus(\"Loading image \" + image);\r\n        let img = new Image();\r\n        img.src = assets.images[image];\r\n        img.onload = () => {\r\n            assets.images[image] = img;\r\n        }\r\n    }\r\n    currentRoom.updateStatus(\"Loading complete!\");\r\n\r\n    canvas.fill(\"#222034\");\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    setTimeout(() => {\r\n        currentRoom = rooms[1];\r\n        main();\r\n    }, 1000);\r\n}\r\n\r\nwindow.onload = () => {\r\n    try {\r\n        document.title = GAME_TITLE;\r\n        init();\r\n    } catch (e) {\r\n        text.throwPanic(e);\r\n    }\r\n}\r\n"],
-  "mappings": "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",
+  "sources": ["../src/js/config.js", "../src/js/utils.js", "../src/js/canvas.js", "../src/js/text.js", "../src/js/objects.js", "../src/js/keyboard.js", "../src/js/game.js"],
+  "sourcesContent": ["// Holds all the config for your game.\r\n\r\nconst GAME_TITLE = \"Untitled JS13K23 Game.\"\r\n\r\nconst WIDTH = 160; // pixels\r\nconst HEIGHT = 144; // pixels\r\n\r\nexport { GAME_TITLE, WIDTH, HEIGHT };\r\n", "// random shit\r\n\r\nexport const pi = Math.PI;\r\n\r\nexport const convertTileToScreen = (x, y) => ({x: x<<4, y: y<<4});\r\n", "\r\n// Holds canvas, context and adds endpoints for graphics\r\n\r\nimport { pi } from \"./utils.js\"\r\nclass Canvas {\r\n    constructor(id=\"c\", w=128, h=128) {\r\n        this.canvas = document.getElementById(id);\r\n        this.canvas.width = w;\r\n        this.canvas.height = h;\r\n\r\n        this.ctx = this.canvas.getContext(\"2d\");\r\n        this.ctx.imageSmoothingEnabled = false;\r\n        this.ctx.textBaseline = \"top\";\r\n\r\n        this.width = this.canvas.width;\r\n        this.height = this.canvas.height;\r\n\r\n        // camera\r\n        this.cX = 0;\r\n        this.cY = 0;\r\n    }\r\n\r\n    fill(c=\"black\") {\r\n        this.ctx.fillStyle = c;\r\n        this.ctx.fillRect(0, 0, this.width, this.height);\r\n    }\r\n    \r\n    drawImage(image, x, y, width = image.width, height = image.height) {\r\n        console.debug(\"drawImage\", image, x, y, width, height);\r\n        this.ctx.drawImage(image, x-this.cX, y-this.cY, width, height);\r\n    }\r\n\r\n    sliceImage(img, x, y, w, h, cropX, cropY, cropW, cropH, direction=0) {\r\n        // console.debug(\"sliceImage\", img, x, y, w, h, cropX, cropY, cropW, cropH, direction);\r\n        this.ctx.save();\r\n        this.ctx.translate((x+w/2)-this.cX, (y+h/2)-this.cY);\r\n        this.ctx.rotate(direction * pi/180);\r\n        this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w/2, -h/2, w, h);\r\n        this.ctx.restore();\r\n        // console.log(`${x}, ${y}, ${w}, ${h}, ${cropX}, ${cropY}, ${cropW}, ${cropH}`);\r\n    }\r\n\r\n    drawText(text, x, y, c=\"white\", size=16, font=\"monospace\") {\r\n        this.ctx.fillStyle = c;\r\n        this.ctx.font = `${size}px ${font}`;\r\n        this.ctx.fillText(text, x, y);\r\n    }\r\n\r\n    drawLine(x1, y1, x2, y2, c=\"white\", w=1) {\r\n        this.ctx.strokeStyle = c;\r\n        this.ctx.lineWidth = w;\r\n        this.ctx.beginPath();\r\n        this.ctx.moveTo(x1-this.cX, y1-this.cY);\r\n        this.ctx.lineTo(x2-this.cX, y2-this.cY);\r\n        this.ctx.stroke();\r\n    }\r\n}\r\n\r\nexport { Canvas };\r\n", "// draws text to the screen by splicing a font sheet.\r\n\r\nclass TextRenderer {\r\n    constructor(canvas, fontimg) {\r\n        this.fontimg = fontimg; // MUST BE AN IMAGE OBJECT\r\n        this.fontWidth = 7;\r\n        this.fontHeight = 7;\r\n        this.fontChars = \"abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~>\";\r\n        this.canvas = canvas;\r\n    }\r\n\r\n    drawLetter(letter, x, y, substituteOK=0) {\r\n        let index = this.fontChars.indexOf(letter.toLowerCase());\r\n        if (index == -1) {\r\n            if (!substituteOK) return;\r\n            this.canvas.drawText(letter, x, y, \"#ffffff\", 7, \"monospace\");\r\n        }\r\n        let sx = index * this.fontWidth;\r\n        let sy = 0;\r\n        // draw image to context\r\n        let yOffset = 0;\r\n        // if the letter is \",\", offset it by -1\r\n        if (letter == \",\") {\r\n            yOffset = -1;\r\n        }\r\n        this.canvas.sliceImage(this.fontimg, x, y + yOffset, this.fontWidth, this.fontHeight, sx, sy, this.fontWidth, this.fontHeight);\r\n    }\r\n\r\n    render(text, x, y) {\r\n        let heightOffset = 0;\r\n        let xOffset = 0;\r\n        for (let i = 0; i < text.length; i++) {\r\n            if (text[i] == \"\\n\") {\r\n                heightOffset++;\r\n                xOffset = 0;\r\n                continue;\r\n            }\r\n            this.drawLetter(text[i], x + (xOffset * this.fontWidth), y + (heightOffset * this.fontHeight));\r\n            xOffset++;\r\n        }\r\n    }\r\n\r\n    throwPanic = (err) => {\r\n        // This function is called when an error is caught but unhandled.\r\n        // It'll show the error on-screen.\r\n    \r\n        this.canvas.fill(\"#00000080\") // 50% black\r\n        \r\n        this.render(err, 0, 0);\r\n        throw err;\r\n    }\r\n}\r\n\r\nexport { TextRenderer };", "class Object {\r\n    draw() {}\r\n    step() {}\r\n}\r\n\r\n\r\nclass Room extends Object {\r\n    constructor(name=\"\") {\r\n        super();\r\n        this.objects = [];\r\n        this.name = name; // needs to be unique, otherwise the searching code will just use the first one it finds.\r\n    }\r\n\r\n    draw() {\r\n        for (let i = 0; i < this.objects.length; i++) {\r\n            this.objects[i].draw();\r\n        }\r\n    }\r\n\r\n    drawGUI() {\r\n\r\n    }\r\n\r\n    keyDown(key) {\r\n    }\r\n\r\n    keyUp(key) {\r\n    }\r\n\r\n\r\n\r\n    step() {\r\n        for (let i = 0; i < this.objects.length; i++) {\r\n            this.objects[i].step();\r\n        }\r\n    }\r\n}\r\n\r\n\r\n\r\nexport { Object, Room };", "// Manages keyboard inputs. Code may have been stolen from herebefrogs/gamejam-boilerplate, under MIT license.\r\n\r\n/** Keyboard input\r\n * Record time at which each key gets pressed\r\n * and provide utilities to queries which keys are pressed or released\r\n *\r\n * Note: importing any public function of this module\r\n * will install the keyboard event listeners\r\n */\r\n\r\n/* private */\r\n\r\n// time at which each key was pressed\r\n// key = KeyboardEvent.code\r\n// value = time in ms at which keyboard event was first emitted (repeats are filtered out)\r\nconst KEYS = {};\r\n\r\nconst _isKeyDown = code => KEYS[code] || 0;\r\n\r\nconst _releaseKey = code => delete KEYS[code];\r\n\r\naddEventListener('keydown', e => {\r\n  // prevent itch.io from scrolling the page up/down\r\n  e.preventDefault();\r\n\r\n  if (!e.repeat) {\r\n    KEYS[e.code] = performance.now();\r\n  }\r\n});\r\n\r\naddEventListener('keyup', e => _releaseKey(e.code));\r\n\r\n\r\n\r\n\r\n/* public API */\r\n\r\n// returns the most recent key pressed amongst the array passed as argument (or 0 if none were)\r\nexport const isKeyDown = (...codes) => Math.max(...codes.map(code => _isKeyDown(code)))\r\n\r\n// retuns the list of keys currently pressed\r\nexport const whichKeyDown = () => Object.keys(KEYS).filter(code => _isKeyDown(code));\r\n\r\n// returns if any key is currently pressed\r\nexport const anyKeyDown = () => whichKeyDown().length;\r\n\r\n// return true if a key can be released (must be currently pressed) or false if it can't\r\n// note: this \"consumes\" the key pressed by releasing it (only if it was pressed)\r\nexport const isKeyUp = code => _isKeyDown(code) ? _releaseKey(code) : false;", "\r\nimport { WIDTH, HEIGHT, GAME_TITLE } from \"./config.js\";\r\nimport { Canvas } from \"./canvas.js\";\r\nimport { TextRenderer } from \"./text.js\";\r\nimport { Room, Object } from \"./objects.js\";\r\nimport { whichKeyDown } from \"./keyboard.js\";\r\nimport { convertTileToScreen } from \"./utils.js\";\r\n\r\nconsole.debug(convertTileToScreen(1, 1));\r\n\r\nlet assets = {\r\n    images: {\r\n        splash: \"../img/splash1.webp\",\r\n        font: \"../img/hampsterfont.webp\",\r\n        tiles: \"../img/t.webp\"\r\n    },\r\n    spritesheets: {\r\n        player: [\r\n            {x: 0}, // looking up\r\n            {x: 16}, // looking right\r\n            {x: 32}, // looking down\r\n            {x: 48} // looking left\r\n        ]\r\n    },\r\n    tilesets: {\r\n        castle: [\r\n            {x: 0, y: 0}, // ???\r\n            {x: 16, y: 0}, // floor\r\n        ]\r\n    }\r\n\r\n}\r\n\r\nlet running = 1;\r\n\r\nlet currentFrame = 0;\r\nlet targetFrames = 60;\r\n\r\nlet lastFrameTime = performance.now();\r\n\r\nlet rooms = [];\r\nlet debugStatuses = [];\r\nlet canvas = new Canvas(\"c\", WIDTH, HEIGHT);\r\nlet text;\r\n\r\nlet pressedLastFrame = [];\r\ncanvas.fill(\"#222034\");\r\n\r\nlet splash = new Image();\r\nsplash.src = assets.images.splash;\r\nsplash.onload = () => {\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    let font = new Image();\r\n    font.src = assets.images.font;\r\n    font.onload = () => {\r\n        console.log(\"font loaded\")\r\n        text = new TextRenderer(canvas, font);\r\n        window.onerror = (e) => {\r\n            running = 0;\r\n            text.throwPanic(e);\r\n        }\r\n    }\r\n}\r\n\r\n// Entity class is here becuase otherwise every entity would need the canvas passed into it\r\nclass Entity extends Object {\r\n    constructor(x=0, y=0, spritesheet=null, sprite=null) {\r\n        super();\r\n        this.x = x;\r\n        this.y = y;\r\n        this.sprite = sprite;\r\n        this.spritesheet = spritesheet;\r\n    }\r\n\r\n    draw() {\r\n        canvas.drawImage(this.sprite, this.x, this.y);\r\n    }\r\n}\r\n\r\n// Create all the game rooms\r\nlet roomIndex = 0;\r\nlet currentRoom = rooms[roomIndex];\r\n\r\nlet searchForRoom = (name) => {\r\n    // returns the room's index in the rooms array\r\n    for (let i = 0; i < rooms.length; i++) {\r\n        if (rooms[i].name == name) return i;\r\n    } throw new Error(\"Room not found:\"+name);\r\n}\r\n\r\nconst changeRoom = (index) => {\r\n    currentRoom = rooms[index];\r\n    roomIndex = index;\r\n}\r\n\r\nconst loadingRoom = new Room(\"loading\");\r\nloadingRoom.updateStatus = (status) => {\r\n    console.log(status);\r\n    canvas.fill(\"#222034\");\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    text.render(status, 0, 0);\r\n}\r\n\r\nconst debugRoom = new Room(\"debug\");\r\ndebugRoom.draw = () => {\r\n    canvas.fill(\"black\");\r\n}\r\ndebugRoom.drawGUI = () => {\r\n    debugStatuses.push(\"Current Frame:\"+currentFrame+`(~${Math.round((currentFrame/targetFrames)*100)/100} sec)`);\r\n}\r\ndebugRoom.keyDown = (key) => {\r\n    if (key == \"Escape\") changeRoom(searchForRoom(\"menu\"));\r\n}\r\n\r\nconst menuRoom = new Room(\"menu\");\r\nlet menuOptions = [\r\n    {\"label\": \"Start Game\", \"action\": _ => {changeRoom(searchForRoom(\"game\"))}},\r\n    {\"label\": \"Debug Room\", \"action\": _ => changeRoom(searchForRoom(\"debug\"))},\r\n    {\"label\": \"Reload\", \"action\": _ => {running = 0; location.reload();}}\r\n];\r\nlet menuIndex = 0;\r\n\r\nmenuRoom.draw = () => {\r\n    canvas.fill(\"black\");\r\n}\r\nmenuRoom.drawGUI = () => {\r\n    text.render(GAME_TITLE, 8, 7*4);\r\n    for (let i = 0; i < menuOptions.length; i++) {\r\n        if (i == menuIndex) {\r\n            text.render(\">\", 8, 7*(i+5));\r\n        }\r\n        text.render(menuOptions[i].label, 16, 7*(i+5));\r\n    }\r\n}\r\nmenuRoom.keyDown = (key) => {\r\n    if (pressedLastFrame.includes(key)) return;\r\n    switch (key) {\r\n        case \"ArrowUp\":\r\n            menuIndex--;\r\n            break;\r\n        case \"ArrowDown\":\r\n            menuIndex++;\r\n            break;\r\n        case \"Enter\":\r\n            menuOptions[menuIndex].action();\r\n            break;\r\n    }\r\n    if (menuIndex >= menuOptions.length) menuIndex = 0;\r\n    if (menuIndex < 0) menuIndex = menuOptions.length-1;\r\n}\r\n\r\nlet currentLevelData = {\r\n    tiles: [\r\n        {id: 1, x: 1, y: 1}, // floor at tile coords 1, 1\r\n        {id:123, x: 2, y: 2},\r\n    ]\r\n}\r\n\r\nconst gameRoom = new Room(\"game\"); \r\ngameRoom.draw = () => {\r\n    canvas.fill(\"black\");\r\n    for (let i = 0; i < currentLevelData.tiles.length; i++) {\r\n        let tile = currentLevelData.tiles[i];\r\n        if (tile.id > currentLevelData.length) tile.id = 0;\r\n        let tileLocation = convertTileToScreen(tile.x, tile.y);\r\n        canvas.sliceImage(assets.images.tiles, tileLocation.x, tileLocation.y, 16, 16, tile.id*16, 0, 16, 16);\r\n    }\r\n\r\n    \r\n}\r\n\r\nrooms.push(loadingRoom);\r\nrooms.push(menuRoom);\r\nrooms.push(gameRoom);\r\nrooms.push(debugRoom);\r\n\r\ncurrentRoom = rooms[roomIndex];\r\n\r\nlet main = () => { // main game loop\r\n    if (!running) return;\r\n    requestAnimationFrame(main);\r\n    let now = performance.now();\r\n    let delta = now - lastFrameTime;\r\n\r\n    if (delta < 1000 / targetFrames) return;\r\n\r\n    currentFrame++;\r\n    debugStatuses = [];\r\n\r\n    currentRoom.draw();\r\n    currentRoom.drawGUI();\r\n\r\n    let currentKeys = whichKeyDown();\r\n    for (let i = 0; i < currentKeys.length; i++) {\r\n        debugStatuses.push(currentKeys[i]);\r\n        currentRoom.keyDown(currentKeys[i]);\r\n    }\r\n    \r\n    pressedLastFrame = currentKeys;    \r\n    \r\n    text.render(\"FPS:\" + Math.round(1000 / delta), 0, 0);\r\n    text.render(currentRoom.name, canvas.width-8*(currentRoom.name.length), 0);\r\n\r\n    if (currentFrame <= 60*5) {\r\n        debugStatuses.push(\"Debug mode.\");\r\n        debugStatuses.push(\"Dimensions:\"+canvas.width+\"x\"+canvas.height);\r\n        debugStatuses.push(\"Have fun!\");\r\n    }\r\n\r\n    for (let i = 0; i < debugStatuses.length; i++) {\r\n        text.render(debugStatuses[i], 0, canvas.height-7*(debugStatuses.length-i));\r\n    }\r\n\r\n    lastFrameTime = now;\r\n    }\r\n\r\nlet init = () => {\r\n    // begin loading all the assets.\r\n    currentRoom.updateStatus(\"Loading images...\");\r\n    for (let image in assets.images) {\r\n        currentRoom.updateStatus(\"Loading image \" + image);\r\n        let img = new Image();\r\n        img.src = assets.images[image];\r\n        img.onload = () => {\r\n            assets.images[image] = img;\r\n        }\r\n    }\r\n    console.log(assets.images);\r\n    console.log(\"Images loaded.\")\r\n    currentRoom.updateStatus(\"Loading complete!\");\r\n\r\n    canvas.fill(\"#222034\");\r\n    canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);\r\n    setTimeout(() => {\r\n        currentRoom = rooms[1];\r\n        main();\r\n    }, 1000);\r\n}\r\n\r\nwindow.onload = () => {\r\n    document.title = GAME_TITLE;\r\n    init();\r\n}\r\n"],
+  "mappings": "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",
   "names": []
 }
diff --git a/oldgame.js b/oldgame.js
deleted file mode 100644
index 895f09e8a27b13db8fc4d33d2af66b491f263329..0000000000000000000000000000000000000000
--- a/oldgame.js
+++ /dev/null
@@ -1,1395 +0,0 @@
-/*
-    For js13k 2022
-    Theme: death
-*/
-
-// CONFIG
-let id = 0;
-const pi = Math.PI;
-let pause = 0;
-let lP = "bye_dbh_" // this is for JS13K's shared localStorage
-const gPar = (key) => {
-
-    // Address of the current window
-    let address = window.location.search
-
-    // Returns a URLSearchParams object instance
-    let parameterList = new URLSearchParams(address)
-
-    // Returning the respected value associated
-    // with the provided key
-    return parameterList.get(key)
-};
-
-let lS = localStorage
-
-let gS = (o) => {
-    return lS.getItem(o);
-}
-let sS = (o, v, ops={}) => {
-    if (ops.c) { // compression
-        v = lzs.compress(v);
-    }
-    lS.setItem(`${lP}${o}`, `${v}`);
-}
-let o = {
-}
-
-for (let i of Object.keys(lS)) {
-    console.log(i)
-    if (i.startsWith(`${lP}o_`)) {
-        switch(gS(i)) {
-            case "true":
-                o[i.slice(10)] = 1
-                break;
-            case "false":
-                o[i.slice(10)] = 0
-                break;
-        }
-        break;
-    }
-}
-
-const cLV = gPar("lv");
-
-class Canvas {
-    constructor(id) {
-        this.c = document.getElementById(id);
-        this.ctx = this.c.getContext('2d');
-        this.w = this.c.width;
-        this.h = this.c.height;
-        // get the width and height of the canvas from CSS
-        this.tW = this.c.offsetWidth;
-        this.tH = this.c.offsetHeight;
-        this.cam = {x: 0, y: 0};
-
-        this.mPos = {x: 0, y: 0};
-
-    }
-
-    fill(color) {
-        this.ctx.fillStyle = color;
-        this.ctx.fillRect(0, 0, this.w, this.h);
-    }
-
-    // Mouse position crap
-    gMP(evt) {
-        const rect = this.c.getBoundingClientRect(), // abs. size of element
-            scaleX = this.c.width / rect.width,    // relationship bitmap vs. element for x
-            scaleY = this.c.height / rect.height;  // relationship bitmap vs. element for y
-
-        this.mPos.x = ((evt.clientX - rect.left) * scaleX) + this.cam.x;
-        this.mPos.y = ((evt.clientY - rect.top) * scaleY) + this.cam.y;
-
-        return {
-        x: (evt.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
-        y: (evt.clientY - rect.top) * scaleY     // been adjusted to be relative to element
-        }
-    }
-
-    translate(x, y) {
-        this.ctx.translate(x, y);
-    }
-
-    rotate(angle) {
-        this.ctx.rotate(angle);
-    }
-
-    // Drawing
-    dImg(img, x, y, w, h, direction=0, originx=x+w/2, originy=y+h/2) {
-        this.ctx.save();
-        this.ctx.translate(originx-this.cam.x, originy-this.cam.y);
-        this.ctx.rotate(direction * pi/180);
-        this.ctx.drawImage(img, (-w/2), -h/2, w, h);
-        this.ctx.restore();
-    }
-    sImg(img, x, y, w, h, cropX, cropY, cropW, cropH, direction=0) {
-        this.ctx.save();
-        this.ctx.translate((x+w/2)-this.cam.x, (y+h/2)-this.cam.y);
-        this.ctx.rotate(direction * pi/180);
-        this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w/2, -h/2, w, h);
-        this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w/2, -h/2, w, h);
-        this.ctx.restore();
-        // console.log(`${x}, ${y}, ${w}, ${h}, ${cropX}, ${cropY}, ${cropW}, ${cropH}`);
-    }
-
-    dI(img, x, y, w, h, direction=0) {
-        // alias for drawImg
-        this.dImg(img, x, y, w, h, direction);
-    }
-
-    dR(x, y, w, h, color="white") {
-        this.ctx.fillStyle = color;
-        this.ctx.fillRect(x-this.cam.x, y-this.cam.y, w, h);
-    }
-
-    sR(x, y, w, h, color) {
-        this.ctx.strokeStyle = color;
-        this.ctx.strokeRect(x-this.cam.x, y-this.cam.y, w, h);
-    }
-
-    dT(string, x, y, scaley, scalex, color, align="", vAliign="top") {
-        string = string.toUpperCase();
-        let chars = string.split("");
-        // console.log(chars);
-
-        let charWidth = 7
-        let charOff = 0;
-        // check if there's an odd number of chars
-        if (chars.length % 2 == 1) {
-             charOff = 1
-        }
-        let strLength = (chars.length * charWidth - charOff) * scalex;
-
-        let charHeight = 7
-        let strHeight = (charHeight * scaley);
-        if (strHeight % 2 == 1) {
-            strHeight += 1;
-        }
-
-        if (align === "middle") {
-            x = x - strLength / 2;
-        } else if (align === "end") {
-            x = x - strLength;
-        }
-        
-        switch(vAliign) {
-            case "middle":
-            case "center":
-                y = y - strHeight/2;
-                break;
-            case "bottom":
-                y = y - strHeight;
-                break;
-        }
-
-
-        let charI = 0;
-        let nextOffset = (7 * scalex);
-        for (let char of chars) {
-
-            this.ctx.fillStyle = color;
-            let row = 0;
-            let col = 0;
-            // offset is the amount of pixels to offset the character by. you can calculate this by multiplying the current character (they're all the same size) by the scalex and scaley
-            let offset = nextOffset;
-
-            char = fI[char];
-            if (char == undefined) {
-                // leave a blank space
-            } else {
-                for (let cRow in char) {
-                    col = 0;
-                    // for each pixel in the row
-                    for (let c of char[cRow]) {
-                        if (c == 1) {
-                            this.ctx.fillRect((x + (col * scalex) + (charI * offset)) - this.cam.x,( y + (row * scaley)) - this.cam.y, scalex, scaley);
-
-                        }
-                        col++;
-                    }
-                    row++;
-                }
-            }
-
-            charI++;
-            // console.log(charI)
-
-            nextOffset = (7 * scalex);
-
-        }
-
-        return {
-            "w": strLength,
-            "h": strHeight
-        }
-
-    }
-
-    sC(x, y) {
-        this.cam.x = x;
-        this.cam.y = y;
-    }
-
-}
-
-// Entity classes
-
-class Entity {
-    constructor(name, x, y, sprite=undefined) {
-        this.name = name,
-        this.x = x,
-        this.y = y,
-        this.sprite = sprite
-    }
-    step() {
-        console.log(`${this.name} is stepping`);
-        console.log(`${this.name} is at ${this.x}, ${this.y}`);
-    }
-    draw () {
-
-    }
-    intersects(other) {
-        return (this.x < other.x + other.w && this.x + this.w > other.x && this.y < other.y + other.h && this.y + this.h > other.y)
-    }
-}
-
-class Room {
-    constructor(name) {
-        this.id = id;
-        id += 1;
-        this.name = name;
-        this.objects = [];
-        this.background = "#111";
-        this.w = c.w;
-        this.h = c.h;
-    }
-
-    spawn(entity) {
-        this.objects.push(entity)
-    }
-
-    step() {
-        // step all objects in the room
-        for (let obj of this.objects) {
-            obj.step();
-        }
-    }
-
-    draw() {
-        // draw all objects in the room
-        for (let obj of this.objects) {
-            obj.draw();
-        }
-    }
-
-    dGUI() {
-
-    }
-
-    kD(key) {
-        // console.log(key);
-    }
-    kH(key) {
-        // console.log(key);
-    }
-    click(x, y) {
-        // console.log(x, y);
-    }
-
-    start() {
-        c.cam = {x:0,y:0}
-    }
-
-}
-
-// INIT CANVAS
-let c = new Canvas('gameCanvas');
-gameCtx = c.ctx;
-c.fill("#151f1f");
-gameCtx.imageSmoothingEnabled = false;
-
-let dPM = _=>{
-    c.ctx.globalAlpha = .7;
-    c.fill("#000");
-    c.ctx.globalAlpha = .85;
-    c.dR((c.w/2-150)+c.cam.x,120+c.cam.y, 300,120, "#000")
-    c.ctx.globalAlpha = 1;
-    c.dT("paused", c.w/2+c.cam.x,c.h/2-30+c.cam.y, 3,3,"#fff", "middle","middle");
-    for (let o in gameRoom.pseo) {
-        let t = c.dT(gameRoom.pseo[o].t, c.w/2+c.cam.x, c.h/2+(o*9)+c.cam.y, 1,1,"#fff", "middle");
-        if (o == gameRoom.pses) {
-            let a = img.a;
-            c.dImg(a, ((c.w/2+c.cam.x)-t.w/2)-8, c.h/2+(o*9)+c.cam.y, 6,7)
-        }
-    }
-}
-
-c.dT("Death By Hamster", c.w / 2, c.h / 2 - 40, 2, 2, "white", "middle");
-
-// Load images
-let img = {
-        "ingame": "./aimerthing.png",
-        "cursor": "./cursor.png",
-        "tileset": "./t.png",
-        "human": "./human.png",
-        "car": "./hamster.png",
-        "gun": "./gun.png",
-        "a": "./arw.png" // arrow
-};
-
-let snd = {
-    select: "./blip.mp3"
-}
-
-const beep = _=> {
-    snd.select.pause()
-    snd.select.currentTime = 0;
-    snd.select.play()
-}
-
-let loader = new Room("loader");
-let lText = "Loading...";
-let lErrT;
-let lErr;
-loader.dGUI = () => {
-    c.dT(lText, c.w / 2, c.h / 2, 2, 2, "white", "middle");
-    if (lErr) {
-        c.dT(lErrT, c.w / 2, c.h / 2 + 20, 1, 1, "red", "middle");
-    }
-}
-let rooms = [];
-
-let limg = 0;
-let timg = 7;
-
-lText = `Loading...`;
-
-// after all images are loaded, and no errors occured, start the game
-for (let key in img) {
-    // attempt to load the image
-    let IMG = new Image();
-    IMG.addEventListener('load', () => {
-        limg++;
-        lText = `Loading images (${limg} / ${timg})`
-    });
-    IMG.addEventListener('error', (e) => {
-        lErr = 1;
-        lErrT = `Error loading image ${e.target.src}`;
-    } );
-    IMG.src = img[key];
-
-    // add the image to the images object
-    img[key] = IMG;
-}
-
-console.log("SAAA")
-
-let lsnd = 0;
-let tsnd = 0;
-
-for (let key in snd) {
-    let SND = new Audio(snd[key]);
-    // SND.addEventListener('load', () => {
-    //     lsnd++;
-    //     lText = `Loading sounds (${lsnd} / ${tsnd})`
-    //     if (lsnd == tsnd) {
-    //         console.log("Finish")
-    //     }
-    // });
-    // SND.addEventListener('error', (e) => {
-    //     lErr = 1;
-    //     lErrT = `Error loading image ${e.target.src}`;
-    // } );
-
-    // add the image to the images object
-    snd[key] = SND;
-}
-
-loader.step = _=> {
-    setRoom(1)
-}
-
-let levels = [
-        /*tutorial*/ "NrCMBoIJgXXNLgMx2AVkQFlRXqrgAMy+R4s8BxoqmZhqGED8GVjyRHdL64AbF1bgMvDAHYhwQQA4p0EvAhJFCOiiUDVESRoSSK+yDi01NbE4MMQMem8c10za8qgCc5V5pXXOzhc6SxNjCBCEIcnbgcuE64LHgHglyaCYeqZqSGQgeUXK+ggmgwSbFIqXE-GkCJnJV8IKC2YKS9dIi8ahZ5fCtNb3RDu0egYle7WWGkmV6tp3CdOEEkuIcoMprBHqCoCp6BLvzwAcq2Sf9x5Aqq5RX0aSHbqSSMs+JXeDTvHKHxZuQYkguEBZT+whGgJ+vAgclemjkT3hn2qNwQZVRuB0pQgbUxRzx2VwYVKBFxkAIhPJyM0oAIcLRBERaIgTLx9NBxHZYy5HlZAPeMCAA",
-        /* lv 2 */ "NrCsBoGZwBgXXMALLWCzgIxsRATDsAJzgF7qYEry7gQ0YBshEA7C+ABwckMSYwOmbAwKDMFKFknRyibAQnys05QvRVVwTXO2pdzSoQFZBuxYo1YyVo5EnCoD9WuxLgb8ZJLvsJXX5OaoL2ytyhHuDsEdgQMeDM8fiS7AFcpBQozGn8koYpWtjcvlLxBPHYEWJBeigR7ChI6BAQTbTMbRgNzemdECR9puCDjp2ORp2G0J2K0KC20IxWgjOo84jVSxtY0Kw9Rpz7RfuCh7QkZxjcl2xcPRA3Ko8EjyiP0I-Ml8Uf6OynyyiMmGkioDhBajooKhyjmkhQ60ii3hCRRe1hQOUBHRkQIW0i2HxbkxkRaeRhkXYiKKFMC1KG9McjIIzNRamxzhJni5QyJ4BIfJIOJpwvSfPY4p5zGFgmYfIg8q5KEcSzgQA",
-        /* lv 3 */ "NrCMBoCZwFgXXGcBmcBWBTX0dCPg91MiA2E8CAdkwlRsTRXAA5Mno3ErLXapiiCNHJCBDMDGaiwwlBWiQFlTFOgAGds02NY4HcCZMDTUvq0tzunifABOK4crrHTUBFugNW0Kk9SDM1BjTB4pAiNYLTMI8DD+HgxEenAZdzi+XSkuJyYc00zCDIl8OP4pNJdTcsEkI34zJKQzNNSysSYS5lB+VCVdVGRMGPkxNRqejpUhKqh+JiGxM0XmuaXppB5JzbWdlYhLfdZdg42IB23zk-tRpFAXI-vrp8vKCFf0x6r+L3a7itoLlAUiaeSiugcsSeUPwPmgBCC2AovlqKJRMjcqHyb0Kbk4Phc2Ic2MsOVOTVOXUsrQcFJuNL+7xcJSBLla6XZ1B+Im5qJxdJRXWBfzc2UwlmChTwnWR1VwlHq8slBGlu1VK1V2wuwl5H0UvMegx+fWNZ0oUg+Uke4zEwoI70s-SKoB4TrwWx+Ep+F2RPEeh29tyCkORtNClAcGKgbK0kAgUcgPLEib5KftUGgRxTTo4eH4kCB4bjZuLFItDidwhclejtyr4KQBdR1dhybo+Z1iEdqBkZkgqG2ihN8v7tyHDfHoMolgIW3iiAtNmGUA8PksngctibBgt8jgQA"
-]
-
-hamsterRef = {
-    "file": img.car,
-    "nl": {
-        "x": 0,
-        "y": 0,
-        "w": 32,
-        "h": 16,
-    }
-}
-
-let lRef = {
-    "file": img.tileset,
-    "default": {
-        "x": 0,
-        "y": 0,
-        "w": 32,
-        "h": 32,
-        "type": "blank"
-    },
-    "tiles": [
-        {
-        },
-        {
-            "x": 32,
-            "type": "floor"
-        },
-        {
-            "x": 64,
-            "type": "wall"
-        },
-        {
-            "x": 96,
-            "type": "wall"
-
-        },
-        {
-            "x": 128,
-            "type": "wall"
-        },
-        {
-            "x": 160,
-            "type": "wall"
-        },
-        {
-            "x": 192,
-            "type": "wall"
-        },
-        {
-            "x": 224,
-            "type": "wall"
-        },
-        {
-            "x": 256,
-            "type": "wall"
-        },
-        { // player
-            "x": 32,
-            "type": "floor"
-        },
-        { // human
-            "x": 32,
-            "type": "floor"
-        },
-        {
-            "x": 352,
-            "type": "wall"
-        },
-        {
-            "x": 384,
-            "type": "wall"
-        },
-        {
-            "x": 416,
-            "type": "wall"
-        },
-        {
-            "x": 448,
-            "type": "vent"
-        },
-    ]
-}
-
-
-for (let tile of lRef.tiles) {
-    // if the tile is missing properties from the default, add them
-    for (let key in lRef.default) {
-        if (!tile[key]) {
-            tile[key] = lRef.default[key];
-        }
-    }
-}
-
-console.debug(img)
-let targFPS = 60;
-let frame = 0;
-
-
-let menu = new Room("menu");
-
-menu.s = 0
-menu.o = [
-    {
-        "t": "Play",
-        "a": _=>{ setRoom(4) } // go to game room
-    },
-    {
-        "t": "Editor",
-        "a": _=>{ setRoom(3) } // go to level editor
-    },
-    {
-        "t": "Settings",
-        "a": _=>{ setRoom(5) }
-    }
-]
-
-
-menu.dGUI = () => {
-    c.dT("Death by Hamster", c.w/2, c.h/2-25, 4, 4, "white", "middle", "middle");
-    c.dT("W/Up or S/Down to select", c.w/2, c.h/2, 1,1,"gray","middle","middle");
-    c.dT("Space or ENTER to activate", c.w/2, c.h/2+8, 1,1,"gray","middle","middle")
-    for (let o in menu.o) {
-        let txt = c.dT(`${menu.o[o].t}`, c.w/2, (c.h/2+50)+(o*20), 2,2,"#fff","middle","top");
-        if (menu.s == o) {
-            let a = img.a;
-            let ap = ((c.w/2)-(txt.w/2))-a.width-4;
-            let ap2 = ((c.w/2)+(txt.w/2))+a.width-4;
-            c.dImg(a, ap, (c.h/2+50)+(o*20), a.width*2, a.height*2)
-            c.dImg(a, ap2, (c.h/2+50)+(o*20), a.width*2, a.height*2, 180)
-        }
-    }
-}
-const nextRoom = () => {
-    // move to the next room
-    roomI++;
-    if (roomI >= rooms.length) {
-        roomI = 0;
-    }
-    cRoom = rooms[roomI];
-    cRoom.start();
-}
-
-const prevRoom = () => {
-    // move to the previous room
-    roomI--;
-    if (roomI < 0) {
-        roomI = rooms.length - 1;
-    }
-    cRoom = rooms[roomI];
-    cRoom.start();
-}
-
-const setRoom = (roomI) => {
-    // set the current room to the given room
-    cRoom = rooms[roomI];
-    cRoom.start();
-}
-menu.kD = (key) => {
-    switch (key) {
-        case "ArrowUp":
-        case "KeyW":
-            menu.s -= 1
-            if (menu.s < 0) {
-                menu.s = menu.o.length - 1
-            }
-            beep()
-            break;
-        case "ArrowDown":
-        case "KeyS":
-            menu.s += 1
-            if (menu.s > menu.o.length - 1) {
-                menu.s = 0
-            }
-            beep()
-            break;
-        case "Space":
-        case "Enter":
-            menu.o[menu.s].a();
-            break;
-    }
-}
-
-let gameRoom = new Room("Game");
-let lvlS = new Room("Level Select")
-lvlS.s = 0
-lvlS.o = levels
-gameRoom.humans = 0
-gameRoom.li = 0
-let player   = new Entity("Player", 0,0);
-player.speed = 0;
-player.maxSpeed = 20;
-player.direction = 0;
-player.sprite = img.car;
-player.crop = hamsterRef.nl;
-player.x = 0;
-player.y = 0;
-player.w = player.crop.w*2;
-player.h = player.crop.h*2;
-gameRoom.o = [{t:"Next Level",a:_=>{lvlS.s += 1; lvlS.kD("Space"); gameRoom.tutorial=0}}, {t:"Level Select",a: _=>{setRoom(4)}}, {t:"Menu", a: _=>{setRoom(1)}}]
-
-gameRoom.s = 0
-gameRoom.pseo = [{t:"Back to Menu", a:_=>{setRoom(1)}},{t:"Level Select",a:_=>{setRoom(4)}}]
-gameRoom.pses = 0
-player.oldDir = 0;
-
-player.step = _=> {
-    // move in this.direction, which is an angle in degrees
-    player.tooltip = ""
-    player.x += player.speed * Math.cos(player.direction * pi / 180);
-    player.y += player.speed * Math.sin(player.direction * pi / 180);
-    // check that the player won't go into a wall on the next step, and if so, stop.
-    player.checkpoints = [];
-    for (let i = 0; i < 9; i++) {
-
-        let carCx = player.x + player.w/2;
-        let carCy = player.y + player.h/2;
-
-        let pointOx = 0;
-        let pointOy = 0;
-        switch (i) {
-            case 0:
-                pointOx = -32;
-                break;
-            case 1:
-                pointOx = 32;
-                break;
-            case 2:
-                pointOx = -30;
-                pointOy = -15;
-                break;
-            case 3:
-                pointOx = -30;
-                pointOy = 15;
-                break;
-            case 4:
-                pointOx = 30;
-                pointOy = -15;
-                break;
-            case 5:
-                pointOx = 30;
-                pointOy = 15;
-                break;
-            case 6:
-                pointOx = 20;
-                break;
-            case 7:
-                pointOx = -20;
-        }
-
-        let pointX = carCx - pointOx * Math.cos(player.direction * pi / 180) - pointOy * Math.sin(player.direction * pi / 180);
-        let pointY = carCy - pointOx * Math.sin(player.direction * pi / 180) + pointOy * Math.cos(player.direction * pi / 180);
-
-        player.checkpoints.push({x: pointX, y: pointY});
-
-    }
-
-    for (let checkpoint of player.checkpoints) {
-        let x = checkpoint.x / 64;
-        let y = checkpoint.y / 64;
-        if (gameRoom.checktile(x, y, "wall")) {
-            player.direction = player.oldDir;
-            player.x = player.xy[0];
-            player.y = player.xy[1];
-            player.speed *= 0.001;
-        } else if (gameRoom.checktile(x, y, "vent")) {
-            player.tooltip = "Press SHIFT to vent"
-        }
-    }
-
-    // keep the camera centered on the player
-    c.sC(player.x - c.w/2, player.y - c.h/2);
-
-    player.oldDir = player.direction;
-    player.xy = [player.x, player.y]
-
-    player.speed *= .99
-    if (player.speed < 0) {
-        player.speed *= .009 
-    }
-
-}
-
-console.log(player);
-
-player.draw = _=> {
-    // draw this.sprite at this.x, this.y
-    c.sImg(player.sprite, player.x, player.y, player.w, player.h, player.crop.x, player.crop.y, player.crop.w, player.crop.h, player.direction);
-    // c.dT(`${player.x/64} ${player.y/64}`, player.x, player.y, 1,1,"white","middle","middle");
-    // canvas.strokeRect(player.x, player.y, player.w, player.h, "white");
-
-    let gun = img.gun;
-    let gunOx = 13;
-    let gunOy = 0;
-
-    let carCx = player.x + player.w/2;
-    let carCy = player.y + player.h/2;
-
-    // get gunx and guny by moving backwards (gunOx and gunOy) from the center of the car in this.direction
-    let gunx = carCx - gunOx * Math.cos(player.direction * pi / 180) - gunOy * Math.sin(player.direction * pi / 180);
-    let guny = carCy - gunOx * Math.sin(player.direction * pi / 180) + gunOy * Math.cos(player.direction * pi / 180);
-    player.gx = gunx
-    player.gy = guny
-
-    if (!pause&&!gameRoom.finish) {
-
-        // get the angle between the gun and the mouse
-        player.aim = Math.atan2(c.mPos.y - guny, c.mPos.x - gunx) * 180 / pi;
-
-    }
-
-    // canvas.drawText(`Width${gun.width} Height${gun.height}`, gunx, guny-15, 1, 1, "green", "middle", "middle");
-    c.dImg(gun, gunx, guny, gun.width*2, gun.height*2, player.aim, gunx, guny); // these two vars at the end are where the gun's center is placed
-    // canvas.drawRect(gunx, guny, 1,1, "red");
-
-    if (player.tooltip) {
-        c.dT(player.tooltip, player.x+32, player.y-16, 1, 1, "#64bee3", "middle")
-    }
-
-}
-
-player.shoot = () => {
-    // shoot a bullet
-    let bullet = new Entity("Bullet", player.gx, player.gy);
-    bullet.speed = 20;
-    bullet.direction = player.aim;
-    bullet.w = 2;
-    bullet.h = 2;
-
-    bullet.step = () => {
-        // for each step, check if it's path intersects with any other entity
-        for (let i = 0; i < cRoom.objects.length; i++) {
-            let ent = cRoom.objects[i];
-            if (ent != bullet && ent.intersects(bullet)) {
-                // if it does, remove the bullet and the entity unless it's the player
-                console.log(ent);
-                if (ent != player) {
-                    cRoom.objects.splice(i, 1);
-                    cRoom.objects.splice(cRoom.objects.indexOf(bullet), 1);
-                    gameRoom.humans -= 1;
-                    return;
-                }
-            }
-
-        }
-        if (gameRoom.checktile(bullet.x/64,bullet.y/64)) {
-            cRoom.objects.splice(cRoom.objects.indexOf(bullet), 1);
-        }
-        // if it doesn't, move the bullet
-        bullet.x += bullet.speed * Math.cos(bullet.direction * pi / 180);
-        bullet.y += bullet.speed * Math.sin(bullet.direction * pi / 180);
-    }
-    bullet.draw = () => {
-        c.dR(bullet.x, bullet.y, bullet.w,bullet.h, "#2f2f2f");
-    }
-    cRoom.spawn(bullet);
-}
-
-
-
-gameRoom.kD = (key) => {
-    if (!pause&&!gameRoom.finish){
-        switch (key) {
-            case "ArrowUp":
-            case "KeyW":
-                player.speed += player.accel;
-                if (player.speed > player.maxSpeed) {
-                    player.speed = player.maxSpeed;
-                }
-                break;
-            case "ArrowDown":
-            case "KeyS":
-                player.speed -= player.accel * .8
-                if (player.speed < -player.maxSpeed) {
-                    player.speed = -player.maxSpeed;
-                }
-                break;
-            case "ArrowLeft":
-            case "KeyA":
-                player.direction -= 2.5;
-                if (player.direction < 0) {
-                    player.direction = 360;
-                }
-                break;
-            case "ArrowRight":
-            case "KeyD":
-                player.direction += 2.5;
-                if (player.direction > 360) {
-                    player.direction = 0;
-                }
-                break;
-            case "Space":
-                player.shoot()
-                break;
-            case "ShiftLeft":
-                console.log("Triggered!")
-                for (let i = 0; i < 9; i++) {
-                    let x = Math.floor(player.checkpoints[i].x / 64);
-                    let y = Math.floor(player.checkpoints[i].y / 64);
-
-                    for (let tile of gameRoom.level) {
-                        if (lRef.tiles[tile[0]].type == "vent" && tile[1] == x && tile[2] == y) {
-                            for (let tile of gameRoom.level) if (lRef.tiles[tile[0]].type == "vent" && !(tile[1] == x) && !(tile[2] == y)) {
-                                console.log(x, y)
-                                console.log(tile[1], tile[2])
-                                player.x = tile[1] * 64;
-                                player.y = tile[2] * 64 + 16;
-                            }
-                        }
-                    }
-
-                }
-                break;
-        }
-
-    }
-    if (!gameRoom.finish ) {
-        if (key == "KeyP" || key == "Escape") {
-            pause = !pause
-        }
-        if (pause) {
-            switch (key) {
-                case "ArrowUp":
-                case "KeyW":
-                    gameRoom.pses -= 1
-                    if (gameRoom.pses < 0) {
-                        gameRoom.pses = gameRoom.pseo.length - 1
-                    }
-                    beep();
-                    break;
-                case "ArrowDown":
-                case "KeyS":
-                    gameRoom.pses += 1
-                    if (gameRoom.pses > gameRoom.pseo.length - 1) {
-                        gameRoom.pses = 0
-                    }
-                    beep();
-                    break;
-                case "Space":
-                case "Enter":
-                    pause = 0;
-                    gameRoom.tutorial = 0;
-                    gameRoom.pseo[gameRoom.pses].a()
-                    break;
-            }
-        }
-    }
-    if (gameRoom.finish) {
-        switch (key) {
-            case "ArrowUp":
-            case "KeyW":
-                gameRoom.s -= 1
-                if (gameRoom.s < 0) {
-                    gameRoom.s = gameRoom.o.length - 1
-                }
-                beep();
-                break;
-            case "ArrowDown":
-            case "KeyS":
-                gameRoom.s += 1
-                if (gameRoom.s > gameRoom.o.length - 1) {
-                    gameRoom.s = 0
-                }
-                beep();
-                break;
-
-            case "Space":
-            case "Enter":
-                gameRoom.finish = 0;
-                gameRoom.tutorial = 0;
-                gameRoom.o[gameRoom.s].a();
-                break;
-        }
-    }
-}
-gameRoom.kH = (key) => {
-    if (!pause&&!gameRoom.finish){
-        if (key == "ArrowUp" || key == "KeyW") {
-            player.speed += player.accel;
-            if (player.speed > player.maxSpeed) {
-                player.speed = player.maxSpeed;
-            }
-        }
-        if (key == "ArrowDown" || key == "KeyS") {
-            player.speed -= player.accel*1.1;
-            if (player.speed < -player.maxSpeed) {
-                player.speed = -player.maxSpeed;
-            }
-        }
-        if (key == "ArrowLeft" || key == "KeyA") {
-            player.direction -= 2.5;
-            if (player.direction < 0) {
-                player.direction = 360;
-            }
-        }
-        if (key == "ArrowRight" || key == "KeyD") {
-            player.direction += 2.5;
-            if (player.direction > 360) {
-                player.direction = 0;
-            }
-        }
-    }
-}
-gameRoom.click = (e) => {
-    if (!pause&&!gameRoom.finish){
-    player.shoot();
-    }
-}
-gameRoom.checktile = (tx, ty, tp) => {
-    tx = Math.floor(tx);
-    ty = Math.floor(ty);
-    for (let tile of gameRoom.level) {
-        if (lRef.tiles[tile[0]].type == tp && tile[1] == tx && tile[2] == ty) {
-            return true;
-        }
-    }
-    return false;
-}
-
-gameRoom.start = () =>{
-
-    if (cLV) {
-        gameRoom.level = cLV
-    }
-
-    if (gameRoom.li) {
-        gameRoom.level = JSON.parse(lzs.decompressFromEncodedURIComponent(levels[gameRoom.li - 1]))
-    }
-
-    gameRoom.finish = 0;
-
-    gameRoom.objects = [];
-
-
-    gameRoom.humans = 0;
-    gameRoom.spawn(player);
-
-
-    if (gameRoom.tutorial) {
-        player.accel = .05
-    } else {
-        player.accel = .1
-
-    }
-
-
-    for (let tile of gameRoom.level) {
-        if (tile[0] === 9) {
-            player.x = (tile[1]*64)+32
-            player.y = (tile[2]*64)+32
-        }
-        if(tile[0]===10){
-
-            let pooman = new Entity("Human", (tile[1]*64),(tile[2]*64), img.human)
-            pooman.w = 26*2
-            pooman.h = 16*2
-            pooman.bh = Math.floor(Math.random()*3);
-            pooman.bb = Math.floor(Math.random()*3)
-            pooman.getT=_=>{
-                pooman.tX = Math.floor((pooman.x + pooman.w) / 64)
-                pooman.tY = Math.floor((pooman.y + pooman.h) / 64)
-            }
-            pooman.step = _=>{
-                let xy = [pooman.x, pooman.y]
-                if (pooman.timer<=0){
-                    let director = Math.floor(Math.random()*4)
-                    pooman.direction = director*90;
-                    if (director === 0){
-                        pooman.y -= pooman.h;
-                    }
-                    if (director === 1){
-                        pooman.x += pooman.w;
-                    }
-                    if (director === 2){
-                        pooman.y += pooman.w;
-                    }
-                    if (director === 3){
-                        pooman.x -= pooman.h;
-                    }
-                    pooman.getT();
-                    if (gameRoom.checktile(pooman.tX, pooman.tY)){
-                        pooman.x = xy[0]
-                        pooman.y = xy[1]
-                        pooman.step()
-                        return
-                    }
-
-                    pooman.timer = Math.floor(Math.random() * (120 - 60) ) + 60;
-                }
-                pooman.timer--;
-            }
-            pooman.draw = _=>{
-                c.sImg(pooman.sprite, pooman.x, pooman.y, pooman.w, pooman.h, pooman.bb*pooman.w/2, 0, pooman.w/2, pooman.h/2, pooman.direction);
-                c.sImg(pooman.sprite, pooman.x, pooman.y, pooman.w, pooman.h, pooman.bh*pooman.w/2, pooman.h/2, pooman.w/2, pooman.h/2, pooman.direction);
-                // c.dT(`${pooman.timer} :: ${pooman.direction}`, pooman.x, pooman.y, 1, 1, "white", "middle", "middle");
-            }
-            pooman.timer = 90;
-            gameRoom.spawn(pooman);
-            gameRoom.humans += 1;
-        }
-    }
-}
-
-gameRoom.step = _=> {
-    if (lvlS.s+1 >= lvlS.o.length) {
-        gameRoom.o[0] = {t:"you killed them all!", a:_=>{alert("well done!!!")}}
-    }
-    if (!pause&&!gameRoom.finish) {
-        if (gameRoom.humans <= 0){
-            gameRoom.tutorial = 0;
-            gameRoom.finish = true;
-        }
-        // step all objects in the room
-        for (let obj of gameRoom.objects) {
-            obj.step();
-        }
-    }
-}
-
-gameRoom.draw = _=> {
-
-    for (let tile of gameRoom.level) {
-        // [index, x, y]
-        c.sImg(lRef.file, (tile[1]*32)*2, (tile[2]*32)*2, 32*2,32*2, lRef.tiles[tile[0]].x, 0, 32, 32);
-    }
-
-    if (gameRoom.tutorial) {
-        c.dT("Welcome to", 3*64, 64+15, 1, 1, "black");
-        c.dT("Death by Hamster", (3*64)+32, 64+25, 2,2, "black", "middle");
-
-        c.dT("Use WASD/arrows to move", 128, 2*64, 1,1, "black");
-        c.dT("Aim with the mouse and click to shoot!", 128, 2*64+10, 1,1, "black");
-
-        c.dT("As a member of the hamster uprising,", 6*64, 3*64+25, 1,1, "black");
-        c.dT("you might want to kill any humans", 6*64, 3*64+35, 1,1, "black");
-        c.dT("you find!", 10*64-16, 3*64+45, 1,1, "black", "end");
-
-
-    }
-    for (let i = 0; i < cRoom.objects.length; i++) {
-        cRoom.objects[i].draw();
-    }
-}
-
-gameRoom.dGUI = _=>{
-    c.dT(`Humans:${gameRoom.humans}`, (c.w-10)+c.cam.x, 10+c.cam.y, 2,2,"#fff", "end")
-
-    if (pause) {
-        dPM(gameRoom);
-    }
-    if (gameRoom.finish) {
-        c.ctx.globalAlpha = .7;
-        c.fill("#000");
-        c.ctx.globalAlpha = .85;
-        c.dR((c.w/2-150)+c.cam.x,120+c.cam.y, 300,150, "#000")
-        c.ctx.globalAlpha = 1;
-
-
-        c.dT("You Won!", c.w/2+c.cam.x,c.h/2-30+c.cam.y, 3,3,"#fff", "middle","middle");
-        for (let o in gameRoom.o) {
-            let t = c.dT(gameRoom.o[o].t, c.w/2+c.cam.x, c.h/2+(o*9)+c.cam.y, 1,1,"#fff", "middle");
-            if (o == gameRoom.s) {
-                let a = img.a;
-                c.dImg(a, ((c.w/2+c.cam.x)-t.w/2)-8, c.h/2+(o*9)+c.cam.y, 6,7)
-            }
-        }
-    }
-}
-
-let editor = new Room("Editor");
-editor.i = 0;
-editor.t = lRef;
-editor.l = []
-editor.saving = false
-editor.sa = 0
-
-editor.start = _=>{
-    editor.dPos = [15,65]
-}
-editor.draw = _=>{
-    for (let tile of editor.l) {
-        // [index, x, y]
-        c.sImg(lRef.file, (tile[1]*32)+editor.dPos[0], tile[2]*32+editor.dPos[1], 32,32, tile[0]*32, 0, 32, 32);
-        c.dR(editor.dPos[0], editor.dPos[1], 1,1, "red")
-    }
-}
-editor.step = _=>{
-    if (editor.i < 0) {
-        editor.i = lRef.tiles.length-1;
-    }
-    if (editor.i > lRef.tiles.length-1) {
-        editor.i = 0;
-    }
-}
-editor.generate = _=>{
-    editor.saving=1
-    for (let tile of editor.l) {
-        if (tile[0] == 0){
-            editor.l.splice(editor.l.indexOf(tile))
-        }
-    }
-    let encodedLevel = lzs.compressToEncodedURIComponent(JSON.stringify(editor.l))
-    console.log(encodedLevel);
-    if (encodedLevel != editor.data){
-        document.getElementById("leveltext").innerText = encodedLevel;
-        document.getElementById("levelLink").innerHTML = `<a href="/?lv=${encodedLevel}&goto=2">Play</a>`
-    }
-    editor.data = encodedLevel;
-    editor.saving=0;
-    editor.sa = 1;
-}
-editor.click = (x,y)=>{
-    if (y < 50) {
-        if (x> 516 && y < 50) {
-            if (!editor.saving){
-                editor.generate()
-            }
-            editor.saveclick = true
-        }
-    }
-    else {
-        x = Math.floor((x-editor.dPos[0])/32)
-        y = Math.floor((y-editor.dPos[1])/32)
-        // console.debug(x,y)
-        for (let t in editor.l) {
-            if (editor.l[t][1] == x && editor.l[t][2] == y) {
-                editor.l[t] = [editor.i, x, y];
-                return;
-            }
-        }
-        editor.l.push([editor.i,x,y])
-        editor.sa = 0
-    }
-}
-editor.kH = (key) => {
-    switch (key) {
-        case "KeyW":
-        case "ArrowUp":
-            editor.dPos[1] += 4
-            break;
-        case "KeyS":
-        case "ArrowDown":
-            editor.dPos[1] -= 4
-            break;
-        case "KeyA":
-        case "ArrowLeft":
-            editor.dPos[0] += 4
-            break;
-        case "KeyD":
-        case "ArrowRight":
-            editor.dPos[0] -= 4
-            break;
-    }
-}
-
-editor.dGUI = _=>{
-    c.dR(0,0,c.w,50,"gray")
-    c.dT(`DBH Editor::${editor.n}`, 15,25,2,2,"#fff","start","middle");
-    let s = c.dT(`Save`, c.w-15,25,2,2,"#fff","end","middle");
-    if (c.mPos.x > (c.w-30)-s.w && c.mPos.y < 50) {
-        // console.debug((c.w-30)-s.w)
-        c.dT(`Save`, c.w-15,25,2,2,"#e5e5e5","end","middle");
-    }
-    if (editor.sa) {
-        c.dT(`Save`, c.w-15,25,2,2,"#1fdc2f","end","middle");
-    } if (editor.saving) {
-        c.dT(`Save`, c.w-15,25,2,2,"#1fccdc","end","middle");
-    }
-
-    c.sImg(editor.t.file, c.mPos.x+16,c.mPos.y+16,32,32,32*editor.i,0,32,32);
-}
-
-
-
-lvlS.dGUI = () => {
-    c.dT("Death by Hamster", c.w/2, 25, 2, 2, "white", "middle", "top");
-    c.dT("Level Select", c.w/2, 44, 1,1,"gray","middle","middle");
-    for (let o in lvlS.o) {
-        let n = parseInt(o)+1
-        c.dT(`${n}`, (20)+(32*n), 70, 2, 2, "#fff", "middle", "middle")
-        if (o == lvlS.s) {
-            c.sR((20-14)+(32*n), 70-16, 32, 32, "#fff")
-        }
-    }
-}
-
-lvlS.kD = (key) => {
-    switch (key) {
-        case "ArrowUp":
-        case "ArrowLeft":
-        case "KeyW":
-        case "KeyA":
-            lvlS.s -= 1
-            if (lvlS.s < 0) {
-                lvlS.s = lvlS.o.length - 1
-            }
-            beep();
-            break;
-        case "ArrowDown":
-        case "ArrowRight":
-        case "KeyS":
-        case "KeyD":
-            lvlS.s += 1
-            if (lvlS.s > lvlS.o.length - 1) {
-                lvlS.s = 0
-            }
-            beep();
-            break;
-        case "Space":
-        case "Enter":
-            gameRoom.li = lvlS.s + 1;
-            if (lvlS.s === 0) {
-                gameRoom.tutorial = 1;
-            }
-            setRoom(2)
-            // beep();
-            break;
-        case "KeyE":
-            editor.l = JSON.parse(lzs.decompressFromEncodedURIComponent(lvlS.o[lvlS.s].data));
-            setRoom(3)
-            break;
-    }
-}
-
-let options = new Room("Settings")
-options.s = 0
-options.ops = o;
-options.o = [{
-    "t": "Show FPS",
-    "a": _=>{ o.showFPS = !o.showFPS; sS("o_showFPS", o.showFPS) },
-    "v": "showFPS"
-}, {
-    "t": "Menu",
-    "a": _=>{ setRoom(0) }
-}]
-
-options.dGUI = () => {
-    c.dT("Settings", c.w/2, 25, 2, 2, "#fff", "middle", "top");
-    for (let o in options.o) {
-        let s = options.o[o]
-        let txt = c.dT(`${options.o[o].t}`, 150, 50+(o*20), 2,2,"#fff","left","top");
-        if (options.s == o) {
-            let a = img.a;
-            c.dImg(a, 136, 50 + (o * 20), a.width * 2, a.height * 2)
-        }
-        let v = options.ops[s.v]
-        if (!(v==undefined)){
-            c.dT(`${v}`, 450, 50+(o*20), 2,2,"#fff", "end");
-
-        }
-    }
-}
-
-options.kD = (key) => {
-    switch (key) {
-        case "ArrowUp":
-        case "ArrowRight":
-        case "KeyW":
-            options.s -= 1
-            if (options.s < 0) {
-                options.s = options.o.length - 1
-            }
-            beep();
-            break;
-        case "ArrowDown":
-        case "ArrowLeft":
-        case "KeyS":
-            options.s += 1
-            if (options.s > options.o.length - 1) {
-                options.s = 0
-            }
-            beep();
-            break;
-        case "Space":
-        case "Enter":
-            if (options.o[options.s].a) {
-                options.o[options.s].a()
-            }
-            break;
-    }
-}
-
-
-rooms.push(loader);
-rooms.push(menu);
-rooms.push(gameRoom);
-rooms.push(editor);
-rooms.push(lvlS);
-rooms.push(options)
-let roomI = !gPar("goto") ? 0 : gPar("goto");
-
-let cRoom = rooms[roomI];
-
-
-let keysPressed = {};
-let keysLastPressed = {};
-
-document.addEventListener('keydown', (e) => {
-    keysPressed[e.code] = true;
-});
-document.addEventListener('keyup', (e) => {
-    keysPressed[e.code] = false;
-    keysLastPressed[e.code] = false;
-} );
-
-let lastTime = 0;
-
-let mse = {x: 0, y: 0};
-let lastClick = {x: 0, y: 0};
-let leftclicked = false;
-let rightclicked = false
-
-c.c.addEventListener('mousemove', (e) => {
-    mse = c.gMP(e);
-} );
-
-c.c.addEventListener("mousedown", (e) => {
-    // console.log(e);
-    e.preventDefault()
-    lastClick = c.gMP(e);
-    mse = c.gMP(e);
-    switch (e.button) {
-        case 0: // left
-            leftclicked=1;
-            break;
-        case 1:
-            rightclicked=1;
-            break;
-    }
-});
-c.c.addEventListener("mouseup", (e)=>{
-    // console.log(e);
-    lastClick = c.gMP(e);
-    mse = c.gMP(e);
-})
-c.c.oncontextmenu = _=>{return 0;}
-
-window.onwheel = (e)=>{
-    if (e.deltaY > 0) {
-        editor.i += 1;
-    }
-    if (e.deltaY < 0) {
-        editor.i -= 1;
-    }
-}
-
-try {
-    cRoom.start();
-
-    setInterval(() => {
-        c.tW = c.c.offsetWidth;
-        c.tH = c.c.offsetHeight;
-        c.scale = c.tW / c.w;
-        frame++;
-        c.fill(cRoom.background);
-
-        for (let key in keysPressed) {
-            if (keysPressed[key]) {
-                if (!keysLastPressed[key]) {
-                    cRoom.kD(key);
-                    keysLastPressed[key] = true;
-                } else if (keysLastPressed[key]) {
-                    cRoom.kH(key);
-                }
-            }
-        }
-        if (leftclicked) {
-            cRoom.click(lastClick.x, lastClick.y);
-            leftclicked = 0;
-        }
-
-        cRoom.step();
-        cRoom.draw();
-        cRoom.dGUI();
-
-        if (o.showFPS){
-            c.dT(`FPS:${Math.round(1000 / (Date.now() - lastTime))}`, 0+c.cam.x, 0+c.cam.y, 1, 1, "#fafafa", "left", "top");
-        }
-
-        switch (cRoom.name) {
-            case "menu":
-            case "Editor":
-                c.ctx.drawImage(img.cursor, Math.round(mse.x), Math.round(mse.y), img.cursor.width*2, img.cursor.height*2);
-                break;
-            case "Game":
-                c.ctx.drawImage(img.ingame, Math.round(mse.x)-16, Math.round(mse.y)-16, 32, 32);
-                break;
-        }
-        lastTime = Date.now();
-
-    } , 1000/targFPS); // 60 fps
-
-} catch (error) {
-    c.fill("#1c1c1c");
-    c.dT("Death By Hamster", c.w / 2, c.h / 2 - 40, 2, 2, "white", "middle");
-    c.dT(`${error}`, c.w/2, c.h / 2, 1, 1, "red", "middle");
-    c.dT(`pls let Bye know by emailing him via`, c.w /2, c.h / 2 + 40, 1, 1, "white", "middle");
-    c.dT('bye at byecorps.com', c.w / 2, c.h / 2 + 60, 2, 2, "white", "middle");
-}
diff --git a/src/img/hampsterfont.webp b/src/img/hampsterfont.webp
index 1fc8acb9d553748de667895d9daf2221aac6d515..a8eddc36fba2ac0e66216ed0d11b68c0bdb77315 100644
Binary files a/src/img/hampsterfont.webp and b/src/img/hampsterfont.webp differ
diff --git a/src/img/splash2.webp b/src/img/splash2.webp
deleted file mode 100644
index 1d6f0d16def6ae932103ea032bb38c508d2c4648..0000000000000000000000000000000000000000
Binary files a/src/img/splash2.webp and /dev/null differ
diff --git a/src/img/t.webp b/src/img/t.webp
new file mode 100644
index 0000000000000000000000000000000000000000..19001b624dc205d7218b15f4329add8f99d6a529
Binary files /dev/null and b/src/img/t.webp differ
diff --git a/src/js/canvas.js b/src/js/canvas.js
index d797244e669b026174fd7050f342f3551a39dfb6..050541a96fe3baf21d403085b845212eac7cf7f2 100644
--- a/src/js/canvas.js
+++ b/src/js/canvas.js
@@ -1,51 +1,58 @@
 
 // Holds canvas, context and adds endpoints for graphics
 
-const floor = function (...args) {
-    return Math.floor(...args);
-}
-
+import { pi } from "./utils.js"
 class Canvas {
     constructor(id="c", w=128, h=128) {
         this.canvas = document.getElementById(id);
         this.canvas.width = w;
         this.canvas.height = h;
 
-        this.context = this.canvas.getContext("2d");
-        this.context.imageSmoothingEnabled = false;
-        this.context.textBaseline = "top";
+        this.ctx = this.canvas.getContext("2d");
+        this.ctx.imageSmoothingEnabled = false;
+        this.ctx.textBaseline = "top";
 
         this.width = this.canvas.width;
         this.height = this.canvas.height;
+
+        // camera
+        this.cX = 0;
+        this.cY = 0;
     }
 
     fill(c="black") {
-        this.context.fillStyle = c;
-        this.context.fillRect(0, 0, this.width, this.height);
+        this.ctx.fillStyle = c;
+        this.ctx.fillRect(0, 0, this.width, this.height);
     }
     
     drawImage(image, x, y, width = image.width, height = image.height) {
         console.debug("drawImage", image, x, y, width, height);
-        this.context.drawImage(image, x, y, width, height);
+        this.ctx.drawImage(image, x-this.cX, y-this.cY, width, height);
     }
 
-    sliceImage(image, sx, sy, sw, sh, dx, dy, dw = sw, dh = sh) {
-        this.context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
+    sliceImage(img, x, y, w, h, cropX, cropY, cropW, cropH, direction=0) {
+        // console.debug("sliceImage", img, x, y, w, h, cropX, cropY, cropW, cropH, direction);
+        this.ctx.save();
+        this.ctx.translate((x+w/2)-this.cX, (y+h/2)-this.cY);
+        this.ctx.rotate(direction * pi/180);
+        this.ctx.drawImage(img, cropX, cropY, cropW, cropH, -w/2, -h/2, w, h);
+        this.ctx.restore();
+        // console.log(`${x}, ${y}, ${w}, ${h}, ${cropX}, ${cropY}, ${cropW}, ${cropH}`);
     }
 
     drawText(text, x, y, c="white", size=16, font="monospace") {
-        this.context.fillStyle = c;
-        this.context.font = `${size}px ${font}`;
-        this.context.fillText(text, x, y);
+        this.ctx.fillStyle = c;
+        this.ctx.font = `${size}px ${font}`;
+        this.ctx.fillText(text, x, y);
     }
 
     drawLine(x1, y1, x2, y2, c="white", w=1) {
-        this.context.strokeStyle = c;
-        this.context.lineWidth = w;
-        this.context.beginPath();
-        this.context.moveTo(x1, y1);
-        this.context.lineTo(x2, y2);
-        this.context.stroke();
+        this.ctx.strokeStyle = c;
+        this.ctx.lineWidth = w;
+        this.ctx.beginPath();
+        this.ctx.moveTo(x1-this.cX, y1-this.cY);
+        this.ctx.lineTo(x2-this.cX, y2-this.cY);
+        this.ctx.stroke();
     }
 }
 
diff --git a/src/js/config.js b/src/js/config.js
index 35cfb3dd3e4e14781eada74da917949295307a7f..2111b811d6f702d161b6ce33010975fba9dec0e2 100644
--- a/src/js/config.js
+++ b/src/js/config.js
@@ -2,7 +2,7 @@
 
 const GAME_TITLE = "Untitled JS13K23 Game."
 
-const WIDTH = 256; // pixels
-const HEIGHT = 256; // pixels
+const WIDTH = 160; // pixels
+const HEIGHT = 144; // pixels
 
 export { GAME_TITLE, WIDTH, HEIGHT };
diff --git a/src/js/game.js b/src/js/game.js
index feaaaafc7c6dc24b8e2835535ddacd08a4297570..3a1c55bad2cff59e1dc33d6fe229e4d15d4c4308 100644
--- a/src/js/game.js
+++ b/src/js/game.js
@@ -3,25 +3,47 @@ import { WIDTH, HEIGHT, GAME_TITLE } from "./config.js";
 import { Canvas } from "./canvas.js";
 import { TextRenderer } from "./text.js";
 import { Room, Object } from "./objects.js";
-import { isKeyDown } from "./keyboard.js";
+import { whichKeyDown } from "./keyboard.js";
+import { convertTileToScreen } from "./utils.js";
+
+console.debug(convertTileToScreen(1, 1));
 
 let assets = {
     images: {
         splash: "../img/splash1.webp",
-        splash2: "../img/splash2.webp",
-        font: "../img/hampsterfont.webp"
+        font: "../img/hampsterfont.webp",
+        tiles: "../img/t.webp"
+    },
+    spritesheets: {
+        player: [
+            {x: 0}, // looking up
+            {x: 16}, // looking right
+            {x: 32}, // looking down
+            {x: 48} // looking left
+        ]
+    },
+    tilesets: {
+        castle: [
+            {x: 0, y: 0}, // ???
+            {x: 16, y: 0}, // floor
+        ]
     }
+
 }
 
+let running = 1;
+
 let currentFrame = 0;
 let targetFrames = 60;
 
 let lastFrameTime = performance.now();
-let startFrameTime = lastFrameTime;
 
 let rooms = [];
+let debugStatuses = [];
 let canvas = new Canvas("c", WIDTH, HEIGHT);
 let text;
+
+let pressedLastFrame = [];
 canvas.fill("#222034");
 
 let splash = new Image();
@@ -34,27 +56,44 @@ splash.onload = () => {
         console.log("font loaded")
         text = new TextRenderer(canvas, font);
         window.onerror = (e) => {
+            running = 0;
             text.throwPanic(e);
         }
     }
 }
 
-class DebugEntity extends Object {
-    constructor() {
+// Entity class is here becuase otherwise every entity would need the canvas passed into it
+class Entity extends Object {
+    constructor(x=0, y=0, spritesheet=null, sprite=null) {
         super();
-        this.x = 0;
-        this.y = 0;
+        this.x = x;
+        this.y = y;
+        this.sprite = sprite;
+        this.spritesheet = spritesheet;
     }
 
     draw() {
-        canvas.context.fillStyle = "red";
-        canvas.context.fillRect(this.x, this.y, 10, 10);
+        canvas.drawImage(this.sprite, this.x, this.y);
     }
 }
 
 // Create all the game rooms
+let roomIndex = 0;
+let currentRoom = rooms[roomIndex];
 
-let loadingRoom = new Room("loading");
+let searchForRoom = (name) => {
+    // returns the room's index in the rooms array
+    for (let i = 0; i < rooms.length; i++) {
+        if (rooms[i].name == name) return i;
+    } throw new Error("Room not found:"+name);
+}
+
+const changeRoom = (index) => {
+    currentRoom = rooms[index];
+    roomIndex = index;
+}
+
+const loadingRoom = new Room("loading");
 loadingRoom.updateStatus = (status) => {
     console.log(status);
     canvas.fill("#222034");
@@ -62,44 +101,118 @@ loadingRoom.updateStatus = (status) => {
     text.render(status, 0, 0);
 }
 
-let debugRoom = new Room("debug");
+const debugRoom = new Room("debug");
 debugRoom.draw = () => {
-    canvas.fill("#222034");
-    canvas
-    for (let i = 0; i < debugRoom.objects.length; i++) {
-        debugRoom.objects[i].draw();
-    }
+    canvas.fill("black");
 }
 debugRoom.drawGUI = () => {
-    text.render("Welcome to the Debug Room,\nwe've got fun and games", 0, canvas.height-14);
-    text.render("Current Frame:" + currentFrame + `(~${Math.floor((currentFrame/targetFrames)*100)/100}sec)`, 0, canvas.height-21);
+    debugStatuses.push("Current Frame:"+currentFrame+`(~${Math.round((currentFrame/targetFrames)*100)/100} sec)`);
+}
+debugRoom.keyDown = (key) => {
+    if (key == "Escape") changeRoom(searchForRoom("menu"));
+}
+
+const menuRoom = new Room("menu");
+let menuOptions = [
+    {"label": "Start Game", "action": _ => {changeRoom(searchForRoom("game"))}},
+    {"label": "Debug Room", "action": _ => changeRoom(searchForRoom("debug"))},
+    {"label": "Reload", "action": _ => {running = 0; location.reload();}}
+];
+let menuIndex = 0;
+
+menuRoom.draw = () => {
+    canvas.fill("black");
+}
+menuRoom.drawGUI = () => {
+    text.render(GAME_TITLE, 8, 7*4);
+    for (let i = 0; i < menuOptions.length; i++) {
+        if (i == menuIndex) {
+            text.render(">", 8, 7*(i+5));
+        }
+        text.render(menuOptions[i].label, 16, 7*(i+5));
+    }
+}
+menuRoom.keyDown = (key) => {
+    if (pressedLastFrame.includes(key)) return;
+    switch (key) {
+        case "ArrowUp":
+            menuIndex--;
+            break;
+        case "ArrowDown":
+            menuIndex++;
+            break;
+        case "Enter":
+            menuOptions[menuIndex].action();
+            break;
+    }
+    if (menuIndex >= menuOptions.length) menuIndex = 0;
+    if (menuIndex < 0) menuIndex = menuOptions.length-1;
+}
+
+let currentLevelData = {
+    tiles: [
+        {id: 1, x: 1, y: 1}, // floor at tile coords 1, 1
+        {id:123, x: 2, y: 2},
+    ]
+}
+
+const gameRoom = new Room("game"); 
+gameRoom.draw = () => {
+    canvas.fill("black");
+    for (let i = 0; i < currentLevelData.tiles.length; i++) {
+        let tile = currentLevelData.tiles[i];
+        if (tile.id > currentLevelData.length) tile.id = 0;
+        let tileLocation = convertTileToScreen(tile.x, tile.y);
+        canvas.sliceImage(assets.images.tiles, tileLocation.x, tileLocation.y, 16, 16, tile.id*16, 0, 16, 16);
+    }
+
+    
 }
-let testObject = new DebugEntity(0, 0);
-debugRoom.objects.push(testObject);
 
 rooms.push(loadingRoom);
+rooms.push(menuRoom);
+rooms.push(gameRoom);
 rooms.push(debugRoom);
 
-let roomIndex = 0;
-let currentRoom = rooms[roomIndex];
+currentRoom = rooms[roomIndex];
 
 let main = () => { // main game loop
+    if (!running) return;
     requestAnimationFrame(main);
-
     let now = performance.now();
     let delta = now - lastFrameTime;
 
     if (delta < 1000 / targetFrames) return;
 
     currentFrame++;
-    
+    debugStatuses = [];
+
     currentRoom.draw();
     currentRoom.drawGUI();
 
-    lastFrameTime = now;
-
+    let currentKeys = whichKeyDown();
+    for (let i = 0; i < currentKeys.length; i++) {
+        debugStatuses.push(currentKeys[i]);
+        currentRoom.keyDown(currentKeys[i]);
+    }
+    
+    pressedLastFrame = currentKeys;    
+    
     text.render("FPS:" + Math.round(1000 / delta), 0, 0);
-}
+    text.render(currentRoom.name, canvas.width-8*(currentRoom.name.length), 0);
+
+    if (currentFrame <= 60*5) {
+        debugStatuses.push("Debug mode.");
+        debugStatuses.push("Dimensions:"+canvas.width+"x"+canvas.height);
+        debugStatuses.push("Have fun!");
+    }
+
+    for (let i = 0; i < debugStatuses.length; i++) {
+        text.render(debugStatuses[i], 0, canvas.height-7*(debugStatuses.length-i));
+    }
+
+    lastFrameTime = now;
+    }
 
 let init = () => {
     // begin loading all the assets.
@@ -112,6 +225,8 @@ let init = () => {
             assets.images[image] = img;
         }
     }
+    console.log(assets.images);
+    console.log("Images loaded.")
     currentRoom.updateStatus("Loading complete!");
 
     canvas.fill("#222034");
@@ -123,10 +238,6 @@ let init = () => {
 }
 
 window.onload = () => {
-    try {
-        document.title = GAME_TITLE;
-        init();
-    } catch (e) {
-        text.throwPanic(e);
-    }
+    document.title = GAME_TITLE;
+    init();
 }
diff --git a/src/js/keyboard.js b/src/js/keyboard.js
index 28acdadd02b173dde131fab92fcfd60d721ed310..e2402e93c84230562cb8f357e19f9a4b252b6c9d 100644
--- a/src/js/keyboard.js
+++ b/src/js/keyboard.js
@@ -21,7 +21,7 @@ const _releaseKey = code => delete KEYS[code];
 
 addEventListener('keydown', e => {
   // prevent itch.io from scrolling the page up/down
-  // e.preventDefault();
+  e.preventDefault();
 
   if (!e.repeat) {
     KEYS[e.code] = performance.now();
diff --git a/src/js/loader.js b/src/js/loader.js
deleted file mode 100644
index d0d3ba5e1b64df42fa385784131265e3389dad91..0000000000000000000000000000000000000000
--- a/src/js/loader.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Loads a list of assets and calls a callback when done
-// Shows a loading screen while loading
-
-// Depends on canvas.js and text.js
-
-class Loader {
-    constructor(canvas, splashImg, fontRenderer) {
-        this.canvas = canvas;
-        this.splashImg = splashImg;
-        this.fontRenderer = fontRenderer;
-        this.assets = [];
-        this.loaded = 0;
-        this.total = 0;
-        this.loading = false;
-        this.callback = null;
-    }
-}
\ No newline at end of file
diff --git a/src/js/objects.js b/src/js/objects.js
index a3b8fafa4b7f5ba3a060295053e33b173bed22cd..9113a0b8b884f786697217ecfa32682b76ff9531 100644
--- a/src/js/objects.js
+++ b/src/js/objects.js
@@ -3,10 +3,12 @@ class Object {
     step() {}
 }
 
+
 class Room extends Object {
-    constructor() {
+    constructor(name="") {
         super();
         this.objects = [];
+        this.name = name; // needs to be unique, otherwise the searching code will just use the first one it finds.
     }
 
     draw() {
@@ -19,6 +21,14 @@ class Room extends Object {
 
     }
 
+    keyDown(key) {
+    }
+
+    keyUp(key) {
+    }
+
+
+
     step() {
         for (let i = 0; i < this.objects.length; i++) {
             this.objects[i].step();
diff --git a/src/js/text.js b/src/js/text.js
index 9494b099b6ffe5235cc282ef04052a4d91013fc8..ae8f2c9235bfb83e2c0187a8f46398e18d65b5c0 100644
--- a/src/js/text.js
+++ b/src/js/text.js
@@ -5,14 +5,15 @@ class TextRenderer {
         this.fontimg = fontimg; // MUST BE AN IMAGE OBJECT
         this.fontWidth = 7;
         this.fontHeight = 7;
-        this.fontChars = "abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~";
+        this.fontChars = "abcdefghijklmnopqrstuvwxyz1234567890.,!?:;)(~>";
         this.canvas = canvas;
     }
 
-    drawLetter(letter, x, y) {
+    drawLetter(letter, x, y, substituteOK=0) {
         let index = this.fontChars.indexOf(letter.toLowerCase());
         if (index == -1) {
-            return;
+            if (!substituteOK) return;
+            this.canvas.drawText(letter, x, y, "#ffffff", 7, "monospace");
         }
         let sx = index * this.fontWidth;
         let sy = 0;
@@ -22,7 +23,7 @@ class TextRenderer {
         if (letter == ",") {
             yOffset = -1;
         }
-        this.canvas.sliceImage(this.fontimg, sx, sy, this.fontWidth, this.fontHeight, x, y-yOffset, this.fontWidth, this.fontHeight);
+        this.canvas.sliceImage(this.fontimg, x, y + yOffset, this.fontWidth, this.fontHeight, sx, sy, this.fontWidth, this.fontHeight);
     }
 
     render(text, x, y) {
@@ -44,6 +45,7 @@ class TextRenderer {
         // It'll show the error on-screen.
     
         this.canvas.fill("#00000080") // 50% black
+        
         this.render(err, 0, 0);
         throw err;
     }
diff --git a/src/js/utils.js b/src/js/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d75fb04c9da82e5c642b881c9ea26091db79a1c
--- /dev/null
+++ b/src/js/utils.js
@@ -0,0 +1,5 @@
+// random shit
+
+export const pi = Math.PI;
+
+export const convertTileToScreen = (x, y) => ({x: x<<4, y: y<<4});