Answers "which key is each skill actually on?" with screenshots and clicks, no
external service. For each cell of the bind grid it hovers, OCRs the tooltip
for the skill name, OCRs the icon's upper-right corner for the bound F-key, and
optionally saves the icon as a template with that corner blanked.
The corner is excluded from the saved template on purpose. D2R draws the hotkey
label there, so an icon captured with it only matches while the skill stays on
that key — rebind it and the template silently stops matching, looking like
template rot rather than a bind change. Same pixels, read separately as data.
Why it exists: on 2026-08-28 an Enigma put Teleport on F5, displacing
Conviction, while config still said conviction=f5 — every attack-aura cast
would have teleported the character mid-fight. F7 was Vengeance, not Holy Bolt;
F8 was Conviction, not Concentration. The startup preflight reported this
correctly and it was dismissed as a marginal template.
Two things learned building it, both encoded here:
- The tooltip renders ABOVE the hovered cell and moves with the row, so a fixed
ROI reads the game world. The first version returned "YEW Y" and "PET". The
band is now taken relative to the cell.
- Identification is a fuzzy match against a known-skill list rather than a
demand for clean OCR. Real reads included "XI BLESSED HAMMER" and "HOLY
SHIELD L", and one frame OCR'd Fist of the Heavens as "LNMEPULE" while the
full text still contained the name. Validated 7/7 offline against saved
frames.
It refuses to compare when it clearly could not read the grid (<3 skills or 0
bound keys) and exits 2. The first version scanned a closed grid, identified
nothing, and then reported all seven configured keys as unbound — presenting
its own blindness as findings.
Exits 1 on a real mismatch so it can gate a run. Menu entry:
python tools/testbed.py spellbook --assets
Co-Authored-By: Claude Opus 5 <[email protected]>