From 270b14d8e5e1026efbc89ba481970879835a5e01 Mon Sep 17 00:00:00 2001
From: Dennis Postma <dennis@directonline.io>
Date: Sat, 29 Jun 2024 22:39:22 +0200
Subject: [PATCH] asset mngr stuff

---
 package-lock.json                             | 20 ++--
 src/assets/scss/_variables.scss               |  2 +-
 src/assets/scss/main.scss                     | 15 +--
 src/components/World.vue                      |  4 +-
 src/components/gui/Chat.vue                   |  3 +-
 src/components/utilities/Controls.vue         | 22 +++--
 src/components/utilities/GmPanel.vue          | 51 +++++-----
 src/components/utilities/Modal.vue            |  1 -
 src/components/utilities/Notifications.vue    |  8 +-
 .../utilities/assetManager/AssetManager.vue   | 44 +++++----
 .../assetManager/partials/ObjectList.vue      | 80 ++++++++++++++++
 .../assetManager/partials/TileDetails.vue     | 31 ++++--
 .../assetManager/partials/TileList.vue        | 33 +++----
 src/components/utilities/zoneEditor/Tiles.vue | 73 ++------------
 .../utilities/zoneEditor/Toolbar.vue          |  8 +-
 .../utilities/zoneEditor/ZoneEditor.vue       | 34 ++++---
 .../utilities/zoneEditor/ZoneSettings.vue     |  2 +-
 src/screens/Game.vue                          | 20 ++--
 src/services/zone.ts                          |  4 +-
 src/stores/assetManager.ts                    | 20 ++++
 src/stores/zoneEditor.ts                      |  8 +-
 src/types.ts                                  | 94 +++++++++----------
 22 files changed, 316 insertions(+), 261 deletions(-)
 create mode 100644 src/components/utilities/assetManager/partials/ObjectList.vue
 create mode 100644 src/stores/assetManager.ts

diff --git a/package-lock.json b/package-lock.json
index ce4587e..71cf6a0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2070,9 +2070,9 @@
       }
     },
     "node_modules/@vitest/runner/node_modules/yocto-queue": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
-      "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.0.tgz",
+      "integrity": "sha512-cMojmlnwkAgIXqga+2sXshlgrrcI0QEPJ5n58pEvtuFo4PaekfomlCudArDD7hj8Hkswjl0/x4eu4q+Xa0WFgQ==",
       "dev": true,
       "license": "MIT",
       "engines": {
@@ -3448,9 +3448,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.814",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.814.tgz",
-      "integrity": "sha512-GVulpHjFu1Y9ZvikvbArHmAhZXtm3wHlpjTMcXNGKl4IQ4jMQjlnz8yMQYYqdLHKi/jEL2+CBC2akWVCoIGUdw==",
+      "version": "1.4.815",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.815.tgz",
+      "integrity": "sha512-OvpTT2ItpOXJL7IGcYakRjHCt8L5GrrN/wHCQsRB4PQa1X9fe+X9oen245mIId7s14xvArCGSTIq644yPUKKLg==",
       "dev": true,
       "license": "ISC"
     },
