Files
florian.berthold 738605b6c0 Commit web/assets/maps/ WebPs so deploys are self-contained
121 MB across 66 dungeon-floor WebPs (~150 KB–6 MB each). Previously
gitignored on the assumption LFS would be needed; plain git handles this
fine and it removes the kg_fetch → kg_stitch dependency from the deploy
path. README and Ansible bring-up step updated.
2026-04-26 12:54:38 +02:00

138 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# mplus-routes
Mythic+ route planner for Ascension classic-vanilla dungeons. Static web app
targeted at `mplus.exil.es`. Uses **Keystone.guru** map tiles + enemy data,
courtesy of RaiderIO (verbal permission, see attribution below).
## Stack
- **Maps:** keystone.guru z=4 tile pyramid stitched to 6144×4096 WebP per
dungeon-floor (~150600 KB each).
- **Data:** keystone.guru `mapcontext/data/<slug>/<mapping_id>/split_floors.js`
— enemies (with positions, classification, NPC linkage), enemy packs
(polygon outlines), enemy patrols (polylines), map icons (skulls, doors,
comments, gateways), NPC names from companion `en_US.js`.
- **Frontend:** vanilla HTML/CSS/JS, single page, no build step. Pan/zoom
via CSS transform on the canvas stage; SVG overlay in image-pixel space.
- **Hosting:** static. ~120 MB of WebPs total, committed to the repo. Drop
behind nginx; no backend.
## Layout
```
mplus-routes/
├── data/
│ ├── kg_dungeons.json registry: tile_key, data_slug, mapping_id per dungeon
│ └── kg/ raw kg tiles + data (gitignored)
│ ├── _summary.json
│ └── <tile_key>/
│ ├── split_floors.js
│ ├── lang.js
│ └── floor<n>/z4/<x>_<y>.png
├── tools/
│ ├── kg_fetch.py fetch tiles + data files for every dungeon in the registry
│ ├── kg_resync_summary.py rebuild data/kg/_summary.json from disk (after partial fetches)
│ ├── kg_stitch.py assemble 16×16 tile grids → web/assets/maps/<key>[_floor<n>].webp
│ ├── kg_build_data.py combine into web/assets/dungeons.json
│ └── check_kg_alignment.py server-side alignment sanity check (PIL renders into /tmp/)
└── web/
├── index.html
├── style.css
├── app.js
└── assets/
├── dungeons.json
└── maps/ per-dungeon WebPs (~120 MB, committed)
```
## Build
```bash
python3 -m venv .venv
.venv/bin/pip install Pillow
.venv/bin/python tools/kg_fetch.py --workers 32 --zoom 4 # fetch tiles + data (~1.3 GB raw)
.venv/bin/python tools/kg_stitch.py --workers 4 # → web/assets/maps/*.webp (~120 MB)
.venv/bin/python tools/kg_build_data.py # → web/assets/dungeons.json
```
## Run locally
```bash
cd web && python3 -m http.server 8765 # → http://localhost:8765/
```
## Deployment
Ansible role + playbook for `mplus.exil.es` live in
`/home/sub/repos/sub-net/ansible/roles/mplus_routes` and
`playbooks/setup_mplus_routes.yml`. Targets `exiles01:/srv/www/mplus.exil.es/`
behind the public HAProxy SNI router. The wildcard `*.exil.es` cert covers
TLS automatically.
First-time bring-up:
1. Add `mplus.exil.es` A/AAAA records in NetBox (→ public HAProxy VIPs)
2. Push the Ansible commit, trigger `Ansible_DeployPublicHaproxy`
3. Run `playbooks/setup_mplus_routes.yml``web/assets/maps/` ships in the
repo, no pre-build step needed.
## Coverage
29 classic dungeons in the picker:
| Dungeon | Enemies | Packs | Map icons |
|---|---:|---:|---:|
| Ragefire Chasm | 139 | 9 | 1 |
| The Deadmines | 218 | 26 | 13 |
| Wailing Caverns | 261 | 18 | 8 |
| Shadowfang Keep | 140 | 6 | 5 |
| The Stockade | 94 | 21 | 5 |
| Blackfathom Deeps | 240 | 20 | 21 |
| Gnomeregan | 282 | 44 | 25 |
| Razorfen Kraul | 199 | 39 | 12 |
| Razorfen Downs | 219 | 53 | 12 |
| SM (4 wings) | 69+96+87+79 | 22+25+20+25 | 7+2+4+4 |
| Uldaman | 261 | 33 | 12 |
| Zul'Farrak | 302 | 40 | 6 |
| Maraudon | 548 | 107 | 4 |
| Blackrock Depths | 819 | 169 | 33 |
| Lower Blackrock Spire | 380 | 98 | 17 |
| Upper Blackrock Spire | 207 | 56 | 20 |
| Stratholme | 377 | 77 | 19 |
| Scholomance | 344 | 64 | 14 |
| Dire Maul (3 wings) | 229+300+241 | 58+44+48 | 7+7+10 |
| Naxxramas (40) | 574 | 92 | 2 |
| Molten Core | 241 | 39 | 1 |
| Blackwing Lair | 79 | 15 | 1 |
| Zul'Gurub | 0 | 0 | 0 |
| Sunken Temple | 0 | 0 | 0 |
ZG and Sunken Temple have map tiles but no enemy data — kg's mapping_id
search didn't find populated data for them at time of build. Picker still
lets you draw routes on the map manually.
## Attribution
Map tiles and enemy data derived from
[Keystone.guru](https://keystone.guru/) (RaiderIO, Inc.). Used with
permission from the maintainers for the Ascension community deployment at
`mplus.exil.es`. World of Warcraft trademarks belong to Blizzard
Entertainment; this site is not affiliated with Blizzard.
## Refresh data sources
Both kg's tiles and data update over time. To refresh:
- Re-run the wide mapping-id probe (`tools/` doesn't ship one — easiest is
to fetch the kg homepage and find current ids, or re-run a probe like the
one in `data/kg/_summary.json` headers note).
- Update `data/kg_dungeons.json` with new mapping_ids.
- Re-run `kg_fetch.py``kg_stitch.py``kg_build_data.py`.
## Known gaps
- 2/29 dungeons (Zul'Gurub, Sunken Temple) are present without enemy data.
- Multi-floor dungeons (LBRS 7, BWL 4, Naxx 6, etc.) have all floors mapped
individually; the floor tabs in the UI let you switch between them.
- No trash-pull authoring beyond kg's data — packs are inherited as-is. For
custom-routing ("skip this pack, take this one"), use the route+pull tools
in the toolbar.