diff --git a/.idea/2023.iml b/.idea/2023.iml
index 24643cc37449b4bde54411a80b8ed61258225e34..d3f1fdaa54b82960b84dd01f99717e44688747a0 100644
--- a/.idea/2023.iml
+++ b/.idea/2023.iml
@@ -5,6 +5,7 @@
       <excludeFolder url="file://$MODULE_DIR$/.tmp" />
       <excludeFolder url="file://$MODULE_DIR$/temp" />
       <excludeFolder url="file://$MODULE_DIR$/tmp" />
+      <excludeFolder url="file://$MODULE_DIR$/dist" />
     </content>
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
diff --git a/assets/ball.ase b/assets/ball.ase
new file mode 100644
index 0000000000000000000000000000000000000000..066d42155ef8a13fb79c430e3f8ec8e63b2bfa4b
Binary files /dev/null and b/assets/ball.ase differ
diff --git a/assets/catapult.ase b/assets/catapult.ase
new file mode 100644
index 0000000000000000000000000000000000000000..a8c382e32a94596922eefc37340c7bbbc4dfcec2
Binary files /dev/null and b/assets/catapult.ase differ
diff --git a/src/img/ball.webp b/src/img/ball.webp
new file mode 100644
index 0000000000000000000000000000000000000000..49d38764d87b47fd9a1391fb90d4ba8b70622c54
Binary files /dev/null and b/src/img/ball.webp differ
diff --git a/src/img/catapult.webp b/src/img/catapult.webp
new file mode 100644
index 0000000000000000000000000000000000000000..12ba75241a220c23e3bc79221a45d51fd70bff06
Binary files /dev/null and b/src/img/catapult.webp differ
diff --git a/src/index.html b/src/index.html
index 6cb5043ddfa1715fcc6329c04e16bdc12059329d..12f261209c2f2ea40590f7d6f04396b682fd518b 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,4 +1,4 @@
-<!-- maybe slightly copied from herebefrog's -->
+<!-- maybe slightly copied from herebefrog -->
 
 <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1">
 <style>
diff --git a/src/js/canvas.js b/src/js/canvas.js
index 2cc5c389fdbc8bf9058124ae432eecc599cbbb99..2b3eb0d1f651ed825bceef381dcf6e7f5ae768ec 100644
--- a/src/js/canvas.js
+++ b/src/js/canvas.js
@@ -18,6 +18,13 @@ class Canvas {
         this.cY = 0;
     }
 
+    setDimensions (w, h) {
+        this.canvas.width = w;
+        this.canvas.height = h;
+        this.width = this.canvas.width;
+        this.height = this.canvas.height;
+    }
+
     fill(c="black") {
         this.ctx.fillStyle = c;
         this.ctx.fillRect(0, 0, this.width, this.height);
diff --git a/src/js/game.js b/src/js/game.js
index e93272ed718b266687bd5d987ff45dca3004033b..9031c014d9ea9a982b9c0f3c160fba140ac7ad96 100644
--- a/src/js/game.js
+++ b/src/js/game.js
@@ -3,14 +3,20 @@ 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 { isKeyUp, whichKeyDown } from "./keyboard.js";
 import { getParameter } from "./utils.js";
+import { getMousePos } from "./inputs/mouse.js";
+import { isKeyUp, whichKeyDown } from "./inputs/keyboard.js";
+
+
+let imgPrefix = "../img/";
 
 let assets = {
     images: {
-        splash: "../img/splash1.webp",
-        font: "../img/hampsterfont.webp",
-        selector: "../img/selector.webp",
+        splash: "splash1.webp",
+        font: "hampsterfont.webp",
+        selector: "selector.webp",
+        catapult: "catapult.webp",
+        debug_ball: "ball.webp",
     },
 }
 
@@ -33,11 +39,11 @@ let pressedLastFrame = [];
 canvas.fill("#222034");
 
 let splash = new Image();
-splash.src = assets.images.splash;
+splash.src = imgPrefix + assets.images.splash;
 splash.onload = () => {
     canvas.drawImage(splash, canvas.width / 2 - splash.width / 2, canvas.height / 2 - splash.height / 2);
     let font = new Image();
-    font.src = assets.images.font;
+    font.src = imgPrefix + assets.images.font;
     font.onload = () => {
         console.log("font loaded")
         text = new TextRenderer(canvas, font);
@@ -48,14 +54,13 @@ splash.onload = () => {
     }
 }
 
-// Entity class is here becuase otherwise every entity would need the canvas passed into it
+// Entity class is here because 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 = x;
         this.y = y;
         this.sprite = sprite;
-        this.spritesheet = spritesheet;
     }
 
     draw() {
@@ -70,7 +75,7 @@ let currentRoom = rooms[roomIndex];
 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;
+        if (rooms[i].name === name) return i;
     } throw new Error("Room not found:"+name+". Are you sure it's pushed?");
 }
 