@@ -5648,9 +5648,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.38",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
-      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "version": "8.4.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz",
+      "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==",
       "funding": [
         {
           "type": "opencollective",
@@ -5668,7 +5668,7 @@
       "license": "MIT",
       "dependencies": {
         "nanoid": "^3.3.7",
-        "picocolors": "^1.0.0",
+        "picocolors": "^1.0.1",
         "source-map-js": "^1.2.0"
       },
       "engines": {
diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss
index 1e2fe8c..ccd1ddb 100644
--- a/src/assets/scss/_variables.scss
+++ b/src/assets/scss/_variables.scss
@@ -19,4 +19,4 @@ $green: #09ad19;
 
 // Fonts
 $titles: 'Poppins', serif;
-$default: 'Inter', serif;
\ No newline at end of file
+$default: 'Inter', serif;
diff --git a/src/assets/scss/main.scss b/src/assets/scss/main.scss
index 9af5a41..c5a47f6 100644
--- a/src/assets/scss/main.scss
+++ b/src/assets/scss/main.scss
@@ -47,13 +47,13 @@ input {
   border: none;
   background-color: transparent;
 
-  &[type="number"] {
+  &[type='number'] {
     -webkit-appearance: textfield;
     -moz-appearance: textfield;
     appearance: textfield;
   }
-  &[type=number]::-webkit-inner-spin-button,
-  &[type=number]::-webkit-outer-spin-button {
+  &[type='number']::-webkit-inner-spin-button,
+  &[type='number']::-webkit-outer-spin-button {
     -webkit-appearance: none;
   }
 }
@@ -64,7 +64,8 @@ input {
   border: 1px solid $cyan;
   background-color: rgba($white, 0.8);
   border-radius: 5px;
-  &:focus, &:focus-visible {
+  &:focus,
+  &:focus-visible {
     outline: $cyan auto 2px;
   }
 }
@@ -82,7 +83,8 @@ button {
     border-radius: 5px;
     text-shadow: 0 3px 6px rgba($black, 0.2);
 
-    &.active, &:hover {
+    &.active,
+    &:hover {
       background-color: $cyan;
     }
   }
@@ -93,7 +95,8 @@ button {
     border-radius: 5px;
     text-shadow: 0 3px 6px rgba($black, 0.2);
 
-    &.active, &:hover {
+    &.active,
+    &:hover {
       background-color: $bordeaux;
     }
   }
diff --git a/src/components/World.vue b/src/components/World.vue
index fc4701a..40d74b1 100644
--- a/src/components/World.vue
+++ b/src/components/World.vue
@@ -23,7 +23,7 @@ import { generateTilemap } from '@/services/zone'
 let scene = useScene()
 let tilemapLayer = ref()
 
-const tileMap = generateTilemap(scene, 10, 10);
+const tileMap = generateTilemap(scene, 10, 10)
 let tileset: Tileset = tileMap.addTilesetImage('default', 'tiles') as Tileset
 let layer: TilemapLayer = tileMap.createBlankLayer('layer', tileset, 0, config.tile_size.y) as TilemapLayer
 
@@ -77,7 +77,7 @@ socket.connection.on('character:moved', (data: CharacterType) => {
 })
 
 onBeforeUnmount(() => {
-  zoneStore.reset();
+  zoneStore.reset()
   socket.connection.emit('character:zone:leave')
   socket.connection.off('character:zone:load')
   socket.connection.off('zone:character:join')
diff --git a/src/components/gui/Chat.vue b/src/components/gui/Chat.vue
index 8391ed6..b3d97ee 100644
--- a/src/components/gui/Chat.vue
+++ b/src/components/gui/Chat.vue
@@ -26,7 +26,7 @@
     background-color: rgba($white, 0.85);
     border: 2px solid $white;
     color: $gray-2;
-    background-image: url("/assets/icons/submit-icon.svg");
+    background-image: url('/assets/icons/submit-icon.svg');
     background-repeat: no-repeat;
     background-size: 30px;
     background-position: calc(100% - 25px) center;
@@ -37,7 +37,6 @@
       left: 500px;
       width: 30px;
       height: 30px;
-      
     }
   }
 }
diff --git a/src/components/utilities/Controls.vue b/src/components/utilities/Controls.vue
index 4ac6571..449fb3f 100644
--- a/src/components/utilities/Controls.vue
+++ b/src/components/utilities/Controls.vue
@@ -10,8 +10,8 @@ import { getTile, tileToWorldXY } from '@/services/zone'
 import { useZoneStore } from '@/stores/zone'
 import { useZoneEditorStore } from '@/stores/zoneEditor'
 
-const zoneStore = useZoneStore();
-const zoneEditorStore = useZoneEditorStore();
+const zoneStore = useZoneStore()
+const zoneEditorStore = useZoneEditorStore()
 const scene = useScene()
 const props = defineProps({
   layer: Phaser.Tilemaps.TilemapLayer
@@ -43,7 +43,7 @@ function onPointerMove(pointer: Phaser.Input.Pointer) {
 scene.input.on(Phaser.Input.Events.POINTER_MOVE, onPointerMove)
 
 // Zone camera system
-function dragZone (pointer: Phaser.Input.Pointer) {
+function dragZone(pointer: Phaser.Input.Pointer) {
   if (!pointer.isDown) return
   cam.scrollX -= (pointer.x - pointer.prevPosition.x) / cam.zoom
   cam.scrollY -= (pointer.y - pointer.prevPosition.y) / cam.zoom
@@ -52,14 +52,16 @@ let cam = scene.cameras.main
 scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone)
 
 watch(
-  () => zoneEditorStore.tool, () => {
+  () => zoneEditorStore.tool,
+  () => {
     // @TODO : change to zone for when loading other maps
-   if (zoneEditorStore.tool === 'move') {
-     scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone)
-   } else {
-     scene.input.off(Phaser.Input.Events.POINTER_MOVE, dragZone)
-   }
-  }, { deep: true }
+    if (zoneEditorStore.tool === 'move') {
+      scene.input.on(Phaser.Input.Events.POINTER_MOVE, dragZone)
+    } else {
+      scene.input.off(Phaser.Input.Events.POINTER_MOVE, dragZone)
+    }
+  },
+  { deep: true }
 )
 
 // Unload funcs
diff --git a/src/components/utilities/GmPanel.vue b/src/components/utilities/GmPanel.vue
index fc09c53..d299322 100644
--- a/src/components/utilities/GmPanel.vue
+++ b/src/components/utilities/GmPanel.vue
@@ -1,22 +1,20 @@
 <template>
-    <Modal :isModalOpen="true" :modal-width="1000" :modal-height="650">
-        <template #modalHeader>
-            <h3 class="modal-title">GM Panel</h3>
-            <div class="gm-selector">
-                <button class="btn-cyan">General</button>
-                <button class="btn-cyan">Users</button>
-                <button class="btn-cyan">Items</button>
-                <button class="btn-cyan">NPCs</button>
-                <button class="btn-cyan">Chats</button>
-                <button class="btn-cyan active">AM</button>
-            </div>
-        </template>
-        <template #modalBody>
-            <div class="container gm-panel">
-                <AssetManager v-if="toggle == 'asset-manager'" />
-            </div>
-        </template>
-    </Modal>
+  <Modal :isModalOpen="true" :modal-width="1000" :modal-height="650">
+    <template #modalHeader>
+      <h3 class="modal-title">GM Panel</h3>
+      <div class="gm-selector">
+        <button class="btn-cyan">General</button>
+        <button class="btn-cyan">Users</button>
+        <button class="btn-cyan">Chats</button>
+        <button class="btn-cyan active">Asset manager</button>
+      </div>
+    </template>
+    <template #modalBody>
+      <div class="container gm-panel">
+        <AssetManager v-if="toggle == 'asset-manager'" />
+      </div>
+    </template>
+  </Modal>
 </template>
 
 <script setup lang="ts">
@@ -31,14 +29,13 @@ let toggle = ref('asset-manager')
 @import '@/assets/scss/main';
 
 .gm-selector {
-    display: flex;
-    gap: 5px;
-    flex-wrap: wrap;
+  display: flex;
+  gap: 5px;
+  flex-wrap: wrap;
 
-    button {
-        padding: 6px 15px;
-        min-width: 100px;
-    }
+  button {
+    padding: 6px 15px;
+    min-width: 100px;
+  }
 }
-
-</style>
\ No newline at end of file
+</style>
diff --git a/src/components/utilities/Modal.vue b/src/components/utilities/Modal.vue
index 8f0bead..e4098cd 100644
--- a/src/components/utilities/Modal.vue
+++ b/src/components/utilities/Modal.vue
@@ -304,7 +304,6 @@ function handleResize() {
             }
           }
         }
-        
       }
     }
   }
diff --git a/src/components/utilities/Notifications.vue b/src/components/utilities/Notifications.vue
index 60f6661..1ca6bd9 100644
--- a/src/components/utilities/Notifications.vue
+++ b/src/components/utilities/Notifications.vue
@@ -56,7 +56,7 @@ onBeforeUnmount(() => {
 </script>
 
 <style lang="scss">
-  .modal-notif {
-    margin: 15px;
-  }
-</style>
\ No newline at end of file
+.modal-notif {
+  margin: 15px;
+}
+</style>
diff --git a/src/components/utilities/assetManager/AssetManager.vue b/src/components/utilities/assetManager/AssetManager.vue
index 5440e42..13cbc1b 100644
--- a/src/components/utilities/assetManager/AssetManager.vue
+++ b/src/components/utilities/assetManager/AssetManager.vue
@@ -1,16 +1,15 @@
 <template>
   <div class="assets-container">
     <div class="asset-categories">
-
       <!-- Asset Categories -->
-      <a class="category" :class="{ selected: selectedCategory === 'tiles' }" @click="() => selectedCategory = 'tiles'">
+      <a class="category" :class="{ selected: selectedCategory === 'tiles' }" @click="() => (selectedCategory = 'tiles')">
         <span class="category-name">Tiles</span>
       </a>
-      <a class="category" :class="{ selected: selectedCategory === 'objects' }" @click="() => selectedCategory = 'objects'">
+      <a class="category" :class="{ selected: selectedCategory === 'objects' }" @click="() => (selectedCategory = 'objects')">
         <span class="category-name">Objects</span>
       </a>
       <a class="category">
-        <span class="category-name">Weapons</span>
+        <span class="category-name">Loot</span>
       </a>
       <a class="category">
         <span class="category-name">NPC's</span>
@@ -20,7 +19,8 @@
 
     <!-- Assets list -->
     <div class="assets" ref="elementToScroll" @scroll="onScroll">
-      <TileList :name="selectedCategory" />
+      <TileList v-if="selectedCategory === 'tiles'" />
+      <ObjectList :name="selectedCategory" v-if="selectedCategory === 'objects'" />
     </div>
 
     <button class="back-to-top" v-show="hasScrolled" @click="toTop">
@@ -30,22 +30,25 @@
 
     <!-- Asset details -->
     <div class="asset-info">
-      <TileDetails :tile="selectedTile" v-if="selectedCategory === 'tiles'" />
+      <TileDetails :tile="selectedTile" v-if="selectedCategory === 'tiles' && assetManagerStore.selectedTile" />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
 import { onMounted, ref } from 'vue'
-import {useSocketStore} from '@/stores/socket'
+import { useSocketStore } from '@/stores/socket'
 import TileList from '@/components/utilities/assetManager/partials/TileList.vue'
 import TileDetails from '@/components/utilities/assetManager/partials/TileDetails.vue'
+import ObjectList from '@/components/utilities/assetManager/partials/ObjectList.vue'
+import { useAssetManagerStore } from '@/stores/assetManager'
 
 const socket = useSocketStore()
+const assetManagerStore = useAssetManagerStore()
 const selectedCategory = ref('tiles')
 const selectedTile = ref('')
 const hasScrolled = ref(false)
-const elementToScroll = ref() 
+const elementToScroll = ref()
 
 const onScroll = (e: Event) => {
   let scrollTop = (e.target as HTMLBodyElement).scrollTop
@@ -61,8 +64,8 @@ function toTop() {
   elementToScroll.value.scrollTo({
     top: 0,
     left: 0,
-    behavior: "smooth",
-  });
+    behavior: 'smooth'
+  })
 }
 </script>
 
@@ -72,7 +75,7 @@ function toTop() {
 .container {
   &.gm-panel {
     height: 100%;
-    margin: 0!important;
+    margin: 0 !important;
   }
 }
 .assets-container {
@@ -103,7 +106,7 @@ function toTop() {
     width: 50px;
     height: 50px;
     border-radius: 8px;
-    background-color: rgba($cyan, 0.5); 
+    background-color: rgba($cyan, 0.5);
     padding: 0;
     img {
       position: absolute;
@@ -119,14 +122,14 @@ function toTop() {
       background-color: rgba($cyan, 0.8);
     }
   }
-  
+
   .asset-categories {
     width: 15%;
     display: flex;
   }
 
   .assets {
-    overflow:auto;
+    overflow: auto;
     height: 100%;
     width: 35%;
     display: flex;
@@ -171,7 +174,6 @@ function toTop() {
 
   .asset-details {
     display: flex;
-    justify-content: center;
     align-items: center;
     gap: 10px;
     img {
@@ -185,11 +187,15 @@ function toTop() {
     }
   }
 
-  .asset-categories, .assets, .asset-info {
+  .asset-categories,
+  .assets,
+  .asset-info {
     flex-direction: column;
     position: relative;
 
-    .category, .asset, .image-container {
+    .category,
+    .asset,
+    .image-container {
       position: relative;
       padding: 10px;
       &::after {
@@ -204,9 +210,7 @@ function toTop() {
       &.selected {
         background-color: rgba($cyan, 0.8);
       }
-      
     }
   }
-  
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/components/utilities/assetManager/partials/ObjectList.vue b/src/components/utilities/assetManager/partials/ObjectList.vue
new file mode 100644
index 0000000..ae0d37d
--- /dev/null
+++ b/src/components/utilities/assetManager/partials/ObjectList.vue
@@ -0,0 +1,80 @@
+<template>
+  <div class="asset">
+    <input class="input-cyan search-field" placeholder="Search..." />
+  </div>
+
+  <!-- TODO: use the passed :name in props to switch out assets-->
+  <a class="asset" :class="{ active: name === 'tiles' }" v-for="(tile, index) in tiles" :key="index">
+    <div class="asset-details">
+      <img :src="`${config.server_endpoint}/assets/tiles/${tile}`" />
+      <span class="asset-name">{{ tile }}</span>
+    </div>
+  </a>
+</template>
+
+<script setup lang="ts">
+import { useSocketStore } from '@/stores/socket'
+import config from '@/config'
+import { onMounted, ref, defineProps } from 'vue'
+
+const props = defineProps<{ name: string }>()
+
+const socket = useSocketStore()
+const tileUploadField = ref(null)
+const tiles = ref()
+
+const handleFileUpload = (e: Event) => {
+  const files = (e.target as HTMLInputElement).files
+  if (!files) return
+  socket.connection.emit('gm:tile:upload', files, (response: boolean) => {
+    if (!response) {
+      console.error('Failed to upload tile')
+      return
+    }
+    socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
+      tiles.value = response
+    })
+  })
+}
+
+onMounted(() => {
+  socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
+    tiles.value = response
+  })
+})
+</script>
+
+<style lang="scss" scoped>
+@import '@/assets/scss/main';
+
+.asset {
+  &.add-new {
+    display: flex;
+    align-items: center;
+    gap: 10px 20px;
+    flex-wrap: wrap;
+    .asset-name {
+      flex-shrink: 0;
+    }
+  }
+  .search-field {
+    width: calc(100% - 20px);
+  }
+  .file-upload {
+    background-color: rgba($cyan, 0.5);
+    border: 1px solid $white;
+    border-radius: 5px;
+    text-shadow: 0 3px 6px rgba($black, 0.2);
+    padding: 6px 15px;
+    display: inline-flex;
+
+    &:hover {
+      background-color: $cyan;
+      cursor: pointer;
+    }
+    input[type='file'] {
+      display: none;
+    }
+  }
+}
+</style>
diff --git a/src/components/utilities/assetManager/partials/TileDetails.vue b/src/components/utilities/assetManager/partials/TileDetails.vue
index 9fb497c..7f5b2cc 100644
--- a/src/components/utilities/assetManager/partials/TileDetails.vue
+++ b/src/components/utilities/assetManager/partials/TileDetails.vue
@@ -1,28 +1,41 @@
 <template>
   <div class="image-container">
-    <img src="/assets/placeholders/wall-1.png" />
+    <img :src="`${config.server_endpoint}/assets/tiles/${assetManagerStore.selectedTile}`" alt="Tile" />
   </div>
   <div class="modal-form asset-manager">
     <form class="form-fields">
       <div class="form-field name">
         <label for="name">Name</label>
-        <input class="input-cyan" type="text" name="name" placeholder="Wall #1" />
+        <input class="input-cyan" type="text" name="name" placeholder="E.g. grass" />
       </div>
 
       <div class="submit">
         <button class="btn-cyan" type="submit">Save</button>
-        <button class="btn-bordeaux" type="submit">Remove</button>
+        <button class="btn-bordeaux" type="button" @click="removeTile">Remove</button>
       </div>
     </form>
   </div>
 </template>
 
 <script setup lang="ts">
-const properties = defineProps({
-  tile: String
-});
+import config from '@/config'
+import { useAssetManagerStore } from '@/stores/assetManager'
+import { useSocketStore } from '@/stores/socket'
+
+const socket = useSocketStore()
+const assetManagerStore = useAssetManagerStore()
+
+function removeTile() {
+  socket.connection.emit('gm:tile:remove', { tile: assetManagerStore.selectedTile }, (response: boolean) => {
+    if (!response) {
+      return
+    }
+    socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
+      assetManagerStore.setTileList(response)
+      assetManagerStore.setSelectedTile('')
+    })
+  })
+}
 </script>
 
-<style lang="scss">
-
-</style>
\ No newline at end of file
+<style lang="scss"></style>
diff --git a/src/components/utilities/assetManager/partials/TileList.vue b/src/components/utilities/assetManager/partials/TileList.vue
index 73ebda2..8d0c325 100644
--- a/src/components/utilities/assetManager/partials/TileList.vue
+++ b/src/components/utilities/assetManager/partials/TileList.vue
@@ -1,34 +1,28 @@
 <template>
-  <div class="asset">
-    <input class="input-cyan search-field" placeholder="Search..." />
-  </div>
   <div class="asset add-new">
-    <span class="asset-name">Upload new</span>
     <label for="upload-asset" class="file-upload">
       <input id="upload-asset" ref="tileUploadField" type="file" accept="image/png" multiple @change="handleFileUpload" />
-      Choose file
+      Upload tile(s)
     </label>
+    <input class="input-cyan search-field" placeholder="Search..." />
   </div>
-
-  <!-- TODO: use the passed :name in props to switch out assets-->
-  <a class="asset" :class="{ active: name === 'tiles' }" v-for="(tile, index) in tiles" :key="index">
+  <a class="asset" :class="{ active: assetManagerStore.selectedTile === tile }" v-for="(tile, index) in assetManagerStore.tileList" :key="index" @click="assetManagerStore.setSelectedTile(tile)">
     <div class="asset-details">
-      <img :src="`${config.server_endpoint}/assets/tiles/${tile}`" />
+      <img :src="`${config.server_endpoint}/assets/tiles/${tile}`" alt="Tile" />
       <span class="asset-name">{{ tile }}</span>
     </div>
   </a>
 </template>
 
 <script setup lang="ts">
-import {useSocketStore} from '@/stores/socket'
 import config from '@/config'
-import { onMounted, ref, defineProps } from 'vue'
-
-const props = defineProps<{ name: string }>()
+import { useSocketStore } from '@/stores/socket'
+import { onMounted, ref } from 'vue'
+import { useAssetManagerStore } from '@/stores/assetManager'
 
 const socket = useSocketStore()
 const tileUploadField = ref(null)
-const tiles = ref()
+const assetManagerStore = useAssetManagerStore()
 
 const handleFileUpload = (e: Event) => {
   const files = (e.target as HTMLInputElement).files
@@ -39,14 +33,14 @@ const handleFileUpload = (e: Event) => {
       return
     }
     socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
-      tiles.value = response
+      assetManagerStore.setTileList(response)
     })
   })
 }
 
 onMounted(() => {
   socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
-    tiles.value = response
+    assetManagerStore.setTileList(response)
   })
 })
 </script>
@@ -55,9 +49,10 @@ onMounted(() => {
 @import '@/assets/scss/main';
 
 .asset {
+  cursor: pointer;
+
   &.add-new {
     display: flex;
-    align-items: center;
     gap: 10px 20px;
     flex-wrap: wrap;
     .asset-name {
@@ -79,9 +74,9 @@ onMounted(() => {
       background-color: $cyan;
       cursor: pointer;
     }
-    input[type="file"] {
+    input[type='file'] {
       display: none;
     }
   }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/src/components/utilities/zoneEditor/Tiles.vue b/src/components/utilities/zoneEditor/Tiles.vue
index d865b1c..7981312 100644
--- a/src/components/utilities/zoneEditor/Tiles.vue
+++ b/src/components/utilities/zoneEditor/Tiles.vue
@@ -6,9 +6,8 @@
       </template>
       <template #modalBody>
         <div class="container tiles">
-          <canvas ref="canvas" :width="tileWidth" :height="tileHeight" style="display: none"></canvas>
           <div class="tiles">
-            <img v-for="(tile, index) in tiles" :key="index" :src="tile" alt="Tile" @click="zoneEditorStore.setSelectedTile(index)" :class="{ selected: zoneEditorStore.selectedTile && zoneEditorStore.selectedTile === index }" />
+            <img v-for="(tile, index) in tiles" :key="index" :src="tile" alt="Tile" @click="zoneEditorStore.setSelectedTile(tile)" :class="{ selected: zoneEditorStore.selectedTile && zoneEditorStore.selectedTile === tile }" />
           </div>
         </div>
       </template>
@@ -17,73 +16,22 @@
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, nextTick } from 'vue'
 import config from '@/config'
-import Modal from '@/components/utilities/Modal.vue'
+import { ref, onMounted } from 'vue'
 import { useZoneEditorStore } from '@/stores/zoneEditor'
-import JSZip from 'jszip'
+import { useSocketStore } from '@/stores/socket'
+import Modal from '@/components/utilities/Modal.vue'
 
-const tileWidth = config.tile_size.x
-const tileHeight = config.tile_size.y
-const tiles = ref<number[][]>([])
-const selectedTile = ref<number | null>(null)
-const canvas = ref<HTMLCanvasElement | null>(null)
+const socket = useSocketStore()
+const tiles = ref<string[]>([])
 const isModalOpen = ref(false)
 const zoneEditorStore = useZoneEditorStore()
 
-// Hardcoded image path
-const imagePath = '/assets/zone/tiles.png'
-
-const loadImage = (src: string): Promise<HTMLImageElement> => {
-  return new Promise((resolve) => {
-    const img = new Image()
-    img.onload = () => resolve(img)
-    img.src = src
-  })
-}
-
-const splitTiles = (img: HTMLImageElement) => {
-  if (!canvas.value) {
-    console.error('Canvas not found')
-    return
-  }
-  const ctx = canvas.value.getContext('2d')
-  if (!ctx) {
-    console.error('Failed to get canvas context')
-    return
-  }
-
-  const tilesetWidth = img.width
-  const tilesetHeight = img.height
-  const columns = Math.floor(tilesetWidth / tileWidth)
-  const rows = Math.floor(tilesetHeight / tileHeight)
-
-  tiles.value = []
-  selectedTile.value = null
-
-  for (let row = 0; row < rows; row++) {
-    for (let col = 0; col < columns; col++) {
-      const x = col * tileWidth
-      const y = row * tileHeight
-
-      ctx.clearRect(0, 0, tileWidth, tileHeight)
-      ctx.drawImage(img, x, y, tileWidth, tileHeight, 0, 0, tileWidth, tileHeight)
-
-      const tileDataURL = canvas.value.toDataURL()
-      tiles.value.push(tileDataURL)
-    }
-  }
-}
-
-const selectTile = (index: number) => {
-  selectedTile.value = index
-}
-
 onMounted(async () => {
   isModalOpen.value = true
-  const img = await loadImage(imagePath)
-  await nextTick()
-  splitTiles(img)
+  socket.connection.emit('gm:tile:list', {}, (response: string[]) => {
+    tiles.value = response.map((tile) => `${config.server_endpoint}/assets/tiles/${tile}`)
+  })
 })
 </script>
 
@@ -107,5 +55,4 @@ onMounted(async () => {
 .tiles img.selected {
   border: 2px solid $red;
 }
-
-</style>
\ No newline at end of file
+</style>
diff --git a/src/components/utilities/zoneEditor/Toolbar.vue b/src/components/utilities/zoneEditor/Toolbar.vue
index ee24ab6..115e6e6 100644
--- a/src/components/utilities/zoneEditor/Toolbar.vue
+++ b/src/components/utilities/zoneEditor/Toolbar.vue
@@ -13,7 +13,7 @@
           <div class="select" v-if="zoneEditorStore.tool === 'pencil'">
             <div class="select-trigger" :class="{ open: selectPencilOpen }" @click="selectPencilOpen = !selectPencilOpen">
               {{ zoneEditorStore.drawMode }}
-              <img src="/assets/icons/zoneEditor/chevron.svg"/>
+              <img src="/assets/icons/zoneEditor/chevron.svg" />
             </div>
             <div class="options" v-show="selectPencilOpen && zoneEditorStore.tool === 'pencil'">
               <span class="option" @click="setDrawMode('tile')">Tile</span>
@@ -31,7 +31,7 @@
           <div class="select" v-if="zoneEditorStore.tool === 'eraser'">
             <div class="select-trigger" :class="{ open: selectEraserOpen }" @click="selectEraserOpen = !selectEraserOpen">
               {{ zoneEditorStore.drawMode }}
-              <img src="/assets/icons/zoneEditor/chevron.svg"/>
+              <img src="/assets/icons/zoneEditor/chevron.svg" />
             </div>
             <div class="options" v-show="selectEraserOpen">
               <span class="option" @click="setDrawMode('tile')">Tile</span>
@@ -75,8 +75,8 @@ const scene = useScene()
 const emit = defineEmits(['move', 'eraser', 'pencil', 'save'])
 
 // track select state
-let selectPencilOpen = ref(false);
-let selectEraserOpen = ref(false);
+let selectPencilOpen = ref(false)
+let selectEraserOpen = ref(false)
 
 // drawMode
 function setDrawMode(value: string) {
diff --git a/src/components/utilities/zoneEditor/ZoneEditor.vue b/src/components/utilities/zoneEditor/ZoneEditor.vue
index 18e7e11..fcd532f 100644
--- a/src/components/utilities/zoneEditor/ZoneEditor.vue
+++ b/src/components/utilities/zoneEditor/ZoneEditor.vue
@@ -2,11 +2,11 @@
   <TilemapLayerC :tilemap="tileTilemap" :tileset="exampleTilesArray" :layerIndex="0" :cull-padding-x="10" :cull-padding-y="10" />
 
   <Controls :layer="exampleTiles" />
-<!--  @TODO: inside asset manager we need to be able to set the originX and originY per individial asset -->
+  <!--  @TODO: inside asset manager we need to be able to set the originX and originY per individial asset -->
   <Container>
-    <Image :texture="'wall1'" :x="pos.position_x" :y="pos.position_y" :originY="1.13" :originX="1"  />
-    <Image :texture="'wall1'" :x="pos2.position_x" :y="pos2.position_y" :originY="1.13" :originX="1"  />
-    <Image :texture="'wall2'" :x="pos3.position_x" :y="pos3.position_y" :originY="1.255" :originX="1"  />
+    <Image :texture="'wall1'" :x="pos.position_x" :y="pos.position_y" :originY="1.13" :originX="1" />
+    <Image :texture="'wall1'" :x="pos2.position_x" :y="pos2.position_y" :originY="1.13" :originX="1" />
+    <Image :texture="'wall2'" :x="pos3.position_x" :y="pos3.position_y" :originY="1.255" :originX="1" />
   </Container>
 
   <Toolbar :layer="exampleTiles" @eraser="eraser" @pencil="pencil" @save="save" />
@@ -38,7 +38,6 @@ let scene = useScene()
 const socket = useSocketStore()
 const zoneEditorStore = useZoneEditorStore()
 
-
 // Tile tilemap
 const tileMapData = new Phaser.Tilemaps.MapData({
   width: zoneEditorStore.width,
@@ -48,18 +47,17 @@ const tileMapData = new Phaser.Tilemaps.MapData({
   orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
   format: Phaser.Tilemaps.Formats.ARRAY_2D
 })
-let tileTilemap = new Phaser.Tilemaps.Tilemap(scene, tileMapData);
+let tileTilemap = new Phaser.Tilemaps.Tilemap(scene, tileMapData)
 let tilesImg = tileTilemap.addTilesetImage('default', 'tiles')
 let exampleTiles = tileTilemap.createBlankLayer('exampleTiles', tilesImg as Tileset, 0, config.tile_size.y) as TilemapLayer
 
 const exampleTilesArray = Array.from({ length: zoneEditorStore.width }, () => Array.from({ length: zoneEditorStore.height }, () => 1))
 
-onMounted(() => {
-})
-  const pos = tileToWorldXY(exampleTiles, 1, 1);
-  const pos2 = tileToWorldXY(exampleTiles, 1, 2);
-  const pos3 = tileToWorldXY(exampleTiles, 2, 1);
-console.log(pos);
+onMounted(() => {})
+const pos = tileToWorldXY(exampleTiles, 1, 1)
+const pos2 = tileToWorldXY(exampleTiles, 1, 2)
+const pos3 = tileToWorldXY(exampleTiles, 2, 1)
+console.log(pos)
 // center camera
 const centerY = (tileTilemap.height * tileTilemap.tileHeight) / 2
 const centerX = (tileTilemap.width * tileTilemap.tileWidth) / 2
@@ -91,12 +89,12 @@ onBeforeMount(() => {
 function eraser(tile: Phaser.Tilemaps.Tile) {
   if (zoneEditorStore.drawMode === 'tile') {
     tiles.putTileAt(0, tile.x, tile.y)
-    zoneEditorStore.updateTile(tile.x, tile.y, 0);
+    zoneEditorStore.updateTile(tile.x, tile.y, 0)
   }
 
   if (zoneEditorStore.drawMode === 'wall') {
-    walls.putTileAt(0, tile.x, tile.y )
-    zoneEditorStore.updateWall(tile.x, tile.y, 0);
+    walls.putTileAt(0, tile.x, tile.y)
+    zoneEditorStore.updateWall(tile.x, tile.y, 0)
   }
 }
 
@@ -104,14 +102,14 @@ function pencil(tile: Phaser.Tilemaps.Tile) {
   if (zoneEditorStore.drawMode === 'tile') {
     if (zoneEditorStore.selectedTile === null) return
     tiles.putTileAt(zoneEditorStore.selectedTile, tile.x, tile.y)
-    zoneEditorStore.setTiles(tile.x, tile.y, zoneEditorStore.selectedTile);
+    zoneEditorStore.setTiles(tile.x, tile.y, zoneEditorStore.selectedTile)
   }
 
   if (zoneEditorStore.drawMode === 'wall') {
     // @TODO fix position
     if (zoneEditorStore.selectedWall === null) return
     walls.putTileAt(zoneEditorStore.selectedWall, tile.x, tile.y)
-    zoneEditorStore.updateWall(tile.x, tile.y, zoneEditorStore.selectedWall);
+    zoneEditorStore.updateWall(tile.x, tile.y, zoneEditorStore.selectedWall)
   }
 }
 
@@ -127,7 +125,7 @@ function save() {
 }
 
 onBeforeUnmount(() => {
-  zoneEditorStore.reset();
+  zoneEditorStore.reset()
 })
 
 /**
diff --git a/src/components/utilities/zoneEditor/ZoneSettings.vue b/src/components/utilities/zoneEditor/ZoneSettings.vue
index 36e75a6..61441c0 100644
--- a/src/components/utilities/zoneEditor/ZoneSettings.vue
+++ b/src/components/utilities/zoneEditor/ZoneSettings.vue
@@ -55,4 +55,4 @@ watch(width, (value) => {
 watch(height, (value) => {
   zoneEditorStore.setHeight(parseInt(value))
 })
-</script>
\ No newline at end of file
+</script>
diff --git a/src/screens/Game.vue b/src/screens/Game.vue
index 2b03ee4..af0123a 100644
--- a/src/screens/Game.vue
+++ b/src/screens/Game.vue
@@ -4,16 +4,16 @@
 
     <Game class="game" :config="gameConfig" @create="createGame" v-if="!zoneEditorStore.active">
       <Scene name="main" @preload="preloadScene" @create="createScene">
-          <div class="top-ui">
-            <Hud />
-          </div>
-          <div class="center-ui">
-            <World />
-          </div>
-          <div class="bottom-ui">
-            <Chat />
-            <Menubar />
-          </div>
+        <div class="top-ui">
+          <Hud />
+        </div>
+        <div class="center-ui">
+          <World />
+        </div>
+        <div class="bottom-ui">
+          <Chat />
+          <Menubar />
+        </div>
       </Scene>
     </Game>
     <Game class="game" :config="gameConfig" @create="createGame" v-else>
diff --git a/src/services/zone.ts b/src/services/zone.ts
index b62794f..6d015d0 100644
--- a/src/services/zone.ts
+++ b/src/services/zone.ts
@@ -23,6 +23,4 @@ export function tileToWorldXY(layer: Phaser.Tilemaps.TilemapLayer, pos_x: number
   return { position_x, position_y }
 }
 
-export function generateTilemap(scene: Phaser.Scene, width: number, height: number) {
-
-}
\ No newline at end of file
+export function generateTilemap(scene: Phaser.Scene, width: number, height: number) {}
diff --git a/src/stores/assetManager.ts b/src/stores/assetManager.ts
new file mode 100644
index 0000000..691ff2d
--- /dev/null
+++ b/src/stores/assetManager.ts
@@ -0,0 +1,20 @@
+import { defineStore } from 'pinia'
+
+export const useAssetManagerStore = defineStore('assetManager', {
+  state: () => ({
+    tileList: [] as string[],
+    selectedTile: ''
+  }),
+  actions: {
+    setTileList(tiles: string[]) {
+      this.tileList = tiles
+    },
+    setSelectedTile(tile: string) {
+      this.selectedTile = tile
+    },
+    reset() {
+      this.tileList = []
+      this.selectedTile = ''
+    }
+  }
+})
diff --git a/src/stores/zoneEditor.ts b/src/stores/zoneEditor.ts
index 8d2ade2..39fe5f7 100644
--- a/src/stores/zoneEditor.ts
+++ b/src/stores/zoneEditor.ts
@@ -10,7 +10,7 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
     decorations: [] as number[][],
     tool: 'move',
     drawMode: 'tile',
-    selectedTile: null,
+    selectedTile: '',
     selectedWall: null,
     selectedDecoration: null,
     isSettingsModalShown: false
@@ -46,7 +46,7 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
     setDrawMode(mode: string) {
       this.drawMode = mode
     },
-    setSelectedTile(tile: any) {
+    setSelectedTile(tile: string) {
       this.selectedTile = tile
     },
     setSelectedWall(wall: any) {
@@ -65,7 +65,7 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
       this.tiles = []
       this.tool = 'move'
       this.drawMode = 'tile'
-      this.selectedTile = null
+      this.selectedTile = ''
       this.selectedWall = null
       this.selectedDecoration = null
       this.isSettingsModalShown = false
@@ -77,4 +77,4 @@ export const useZoneEditorStore = defineStore('zoneEditor', {
  * Resources:
  * https://www.html5gamedevs.com/topic/21908-phaser-is-there-any-tutorial-on-how-to-do-an-isometric-game/
  * http://murdochcarpenter.com/isometric-starling-part-i/
- */
\ No newline at end of file
+ */
diff --git a/src/types.ts b/src/types.ts
index 8748651..93e8fef 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -5,62 +5,62 @@ export type Notification = {
 
 // User model
 export type User = {
-  id: number;
-  username: string;
-  password: string;
-  characters: Character[];
-};
+  id: number
+  username: string
+  password: string
+  characters: Character[]
+}
 
 // Character model
 export type Character = {
-  id: number;
-  userId: number;
-  user: User;
-  name: string;
-  hitpoints: number;
-  mana: number;
-  level: number;
-  experience: number;
-  role: string;
-  position_x: number;
-  position_y: number;
-  rotation: number;
-  zoneId: number;
-  zone: Zone;
-  chats: Chat[];
-};
+  id: number
+  userId: number
+  user: User
+  name: string
+  hitpoints: number
+  mana: number
+  level: number
+  experience: number
+  role: string
+  position_x: number
+  position_y: number
+  rotation: number
+  zoneId: number
+  zone: Zone
+  chats: Chat[]
+}
 
 // Zone model
 export type Zone = {
-  id: number;
-  name: string;
-  width: number;
-  height: number;
-  tiles: number[][];
-  walls: number[][];
-  decorations: ZoneDecoration[];
-  characters: Character[];
-  chats: Chat[];
-  createdAt: Date;
-  updatedAt: Date;
-};
+  id: number
+  name: string
+  width: number
+  height: number
+  tiles: number[][]
+  walls: number[][]
+  decorations: ZoneDecoration[]
+  characters: Character[]
+  chats: Chat[]
+  createdAt: Date
+  updatedAt: Date
+}
 
 export type ZoneDecoration = {
-  id: number;
-  zoneId: number;
-  zone: Zone;
-  type: number;
-  position_x: number;
-  position_y: number;
+  id: number
+  zoneId: number
+  zone: Zone
+  type: number
+  position_x: number
+  position_y: number
 }
 
 // Chat model
 export type Chat = {
-  id: number;
-  characterId: number;
-  character: Character;
-  zoneId: number;
-  zone: Zone;
-  message: string;
-  createdAt: Date;
-};
+  id: number
+  characterId: number
+  character: Character
+  zoneId: number
+  zone: Zone
+  message: string
+  createdAt: Date
+}