diff --git a/package-lock.json b/package-lock.json
index 837ab98..0bdf002 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1360,9 +1360,9 @@
       }
     },
     "node_modules/@prisma/client": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.1.0.tgz",
-      "integrity": "sha512-AbQYc5+EJKm1Ydfq3KxwcGiy7wIbm4/QbjCKWWoNROtvy7d6a3gmAGkKjK0iUCzh+rHV8xDhD5Cge8ke/kiy5Q==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.2.0.tgz",
+      "integrity": "sha512-tmEgej4OR+Wqk8MwZQcu58JzA1iFPmi/z7VPEmjTuTIQDLqHQZ6+MDRLL4wgNJXJkMHUKD9yMD5AkwYH0/0hKA==",
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "engines": {
@@ -1378,53 +1378,53 @@
       }
     },
     "node_modules/@prisma/debug": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.1.0.tgz",
-      "integrity": "sha512-0himsvcM4DGBTtvXkd2Tggv6sl2JyUYLzEGXXleFY+7Kp6rZeSS3hiTW9mwtUlXrwYbJP6pwlVNB7jYElrjWUg==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.2.0.tgz",
+      "integrity": "sha512-Q96rqZVivmEtt29h1hhALceJTqggHDsr3RAWpeSJZOppQu6vcv5PyiY4XxyTf04gZw4Ue+kkqtaRcRms1zC8aQ==",
       "devOptional": true,
       "license": "Apache-2.0"
     },
     "node_modules/@prisma/engines": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.1.0.tgz",
-      "integrity": "sha512-GnYJbCiep3Vyr1P/415ReYrgJUjP79fBNc1wCo7NP6Eia0CzL2Ot9vK7Infczv3oK7JLrCcawOSAxFxNFsAERQ==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.2.0.tgz",
+      "integrity": "sha512-Od7fH2gH+4n0E/XIhhAfO3OaKKNRzD0s1LY8umyvDQXlFmiDYF8kNJydcfWLvU3XNNV40wM2T0jOU+4ua1Zp3A==",
       "devOptional": true,
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "dependencies": {
-        "@prisma/debug": "6.1.0",
-        "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
-        "@prisma/fetch-engine": "6.1.0",
-        "@prisma/get-platform": "6.1.0"
+        "@prisma/debug": "6.2.0",
+        "@prisma/engines-version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
+        "@prisma/fetch-engine": "6.2.0",
+        "@prisma/get-platform": "6.2.0"
       }
     },
     "node_modules/@prisma/engines-version": {
-      "version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
-      "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959.tgz",
-      "integrity": "sha512-PdJqmYM2Fd8K0weOOtQThWylwjsDlTig+8Pcg47/jszMuLL9iLIaygC3cjWJLda69siRW4STlCTMSgOjZzvKPQ==",
+      "version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
+      "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69.tgz",
+      "integrity": "sha512-7tw1qs/9GWSX6qbZs4He09TOTg1ff3gYsB3ubaVNN0Pp1zLm9NC5C5MZShtkz7TyQjx7blhpknB7HwEhlG+PrQ==",
       "devOptional": true,
       "license": "Apache-2.0"
     },
     "node_modules/@prisma/fetch-engine": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.1.0.tgz",
-      "integrity": "sha512-asdFi7TvPlEZ8CzSZ/+Du5wZ27q6OJbRSXh+S8ISZguu+S9KtS/gP7NeXceZyb1Jv1SM1S5YfiCv+STDsG6rrg==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.2.0.tgz",
+      "integrity": "sha512-zz0HmZ2Npsthnh+1cj7aFPRWs57GS4CNlM9uXpVeQm2/YN0LMRNeuI5/zpqRhHrZUXdKde0jltJnvIM1Xz/mPQ==",
       "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
-        "@prisma/debug": "6.1.0",
-        "@prisma/engines-version": "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959",
-        "@prisma/get-platform": "6.1.0"
+        "@prisma/debug": "6.2.0",
+        "@prisma/engines-version": "6.2.0-14.4123509d24aa4dede1e864b46351bf2790323b69",
+        "@prisma/get-platform": "6.2.0"
       }
     },
     "node_modules/@prisma/get-platform": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.1.0.tgz",