@@ -95,15 +100,10 @@ debugRoom.roomList = [];
 debugRoom.options = {
     "main": [
         {"label": "Change Room", "action": _ => {debugRoom.submenu = "changeRoom"; debugRoom.index = 0;}},
-        {"label": "Change Target FPS", "action": _ => {debugRoom.submenu = "changeTargetFPS"; debugRoom.index = 0;}},
         {"label": "Unlock refresh rate", "action": _ => {runAtMonitorRefreshRate = !runAtMonitorRefreshRate;}},
         {"label": "Exit", "action": _ => {changeRoom(searchForRoom("menu"))}},
     ],
     "changeRoom": [],
-    "changeTargetFPS": [
-        {"label": "60", "action": _ => {targetFrames = 60;}},
-        {"label": "30", "action": _ => {targetFrames = 30;}},
-    ],
 };
 debugRoom.init = () => {
     if (!debug) changeRoom(searchForRoom("menu"));
@@ -130,7 +130,6 @@ debugRoom.keyDown = (key) => {
 }
 
 debugRoom.draw = () => {
-    canvas.fill("black");
 
     canvas.drawRect(Math.sin(currentFrame /(canvas.width / 2)) * canvas.width - 32, canvas.height-64, 32, 32, "#222034");
 }
@@ -151,14 +150,10 @@ menuRoom.options = [
 ];
 if (debug) menuRoom.options.push({"label": "Debug Room", "action": _ => {changeRoom(searchForRoom("debug"))}});
 menuRoom.index = 0;
-
-menuRoom.draw = () => {
-    canvas.fill("black");
-}
 menuRoom.drawGUI = () => {
     text.render(GAME_TITLE, 8, 7*4);
     for (let i = 0; i < menuRoom.options.length; i++) {
-        if (i == menuRoom.index) {
+        if (i === menuRoom.index) {
             text.render(">", 8, 7*(i+5));
         }
         text.render(menuRoom.options[i].label, 16, 7*(i+5));
@@ -184,18 +179,22 @@ const testing_graphing = new Room("testing_graphing");
 testing_graphing.yScale = 10;
 testing_graphing.a = 0;
 testing_graphing.b = 0;
-testing_graphing.c = (canvas.height/4)*testing_graphing.yScale;
+testing_graphing.c = 0;
+
+testing_graphing.init = () => {
+    // canvas.setDimensions(window.innerWidth, window.innerHeight);
+}
 
 testing_graphing.keyDown = (key) => {
     if (pressedLastFrame.includes(key)) return;
 
     const keyActions = {
-        ArrowUp: () => testing_graphing.a += 0.25,
-        ArrowDown: () => testing_graphing.a -= 0.25,
-        ArrowLeft: () => testing_graphing.b -= 0.25,
-        ArrowRight: () => testing_graphing.b += 0.25,
-        KeyA: () => testing_graphing.c -= 0.25,
-        KeyD: () => testing_graphing.c += 0.25,
+        ArrowUp: () => testing_graphing.a++,
+        ArrowDown: () => testing_graphing.a--,
+        ArrowLeft: () => testing_graphing.b --,
+        ArrowRight: () => testing_graphing.b ++,
+        KeyA: () => testing_graphing.c++,
+        KeyD: () => testing_graphing.c--,
     };
 
     const action = keyActions[key];
@@ -205,7 +204,6 @@ testing_graphing.keyDown = (key) => {
 testing_graphing.draw = () => {
     // draws a quadratic graph
     // y = ax^2 + bx + c
-    canvas.fill("black");
     canvas.drawLine(0, canvas.height/2, canvas.width, canvas.height/2, "white");
     canvas.drawLine(canvas.width/2, 0, canvas.width/2, canvas.height, "white");
     for (let i = 0; i < canvas.width; i++) {
@@ -219,15 +217,105 @@ testing_graphing.drawGUI = () => {
     text.render(`y = ${testing_graphing.a}x^2 + ${testing_graphing.b}x + ${testing_graphing.c}`, 0, 0);
 }
 
+const testing_physics = new Room("testing_physics");
+testing_physics.init = () => {
+    canvas.setDimensions(1000, 500)
+}
+testing_physics.gravity = 0.00005; // m/s^2
+testing_physics.rho = 1;
+
+let testing_ball = new Entity(canvas.width/2, 0);
+testing_physics.objects.push(testing_ball);
+
+testing_ball.velocity = { x: 10, y: 0 };
+testing_ball.mass = 70; // kg
+testing_ball.radius = 4; // pixels
+testing_ball.restitution = 0.2; // 0-1, 1 being perfectly elastic
+testing_ball.Cd = 0.47; // dimensionless
+
+testing_ball.step = () => {
+    // Calculate forces on the x and y axis
+    var Fx = -0.5 * testing_ball.Cd * testing_ball.A * testing_physics.rho * testing_ball.velocity.x * testing_ball.velocity.x * testing_ball.velocity.x / Math.abs(testing_ball.velocity.x);
+    var Fy = -0.5 * testing_ball.Cd * testing_ball.A * testing_physics.rho * testing_ball.velocity.y * testing_ball.velocity.y * testing_ball.velocity.y / Math.abs(testing_ball.velocity.y);
+
+    Fx = (isNaN(Fx) ? 0 : Fx);
+    Fy = (isNaN(Fy) ? 0 : Fy);
+
+    // Acceleration
+    var ax = (Fx / testing_ball.mass);
+    var ay = testing_physics.gravity + (Fy / testing_ball.mass);
+
+    testing_ball.velocity.x += ax * targetFrames;
+    testing_ball.velocity.y += ay * targetFrames;
+
+    // Position
+    testing_ball.x += testing_ball.velocity.x * targetFrames;
+    testing_ball.y += testing_ball.velocity.y * targetFrames;
+
+    if (testing_ball.y > canvas.height - testing_ball.radius) {
+        testing_ball.velocity.y *= -testing_ball.restitution;
+        testing_ball.y = canvas.height - testing_ball.radius;
+    }
+
+    if (testing_ball.x > canvas.width - testing_ball.radius) {
+        testing_ball.velocity.x *= -testing_ball.restitution;
+        testing_ball.x = canvas.width - testing_ball.radius;
+    }
+
+    if (testing_ball.x < testing_ball.radius) {
+        testing_ball.velocity.x *= -testing_ball.restitution;
+        testing_ball.x = testing_ball.radius;
+    }
+
+    debugStatuses.push(`acceleration: ${ax}, ${ay}`);
+    debugStatuses.push(`force: ${Fx}, ${Fy}`);
+}
+
+testing_ball.draw = () => {
+    canvas.drawImage(assets.images.debug_ball, testing_ball.x - 4, testing_ball.y - 4);
+}
+
+testing_physics.keyDown = (key) => {
+    if (pressedLastFrame.includes(key)) return;
+
+    const keyActions = {
+        KeyL: _=> {
+            testing_ball.velocity = {x: 20, y: 100}
+        },
+        KeyS: _=> {
+            testing_ball.velocity = {x: 0, y: 0}
+        }
+    };
+
+    const action = keyActions[key];
+    if (action) action();
+}
+
+testing_physics.drawGUI = () => {
+    debugStatuses.push(`position: ${testing_ball.x}, ${testing_ball.y}`);
+    debugStatuses.push(`velocity: ${testing_ball.velocity.x}, ${testing_ball.velocity.y}`);
+
+}
+
+testing_physics.onclick = (pos={x:0,y:0}) => {
+    testing_ball.x = pos.x;
+    testing_ball.y = pos.y;
+}
+
 rooms.push(loadingRoom);
 rooms.push(menuRoom);
 rooms.push(debugRoom);
 
 // REMOVE THESE
 rooms.push(testing_graphing);
+rooms.push(testing_physics);
 
 currentRoom = rooms[roomIndex];
 
+canvas.canvas.addEventListener('mousedown', function(evt) {
+    const mousePos = getMousePos(canvas.canvas, evt);
+    currentRoom.onclick(mousePos);
+}, false);
 
 
 let main = () => { // main game loop
@@ -243,7 +331,8 @@ let main = () => { // main game loop
 
     currentRoom.step();
 
-    currentRoom.draw();
+    // canvas.fill(currentRoom.background);
+
     currentRoom.drawGUI();
 
     let currentKeys = whichKeyDown();
@@ -267,12 +356,23 @@ let main = () => { // main game loop
     }
 
     for (let i = 0; i < debugStatuses.length; i++) {
-        // console.debug(debugStatuses[i]);
-        if (typeof(debugStatuses[i]) == "string") text.render(debugStatuses[i], 0, canvas.height-text.charHeight*(debugStatuses.length-i));
-        if (typeof(debugStatuses[i]) == "object") {text.render(debugStatuses[i].msg, 0, canvas.height-text.charHeight*(debugStatuses.length-i)); debugStatuses[i].ttl--;}
+        switch (typeof (debugStatuses[i])) {
+            case "string":
+                text.render(debugStatuses[i], 0, canvas.height - text.charHeight * (debugStatuses.length - i));
+                break;
+            case "object":
+                console.debug("OBJECT!!")
+                text.render(debugStatuses[i].msg, 0, canvas.height-text.charHeight*(debugStatuses.length-i));
+                debugStatuses[i].ttl--;
+                break;
+        }
+        if (typeof(debugStatuses[i]) == "object") {}
 
     }
 
+    currentRoom.draw();
+
+
     lastFrameTime = now;
     }
 
@@ -282,7 +382,7 @@ let init = () => {
     for (let image in assets.images) {
         currentRoom.updateStatus("Loading image " + image);
         let img = new Image();
-        img.src = assets.images[image];
+        img.src = imgPrefix + assets.images[image];
         img.onload = () => {
             assets.images[image] = img;
         }
diff --git a/src/js/keyboard.js b/src/js/inputs/keyboard.js
similarity index 100%
rename from src/js/keyboard.js
rename to src/js/inputs/keyboard.js
diff --git a/src/js/inputs/mouse.js b/src/js/inputs/mouse.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b7c433061e0c336ec18c3a100fe7ef8878aee75
--- /dev/null
+++ b/src/js/inputs/mouse.js
@@ -0,0 +1,11 @@
+export const getMousePos = (canvas, evt) => {
+    const rect = canvas.getBoundingClientRect();
+    let x = evt.clientX - rect.left;
+    let y = evt.clientY - rect.top;
+    x /= rect.width;
+    y /= rect.height;
+    x *= canvas.width;
+    y *= canvas.height;
+    return {x,y};
+  }
+
diff --git a/src/js/objects.js b/src/js/objects.js
index f1941091b405183685b8c6ce3bb0c87165da43f6..0db9387ef2fd3d3339c7621b2b4aaf06ce471e7c 100644
--- a/src/js/objects.js
+++ b/src/js/objects.js
@@ -9,13 +9,14 @@ class Room extends Object {
         super();
         this.objects = [];
         this.name = name; // needs to be unique, otherwise the searching code will just use the first one it finds.
+        this.background = "#000000";
     }
 
     init(){}
 
     draw() {
-        for (let i = 0; i < this.objects.length; i++) {
-            this.objects[i].draw();
+        for (const item of this.objects) {
+            item.draw();
         }
     }
 
@@ -24,6 +25,9 @@ class Room extends Object {
     }
 
     keyDown(key) {
+        for (const item of this.objects) {
+            item.keyDown(key);
+        }
     }
 
     keyUp(key) {
diff --git a/src/js/text.js b/src/js/text.js
index 9fd464c6f1e0d0b203ce3e4d3b6c2354e16b199d..c881cc8f504aeeadb170fe9a4fdb81a5d1569d1c 100644
--- a/src/js/text.js
+++ b/src/js/text.js
@@ -16,20 +16,18 @@ class TextRenderer {
         let { canvas, fontWidth, fontHeight } = this;
 
         let index = this.fontChars.indexOf(letter.toLowerCase());
-        if (index == -1) {
+        if (index === -1) {
             if (!substituteOK) return;
-            canvas.drawText(letter, x, y, "#ffffff", 7, "monospace");
+            canvas.drawText(letter, x, y, "#ffffff", 5, "monospace");
         }
         let sx = index * fontWidth;
         let sy = 0;
         // draw image to context
         let yOffset = 0;
         // if the letter is ",", offset it by -1
-        if (letter == ",") {
-            yOffset = -1;
-        }
+        if (letter === ",") yOffset = 1;
         canvas.sliceImage(this.fontimg, x+canvas.cX, y + yOffset + canvas.cY, fontWidth, fontHeight, sx, sy, fontWidth, fontHeight); 
-            // canvas.cX and canvas.cY are the camera offsets. we dont want to have text flying off the screen.
+            // canvas.cX and canvas.cY are the camera offsets. we don't want to have text flying off the screen.
             // you can counteract this by specifying x-cX and x-cY when calling this.
     }
 
@@ -37,7 +35,7 @@ class TextRenderer {
         let heightOffset = 0;
         let xOffset = 0;
         for (let i = 0; i < text.length; i++) {
-            if (text[i] == "\n") {
+            if (text[i] === "\n") {
                 heightOffset++;
                 xOffset = 0;
                 continue;