diff --git a/package-lock.json b/package-lock.json
index 14348e8..75d3cda 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4222,9 +4222,9 @@
       "dev": true
     },
     "node_modules/json-parse-even-better-errors": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz",
-      "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz",
+      "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==",
       "dev": true,
       "engines": {
         "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
@@ -4456,9 +4456,9 @@
       }
     },
     "node_modules/minipass": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
-      "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.0.tgz",
+      "integrity": "sha512-oGZRv2OT1lO2UF1zUcwdTb3wqUwI0kBGTgt/T7OdSj6M6N5m3o5uPf0AIW6lVxGGoiWUR7e2AwTE+xiwK8WQig==",
       "dev": true,
       "engines": {
         "node": ">=16 || 14 >=14.17"
@@ -4583,9 +4583,9 @@
       "dev": true
     },
     "node_modules/nopt": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz",
-      "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==",
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz",
+      "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==",
       "dev": true,
       "dependencies": {
         "abbrev": "^2.0.0"
@@ -5918,9 +5918,9 @@
       }
     },
     "node_modules/update-browserslist-db": {
-      "version": "1.0.14",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.14.tgz",
-      "integrity": "sha512-JixKH8GR2pWYshIPUg/NujK3JO7JiqEEUiNArE86NQyrgUuZeTlZQN3xuS/yiV5Kb48ev9K6RqNkaJjXsdg7Jw==",
+      "version": "1.0.15",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz",
+      "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==",
       "dev": true,
       "funding": [
         {
diff --git a/src/assets/login.scss b/src/assets/login.scss
index 38eb903..09676a9 100644
--- a/src/assets/login.scss
+++ b/src/assets/login.scss
@@ -66,11 +66,11 @@
       gap: 0.5rem;
 
       .button {
-        padding: 0.8rem 0;
+        padding: 0.6rem 0;
         min-width: 6.25rem;
         text-align: center;
         position: relative;
-        font-size: 0.80rem;
+        font-size: 0.65rem;
         background-color: rgba(71, 65, 230, 0.75);
         border: rgba(255, 255, 255, 0.35) 1px solid;
         border-radius: 5px;
diff --git a/src/components/World.vue b/src/components/World.vue
index c8dd1dd..62ccccf 100644
--- a/src/components/World.vue
+++ b/src/components/World.vue
@@ -1,41 +1,23 @@
 <template>
-  <TilemapLayer ref="tilemapLayer" :tilemap="map" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" :tileset="data" />
-  <Controls :layer="layer" />
-  <Player :layer="layer" />
-  <div v-for="player in playerList">
-    <Player :layer="layer"/>
-  </div>
+  <TilemapLayer  ref="tilemapLayer" :tilemap="map" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" :tileset="mapTiles" />
+<!--  <Controls :layer="layer" />-->
 </template>
 
 <script setup lang="ts">
 import { refObj, TilemapLayer, useScene } from 'phavuer'
 import Player from '@/components/sprites/player/Player.vue'
 import config from '@/config'
-import { ref, type Ref } from 'vue'
+import { reactive, ref, type Ref } from 'vue'
 import Tileset = Phaser.Tilemaps.Tileset
 import Controls from '@/components/Controls.vue'
 import { useSocketStore } from '@/stores/socket'
+import Map from '@/engine/Map/Map'
 
-let playerList = ref([]);
-
+const isMapLoaded = ref(false);
 const socket = useSocketStore();
+const serverMapData = ref([]);
+const mapTiles = ref([]);
 
-socket.socket?.on('playerList', (players) => {
-  playerList.value = players;
-  console.log('players', players);
-  console.log('playerList', playerList.value);
-});
-
-socket.socket?.on('player_moved', (username, coords) => {
-  console.log('player_moved', username, coords);
-  const player = playerList.value.find((player: any) => player.username === username);
-  if (player) {
-    player.x = coords.x;
-    player.y = coords.y;
-  }
-});
-
-const scene = useScene()
 const mapData = new Phaser.Tilemaps.MapData({
   width: 10,
   height: 10,
@@ -45,9 +27,27 @@ const mapData = new Phaser.Tilemaps.MapData({
   format: Phaser.Tilemaps.Formats.ARRAY_2D,
 });
 
+socket.socket?.emit('get_map');
+socket.socket?.on('map', (map) => {
+  // Get map from server
+  mapTiles.value = map.data;
+  map.data.forEach((row, y) => {
+    row.forEach((tile, x) => {
+      layer.putTileAt(tile, x, y);
+    });
+  });
+
+  isMapLoaded.value = true;
+  console.log('map', map);
+});
+
+
+const scene = useScene()
+
 const { width: tileSizeWidth } = mapData;
 const { width, height } = scene.cameras.main;
 const map = new Phaser.Tilemaps.Tilemap(scene, mapData);
+
 /**
  * 1 tile is 64x32
  * the map is 10x10
@@ -57,26 +57,11 @@ const tileset: (Tileset|null) = map.addTilesetImage('default', 'tiles');
 // const layer: (Layer|null) = map.createBlankLayer('layer', tileset);
 
 const layer:TilemapLayer = map.createBlankLayer('layer', tileset, 0, config.tile_size.y);
-const tilemapLayer: Ref<(TilemapLayer|undefined)> = refObj();
+const tilemapLayer= ref();
+
+// const mapp = new Map('default', 10, 10, config.tile_size.x, config.tile_size.y, data, []);
 
-const data: any = [
-  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0 ],
-  [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
-];
 
-data.forEach((row, y) => {
-  row.forEach((tile, x) => {
-    layer.putTileAt(tile, x, y);
-  });
-});
 
 // center camera
 const centerY = (map.height * map.tileHeight) / 2
diff --git a/src/components/screens/Login.vue b/src/components/screens/Login.vue
index 4ae6995..fa3439c 100644
--- a/src/components/screens/Login.vue
+++ b/src/components/screens/Login.vue
@@ -9,7 +9,7 @@
         <form method="post">
           <div class="form-field">
             <label for="username">Username</label>
-            <input v-model="username" type="text" name="username" required>
+            <input v-model="username" type="text" name="username" required autofocus>
           </div>
           <div class="form-field">
             <label for="password">Password</label>
diff --git a/src/components/sprites/player/Player.vue b/src/components/sprites/player/Player.vue
index 50af0fb..b6a74b7 100644
--- a/src/components/sprites/player/Player.vue
+++ b/src/components/sprites/player/Player.vue
@@ -1,55 +1,60 @@
 <template>
-  <Sprite ref="sprite" texture="player" :x :y />
+  <Sprite ref="sprite" texture="IMap" :x="position.x" :y="position.y" />
 </template>
 
 <script lang="ts" setup>
-import { Sprite, useScene } from 'phavuer'
-import { type Ref, ref } from 'vue'
+import { onPostUpdate, onPreUpdate, Sprite, useScene } from 'phavuer'
+import { reactive, type Ref, ref } from 'vue'
 import config from '@/config'
 import { useSocketStore } from '@/stores/socket'
 
 const socket = useSocketStore();
 
-socket.socket?.emit('joinRoom', 'game');
-
 const props = defineProps({
   layer: Phaser.Tilemaps.TilemapLayer,
-  player: Object
+  player: {
+    type: Object,
+    default: undefined
+  },
 })
 
 const scene = useScene()
-const pointer_tile = ref(undefined);
-const x: Ref<number> = ref(0);
-const y: Ref<number> = ref(0);
 
-if (props.player) {
-  x.value = props.player.x;
-  y.value = props.player.y;
+// onPreUpdate((time, delta) => {
+//   console.log(time, delta);
+// })
+
+const pointer_tile = ref(undefined);
+const position = reactive({ x: 0, y: 0 });
+
+if (props.player !== undefined) {
+  position.x = props.player?.coords.x;
+  position.y = props.player?.coords.y;
 }
 
 function onPointerClick(pointer: Phaser.Input.Pointer) {
-  /**
-   * @TODO : Check if player was dragging, if so, don't move player
-   */
   const px = scene.cameras.main.worldView.x + pointer.x;
   const py = scene.cameras.main.worldView.y + pointer.y;
 
   pointer_tile.value = getTile(px, py, props.layer);
   if (pointer_tile.value) {
-    // Convert tile coordinates to world coordinates
     const worldPoint = props.layer.tileToWorldXY(pointer_tile.value.x, pointer_tile.value.y);
-    x.value = worldPoint.x + config.tile_size.y;
-    y.value = worldPoint.y;
+    position.x = worldPoint.x + config.tile_size.y;
+    position.y = worldPoint.y;
+
+    socket.socket?.emit('move', { x: position.x, y: position.y });
   }
 }
-scene.input.on(Phaser.Input.Events.POINTER_DOWN, onPointerClick);
+
+/**
+ * @BUG
+ * when this component is spawned multiple times, the event listener is also added multiple times
+ */
+scene.input.on(Phaser.Input.Events.POINTER_UP, onPointerClick);
 
 function getTile (x: number, y: number, layer: Phaser.Tilemaps.TilemapLayer): Phaser.Tilemaps.Tile | undefined {
   const tile: Phaser.Tilemaps.Tile = layer.getTileAtWorldXY(x, y);
 
-  console.log(x,y);
-  console.log('tile', tile);
-
   if (!tile) {
     return undefined;
   }
diff --git a/src/engine/Map/IMap.ts b/src/engine/Map/IMap.ts
new file mode 100644
index 0000000..154a374
--- /dev/null
+++ b/src/engine/Map/IMap.ts
@@ -0,0 +1,10 @@
+import Player from '../Player/Player';
+
+export default interface IMap {
+  readonly id: number;
+  name: string;
+  width: number;
+  height: number;
+  data: any;
+  players: Array<Player>|[];
+}
\ No newline at end of file
diff --git a/src/engine/Map/Map.ts b/src/engine/Map/Map.ts
new file mode 100644
index 0000000..e86b648
--- /dev/null
+++ b/src/engine/Map/Map.ts
@@ -0,0 +1,36 @@
+import type IMap from '@/engine/Map/IMap';
+import Player from '@/engine/Player/Player';
+
+export default class Map implements IMap {
+    id: number;
+    name: string;
+    width: number;
+    height: number;
+    data: any;
+    players: Array<Player>|[];
+
+    constructor(id: number, name: string, width: number, height: number, data: any, players: Array<Player>|[]) {
+        this.id = id;
+        this.name = name;
+        this.width = width;
+        this.height = height;
+        this.data = data;
+        this.players = players;
+    }
+
+    public addPlayer(player: Player) {
+        this.players.push(player);
+    }
+
+    public removePlayer(player: Player) {
+        this.players = this.players.filter(p => p.id !== player.id);
+    }
+
+    public movePlayer(player: Player, x: number, y: number) {
+        const playerIndex = this.players.findIndex(p => p.id === player.id);
+        if (playerIndex !== -1) {
+            this.players[playerIndex].coords.x = x;
+            this.players[playerIndex].coords.y = y;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/engine/Player/IPlayer.ts b/src/engine/Player/IPlayer.ts
new file mode 100644
index 0000000..f7be52a
--- /dev/null
+++ b/src/engine/Player/IPlayer.ts
@@ -0,0 +1,8 @@
+export default interface IPlayer {
+  readonly id: number;
+  username: string;
+  coords: {
+      x: number;
+      y: number;
+  };
+}
\ No newline at end of file
diff --git a/src/engine/Player/Player.ts b/src/engine/Player/Player.ts
new file mode 100644
index 0000000..753fde8
--- /dev/null
+++ b/src/engine/Player/Player.ts
@@ -0,0 +1,13 @@
+import type IPlayer from '@/engine/Player/IPlayer';
+
+export default class Player implements IPlayer {
+    id: number;
+    username: string;
+    coords: { x: number; y: number; };
+
+    constructor(id: number, username: string, coords: { x: number; y: number; }) {
+        this.id = id;
+        this.username = username;
+        this.coords = coords;
+    }
+}
\ No newline at end of file
diff --git a/src/engine/init.js b/src/engine/init.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/engine/map.js b/src/engine/map.js
deleted file mode 100644
index e69de29..0000000
diff --git a/src/stores/map.ts b/src/stores/map.ts
index e69de29..88078bd 100644
--- a/src/stores/map.ts
+++ b/src/stores/map.ts
@@ -0,0 +1,14 @@
+import { defineStore } from 'pinia';
+import Map from '@/engine/Map/Map'
+
+export const useMapStore = defineStore('map', {
+  state: () => ({
+    map: null as Map | null,
+  }),
+
+  actions: {
+    setMap(map: Map) {
+      this.map = map;
+    }
+  }
+});
\ No newline at end of file
diff --git a/src/stores/player.ts b/src/stores/player.ts
new file mode 100644
index 0000000..3438e61
--- /dev/null
+++ b/src/stores/player.ts
@@ -0,0 +1,14 @@
+import { defineStore } from 'pinia';
+import Player from '@/engine/Player/Player'
+
+export const usePlayerStore = defineStore('player', {
+  state: () => ({
+    player: null as Player | null,
+  }),
+
+  actions: {
+    setPlayer(player: Player) {
+      this.player = player;
+    },
+  }
+});
\ No newline at end of file