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.
The 4-floor upreza experiment placed bosses on Cata-redesign rooms which don't match Ascension's classic boss spawns. Going back to commit 58b3f74's single-floor approach: Real-ESRGAN-upscaled Atlas BLP (2048x2048) with 14 hand-pinned bosses.
The 'floors' schema added to dungeon_replacements stays in tools/kg_build_data.py — useful if a future high-quality classic-layout multi-floor map shows up.
Same multi-floor look as every other dungeon: 4 webps with floor tabs (The Reliquary / Chamber of Summoning / The Upper Study / Headmaster's Study).
Each of the 14 classic Scholo bosses hand-pinned to a specific room within its floor:
f1 (Reliquary): Blood Steward of Kirtonos
f2 (CoS): Kirtonos summon, Vectus, Marduk Blackpool
f3 (Upper Study): Jandice, Rattlegore, Polkelt, Krastinov, Malicia
f4 (Headmaster's): Illucia, Alexei, Ravenian, Ras, Gandling
Schema change: dungeon_replacements now supports a 'floors' array for multi-floor manual overrides, alongside the existing single-floor 'bosses'/'atlasloot_id' modes.
Real path forward for Scholomance after exhausting the upreza ecosystem (no classic-layout dungeon interior maps exist there because vanilla/TBC clients didn't ship dungeon interior maps — confirmed from WoWMapUprezClassic README + WoWMapUprezTBC contents).
Solution:
- Atlas-addon Scholomance.blp (512x512, classic single-room layout) upscaled to 2048x2048 with Real-ESRGAN x4plus. Numbers 1-14 are crisp and readable.
- New 'bosses' field in dungeon_replacements lets us hand-pin every enemy to a specific (x,y) on the new map. 14 classic Scholo bosses placed on their Atlas-numbered rooms.
- Single-floor dungeon (kg's 4-floor split is bypassed entirely).
The Atlas single-room override was too low-res and too lossy (no kg packs/patrols, only 14 hand-curated bosses). Better to keep kg's 4-floor layout and figure out per-floor edge cases as we go.
dungeon_replacements is left in place as a mechanism but with no entries; we'll use it only when we have a high-resolution alternative map.
kg only ships the post-Cataclysm Scholomance (4 floors split as you ascend the school) but Ascension uses the classic single-floor layout where every wing branches off the central rooms.
Fix: new dungeon_replacements section in ascension_overrides.json. When a tile_key is listed there, build_data skips kg entirely for that dungeon and synthesises a single-floor entry from a manually-supplied map (Atlas-addon Scholomance.blp upscaled to 2048x2048) and AtlasLoot's per-dungeon boss list.
Coords come from AtlasLoot's 0..100 percent space scaled to the new map's pixel space directly. Pin classification: dungeonskull → boss (cls=3), None+name-contains-Rare → rare elite (cls=5), other interactives → cls=2.
kg pinned Lorgus on floor 1 (entrance Pool of Ask'ar) but he actually spawns on floor 2 in Moonshrine Sanctum on Ascension. AtlasLoot's subzone tagging confirms this — Lorgus sits with Twilight Lord Kelris and Aku'mai, not the floor-1 lake bosses.
ascension_overrides.json now also supports relocating an enemy across floors (not just position-changing). build_data.py removes the enemy from its source floor and appends it to the target.
- atlasloot_extras: fit one transform per (kg_dungeon, floor_id) instead of mixing all kg bosses into one fit. Each AL extra is assigned to whichever floor's anchors it's nearest to (in AL coord space). Strat's Stonespine now correctly lands on floor 235 (Undead) instead of being hidden because the mixed-floor fit pushed it off.
- new data/ascension_overrides.json: per-name position/floor patches for places where Ascension diverges from retail. Seeded with Magistrate Barthilas → moved to the southern courtyard (3498, 3300 on Undead Side) per Ascension spawns.
- frontend renders extras only on their assigned floor; previously hard-coded to floor 0.
- new layer-toggle checkboxes (Enemies / Packs / Patrols / Icons) in the toolbar — flip patrols off if mob routes are noise for your route.
Clicking a Note (or any pin) in Route mode used to:
1. fire the canvas click handler → drop a waypoint at the note's spot
2. only THEN run the pin's own click/dblclick handlers
So a single click on a note added a stray waypoint, and a double-click added two and may not have reliably reached the dblclick handler. Edit-via-dblclick therefore felt broken.
Fix: every interactive pin (note, text label, route waypoint, pull marker) now stops 'click' propagation explicitly. Click and dblclick on a pin no longer affect the active tool. Drag detection bumped to a 3px threshold and now only persists history when the pin actually moved.
- new tools/atlasloot_extras.py: matches AL bosses to kg cls>=3 enemies by name, fits per-(dungeon,wing) affine x/y transform, applies to AL pinType=None entries to recover ~14 rare bosses kg's spawn-bound data model omits (Blind Hunter, Stonespine, Deathsworn Captain, Spirestone Butcher, Bannok Grimaxe, Jed Runewatcher, Tsu'zee, …) plus 140+ AtlasLoot interactives (postboxes, summon stones, levers)
- WING_FORCE map disambiguates multi-wing dungeons (BRS, Dire Maul, Scarlet Monastery) where the same AL coord transforms into multiple wings
- frontend renders rare extras as silver-blue skull pins, non-rare extras as muted squares; both have hover-tooltips with their AtlasLoot name
- start, graveyard, dot_yellow, gateway, door_locked icon types from kg now render with distinct shapes (were silently empty before)
- kg_build_data.py merges atlasloot_extras.json into each dungeon's 'extras' field
Note: Ascension always-spawns rare bosses (vs retail's RNG), so they're now reliably visible on the planner.
- exportJson now includes per-floor notes and texts arrays alongside route/pulls; bumps a version field for forward-compat
- new importJson: file picker, parses JSON, resolves dungeon by id against current build, replaces this dungeon's pins on every floor present in the file
- Import button next to Export in the toolbar
- Note tool (existing) now strictly hover-only: drops a yellow (i) pin, text appears in the instant tooltip on hover; no inline label
- new Text tool: drops the user-typed string as an always-visible map label, no icon — for naming pull groups, calling out hazards, etc.
- both tools support drag, right-click delete, double-click edit; share-URL hash carries them in 'n' (notes) and 't' (texts) keys
- replaced SVG <title> tooltips (which use the OS dwell-delay) with an instant custom tooltip rendered in #custom-tooltip
- note pins now also render their text inline next to the icon, so a route can be read at a glance without hovering each pin (truncated at 80 chars in the SVG; full text still in the tooltip)
- classification 5 (rare-elite) now renders with silver-blue skull pin and shows up in the boss list with a 'rare' tag (was falling through to default trash style)
- new Note tool: click map → enter text → drops yellow info pin; hover for tooltip, double-click to edit, drag to move, right-click to remove. Notes are included in the share-URL hash and history.
- Clear button now confirms before wiping the current floor's waypoints/pulls/notes
Replaces the upreza-derived 4K dungeon textures + AtlasLoot boss-coord
overlay (which had a consistent positional offset against texture skulls)
with keystone.guru's z=4 tile pyramid stitched to 6144x4096 WebP per floor.
kg's split_floors.js gives per-dungeon enemies, packs (polygons), patrols
(polylines), and map icons calibrated to those tiles, so overlays align
pixel-perfectly. 27/29 classic dungeons now have full enemy/pack data;
ZG + Sunken Temple have maps only.
Pipeline: tools/kg_fetch.py -> tools/kg_stitch.py -> tools/kg_build_data.py.