diff --git a/.cursor/rules/pixellab-sprite-pipeline.mdc b/.cursor/rules/pixellab-sprite-pipeline.mdc index 154dfa3..ac9ba6e 100644 --- a/.cursor/rules/pixellab-sprite-pipeline.mdc +++ b/.cursor/rules/pixellab-sprite-pipeline.mdc @@ -1,6 +1,7 @@ --- description: PixelLab MCP — генерация спрайтов для AutoHero, сохранение в репо и ключи манифеста globs: + - frontend/assets/** - frontend/public/assets/game/** - frontend/src/game/assets/** - docs/art-bible.md @@ -17,10 +18,10 @@ globs: ## Обязательное правило после генерации -1. **Сразу после успешного `get_*` (статус completed)** сохранить изображение в репозиторий под стабильным именем, согласованным с будущим манифестом, например: - - каталог: `frontend/public/assets/game/` (подпапки по желанию: `terrain/`, `props/`, `characters/`, …); +1. **Сразу после успешного `get_*` (статус completed)** сохранить изображение в репозиторий под стабильным именем, согласованным с манифестом: + - каталог: **`frontend/assets/`** с подпапками по типу: `tiles/` (тайлы `terrain.*.vN.png`), `prop/`, `building/`, `enemies/`, `characters/`; - имя файла: совпадает с контент-ключом или префиксом ключа (`terrain.grass.v0.png`, `prop.tree.v1.png`, `enemy.wolf_forest.png`, …). -2. **Если в проекте уже есть `manifest.json`** (или аналог для Pixi/atlas) — **добавить или обновить регион** для этого файла в том же PR/шаге. Не оставлять ассет только по временной ссылке MCP. +2. **`frontend/public/assets/game/manifest.json`** — поле `file` для каждой текстуры **относительно `frontend/assets/`** (например `tiles/terrain.grass.v0.png`). Обновить манифест в том же шаге. Не оставлять ассет только по временной ссылке MCP. 3. Для **асинхронных** задач: вызвать `create_*`, затем периодически `get_*` по `tile_id` / `object_id` / `character_id`, пока не `completed`. ## Маппинг задач на инструменты (кратко) diff --git a/docs/pixellab-mcp-schema.md b/docs/pixellab-mcp-schema.md index a1d16e1..119f13f 100644 --- a/docs/pixellab-mcp-schema.md +++ b/docs/pixellab-mcp-schema.md @@ -6,7 +6,7 @@ Reference date: aligned with [https://api.pixellab.ai/mcp/docs](https://api.pixe - Creation tools **return immediately** with IDs; generation runs in the background (order of minutes). - Poll with matching **`get_*`** tools until status is **completed** (or handle `processing` / `failed` per response). -- **Do not** treat remote URLs as durable storage for the repo: **download or decode base64 and write files under** `frontend/public/assets/game/` immediately. +- **Do not** treat remote URLs as durable storage for the repo: **download or decode base64 and write PNGs under** `frontend/assets/` (`tiles/`, `prop/`, `building/`, `enemies/`, `characters/`). Register each texture in `frontend/public/assets/game/manifest.json` (`file` paths are relative to `frontend/assets/`). ## Character and animation diff --git a/frontend/assets/building/building.house.v0.png b/frontend/assets/building/building.house.v0.png new file mode 100644 index 0000000..fa0a9f7 Binary files /dev/null and b/frontend/assets/building/building.house.v0.png differ diff --git a/frontend/assets/building/building.house.v1.png b/frontend/assets/building/building.house.v1.png new file mode 100644 index 0000000..382b16d Binary files /dev/null and b/frontend/assets/building/building.house.v1.png differ diff --git a/frontend/assets/characters/hero.meet_partner.png b/frontend/assets/characters/hero.meet_partner.png new file mode 100644 index 0000000..b117975 Binary files /dev/null and b/frontend/assets/characters/hero.meet_partner.png differ diff --git a/frontend/assets/characters/hero.player.png b/frontend/assets/characters/hero.player.png new file mode 100644 index 0000000..b117975 Binary files /dev/null and b/frontend/assets/characters/hero.player.png differ diff --git a/frontend/assets/characters/hero.player.v0.east.png b/frontend/assets/characters/hero.player.v0.east.png new file mode 100644 index 0000000..8fa24f9 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.east.png differ diff --git a/frontend/assets/characters/hero.player.v0.north-east.png b/frontend/assets/characters/hero.player.v0.north-east.png new file mode 100644 index 0000000..ee2f5c7 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.north-east.png differ diff --git a/frontend/assets/characters/hero.player.v0.north-west.png b/frontend/assets/characters/hero.player.v0.north-west.png new file mode 100644 index 0000000..e340869 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.north-west.png differ diff --git a/frontend/assets/characters/hero.player.v0.north.png b/frontend/assets/characters/hero.player.v0.north.png new file mode 100644 index 0000000..be0e197 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.north.png differ diff --git a/frontend/assets/characters/hero.player.v0.south-east.png b/frontend/assets/characters/hero.player.v0.south-east.png new file mode 100644 index 0000000..b99d080 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.south-east.png differ diff --git a/frontend/assets/characters/hero.player.v0.south-west.png b/frontend/assets/characters/hero.player.v0.south-west.png new file mode 100644 index 0000000..22b5070 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.south-west.png differ diff --git a/frontend/assets/characters/hero.player.v0.south.png b/frontend/assets/characters/hero.player.v0.south.png new file mode 100644 index 0000000..eb69a00 Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.south.png differ diff --git a/frontend/assets/characters/hero.player.v0.west.png b/frontend/assets/characters/hero.player.v0.west.png new file mode 100644 index 0000000..192f25e Binary files /dev/null and b/frontend/assets/characters/hero.player.v0.west.png differ diff --git a/frontend/assets/characters/hero.player.v1.east.png b/frontend/assets/characters/hero.player.v1.east.png new file mode 100644 index 0000000..3f1d2c1 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.east.png differ diff --git a/frontend/assets/characters/hero.player.v1.north-east.png b/frontend/assets/characters/hero.player.v1.north-east.png new file mode 100644 index 0000000..92315ef Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.north-east.png differ diff --git a/frontend/assets/characters/hero.player.v1.north-west.png b/frontend/assets/characters/hero.player.v1.north-west.png new file mode 100644 index 0000000..02e6270 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.north-west.png differ diff --git a/frontend/assets/characters/hero.player.v1.north.png b/frontend/assets/characters/hero.player.v1.north.png new file mode 100644 index 0000000..1c4a6f9 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.north.png differ diff --git a/frontend/assets/characters/hero.player.v1.south-east.png b/frontend/assets/characters/hero.player.v1.south-east.png new file mode 100644 index 0000000..89a6d4a Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.south-east.png differ diff --git a/frontend/assets/characters/hero.player.v1.south-west.png b/frontend/assets/characters/hero.player.v1.south-west.png new file mode 100644 index 0000000..01be5e5 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.south-west.png differ diff --git a/frontend/assets/characters/hero.player.v1.south.png b/frontend/assets/characters/hero.player.v1.south.png new file mode 100644 index 0000000..48b1c51 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.south.png differ diff --git a/frontend/assets/characters/hero.player.v1.west.png b/frontend/assets/characters/hero.player.v1.west.png new file mode 100644 index 0000000..d678520 Binary files /dev/null and b/frontend/assets/characters/hero.player.v1.west.png differ diff --git a/frontend/assets/characters/hero.player.v2.east.png b/frontend/assets/characters/hero.player.v2.east.png new file mode 100644 index 0000000..359f073 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.east.png differ diff --git a/frontend/assets/characters/hero.player.v2.north-east.png b/frontend/assets/characters/hero.player.v2.north-east.png new file mode 100644 index 0000000..a80440f Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.north-east.png differ diff --git a/frontend/assets/characters/hero.player.v2.north-west.png b/frontend/assets/characters/hero.player.v2.north-west.png new file mode 100644 index 0000000..32350c0 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.north-west.png differ diff --git a/frontend/assets/characters/hero.player.v2.north.png b/frontend/assets/characters/hero.player.v2.north.png new file mode 100644 index 0000000..bfbc7b6 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.north.png differ diff --git a/frontend/assets/characters/hero.player.v2.south-east.png b/frontend/assets/characters/hero.player.v2.south-east.png new file mode 100644 index 0000000..eecace8 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.south-east.png differ diff --git a/frontend/assets/characters/hero.player.v2.south-west.png b/frontend/assets/characters/hero.player.v2.south-west.png new file mode 100644 index 0000000..e756636 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.south-west.png differ diff --git a/frontend/assets/characters/hero.player.v2.south.png b/frontend/assets/characters/hero.player.v2.south.png new file mode 100644 index 0000000..b60d876 Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.south.png differ diff --git a/frontend/assets/characters/hero.player.v2.west.png b/frontend/assets/characters/hero.player.v2.west.png new file mode 100644 index 0000000..caab2fb Binary files /dev/null and b/frontend/assets/characters/hero.player.v2.west.png differ diff --git a/frontend/assets/characters/npc.armorer.png b/frontend/assets/characters/npc.armorer.png new file mode 100644 index 0000000..eae4ea1 Binary files /dev/null and b/frontend/assets/characters/npc.armorer.png differ diff --git a/frontend/assets/characters/npc.bounty_hunter.png b/frontend/assets/characters/npc.bounty_hunter.png new file mode 100644 index 0000000..ce84efb Binary files /dev/null and b/frontend/assets/characters/npc.bounty_hunter.png differ diff --git a/frontend/assets/characters/npc.elder.png b/frontend/assets/characters/npc.elder.png new file mode 100644 index 0000000..1626253 Binary files /dev/null and b/frontend/assets/characters/npc.elder.png differ diff --git a/frontend/assets/characters/npc.healer.png b/frontend/assets/characters/npc.healer.png new file mode 100644 index 0000000..e8fed10 Binary files /dev/null and b/frontend/assets/characters/npc.healer.png differ diff --git a/frontend/assets/characters/npc.jeweler.png b/frontend/assets/characters/npc.jeweler.png new file mode 100644 index 0000000..61c6a1f Binary files /dev/null and b/frontend/assets/characters/npc.jeweler.png differ diff --git a/frontend/assets/characters/npc.merchant.png b/frontend/assets/characters/npc.merchant.png new file mode 100644 index 0000000..7387bbd Binary files /dev/null and b/frontend/assets/characters/npc.merchant.png differ diff --git a/frontend/assets/characters/npc.quest_giver.png b/frontend/assets/characters/npc.quest_giver.png new file mode 100644 index 0000000..bd996be Binary files /dev/null and b/frontend/assets/characters/npc.quest_giver.png differ diff --git a/frontend/assets/characters/npc.weapon.png b/frontend/assets/characters/npc.weapon.png new file mode 100644 index 0000000..13e53eb Binary files /dev/null and b/frontend/assets/characters/npc.weapon.png differ diff --git a/frontend/assets/enemies/enemy.battle_lizard.png b/frontend/assets/enemies/enemy.battle_lizard.png new file mode 100644 index 0000000..31e75df Binary files /dev/null and b/frontend/assets/enemies/enemy.battle_lizard.png differ diff --git a/frontend/assets/enemies/enemy.boar.png b/frontend/assets/enemies/enemy.boar.png new file mode 100644 index 0000000..93695db Binary files /dev/null and b/frontend/assets/enemies/enemy.boar.png differ diff --git a/frontend/assets/enemies/enemy.fire_demon.png b/frontend/assets/enemies/enemy.fire_demon.png new file mode 100644 index 0000000..301848e Binary files /dev/null and b/frontend/assets/enemies/enemy.fire_demon.png differ diff --git a/frontend/assets/enemies/enemy.forest_warden.png b/frontend/assets/enemies/enemy.forest_warden.png new file mode 100644 index 0000000..df44243 Binary files /dev/null and b/frontend/assets/enemies/enemy.forest_warden.png differ diff --git a/frontend/assets/enemies/enemy.ice_guardian.png b/frontend/assets/enemies/enemy.ice_guardian.png new file mode 100644 index 0000000..7edc51b Binary files /dev/null and b/frontend/assets/enemies/enemy.ice_guardian.png differ diff --git a/frontend/assets/enemies/enemy.lightning_titan.png b/frontend/assets/enemies/enemy.lightning_titan.png new file mode 100644 index 0000000..f61c103 Binary files /dev/null and b/frontend/assets/enemies/enemy.lightning_titan.png differ diff --git a/frontend/assets/enemies/enemy.orc.png b/frontend/assets/enemies/enemy.orc.png new file mode 100644 index 0000000..bfd55c7 Binary files /dev/null and b/frontend/assets/enemies/enemy.orc.png differ diff --git a/frontend/assets/enemies/enemy.skeleton_archer.png b/frontend/assets/enemies/enemy.skeleton_archer.png new file mode 100644 index 0000000..4591bbe Binary files /dev/null and b/frontend/assets/enemies/enemy.skeleton_archer.png differ diff --git a/frontend/assets/enemies/enemy.skeleton_king.png b/frontend/assets/enemies/enemy.skeleton_king.png new file mode 100644 index 0000000..aae269a Binary files /dev/null and b/frontend/assets/enemies/enemy.skeleton_king.png differ diff --git a/frontend/assets/enemies/enemy.spider.png b/frontend/assets/enemies/enemy.spider.png new file mode 100644 index 0000000..8a638b1 Binary files /dev/null and b/frontend/assets/enemies/enemy.spider.png differ diff --git a/frontend/assets/enemies/enemy.water_element.png b/frontend/assets/enemies/enemy.water_element.png new file mode 100644 index 0000000..de5c6e3 Binary files /dev/null and b/frontend/assets/enemies/enemy.water_element.png differ diff --git a/frontend/assets/enemies/enemy.wolf.png b/frontend/assets/enemies/enemy.wolf.png new file mode 100644 index 0000000..21476d8 Binary files /dev/null and b/frontend/assets/enemies/enemy.wolf.png differ diff --git a/frontend/assets/enemies/enemy.zombie.png b/frontend/assets/enemies/enemy.zombie.png new file mode 100644 index 0000000..62d2ade Binary files /dev/null and b/frontend/assets/enemies/enemy.zombie.png differ diff --git a/frontend/assets/prop/prop.barrel.v0.png b/frontend/assets/prop/prop.barrel.v0.png new file mode 100644 index 0000000..b189070 Binary files /dev/null and b/frontend/assets/prop/prop.barrel.v0.png differ diff --git a/frontend/assets/prop/prop.barrel.v1.png b/frontend/assets/prop/prop.barrel.v1.png new file mode 100644 index 0000000..d96f596 Binary files /dev/null and b/frontend/assets/prop/prop.barrel.v1.png differ diff --git a/frontend/public/assets/game/prop.cart.v0.png b/frontend/assets/prop/prop.cart.v0.png similarity index 100% rename from frontend/public/assets/game/prop.cart.v0.png rename to frontend/assets/prop/prop.cart.v0.png diff --git a/frontend/public/assets/game/prop.cart.v1.png b/frontend/assets/prop/prop.cart.v1.png similarity index 100% rename from frontend/public/assets/game/prop.cart.v1.png rename to frontend/assets/prop/prop.cart.v1.png diff --git a/frontend/public/assets/game/prop.rock.v0.png b/frontend/assets/prop/prop.rock.v0.png similarity index 100% rename from frontend/public/assets/game/prop.rock.v0.png rename to frontend/assets/prop/prop.rock.v0.png diff --git a/frontend/public/assets/game/prop.rock.v1.png b/frontend/assets/prop/prop.rock.v1.png similarity index 100% rename from frontend/public/assets/game/prop.rock.v1.png rename to frontend/assets/prop/prop.rock.v1.png diff --git a/frontend/public/assets/game/prop.tree.v0.png b/frontend/assets/prop/prop.tree.v0.png similarity index 100% rename from frontend/public/assets/game/prop.tree.v0.png rename to frontend/assets/prop/prop.tree.v0.png diff --git a/frontend/public/assets/game/prop.tree.v1.png b/frontend/assets/prop/prop.tree.v1.png similarity index 100% rename from frontend/public/assets/game/prop.tree.v1.png rename to frontend/assets/prop/prop.tree.v1.png diff --git a/frontend/public/assets/game/terrain.astral_floor.v0.png b/frontend/assets/tiles/terrain.astral_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.astral_floor.v0.png rename to frontend/assets/tiles/terrain.astral_floor.v0.png diff --git a/frontend/public/assets/game/terrain.astral_floor.v1.png b/frontend/assets/tiles/terrain.astral_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.astral_floor.v1.png rename to frontend/assets/tiles/terrain.astral_floor.v1.png diff --git a/frontend/public/assets/game/terrain.astral_floor.v2.png b/frontend/assets/tiles/terrain.astral_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.astral_floor.v2.png rename to frontend/assets/tiles/terrain.astral_floor.v2.png diff --git a/frontend/public/assets/game/terrain.canyon_floor.v0.png b/frontend/assets/tiles/terrain.canyon_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.canyon_floor.v0.png rename to frontend/assets/tiles/terrain.canyon_floor.v0.png diff --git a/frontend/public/assets/game/terrain.canyon_floor.v1.png b/frontend/assets/tiles/terrain.canyon_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.canyon_floor.v1.png rename to frontend/assets/tiles/terrain.canyon_floor.v1.png diff --git a/frontend/public/assets/game/terrain.canyon_floor.v2.png b/frontend/assets/tiles/terrain.canyon_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.canyon_floor.v2.png rename to frontend/assets/tiles/terrain.canyon_floor.v2.png diff --git a/frontend/public/assets/game/terrain.dirt.v0.png b/frontend/assets/tiles/terrain.dirt.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.dirt.v0.png rename to frontend/assets/tiles/terrain.dirt.v0.png diff --git a/frontend/public/assets/game/terrain.dirt.v1.png b/frontend/assets/tiles/terrain.dirt.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.dirt.v1.png rename to frontend/assets/tiles/terrain.dirt.v1.png diff --git a/frontend/public/assets/game/terrain.dirt.v2.png b/frontend/assets/tiles/terrain.dirt.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.dirt.v2.png rename to frontend/assets/tiles/terrain.dirt.v2.png diff --git a/frontend/public/assets/game/terrain.forest_floor.v0.png b/frontend/assets/tiles/terrain.forest_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.forest_floor.v0.png rename to frontend/assets/tiles/terrain.forest_floor.v0.png diff --git a/frontend/public/assets/game/terrain.forest_floor.v1.png b/frontend/assets/tiles/terrain.forest_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.forest_floor.v1.png rename to frontend/assets/tiles/terrain.forest_floor.v1.png diff --git a/frontend/public/assets/game/terrain.forest_floor.v2.png b/frontend/assets/tiles/terrain.forest_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.forest_floor.v2.png rename to frontend/assets/tiles/terrain.forest_floor.v2.png diff --git a/frontend/public/assets/game/terrain.grass.v0.png b/frontend/assets/tiles/terrain.grass.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.grass.v0.png rename to frontend/assets/tiles/terrain.grass.v0.png diff --git a/frontend/public/assets/game/terrain.grass.v1.png b/frontend/assets/tiles/terrain.grass.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.grass.v1.png rename to frontend/assets/tiles/terrain.grass.v1.png diff --git a/frontend/public/assets/game/terrain.grass.v2.png b/frontend/assets/tiles/terrain.grass.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.grass.v2.png rename to frontend/assets/tiles/terrain.grass.v2.png diff --git a/frontend/public/assets/game/terrain.plaza.v0.png b/frontend/assets/tiles/terrain.plaza.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.plaza.v0.png rename to frontend/assets/tiles/terrain.plaza.v0.png diff --git a/frontend/public/assets/game/terrain.plaza.v1.png b/frontend/assets/tiles/terrain.plaza.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.plaza.v1.png rename to frontend/assets/tiles/terrain.plaza.v1.png diff --git a/frontend/public/assets/game/terrain.plaza.v2.png b/frontend/assets/tiles/terrain.plaza.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.plaza.v2.png rename to frontend/assets/tiles/terrain.plaza.v2.png diff --git a/frontend/public/assets/game/terrain.road.v0.png b/frontend/assets/tiles/terrain.road.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.road.v0.png rename to frontend/assets/tiles/terrain.road.v0.png diff --git a/frontend/public/assets/game/terrain.road.v1.png b/frontend/assets/tiles/terrain.road.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.road.v1.png rename to frontend/assets/tiles/terrain.road.v1.png diff --git a/frontend/public/assets/game/terrain.road.v2.png b/frontend/assets/tiles/terrain.road.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.road.v2.png rename to frontend/assets/tiles/terrain.road.v2.png diff --git a/frontend/public/assets/game/terrain.ruins_floor.v0.png b/frontend/assets/tiles/terrain.ruins_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.ruins_floor.v0.png rename to frontend/assets/tiles/terrain.ruins_floor.v0.png diff --git a/frontend/public/assets/game/terrain.ruins_floor.v1.png b/frontend/assets/tiles/terrain.ruins_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.ruins_floor.v1.png rename to frontend/assets/tiles/terrain.ruins_floor.v1.png diff --git a/frontend/public/assets/game/terrain.ruins_floor.v2.png b/frontend/assets/tiles/terrain.ruins_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.ruins_floor.v2.png rename to frontend/assets/tiles/terrain.ruins_floor.v2.png diff --git a/frontend/public/assets/game/terrain.stone.v0.png b/frontend/assets/tiles/terrain.stone.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.stone.v0.png rename to frontend/assets/tiles/terrain.stone.v0.png diff --git a/frontend/public/assets/game/terrain.stone.v1.png b/frontend/assets/tiles/terrain.stone.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.stone.v1.png rename to frontend/assets/tiles/terrain.stone.v1.png diff --git a/frontend/public/assets/game/terrain.stone.v2.png b/frontend/assets/tiles/terrain.stone.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.stone.v2.png rename to frontend/assets/tiles/terrain.stone.v2.png diff --git a/frontend/public/assets/game/terrain.swamp_floor.v0.png b/frontend/assets/tiles/terrain.swamp_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.swamp_floor.v0.png rename to frontend/assets/tiles/terrain.swamp_floor.v0.png diff --git a/frontend/public/assets/game/terrain.swamp_floor.v1.png b/frontend/assets/tiles/terrain.swamp_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.swamp_floor.v1.png rename to frontend/assets/tiles/terrain.swamp_floor.v1.png diff --git a/frontend/public/assets/game/terrain.swamp_floor.v2.png b/frontend/assets/tiles/terrain.swamp_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.swamp_floor.v2.png rename to frontend/assets/tiles/terrain.swamp_floor.v2.png diff --git a/frontend/public/assets/game/terrain.volcanic_floor.v0.png b/frontend/assets/tiles/terrain.volcanic_floor.v0.png similarity index 100% rename from frontend/public/assets/game/terrain.volcanic_floor.v0.png rename to frontend/assets/tiles/terrain.volcanic_floor.v0.png diff --git a/frontend/public/assets/game/terrain.volcanic_floor.v1.png b/frontend/assets/tiles/terrain.volcanic_floor.v1.png similarity index 100% rename from frontend/public/assets/game/terrain.volcanic_floor.v1.png rename to frontend/assets/tiles/terrain.volcanic_floor.v1.png diff --git a/frontend/public/assets/game/terrain.volcanic_floor.v2.png b/frontend/assets/tiles/terrain.volcanic_floor.v2.png similarity index 100% rename from frontend/public/assets/game/terrain.volcanic_floor.v2.png rename to frontend/assets/tiles/terrain.volcanic_floor.v2.png diff --git a/frontend/public/assets/game/manifest.json b/frontend/public/assets/game/manifest.json index 854c746..beb9f56 100644 --- a/frontend/public/assets/game/manifest.json +++ b/frontend/public/assets/game/manifest.json @@ -1,201 +1,489 @@ { - "version": 3, - "note": "Terrain: v0–v2 per key. Props: tree/rock/cart x2 where present. Pending (PixelLab quota): prop.barrel v0/v1, building.house v0/v1, enemy.* x13, hero.player, hero.meet_partner — regenerate in batches of ≤8 after topping up generations.", + "version": 7, + "assetsRoot": "frontend/assets", + "note": "file paths relative to frontend/assets. hero.player.v0 Sellsword, v1 Duelist, v2 Spellblade — 8 dirs each (PixelLab create_character). Legacy hero.player.png kept. NPC npc.* south-only.", "textures": { "terrain.grass.v0": { - "file": "terrain.grass.v0.png", + "file": "tiles/terrain.grass.v0.png", "kind": "isometric_tile", "pixellabTileId": "5064b2f4-5f68-4f1b-b40d-a8c8fdef5ce8" }, "terrain.grass.v1": { - "file": "terrain.grass.v1.png", + "file": "tiles/terrain.grass.v1.png", "kind": "isometric_tile", "pixellabTileId": "f75118bd-cde7-4c95-93a0-b8276d9d183d" }, "terrain.grass.v2": { - "file": "terrain.grass.v2.png", + "file": "tiles/terrain.grass.v2.png", "kind": "isometric_tile", "pixellabTileId": "a5bb5a50-ea80-4054-bb0c-39346baaa859" }, "terrain.dirt.v0": { - "file": "terrain.dirt.v0.png", + "file": "tiles/terrain.dirt.v0.png", "kind": "isometric_tile", "pixellabTileId": "a57e5ce3-0726-4049-86cd-c3470d2c9fae" }, "terrain.dirt.v1": { - "file": "terrain.dirt.v1.png", + "file": "tiles/terrain.dirt.v1.png", "kind": "isometric_tile", "pixellabTileId": "f120f6d1-9c3e-47f5-abf7-c5f534dfc750" }, "terrain.dirt.v2": { - "file": "terrain.dirt.v2.png", + "file": "tiles/terrain.dirt.v2.png", "kind": "isometric_tile", "pixellabTileId": "b0834e85-d4cd-438b-b7c1-e3dae12d5962" }, "terrain.stone.v0": { - "file": "terrain.stone.v0.png", + "file": "tiles/terrain.stone.v0.png", "kind": "isometric_tile", "pixellabTileId": "25109007-dcd4-46e5-a84d-b12aac187065" }, "terrain.stone.v1": { - "file": "terrain.stone.v1.png", + "file": "tiles/terrain.stone.v1.png", "kind": "isometric_tile", "pixellabTileId": "17227c21-758d-47d7-bfe5-052479d77c37" }, "terrain.stone.v2": { - "file": "terrain.stone.v2.png", + "file": "tiles/terrain.stone.v2.png", "kind": "isometric_tile", "pixellabTileId": "7e89f9fc-d228-4004-a509-5a17e643fb6e" }, "terrain.road.v0": { - "file": "terrain.road.v0.png", + "file": "tiles/terrain.road.v0.png", "kind": "isometric_tile", "pixellabTileId": "9e76129e-f158-4bc5-8f88-a1167b209aff" }, "terrain.road.v1": { - "file": "terrain.road.v1.png", + "file": "tiles/terrain.road.v1.png", "kind": "isometric_tile", "pixellabTileId": "6b210ee4-d15b-4929-9e63-afe66ff22d51" }, "terrain.road.v2": { - "file": "terrain.road.v2.png", + "file": "tiles/terrain.road.v2.png", "kind": "isometric_tile", "pixellabTileId": "03ad957c-27a9-4fb9-88e0-cf826fa9117a" }, "terrain.plaza.v0": { - "file": "terrain.plaza.v0.png", + "file": "tiles/terrain.plaza.v0.png", "kind": "isometric_tile", "pixellabTileId": "fa2de588-874b-471b-9c5b-aab09405edc7" }, "terrain.plaza.v1": { - "file": "terrain.plaza.v1.png", + "file": "tiles/terrain.plaza.v1.png", "kind": "isometric_tile", "pixellabTileId": "22dfbf77-d8df-4e73-a151-b427cc4ff117" }, "terrain.plaza.v2": { - "file": "terrain.plaza.v2.png", + "file": "tiles/terrain.plaza.v2.png", "kind": "isometric_tile", "pixellabTileId": "87feb620-ef7c-442a-b632-e2a210963c98" }, "terrain.forest_floor.v0": { - "file": "terrain.forest_floor.v0.png", + "file": "tiles/terrain.forest_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "bc70968a-023e-4599-a6f9-958e157a459d" }, "terrain.forest_floor.v1": { - "file": "terrain.forest_floor.v1.png", + "file": "tiles/terrain.forest_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "0f50401c-2db4-49e3-bf80-469b4c88d368" }, "terrain.forest_floor.v2": { - "file": "terrain.forest_floor.v2.png", + "file": "tiles/terrain.forest_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "845d159b-2bf8-453c-9b3e-7e124d288e76" }, "terrain.ruins_floor.v0": { - "file": "terrain.ruins_floor.v0.png", + "file": "tiles/terrain.ruins_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "fbadf88a-8f35-454b-a615-9de55ddd7ee7" }, "terrain.ruins_floor.v1": { - "file": "terrain.ruins_floor.v1.png", + "file": "tiles/terrain.ruins_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "60967293-75e4-4a9f-b7e0-2bc6fdfb4442" }, "terrain.ruins_floor.v2": { - "file": "terrain.ruins_floor.v2.png", + "file": "tiles/terrain.ruins_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "22ef3ad0-77f5-42fb-bff3-35637956e936" }, "terrain.canyon_floor.v0": { - "file": "terrain.canyon_floor.v0.png", + "file": "tiles/terrain.canyon_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "ecb56a64-48c9-4036-ae84-a9e939515852" }, "terrain.canyon_floor.v1": { - "file": "terrain.canyon_floor.v1.png", + "file": "tiles/terrain.canyon_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "9d62ae3f-b94d-4618-b4ae-4a383c402375" }, "terrain.canyon_floor.v2": { - "file": "terrain.canyon_floor.v2.png", + "file": "tiles/terrain.canyon_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "43220b53-6a25-4f37-9e71-66292d1119f2" }, "terrain.swamp_floor.v0": { - "file": "terrain.swamp_floor.v0.png", + "file": "tiles/terrain.swamp_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "5d570f8f-57f7-45f7-8017-f8df68358976" }, "terrain.swamp_floor.v1": { - "file": "terrain.swamp_floor.v1.png", + "file": "tiles/terrain.swamp_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "53dda79c-ef06-427b-9d23-54f9a140c908" }, "terrain.swamp_floor.v2": { - "file": "terrain.swamp_floor.v2.png", + "file": "tiles/terrain.swamp_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "07d07b99-caae-4999-a3ee-96e1640a0555" }, "terrain.volcanic_floor.v0": { - "file": "terrain.volcanic_floor.v0.png", + "file": "tiles/terrain.volcanic_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "2461e194-679e-4491-a3e0-dbb351ec8b16" }, "terrain.volcanic_floor.v1": { - "file": "terrain.volcanic_floor.v1.png", + "file": "tiles/terrain.volcanic_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "6704b1e5-674f-4c36-a272-211275f2e664" }, "terrain.volcanic_floor.v2": { - "file": "terrain.volcanic_floor.v2.png", + "file": "tiles/terrain.volcanic_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "c58a42db-55d8-4d7c-9b9e-792039c9a17d" }, "terrain.astral_floor.v0": { - "file": "terrain.astral_floor.v0.png", + "file": "tiles/terrain.astral_floor.v0.png", "kind": "isometric_tile", "pixellabTileId": "40b81fe0-5c58-4605-a3cb-9ce8a81bbe79" }, "terrain.astral_floor.v1": { - "file": "terrain.astral_floor.v1.png", + "file": "tiles/terrain.astral_floor.v1.png", "kind": "isometric_tile", "pixellabTileId": "39fa3752-acb2-4f0c-8f38-eeaeaefd8e67" }, "terrain.astral_floor.v2": { - "file": "terrain.astral_floor.v2.png", + "file": "tiles/terrain.astral_floor.v2.png", "kind": "isometric_tile", "pixellabTileId": "e995a9ce-2dcc-41d1-999c-f4f693ed7f70" }, "prop.tree.v0": { - "file": "prop.tree.v0.png", + "file": "prop/prop.tree.v0.png", "kind": "map_object", "pixellabObjectId": "324d847e-5678-4b91-806f-4905ef69597f" }, "prop.tree.v1": { - "file": "prop.tree.v1.png", + "file": "prop/prop.tree.v1.png", "kind": "map_object", "pixellabObjectId": "f5ebfddc-f518-4b0e-b6c9-2cc9b038569b" }, "prop.rock.v0": { - "file": "prop.rock.v0.png", + "file": "prop/prop.rock.v0.png", "kind": "map_object", "pixellabObjectId": "e63619b4-29ed-40f2-a1e3-4a0f4a4c0e6a" }, "prop.rock.v1": { - "file": "prop.rock.v1.png", + "file": "prop/prop.rock.v1.png", "kind": "map_object", "pixellabObjectId": "90992b8c-643f-4566-b433-3a9ac0bac01c" }, "prop.cart.v0": { - "file": "prop.cart.v0.png", + "file": "prop/prop.cart.v0.png", "kind": "map_object", "pixellabObjectId": "b31728f7-b7be-49a1-a043-09d17eac3622" }, "prop.cart.v1": { - "file": "prop.cart.v1.png", + "file": "prop/prop.cart.v1.png", "kind": "map_object", "pixellabObjectId": "92bca514-f054-4ba3-b98b-1feb4201c89c" + }, + "prop.barrel.v0": { + "file": "prop/prop.barrel.v0.png", + "kind": "map_object", + "pixellabObjectId": "e834ff26-801c-4441-9c76-20d7985c209f" + }, + "prop.barrel.v1": { + "file": "prop/prop.barrel.v1.png", + "kind": "map_object", + "pixellabObjectId": "3aa0dcd6-0868-432f-b36e-5574e226b58c" + }, + "building.house.v0": { + "file": "building/building.house.v0.png", + "kind": "map_object", + "pixellabObjectId": "fd4f7648-a6c8-4114-9f72-fe187fd7631e" + }, + "building.house.v1": { + "file": "building/building.house.v1.png", + "kind": "map_object", + "pixellabObjectId": "84f736b6-12dd-4d94-93e5-d65dad6b2c42" + }, + "enemy.wolf": { + "file": "enemies/enemy.wolf.png", + "kind": "map_object", + "pixellabObjectId": "b0ba5cda-85b5-4b75-9244-bb0a098c1e16" + }, + "enemy.boar": { + "file": "enemies/enemy.boar.png", + "kind": "map_object", + "pixellabObjectId": "82a1bda9-f09d-4356-867c-cc8495632b70" + }, + "enemy.zombie": { + "file": "enemies/enemy.zombie.png", + "kind": "map_object", + "pixellabObjectId": "8af7f7ea-83be-450b-b830-2c3ca0e1474b" + }, + "enemy.spider": { + "file": "enemies/enemy.spider.png", + "kind": "map_object", + "pixellabObjectId": "5c28a3f7-951a-449a-bbb7-0fd73fc6ac84" + }, + "enemy.orc": { + "file": "enemies/enemy.orc.png", + "kind": "map_object", + "pixellabObjectId": "d6ab7c25-f03c-4c05-ba16-25d5d76fc9cd" + }, + "enemy.skeleton_archer": { + "file": "enemies/enemy.skeleton_archer.png", + "kind": "map_object", + "pixellabObjectId": "62eb4fa8-4782-407d-b4f2-e5d1120f01b5" + }, + "enemy.battle_lizard": { + "file": "enemies/enemy.battle_lizard.png", + "kind": "map_object", + "pixellabObjectId": "5fc9c9e9-cfe5-4ec8-a005-11bbe28c663e" + }, + "enemy.fire_demon": { + "file": "enemies/enemy.fire_demon.png", + "kind": "map_object", + "pixellabObjectId": "9078284d-fd78-4904-a593-6ee23c65c488" + }, + "enemy.ice_guardian": { + "file": "enemies/enemy.ice_guardian.png", + "kind": "map_object", + "pixellabObjectId": "8ca7b8b2-a417-4253-bb6e-20a6a489b8cc" + }, + "enemy.skeleton_king": { + "file": "enemies/enemy.skeleton_king.png", + "kind": "map_object", + "pixellabObjectId": "cee0910b-8f2c-44ef-a75a-a3b92e93b565" + }, + "enemy.water_element": { + "file": "enemies/enemy.water_element.png", + "kind": "map_object", + "pixellabObjectId": "953ab061-7521-4cf2-b7bd-9ba6bb5cc540" + }, + "enemy.forest_warden": { + "file": "enemies/enemy.forest_warden.png", + "kind": "map_object", + "pixellabObjectId": "62bee3a7-428c-413e-9e5c-75731830d769" + }, + "enemy.lightning_titan": { + "file": "enemies/enemy.lightning_titan.png", + "kind": "map_object", + "pixellabObjectId": "72db0b9e-c3ec-4e17-baa6-a08e30065ab2" + }, + "hero.player": { + "file": "characters/hero.player.png", + "kind": "map_object", + "pixellabObjectId": "ec888b01-9f9d-4b77-a51e-fa31af73a241" + }, + "hero.meet_partner": { + "file": "characters/hero.meet_partner.png", + "kind": "map_object", + "pixellabObjectId": "6c058a33-77bb-4c8e-9192-030c5aa9d305" + }, + "npc.merchant": { + "file": "characters/npc.merchant.png", + "kind": "character", + "pixellabCharacterId": "d3602dd1-3fff-4daf-9067-2ebd31adac2f", + "rotation": "south" + }, + "npc.armorer": { + "file": "characters/npc.armorer.png", + "kind": "character", + "pixellabCharacterId": "7b0eda69-d0b9-46a3-a922-d8f9d71059c4", + "rotation": "south" + }, + "npc.weapon": { + "file": "characters/npc.weapon.png", + "kind": "character", + "pixellabCharacterId": "10a2c896-7507-4df9-a9be-ea4c338e2f03", + "rotation": "south" + }, + "npc.jeweler": { + "file": "characters/npc.jeweler.png", + "kind": "character", + "pixellabCharacterId": "26cfd542-6eaa-4455-b6ab-433ee5996507", + "rotation": "south" + }, + "npc.healer": { + "file": "characters/npc.healer.png", + "kind": "character", + "pixellabCharacterId": "0671ca99-f93c-492b-8a6e-46e13f642747", + "rotation": "south" + }, + "npc.bounty_hunter": { + "file": "characters/npc.bounty_hunter.png", + "kind": "character", + "pixellabCharacterId": "de618a37-017f-4d88-a1d8-9eb08d7aa282", + "rotation": "south" + }, + "npc.elder": { + "file": "characters/npc.elder.png", + "kind": "character", + "pixellabCharacterId": "139bbbff-4299-4c39-9e39-94a817426dd9", + "rotation": "south" + }, + "npc.quest_giver": { + "file": "characters/npc.quest_giver.png", + "kind": "character", + "pixellabCharacterId": "f6877fb7-1ee6-4ed5-bd3c-23446bedaf63", + "rotation": "south" + }, + "hero.player.v0.south": { + "file": "characters/hero.player.v0.south.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "south" + }, + "hero.player.v0.east": { + "file": "characters/hero.player.v0.east.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "east" + }, + "hero.player.v0.north": { + "file": "characters/hero.player.v0.north.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "north" + }, + "hero.player.v0.west": { + "file": "characters/hero.player.v0.west.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "west" + }, + "hero.player.v0.south-east": { + "file": "characters/hero.player.v0.south-east.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "south-east" + }, + "hero.player.v0.north-east": { + "file": "characters/hero.player.v0.north-east.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "north-east" + }, + "hero.player.v0.north-west": { + "file": "characters/hero.player.v0.north-west.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "north-west" + }, + "hero.player.v0.south-west": { + "file": "characters/hero.player.v0.south-west.png", + "kind": "character", + "pixellabCharacterId": "73fc6cae-e61b-4d86-88b2-ed774fe6efff", + "rotation": "south-west" + }, + "hero.player.v1.south": { + "file": "characters/hero.player.v1.south.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "south" + }, + "hero.player.v1.east": { + "file": "characters/hero.player.v1.east.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "east" + }, + "hero.player.v1.north": { + "file": "characters/hero.player.v1.north.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "north" + }, + "hero.player.v1.west": { + "file": "characters/hero.player.v1.west.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "west" + }, + "hero.player.v1.south-east": { + "file": "characters/hero.player.v1.south-east.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "south-east" + }, + "hero.player.v1.north-east": { + "file": "characters/hero.player.v1.north-east.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "north-east" + }, + "hero.player.v1.north-west": { + "file": "characters/hero.player.v1.north-west.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "north-west" + }, + "hero.player.v1.south-west": { + "file": "characters/hero.player.v1.south-west.png", + "kind": "character", + "pixellabCharacterId": "4bb0ba6b-4f4e-4765-8631-9865eff7bd72", + "rotation": "south-west" + }, + "hero.player.v2.south": { + "file": "characters/hero.player.v2.south.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "south" + }, + "hero.player.v2.east": { + "file": "characters/hero.player.v2.east.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "east" + }, + "hero.player.v2.north": { + "file": "characters/hero.player.v2.north.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "north" + }, + "hero.player.v2.west": { + "file": "characters/hero.player.v2.west.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "west" + }, + "hero.player.v2.south-east": { + "file": "characters/hero.player.v2.south-east.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "south-east" + }, + "hero.player.v2.north-east": { + "file": "characters/hero.player.v2.north-east.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "north-east" + }, + "hero.player.v2.north-west": { + "file": "characters/hero.player.v2.north-west.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "north-west" + }, + "hero.player.v2.south-west": { + "file": "characters/hero.player.v2.south-west.png", + "kind": "character", + "pixellabCharacterId": "091ce71e-d1e2-4aa6-91dd-e37a033bfd14", + "rotation": "south-west" } } } diff --git a/frontend/src/game/assets/resolveGameAssetUrl.ts b/frontend/src/game/assets/resolveGameAssetUrl.ts new file mode 100644 index 0000000..177f4f3 --- /dev/null +++ b/frontend/src/game/assets/resolveGameAssetUrl.ts @@ -0,0 +1,59 @@ +/** + * Maps manifest `file` paths (relative to `frontend/assets/`) to Vite-resolved URLs. + * Keep in sync with [public/assets/game/manifest.json](../../../../public/assets/game/manifest.json). + */ + +const raw = import.meta.glob('../../assets/**/*.png', { eager: true, as: 'url' }); + +function toManifestRelativePath(globModulePath: string): string { + const n = globModulePath.replace(/\\/g, '/'); + const marker = '/assets/'; + const i = n.indexOf(marker); + if (i === -1) { + const parts = n.split('/'); + const ai = parts.lastIndexOf('assets'); + if (ai === -1) return n; + return parts.slice(ai + 1).join('/'); + } + return n.slice(i + marker.length); +} + +const urlByManifestFile: Record = {}; +for (const [modPath, url] of Object.entries(raw)) { + urlByManifestFile[toManifestRelativePath(modPath)] = url; +} + +export function resolveGameAssetFile(manifestFile: string): string { + const url = urlByManifestFile[manifestFile]; + if (!url) { + throw new Error(`Game asset not found in bundle: ${manifestFile}`); + } + return url; +} + +export function tryResolveGameAssetFile(manifestFile: string): string | undefined { + return urlByManifestFile[manifestFile]; +} + +export interface GameTextureManifestEntry { + file: string; + kind: string; + pixellabTileId?: string; + pixellabObjectId?: string; + pixellabCharacterId?: string; + /** When only one rotation is exported to PNG (e.g. south). */ + rotation?: string; +} + +export interface GameTextureManifest { + version: number; + note?: string; + assetsRoot?: string; + textures: Record; +} + +export async function fetchGameTextureManifest(url = '/assets/game/manifest.json'): Promise { + const res = await fetch(url); + if (!res.ok) throw new Error(`Game manifest fetch failed: ${res.status}`); + return res.json() as Promise; +}