diff --git a/hampsterengine b/hampsterengine
index dd760ba404d7b679b0fb46aa0abaaa05f40b329c..32245348ac2e1223b8742bfb60d68391e29ffe7e 160000
--- a/hampsterengine
+++ b/hampsterengine
@@ -1 +1 @@
-Subproject commit dd760ba404d7b679b0fb46aa0abaaa05f40b329c
+Subproject commit 32245348ac2e1223b8742bfb60d68391e29ffe7e
diff --git a/package.json b/package.json
index 6b56efc43917e106d54e603ba48b04279a27f898..5fb32f44ed587a552d58b4b0be4225a609aa1219 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
     "dev:js": "esbuild src/js/main.js --bundle --watch --sourcemap --format=iife --loader:.webp=dataurl --outfile=build/main.js",
     "dev:html": "browser-sync build src --watch --https",
     "build": "run-s clear build:*",
-    "build:js": "esbuild src/js/main.js --bundle --format=iife --loader:.webp=dataurl | terser -c -m --mangle-props keep_quoted -o build/main.js",
+    "build:js": "esbuild src/js/main.js --bundle --format=iife --loader:.webp=dataurl | terser -c -m --mangle-props keep_quoted | roadroller -t js - -o build/main.js",
     "build:html": "html-inline src/index.html -b build | html-minifier -c configs/html-minifier.json -o build/index.html",
     "build:zip": "zip -FS -qjX9 build/game.zip build/index.html && advzip -z -4 build/game.zip",
     "build:zipSize": "node utils/size.js"
