master
Denis Ranneft 1 month ago
parent 59db6dc43d
commit 80a18a24f6

@ -1,6 +1,7 @@
--- ---
description: PixelLab MCP — генерация спрайтов для AutoHero, сохранение в репо и ключи манифеста description: PixelLab MCP — генерация спрайтов для AutoHero, сохранение в репо и ключи манифеста
globs: globs:
- frontend/assets/**
- frontend/public/assets/game/** - frontend/public/assets/game/**
- frontend/src/game/assets/** - frontend/src/game/assets/**
- docs/art-bible.md - docs/art-bible.md
@ -17,10 +18,10 @@ globs:
## Обязательное правило после генерации ## Обязательное правило после генерации
1. **Сразу после успешного `get_*` (статус completed)** сохранить изображение в репозиторий под стабильным именем, согласованным с будущим манифестом, например: 1. **Сразу после успешного `get_*` (статус completed)** сохранить изображение в репозиторий под стабильным именем, согласованным с манифестом:
- каталог: `frontend/public/assets/game/` (подпапки по желанию: `terrain/`, `props/`, `characters/`, …); - каталог: **`frontend/assets/`** с подпапками по типу: `tiles/` (тайлы `terrain.*.vN.png`), `prop/`, `building/`, `enemies/`, `characters/`;
- имя файла: совпадает с контент-ключом или префиксом ключа (`terrain.grass.v0.png`, `prop.tree.v1.png`, `enemy.wolf_forest.png`, …). - имя файла: совпадает с контент-ключом или префиксом ключа (`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`. 3. Для **асинхронных** задач: вызвать `create_*`, затем периодически `get_*` по `tile_id` / `object_id` / `character_id`, пока не `completed`.
## Маппинг задач на инструменты (кратко) ## Маппинг задач на инструменты (кратко)

@ -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). - 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). - 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 ## Character and animation

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

@ -1,201 +1,489 @@
{ {
"version": 3, "version": 7,
"note": "Terrain: v0v2 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.", "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": { "textures": {
"terrain.grass.v0": { "terrain.grass.v0": {
"file": "terrain.grass.v0.png", "file": "tiles/terrain.grass.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "5064b2f4-5f68-4f1b-b40d-a8c8fdef5ce8" "pixellabTileId": "5064b2f4-5f68-4f1b-b40d-a8c8fdef5ce8"
}, },
"terrain.grass.v1": { "terrain.grass.v1": {
"file": "terrain.grass.v1.png", "file": "tiles/terrain.grass.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "f75118bd-cde7-4c95-93a0-b8276d9d183d" "pixellabTileId": "f75118bd-cde7-4c95-93a0-b8276d9d183d"
}, },
"terrain.grass.v2": { "terrain.grass.v2": {
"file": "terrain.grass.v2.png", "file": "tiles/terrain.grass.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "a5bb5a50-ea80-4054-bb0c-39346baaa859" "pixellabTileId": "a5bb5a50-ea80-4054-bb0c-39346baaa859"
}, },
"terrain.dirt.v0": { "terrain.dirt.v0": {
"file": "terrain.dirt.v0.png", "file": "tiles/terrain.dirt.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "a57e5ce3-0726-4049-86cd-c3470d2c9fae" "pixellabTileId": "a57e5ce3-0726-4049-86cd-c3470d2c9fae"
}, },
"terrain.dirt.v1": { "terrain.dirt.v1": {
"file": "terrain.dirt.v1.png", "file": "tiles/terrain.dirt.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "f120f6d1-9c3e-47f5-abf7-c5f534dfc750" "pixellabTileId": "f120f6d1-9c3e-47f5-abf7-c5f534dfc750"
}, },
"terrain.dirt.v2": { "terrain.dirt.v2": {
"file": "terrain.dirt.v2.png", "file": "tiles/terrain.dirt.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "b0834e85-d4cd-438b-b7c1-e3dae12d5962" "pixellabTileId": "b0834e85-d4cd-438b-b7c1-e3dae12d5962"
}, },
"terrain.stone.v0": { "terrain.stone.v0": {
"file": "terrain.stone.v0.png", "file": "tiles/terrain.stone.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "25109007-dcd4-46e5-a84d-b12aac187065" "pixellabTileId": "25109007-dcd4-46e5-a84d-b12aac187065"
}, },
"terrain.stone.v1": { "terrain.stone.v1": {
"file": "terrain.stone.v1.png", "file": "tiles/terrain.stone.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "17227c21-758d-47d7-bfe5-052479d77c37" "pixellabTileId": "17227c21-758d-47d7-bfe5-052479d77c37"
}, },
"terrain.stone.v2": { "terrain.stone.v2": {
"file": "terrain.stone.v2.png", "file": "tiles/terrain.stone.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "7e89f9fc-d228-4004-a509-5a17e643fb6e" "pixellabTileId": "7e89f9fc-d228-4004-a509-5a17e643fb6e"
}, },
"terrain.road.v0": { "terrain.road.v0": {
"file": "terrain.road.v0.png", "file": "tiles/terrain.road.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "9e76129e-f158-4bc5-8f88-a1167b209aff" "pixellabTileId": "9e76129e-f158-4bc5-8f88-a1167b209aff"
}, },
"terrain.road.v1": { "terrain.road.v1": {
"file": "terrain.road.v1.png", "file": "tiles/terrain.road.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "6b210ee4-d15b-4929-9e63-afe66ff22d51" "pixellabTileId": "6b210ee4-d15b-4929-9e63-afe66ff22d51"
}, },
"terrain.road.v2": { "terrain.road.v2": {
"file": "terrain.road.v2.png", "file": "tiles/terrain.road.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "03ad957c-27a9-4fb9-88e0-cf826fa9117a" "pixellabTileId": "03ad957c-27a9-4fb9-88e0-cf826fa9117a"
}, },
"terrain.plaza.v0": { "terrain.plaza.v0": {
"file": "terrain.plaza.v0.png", "file": "tiles/terrain.plaza.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "fa2de588-874b-471b-9c5b-aab09405edc7" "pixellabTileId": "fa2de588-874b-471b-9c5b-aab09405edc7"
}, },
"terrain.plaza.v1": { "terrain.plaza.v1": {
"file": "terrain.plaza.v1.png", "file": "tiles/terrain.plaza.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "22dfbf77-d8df-4e73-a151-b427cc4ff117" "pixellabTileId": "22dfbf77-d8df-4e73-a151-b427cc4ff117"
}, },
"terrain.plaza.v2": { "terrain.plaza.v2": {
"file": "terrain.plaza.v2.png", "file": "tiles/terrain.plaza.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "87feb620-ef7c-442a-b632-e2a210963c98" "pixellabTileId": "87feb620-ef7c-442a-b632-e2a210963c98"
}, },
"terrain.forest_floor.v0": { "terrain.forest_floor.v0": {
"file": "terrain.forest_floor.v0.png", "file": "tiles/terrain.forest_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "bc70968a-023e-4599-a6f9-958e157a459d" "pixellabTileId": "bc70968a-023e-4599-a6f9-958e157a459d"
}, },
"terrain.forest_floor.v1": { "terrain.forest_floor.v1": {
"file": "terrain.forest_floor.v1.png", "file": "tiles/terrain.forest_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "0f50401c-2db4-49e3-bf80-469b4c88d368" "pixellabTileId": "0f50401c-2db4-49e3-bf80-469b4c88d368"
}, },
"terrain.forest_floor.v2": { "terrain.forest_floor.v2": {
"file": "terrain.forest_floor.v2.png", "file": "tiles/terrain.forest_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "845d159b-2bf8-453c-9b3e-7e124d288e76" "pixellabTileId": "845d159b-2bf8-453c-9b3e-7e124d288e76"
}, },
"terrain.ruins_floor.v0": { "terrain.ruins_floor.v0": {
"file": "terrain.ruins_floor.v0.png", "file": "tiles/terrain.ruins_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "fbadf88a-8f35-454b-a615-9de55ddd7ee7" "pixellabTileId": "fbadf88a-8f35-454b-a615-9de55ddd7ee7"
}, },
"terrain.ruins_floor.v1": { "terrain.ruins_floor.v1": {
"file": "terrain.ruins_floor.v1.png", "file": "tiles/terrain.ruins_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "60967293-75e4-4a9f-b7e0-2bc6fdfb4442" "pixellabTileId": "60967293-75e4-4a9f-b7e0-2bc6fdfb4442"
}, },
"terrain.ruins_floor.v2": { "terrain.ruins_floor.v2": {
"file": "terrain.ruins_floor.v2.png", "file": "tiles/terrain.ruins_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "22ef3ad0-77f5-42fb-bff3-35637956e936" "pixellabTileId": "22ef3ad0-77f5-42fb-bff3-35637956e936"
}, },
"terrain.canyon_floor.v0": { "terrain.canyon_floor.v0": {
"file": "terrain.canyon_floor.v0.png", "file": "tiles/terrain.canyon_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "ecb56a64-48c9-4036-ae84-a9e939515852" "pixellabTileId": "ecb56a64-48c9-4036-ae84-a9e939515852"
}, },
"terrain.canyon_floor.v1": { "terrain.canyon_floor.v1": {
"file": "terrain.canyon_floor.v1.png", "file": "tiles/terrain.canyon_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "9d62ae3f-b94d-4618-b4ae-4a383c402375" "pixellabTileId": "9d62ae3f-b94d-4618-b4ae-4a383c402375"
}, },
"terrain.canyon_floor.v2": { "terrain.canyon_floor.v2": {
"file": "terrain.canyon_floor.v2.png", "file": "tiles/terrain.canyon_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "43220b53-6a25-4f37-9e71-66292d1119f2" "pixellabTileId": "43220b53-6a25-4f37-9e71-66292d1119f2"
}, },
"terrain.swamp_floor.v0": { "terrain.swamp_floor.v0": {
"file": "terrain.swamp_floor.v0.png", "file": "tiles/terrain.swamp_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "5d570f8f-57f7-45f7-8017-f8df68358976" "pixellabTileId": "5d570f8f-57f7-45f7-8017-f8df68358976"
}, },
"terrain.swamp_floor.v1": { "terrain.swamp_floor.v1": {
"file": "terrain.swamp_floor.v1.png", "file": "tiles/terrain.swamp_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "53dda79c-ef06-427b-9d23-54f9a140c908" "pixellabTileId": "53dda79c-ef06-427b-9d23-54f9a140c908"
}, },
"terrain.swamp_floor.v2": { "terrain.swamp_floor.v2": {
"file": "terrain.swamp_floor.v2.png", "file": "tiles/terrain.swamp_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "07d07b99-caae-4999-a3ee-96e1640a0555" "pixellabTileId": "07d07b99-caae-4999-a3ee-96e1640a0555"
}, },
"terrain.volcanic_floor.v0": { "terrain.volcanic_floor.v0": {
"file": "terrain.volcanic_floor.v0.png", "file": "tiles/terrain.volcanic_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "2461e194-679e-4491-a3e0-dbb351ec8b16" "pixellabTileId": "2461e194-679e-4491-a3e0-dbb351ec8b16"
}, },
"terrain.volcanic_floor.v1": { "terrain.volcanic_floor.v1": {
"file": "terrain.volcanic_floor.v1.png", "file": "tiles/terrain.volcanic_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "6704b1e5-674f-4c36-a272-211275f2e664" "pixellabTileId": "6704b1e5-674f-4c36-a272-211275f2e664"
}, },
"terrain.volcanic_floor.v2": { "terrain.volcanic_floor.v2": {
"file": "terrain.volcanic_floor.v2.png", "file": "tiles/terrain.volcanic_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "c58a42db-55d8-4d7c-9b9e-792039c9a17d" "pixellabTileId": "c58a42db-55d8-4d7c-9b9e-792039c9a17d"
}, },
"terrain.astral_floor.v0": { "terrain.astral_floor.v0": {
"file": "terrain.astral_floor.v0.png", "file": "tiles/terrain.astral_floor.v0.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "40b81fe0-5c58-4605-a3cb-9ce8a81bbe79" "pixellabTileId": "40b81fe0-5c58-4605-a3cb-9ce8a81bbe79"
}, },
"terrain.astral_floor.v1": { "terrain.astral_floor.v1": {
"file": "terrain.astral_floor.v1.png", "file": "tiles/terrain.astral_floor.v1.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "39fa3752-acb2-4f0c-8f38-eeaeaefd8e67" "pixellabTileId": "39fa3752-acb2-4f0c-8f38-eeaeaefd8e67"
}, },
"terrain.astral_floor.v2": { "terrain.astral_floor.v2": {
"file": "terrain.astral_floor.v2.png", "file": "tiles/terrain.astral_floor.v2.png",
"kind": "isometric_tile", "kind": "isometric_tile",
"pixellabTileId": "e995a9ce-2dcc-41d1-999c-f4f693ed7f70" "pixellabTileId": "e995a9ce-2dcc-41d1-999c-f4f693ed7f70"
}, },
"prop.tree.v0": { "prop.tree.v0": {
"file": "prop.tree.v0.png", "file": "prop/prop.tree.v0.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "324d847e-5678-4b91-806f-4905ef69597f" "pixellabObjectId": "324d847e-5678-4b91-806f-4905ef69597f"
}, },
"prop.tree.v1": { "prop.tree.v1": {
"file": "prop.tree.v1.png", "file": "prop/prop.tree.v1.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "f5ebfddc-f518-4b0e-b6c9-2cc9b038569b" "pixellabObjectId": "f5ebfddc-f518-4b0e-b6c9-2cc9b038569b"
}, },
"prop.rock.v0": { "prop.rock.v0": {
"file": "prop.rock.v0.png", "file": "prop/prop.rock.v0.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "e63619b4-29ed-40f2-a1e3-4a0f4a4c0e6a" "pixellabObjectId": "e63619b4-29ed-40f2-a1e3-4a0f4a4c0e6a"
}, },
"prop.rock.v1": { "prop.rock.v1": {
"file": "prop.rock.v1.png", "file": "prop/prop.rock.v1.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "90992b8c-643f-4566-b433-3a9ac0bac01c" "pixellabObjectId": "90992b8c-643f-4566-b433-3a9ac0bac01c"
}, },
"prop.cart.v0": { "prop.cart.v0": {
"file": "prop.cart.v0.png", "file": "prop/prop.cart.v0.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "b31728f7-b7be-49a1-a043-09d17eac3622" "pixellabObjectId": "b31728f7-b7be-49a1-a043-09d17eac3622"
}, },
"prop.cart.v1": { "prop.cart.v1": {
"file": "prop.cart.v1.png", "file": "prop/prop.cart.v1.png",
"kind": "map_object", "kind": "map_object",
"pixellabObjectId": "92bca514-f054-4ba3-b98b-1feb4201c89c" "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"
} }
} }
} }

@ -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<string>('../../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<string, string> = {};
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<string, GameTextureManifestEntry>;
}
export async function fetchGameTextureManifest(url = '/assets/game/manifest.json'): Promise<GameTextureManifest> {
const res = await fetch(url);
if (!res.ok) throw new Error(`Game manifest fetch failed: ${res.status}`);
return res.json() as Promise<GameTextureManifest>;
}
Loading…
Cancel
Save