-      "integrity": "sha512-ia8bNjboBoHkmKGGaWtqtlgQOhCi7+f85aOkPJKgNwWvYrT6l78KgojLekE8zMhVk0R9lWcifV0Pf8l3/15V0Q==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.2.0.tgz",
+      "integrity": "sha512-Nnk2fcjiRB9E0uRKCMl+EmBC1Vs6kXqaHa2E108pDrEXAgxj0Ns/YQSeZE0o4QJiK5m1PGmImA9/FFUAgCUTHA==",
       "devOptional": true,
       "license": "Apache-2.0",
       "dependencies": {
-        "@prisma/debug": "6.1.0"
+        "@prisma/debug": "6.2.0"
       }
     },
     "node_modules/@rtsao/scc": {
@@ -1840,21 +1840,21 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.0.tgz",
-      "integrity": "sha512-NggSaEZCdSrFddbctrVjkVZvFC6KGfKfNK0CU7mNK/iKHGKbzT4Wmgm08dKpcZECBu9f5FypndoMyRHkdqfT1Q==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz",
+      "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
         "@eslint-community/regexpp": "^4.10.0",
-        "@typescript-eslint/scope-manager": "8.19.0",
-        "@typescript-eslint/type-utils": "8.19.0",
-        "@typescript-eslint/utils": "8.19.0",
-        "@typescript-eslint/visitor-keys": "8.19.0",
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/type-utils": "8.19.1",
+        "@typescript-eslint/utils": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "graphemer": "^1.4.0",
         "ignore": "^5.3.1",
         "natural-compare": "^1.4.0",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1870,16 +1870,16 @@
       }
     },
     "node_modules/@typescript-eslint/parser": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.0.tgz",
-      "integrity": "sha512-6M8taKyOETY1TKHp0x8ndycipTVgmp4xtg5QpEZzXxDhNvvHOJi5rLRkLr8SK3jTgD5l4fTlvBiRdfsuWydxBw==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz",
+      "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/scope-manager": "8.19.0",
-        "@typescript-eslint/types": "8.19.0",
-        "@typescript-eslint/typescript-estree": "8.19.0",
-        "@typescript-eslint/visitor-keys": "8.19.0",
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/typescript-estree": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -1895,14 +1895,14 @@
       }
     },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.0.tgz",
-      "integrity": "sha512-hkoJiKQS3GQ13TSMEiuNmSCvhz7ujyqD1x3ShbaETATHrck+9RaDdUbt+osXaUuns9OFwrDTTrjtwsU8gJyyRA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz",
+      "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.19.0",
-        "@typescript-eslint/visitor-keys": "8.19.0"
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1913,16 +1913,16 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.0.tgz",
-      "integrity": "sha512-TZs0I0OSbd5Aza4qAMpp1cdCYVnER94IziudE3JU328YUHgWu9gwiwhag+fuLeJ2LkWLXI+F/182TbG+JaBdTg==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz",
+      "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "8.19.0",
-        "@typescript-eslint/utils": "8.19.0",
+        "@typescript-eslint/typescript-estree": "8.19.1",
+        "@typescript-eslint/utils": "8.19.1",
         "debug": "^4.3.4",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1937,9 +1937,9 @@
       }
     },
     "node_modules/@typescript-eslint/types": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.0.tgz",
-      "integrity": "sha512-8XQ4Ss7G9WX8oaYvD4OOLCjIQYgRQxO+qCiR2V2s2GxI9AUpo7riNwo6jDhKtTcaJjT8PY54j2Yb33kWtSJsmA==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz",
+      "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==",
       "dev": true,
       "license": "MIT",
       "engines": {
@@ -1951,20 +1951,20 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.0.tgz",
-      "integrity": "sha512-WW9PpDaLIFW9LCbucMSdYUuGeFUz1OkWYS/5fwZwTA+l2RwlWFdJvReQqMUMBw4yJWJOfqd7An9uwut2Oj8sLw==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz",
+      "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.19.0",
-        "@typescript-eslint/visitor-keys": "8.19.0",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/visitor-keys": "8.19.1",
         "debug": "^4.3.4",
         "fast-glob": "^3.3.2",
         "is-glob": "^4.0.3",
         "minimatch": "^9.0.4",
         "semver": "^7.6.0",
-        "ts-api-utils": "^1.3.0"
+        "ts-api-utils": "^2.0.0"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1978,16 +1978,16 @@
       }
     },
     "node_modules/@typescript-eslint/utils": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.0.tgz",