diff --git a/src/js/extras.js b/src/js/extras.js
index 77f3731c8e5c19e427a6ce494cad7ba3bff4f1c7..3dfd06caa0f12ac0d91f77149ac0bf633d2958e3 100644
--- a/src/js/extras.js
+++ b/src/js/extras.js
@@ -6,9 +6,21 @@ export function drawLineThroughPoint(x, y) {
 
 export const clone = structuredClone;
 
+export const GRAVITY_X = 0; // I don't think we're going to use X gravity but i'm going to keep in the source in case i do
+export const GRAVITY_Y = 450; // Per second
+
 export const round = Math.round;
 export const roundToRatio = x => {
-    return round(x * canvas.pixelRatio) / canvas.pixelRatio
+    return round(x * canvas.pixelRatio * canvas.scale) / canvas.pixelRatio / canvas.scale
+}
+
+export const easeOutCubic = (x) => {
+    return 1 - Math.pow(1 - x, 3);
+}
+
+export const easeOutSine = (x) => {
+    return Math.sin((x * Math.PI) / 2);
+
 }
 
 export const abs = Math.abs;
diff --git a/src/js/main.js b/src/js/main.js
index ededfba7a78dde301186c3b2567b76230bcabb6d..a07f2cbbd5880913cc4b1baf755b30ef968d6f22 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -13,7 +13,7 @@ const keyboard = new Keyboard();
 import SoundBox from "./sb-player-small";
 // import {mus_DEMOSONG} from "./songs/DEMOSONGDONOTCOMMIT";
 
-// dependencies used for debugging. comment out code that uses this and they won't be included
+// dependencies used for debugging. comment out code that uses this, and they won't be included
 // import Stats from "stats.js";
 
 // Images
@@ -29,6 +29,7 @@ import {rm_DEBUG_INCURSION} from "./rooms/debug_incursion";
 import {rm_DEBUG_text} from "./rooms/debug_text";
 import {rm_DEBUG_stars} from "./rooms/debug_stars";
 import {rm_DEBUG_sprites} from "./rooms/debug_sprites";
+import {round} from "./extras";
 
 // Music
 // There is none
@@ -85,6 +86,15 @@ engine.running = false; // Game uses this as a pause state actually
 const GROUND_PALETTE = ['#2a6', '#964', '#853']
 assets.addMiniSprite('grass', 'IIIIIIQIQQQJZQZZRZRRZRZRSSRSRZZR', 8, GROUND_PALETTE);
 assets.addMiniSprite('dirt', 'SSRRRZ[ZZZRRZRZZRZRRZRZRSSRSRZZR', 8, GROUND_PALETTE);
+// assets.addMiniSprite('player', '@@@@@@@@@@@@@@@@@@_XCx@@@@@II@@@@@HSSA@@@@H[[A@@@@@II@@@@@@@@@@@@@`dd@@@@@dddD@@@@dddD@@@@mdlE@@@@@dD@@@@@@[C@@@@@@[C@@@@@G[[x@@', 16, [
+//         '#000', '#fff', '#241F31',   '#77b19d', '#FAB80C',,'pink'
+// ]);
+assets.addMiniSprite('player_head', '@@@C[@HIAYZJY[KHIA', 6, [
+    '#000', '#fff', '#241F31'
+]);
+assets.addMiniSprite('body', 'HIIAIIIIIIII[II[@II@@RR@@RR@@RRB', 8, [
+    '#77b19d', '#241F31', '#FAB80C'
+]);
 
 engine.registerRoom(rm_mainMenu, 'mainMenu');
 engine.registerRoom(rm_game, 'game');
@@ -124,7 +134,7 @@ function main() {
 
         if (debug) {
             canvas.drawText(`physics ticks: ${engine.physicsFrames} (~${(engine.physicsFrames/60).toFixed(1)}sec)`, 0, 0,{textBaseline:'top'})
-            canvas.drawText(`camera pos: ${canvas.camera.x},${canvas.camera.y}`, 0, 8,{textBaseline:'top'})
+            canvas.drawText(`camera pos: ${round(canvas.camera.x)},${round(canvas.camera.y)}`, 0, 8,{textBaseline:'top'})
             canvas.drawText(`run time: ${((performance.now()-readyTime)/1000).toFixed(1)}sec`, 0, 16, {textBaseline:'top'})
             canvas.drawText(`keys: ${JSON.stringify(keyboard.keys)}`, 0, 24, {textBaseline:'top'})
         }
diff --git a/src/js/objects/player.js b/src/js/objects/player.js
index 885cd6bfb97990975b93d9f3cc1d651e26faf4cf..df4db12d61482005cadd3b36bc045c8f5fa528e2 100644
--- a/src/js/objects/player.js
+++ b/src/js/objects/player.js
@@ -1,5 +1,6 @@
 import {Entity} from "../../../hampsterengine/src/things";
-import {round, roundToRatio} from "../extras";
+import {abs, easeOutSine, GRAVITY_X, GRAVITY_Y, round, roundToRatio} from "../extras";
+import {rm_game} from "../rooms/game";
 
 export default class Player extends Entity {
     constructor(props) {
@@ -7,7 +8,98 @@ export default class Player extends Entity {
 
         this.jumping = false;
 
+        this.width = 4;
+        this.height = 8;
+
+        this.flipped = 0;
+
+        this.stepUp = 0;
+
         this.lastFramePos = {x: this.x, y: this.y};
+
+        this.headTarget = {x:this.x, y:this.y};
+        this.headPos = {x:this.x, y: this.y};
+        this.headPosStart = {x:this.x, y: this.y};
+        this.headTrans = 25;
+        this.headStartTime = performance.now();
+
+        this.collideRects = [
+            {x:0, y:0, w: this.width, h: this.height}
+        ];
+    }
+
+    step() {
+        const elapsed = 1 / 60;
+
+        const keys = keyboard.keys;
+        const keysUp = keyboard.keysUpThisFrame;
+
+        let friction = 0.95;
+        const boost = keys.includes("Shift") ? 40 : 0;
+
+        for (let key of keys) {
+            switch (key) {
+                case "ArrowLeft":
+                    this.flipped = !0;
+                    if (!(engine.physicsFrames % 15)) this.stepUp ^= true;
+                    this.vx = -50-boost;
+                    break;
+                case "ArrowRight":
+                    this.flipped = 0;
+                    if (!(engine.physicsFrames % 15)) this.stepUp ^= true;
+                    this.vx = 50+boost;
+                    break;
+                case " ":
+                    if (!this.jumping) {
+                        this.jumping = true;
+                        this.vy -= 150;
+                    }
+                    break;
+            }
+        }
+
+        if ((!(engine.physicsFrames % 15) && this.vx == 0) || this.vy) this.stepUp = 0;
+
+
+        const entities = engine.room.entities;
+        const entitiesWithoutThePlayer = [...entities].toSpliced(entities.indexOf(this), 1);
+        // console.debug(entitiesWithoutThePlayer);
+
+        this.vx = Math.min(400, this.vx + (this.ax * elapsed + GRAVITY_X*elapsed));
+        this.vy = Math.min(400, this.vy + (this.ay * elapsed + GRAVITY_Y*elapsed));
+        this.x += this.vx * elapsed;
+        this.y += this.vy * elapsed;
+
+        // Make acceleration decay
+        this.ax *= 0.1;
+        this.ay *= 0.1;
+
+        if (abs(this.ax) < 0.01) this.ax = 0;
+        if (abs(this.ay) < 0.01) this.ay = 0;
+
+        engine.room.x = this.x;
+        engine.room.y = this.y;
+
+        for (const entity of entitiesWithoutThePlayer) {
+            if (this.checkCollision(entity)) {
+                friction = 0.8;
+                let side = this.resolveCollision(entity);
+                if (side === 2) this.jumping = 0;
+                if (side === 1 || side === 3) friction = 0.5;
+            }
+        }
+
+        // player.vy *= friction;
+        this.vx *= friction;
+
+        if (abs(this.vy) < 1) this.vy = 0;
+        if (abs(this.vx) < 1) this.vx = 0;
+
+        if (player.x !== player.lastFramePos.x || player.y !== player.lastFramePos.y || !this.stepUp    ) {
+            this.headTarget = {x: this.x, y: this.y - (this.stepUp ? 1 : 0)}
+            this.headPosStart = structuredClone(this.headPos);
+            this.headStartTime = performance.now();
+        }
     }
 
     draw() {
@@ -17,6 +109,45 @@ export default class Player extends Entity {
         // const interpolationY = this.vy * timeSinceLastFrame;
         // const interpolationX = 0;
         // const interpolationY = 0;
-        canvas.fillRect(roundToRatio(this.x),roundToRatio(this.y),this.width,this.height);
+        for (let rect of this.collideRects) {
+            console.debug(rect);
+            canvas.fillRect(roundToRatio(this.x + rect.x),roundToRatio(this.y + rect.y),rect.w,rect.h);
+        }
+
+        canvas.tempFilter(_=>{
+            const img = this.flipped ? engine.assetStore.get`body`.flipped : engine.assetStore.get`body`.sprite
+            canvas.drawImage(
+                img,
+                this.x - 2,
+                this.y - (this.stepUp ? 1 : 0),
+                8, (this.stepUp ? 9 : 8)
+            )
+        }, 'opacity(0.7)');
+
+        // calculate the position of the head
+        let distX = this.headTarget.x - this.headPosStart.x;
+        let distY = this.headTarget.y - this.headPosStart.y;
+
+        const elapsed = Math.min(performance.now() - this.headStartTime, this.headTrans);
+        const end = this.headTrans;
+        const pos = easeOutSine(elapsed / end || 1);
+
+        this.headPos.x = Math.min(
+            this.headTarget.x,
+            this.headPosStart.x + (distX * pos)
+        );
+        this.headPos.y = Math.min(
+            this.headTarget.y,
+            this.headPosStart.y + (distY * pos)
+        );
+
+        // Draw the head
+        canvas.drawImage(
+            engine.assetStore.get`player_head`.sprite,
+            roundToRatio(this.headPos.x - 1),
+            roundToRatio(this.headPos.y - 7),
+            engine.assetStore.get`player_head`.size,
+            engine.assetStore.get`player_head`.size
+        )
     }
 }
diff --git a/src/js/rooms/game.js b/src/js/rooms/game.js
index 60eeca4e721598e8bdda6d8af82c2627d19efd21..8b5d6d13590c28587bb88836e9aa258720a279db 100644
--- a/src/js/rooms/game.js
+++ b/src/js/rooms/game.js
@@ -5,8 +5,7 @@ import {clone, clonePlayer, abs, roundToRatio} from "../extras";
 import Ground from "../objects/ground";
 
 export const rm_game = new Room();
-const GRAVITY_X = 0; // I don't think we're going to use X gravity but i'm going to keep in the source in case i do
-const GRAVITY_Y = 600; // Per second
+
 const entities = rm_game.entities;
 
 rm_game.width = 2560;
@@ -23,61 +22,8 @@ rm_game.stop = _=>{
 
 rm_game.step = _=>{
     canvas.camera.step();
-
-    const elapsed = 1 / 60;
     const player = rm_game.get('plr');
-
-    let friction = 0.95;
-    const boost = keyboard.keys.includes("Shift") ? 40 : 0;
-
-    for (const key of keyboard.keys) {
-        switch (key) {
-            case "ArrowLeft":
-                player.vx = -50-boost;
-                break;
-            case "ArrowRight":
-                player.vx = 50+boost;
-                break;
-            case " ":
-                if (!player.jumping) {
-                    player.jumping = true;
-                    player.vy -= 150;
-                }
-        }
-    }
-
-    const entitiesWithoutThePlayer = [...entities].toSpliced(entities.indexOf(player), 1);
-    // console.debug(entitiesWithoutThePlayer);
-
-    player.vx = Math.min(400, player.vx + (player.ax * elapsed + GRAVITY_X*elapsed));
-    player.vy = Math.min(400, player.vy + (player.ay * elapsed + GRAVITY_Y*elapsed));
-    player.x += player.vx * elapsed;
-    player.y += player.vy * elapsed;
-
-    // Make acceleration decay
-    player.ax *= 0.1;
-    player.ay *= 0.1;
-
-    if (abs(player.ax) < 0.01) player.ax = 0;
-    if (abs(player.ay) < 0.01) player.ay = 0;
-
-    rm_game.x = player.x;
-    rm_game.y = player.y;
-
-    for (const entity of entitiesWithoutThePlayer) {
-        if (player.checkCollision(entity)) {
-            friction = 0.8;
-            let side = player.resolveCollision(entity);
-            if (side === 2) player.jumping = 0;
-            if (side === 1 || side === 3) friction = 0.5;
-        }
-    }
-
-    // player.vy *= friction;
-    player.vx *= friction;
-
-    if (abs(player.vy) < 1) player.vy = 0;
-    if (abs(player.vx) < 1) player.vx = 0;
+    player.step();
 
     if (player.x !== player.lastFramePos.x || player.y !== player.lastFramePos.y) {
         player.lastFramePos = {x: player.x, y: player.y};
@@ -85,18 +31,19 @@ rm_game.step = _=>{
         canvas.camera.goTo(
             Math.min(Math.max(player.x+(player.width/2)-canvas.width/2, canvas.width/8), rm_game.width-canvas.width),
             Math.min(Math.max(player.y-canvas.height/8, canvas.height/8), rm_game.height-canvas.height),
-            100
+            150
         );
     }
+
 }
 
 rm_game.draw = _ => {
     canvas.ctx.save();
-    canvas.ctx.translate(roundToRatio(-canvas.camera.x), roundToRatio(-canvas.camera.y));
+    canvas.ctx.translate(roundToRatio(-canvas.camera.x,), roundToRatio(-canvas.camera.y));
     for (let thing of rm_game.entities) {
         thing.draw();
     }
-    canvas.strokeRect(rm_game.x, rm_game.y, player.width, player.height);
+    // canvas.strokeRect(rm_game.x, rm_game.y, player.width, player.height);
     canvas.ctx.restore();
 }
 
@@ -115,6 +62,14 @@ rm_game.drawGui = _ => {
         maxWidth: canvas.width-10,
         size: 4
     });
+    canvas.drawText(`Head: x:${player.headPosStart.x} y:${player.headPosStart.y}`, 5, canvas.height-17, {
+        maxWidth: canvas.width-10,
+        size: 4
+    });
+    canvas.drawText(`Head Target: x:${player.headTarget.x} y:${player.headTarget.y}`, 5, canvas.height-21, {
+        maxWidth: canvas.width-10,
+        size: 4
+    });
 }
 
 rm_game.init = _=>{
@@ -122,8 +77,6 @@ rm_game.init = _=>{
 
     player.x = 40;
     player.y = 40;
-    player.width = 8;
-    player.height = 8*(8/5);
     window.player = player;
     rm_game.push(player, 'plr');
 
@@ -132,6 +85,5 @@ rm_game.init = _=>{
     ground.y = rm_game.height - ground.height;
 
     rm_game.push(ground);
-
 }