-      "integrity": "sha512-PTBG+0oEMPH9jCZlfg07LCB2nYI0I317yyvXGfxnvGvw4SHIOuRnQ3kadyyXY6tGdChusIHIbM5zfIbp4M6tCg==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz",
+      "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
         "@eslint-community/eslint-utils": "^4.4.0",
-        "@typescript-eslint/scope-manager": "8.19.0",
-        "@typescript-eslint/types": "8.19.0",
-        "@typescript-eslint/typescript-estree": "8.19.0"
+        "@typescript-eslint/scope-manager": "8.19.1",
+        "@typescript-eslint/types": "8.19.1",
+        "@typescript-eslint/typescript-estree": "8.19.1"
       },
       "engines": {
         "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2002,13 +2002,13 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "8.19.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.0.tgz",
-      "integrity": "sha512-mCFtBbFBJDCNCWUl5y6sZSCHXw1DEFEk3c/M3nRK2a4XUB8StGFtmcEMizdjKuBzB6e/smJAAWYug3VrdLMr1w==",
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz",
+      "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "@typescript-eslint/types": "8.19.0",
+        "@typescript-eslint/types": "8.19.1",
         "eslint-visitor-keys": "^4.2.0"
       },
       "engines": {
@@ -2457,9 +2457,9 @@
       "license": "BSD-3-Clause"
     },
     "node_modules/bullmq": {
-      "version": "5.34.6",
-      "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.6.tgz",
-      "integrity": "sha512-pRCYyO9RlkQWxdmKlrNnUthyFwurYXRYLVXD1YIx+nCCdhAOiHatD8FDHbsT/w2I31c0NWoMcfZiIGuipiF7Lg==",
+      "version": "5.34.7",
+      "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.7.tgz",
+      "integrity": "sha512-Z6nKi8skD9n5/ErddTngeeEd8dRvZCu8wgZqpeH9zK0DlyTxYKceTnkGab3FkA+U9mzlqa0z34ZKGMbn4GWdgQ==",
       "license": "MIT",
       "dependencies": {
         "cron-parser": "^4.9.0",
@@ -5992,14 +5992,14 @@
       }
     },
     "node_modules/prisma": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.1.0.tgz",
-      "integrity": "sha512-aFI3Yi+ApUxkwCJJwyQSwpyzUX7YX3ihzuHNHOyv4GJg3X5tQsmRaJEnZ+ZyfHpMtnyahhmXVfbTZ+lS8ZtfKw==",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.2.0.tgz",
+      "integrity": "sha512-3bnAPqtWXbyA9QEKYEstPcsQMxoQ97rjC0E1OZ+QVKuNNpzRDdIgdCpTVpHvqj/9UaWpqaEiENYqS2At8DtESA==",
       "devOptional": true,
       "hasInstallScript": true,
       "license": "Apache-2.0",
       "dependencies": {
-        "@prisma/engines": "6.1.0"
+        "@prisma/engines": "6.2.0"
       },
       "bin": {
         "prisma": "build/index.js"
@@ -7090,16 +7090,16 @@
       }
     },
     "node_modules/ts-api-utils": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
-      "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz",
+      "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==",
       "dev": true,
       "license": "MIT",
       "engines": {
-        "node": ">=16"
+        "node": ">=18.12"
       },
       "peerDependencies": {
-        "typescript": ">=4.2.0"
+        "typescript": ">=4.8.4"
       }
     },
     "node_modules/ts-morph": {
diff --git a/src/controllers/assets.ts b/src/controllers/assets.ts
index e2ec4ac..e46332b 100644
--- a/src/controllers/assets.ts
+++ b/src/controllers/assets.ts
@@ -2,57 +2,10 @@ import { Request, Response } from 'express'
 
 import { BaseController } from '#application/base/baseController'
 import { AssetData, UUID } from '#application/types'
-import MapRepository from '#repositories/mapRepository'
 import SpriteRepository from '#repositories/spriteRepository'
-import TileRepository from '#repositories/tileRepository'
 
 export class AssetsController extends BaseController {
-  private readonly mapRepository = new MapRepository()
   private readonly spriteRepository = new SpriteRepository()
-  private readonly tileRepository = new TileRepository()
-
-  /**
-   * List tiles
-   * @param req
-   * @param res
-   */
-  public async listTiles(req: Request, res: Response) {
-    const assets: AssetData[] = []
-    const tiles = await this.tileRepository.getAll()
-
-    for (const tile of tiles) {
-      assets.push({ key: tile.getId(), data: '/textures/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
-    }
-
-    return this.sendSuccess(res, assets)
-  }
-
-  /**
-   * List tiles by map
-   * @param req
-   * @param res
-   */
-  public async listTilesByMap(req: Request, res: Response) {
-    const mapId = req.params.mapId as UUID
-
-    if (!mapId) {
-      return this.sendError(res, 'Invalid map ID', 400)
-    }
-
-    const map = await this.mapRepository.getById(mapId)
-    if (!map) {
-      return this.sendError(res, 'Map not found', 404)
-    }
-
-    const assets: AssetData[] = []
-    const tiles = await this.tileRepository.getByMapId(mapId)
-
-    for (const tile of tiles) {
-      assets.push({ key: tile.getId(), data: '/textures/tiles/' + tile.getId() + '.png', group: 'tiles', updatedAt: tile.getUpdatedAt() } as AssetData)
-    }
-
-    return this.sendSuccess(res, assets)
-  }
 
   /**
    * List sprite actions
diff --git a/src/controllers/cache.ts b/src/controllers/cache.ts
index 3a9ced2..b12b0fc 100644
--- a/src/controllers/cache.ts
+++ b/src/controllers/cache.ts
@@ -5,8 +5,28 @@ import MapObjectRepository from '#repositories/mapObjectRepository'
 import MapRepository from '#repositories/mapRepository'
 import SpriteRepository from '#repositories/spriteRepository'
 import TileRepository from '#repositories/tileRepository'
+import CharacterHairRepository from '#repositories/characterHairRepository'
+import CharacterTypeRepository from '#repositories/characterTypeRepository'
 
 export class CacheController extends BaseController {
+  /**
+   * Serve a list of tiles and send as JSON
+   * @param req
+   * @param res
+   */
+  public async tiles(req: Request, res: Response) {
+    const items: any[] = []
+
+    const tileRepository = new TileRepository()
+    const tiles = await tileRepository.getAll()
+
+    for (const tile of tiles) {
+      items.push(await tile.cache())
+    }
+
+    return this.sendSuccess(res, items)
+  }
+
   /**
    * Serve a list of maps and send as JSON
    * @param req
@@ -42,4 +62,58 @@ export class CacheController extends BaseController {
 
     return this.sendSuccess(res, items)
   }
+
+  /**
+   * Serve a list of character hairs and send as JSON
+   * @param req
+   * @param res
+   */
+  public async characterHair(req: Request, res: Response) {
+    const items: any[] = []
+
+    const characterHairRepository = new CharacterHairRepository()
+    const characterHairs = await characterHairRepository.getAll()
+
+    for (const characterHair of characterHairs) {
+      items.push(await characterHair.cache())
+    }
+
+    return this.sendSuccess(res, items)
+  }
+
+  /**
+   * Serve a list of character types and send as JSON
+   * @param req
+   * @param res
+   */
+  public async characterTypes(req: Request, res: Response) {
+    const items: any[] = []
+
+    const characterTypeRepository = new CharacterTypeRepository()
+    const characterTypes = await characterTypeRepository.getAll()
+
+    for (const characterType of characterTypes) {
+      items.push(await characterType.cache())
+    }
+
+    return this.sendSuccess(res, items)
+  }
+
+  /**
+   * Serve a list of sprites and send as JSON
+   * @param req
+   * @param res
+   */
+  public async sprites(req: Request, res: Response) {
+    const items: any[] = []
+
+    const spriteRepository = new SpriteRepository()
+    const sprites = await spriteRepository.getAll()
+
+    for (const sprite of sprites) {
+      items.push(await sprite.cache())
+    }
+
+    return this.sendSuccess(res, items)
+  }
 }
diff --git a/src/entities/characterHair.ts b/src/entities/characterHair.ts
index e177819..1c85ce3 100644
--- a/src/entities/characterHair.ts
+++ b/src/entities/characterHair.ts
@@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
 import { BaseCharacterHair } from '#entities/base/characterHair'
 
 @Entity()
-export class CharacterHair extends BaseCharacterHair {}
+export class CharacterHair extends BaseCharacterHair {
+  public async cache() {
+    try {
+      return this
+    } catch (error) {
+      console.error(error)
+      return {}
+    }
+  }
+}
diff --git a/src/entities/characterType.ts b/src/entities/characterType.ts
index 0884ed1..cff76b9 100644
--- a/src/entities/characterType.ts
+++ b/src/entities/characterType.ts
@@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
 import { BaseCharacterType } from '#entities/base/characterType'
 
 @Entity()
-export class CharacterType extends BaseCharacterType {}
+export class CharacterType extends BaseCharacterType {
+  public async cache() {
+    try {
+      return this
+    } catch (error) {
+      console.error(error)
+      return {}
+    }
+  }
+}
diff --git a/src/entities/sprite.ts b/src/entities/sprite.ts
index 7b1ab3a..cbd4551 100644
--- a/src/entities/sprite.ts
+++ b/src/entities/sprite.ts
@@ -3,4 +3,33 @@ import { Entity } from '@mikro-orm/core'
 import { BaseSprite } from '#entities/base/sprite'
 
 @Entity()
-export class Sprite extends BaseSprite {}
+export class Sprite extends BaseSprite {
+  public async cache() {
+    await this.getSpriteActions().load()
+
+    try {
+      return {
+        id: this.getId(),
+        name: this.getName(),
+        createdAt: this.getCreatedAt(),
+        updatedAt: this.getUpdatedAt(),
+        spriteActions: this.getSpriteActions().map((spriteAction) => ({
+          id: spriteAction.getId(),
+          sprite: spriteAction.getSprite().getId(),
+          action: spriteAction.getAction(),
+          // sprites: spriteAction.getSprites(), // We dont want to send this to the client
+          originX: spriteAction.getOriginX(),
+          originY: spriteAction.getOriginY(),
+          isAnimated: spriteAction.getIsAnimated(),
+          isLooping: spriteAction.getIsLooping(),
+          frameWidth: spriteAction.getFrameWidth(),
+          frameHeight: spriteAction.getFrameHeight(),
+          frameRate: spriteAction.getFrameRate()
+        }))
+      }
+    } catch (error) {
+      console.error(error)
+      return {}
+    }
+  }
+}
diff --git a/src/entities/tile.ts b/src/entities/tile.ts
index 9330748..abe16e2 100644
--- a/src/entities/tile.ts
+++ b/src/entities/tile.ts
@@ -3,4 +3,13 @@ import { Entity } from '@mikro-orm/core'
 import { BaseTile } from '#entities/base/tile'
 
 @Entity()
-export class Tile extends BaseTile {}
+export class Tile extends BaseTile {
+  public async cache() {
+    try {
+      return this
+    } catch (error) {
+      console.error(error)
+      return {}
+    }
+  }
+}
diff --git a/src/events/character/charactersScreen/characterHairList.ts b/src/events/character/charactersScreen/characterHairList.ts
deleted file mode 100644
index c660367..0000000
--- a/src/events/character/charactersScreen/characterHairList.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { BaseEvent } from '#application/base/baseEvent'
-import { CharacterHair } from '#entities/characterHair'
-import CharacterHairRepository from '#repositories/characterHairRepository'
-
-interface IPayload {}
-
-export default class characterHairListEvent extends BaseEvent {
-  public listen(): void {
-    this.socket.on('character:hair:list', this.handleEvent.bind(this))
-  }
-
-  private async handleEvent(data: IPayload, callback: (response: CharacterHair[]) => void): Promise<void> {
-    try {
-      const characterHairRepository = new CharacterHairRepository()
-      const items: CharacterHair[] = await characterHairRepository.getAllSelectable(['sprite'])
-
-      return callback(items)
-    } catch (error) {
-      this.logger.error('character:hair:list error', error)
-      return callback([])
-    }
-  }
-}
diff --git a/src/events/character/connect.ts b/src/events/character/connect.ts
index bfb5dd0..6422a47 100644
--- a/src/events/character/connect.ts
+++ b/src/events/character/connect.ts
@@ -32,9 +32,6 @@ export default class CharacterConnectEvent extends BaseEvent {
         return
       }
 
-      // Populate character with characterType and characterHair
-      await this.characterRepository.getEntityManager().populate(character, ['characterType', 'characterHair'])
-
       // Set character id
       this.socket.characterId = character.id
 
diff --git a/src/events/character/list.ts b/src/events/character/list.ts
index 85ceb13..3c8226a 100644
--- a/src/events/character/list.ts
+++ b/src/events/character/list.ts
@@ -12,9 +12,6 @@ export default class CharacterListEvent extends BaseEvent {
       const characterRepository = new CharacterRepository()
       let characters: Character[] = await characterRepository.getByUserId(this.socket.userId!)
 
-      // Populate characters with characterType and characterHair
-      await characterRepository.getEntityManager().populate(characters, ['characterType', 'characterHair'])
-
       this.socket.emit('character:list', characters)
     } catch (error: any) {
       this.logger.error('character:list error', error.message)
diff --git a/src/managers/httpManager.ts b/src/managers/httpManager.ts
index ed50ba7..3d82af9 100644
--- a/src/managers/httpManager.ts
+++ b/src/managers/httpManager.ts
@@ -37,16 +37,18 @@ class HttpManager {
     app.get('/avatar/s/:characterTypeId/:characterHairId?', (req, res) => this.avatarController.getByParams(req, res))
 
     // Assets routes
-    app.get('/assets/list_tiles', (req, res) => this.assetsController.listTiles(req, res))
-    app.get('/assets/list_tiles/:mapId', (req, res) => this.assetsController.listTilesByMap(req, res))
     app.get('/assets/list_sprite_actions/:spriteId', (req, res) => this.assetsController.listSpriteActions(req, res))
 
     // Download texture file
     app.get('/textures/:type/:spriteId?/:file', (req, res) => this.texturesController.download(req, res))
 
     // Cache routes
+    app.get('/cache/tiles', (req, res) => this.cacheController.tiles(req, res))
     app.get('/cache/maps', (req, res) => this.cacheController.maps(req, res))
     app.get('/cache/map_objects', (req, res) => this.cacheController.mapObjects(req, res))
+    app.get('/cache/sprites', (req, res) => this.cacheController.sprites(req, res))
+    app.get('/cache/character_types', (req, res) => this.cacheController.characterTypes(req, res))
+    app.get('/cache/character_hair', (req, res) => this.cacheController.characterHair(req, res))
   }
 }
 
diff --git a/src/services/teleportService.ts b/src/services/teleportService.ts
index 1a64982..cf1b441 100644
--- a/src/services/teleportService.ts
+++ b/src/services/teleportService.ts
@@ -74,7 +74,7 @@ class TeleportService {
       // Notify clients
       io.in(options.targetMapId).emit('map:character:join', mapCharacter)
       socket.emit('map:character:teleport', {
-        map: map,
+        mapId: options.targetMapId,
         characters: targetMap.getCharactersInMap()
       })