promotional bannermobile promotional banner

Shiny Hunter

A self-contained hunter bestiary and rare-pet tracking journal for World of Warcraft Retail.
Back to Files

v0.31.0

File nameShinyHunter-v0.31.0.zip
Uploader
NheozPlayNheozPlay
Uploaded
Aug 22, 2026
Downloads
75
Size
4.4 MB
Flavors
Retail
File ID
8708219
Type
R
Release
Supported game versions
  • 12.1.0

What's new

# Changelog

## [0.31.0] — 2026-08-22

### Some beasts were never being recorded at all

If you killed or tamed Rockhoof, or any other rare the game treats as a mount
or a carrier, **your journal never noticed**. The addon was reading the
creature's identity in a way that quietly discarded that whole group. Fixed —
and if you have already earned one of them, targeting it once now files it.

### Beasts called "Unknown Entity"

Four creatures in the journal had learned the wrong name — the placeholder the
game shows for a heartbeat before the real name arrives. It had been saved to
disk, so it stuck: **Gondria and Insha'tar were literally called "Unknown
Entity"** on their card and on their nameplate. The bad names are deleted when
you log in and the real ones are learned again.

### Your language, everywhere

The journal shipped with English names and only compared against those, so
searching or matching a beast by the name your client shows never worked.
Names your game teaches the addon are now used everywhere the English ones
were, including names it learned months ago.

### How often a beast comes back

Every one of the 633 beasts was researched individually, and **156 now carry an
appearance rate** on their card: appears frequently, infrequently, or very
rarely. The Field Guide explains what each one means in hours.

The other 477 say nothing, on purpose. A rate is shown only where several
independent player reports agree — where they contradict each other, or where
nobody has timed the beast, **an invented answer would look exactly like a real
one**, so there is none.

Underneath, each card also shows what *your own* hunts have measured: how long
ago you last earned that beast, and the shortest return you have actually seen.
Reported and measured are kept apart and never averaged — they can genuinely
disagree, because a spawn timer belongs to the shard rather than to you.

### Minimap marks pointed the wrong way

Every mark on the minimap was drawn a quarter turn out of place. A beast to
your north appeared to your side.

## [0.30.0] — 2026-08-13

### Know what you still need without clicking a thing

Map paws are colour coded now. **Crimson means the beast is still missing from
your journal. Turquoise means you already have it.** Open a zone map and what
is left of your hunt reads itself.

### Your paws stay visible

Shiny Hunter's markers were being drawn underneath other addons' icons and
could vanish entirely on a busy map. They hold their place now.

### 1,004 new spawn locations

191 beasts that only knew one place to look now carry their full set of known
spots. **626 of the 632 beasts in the journal can now tell you where to hunt
them.**

### No more walking to an empty patch of ground

The Kurken was sending hunters to the far side of Azuremyst Isle. It now points
at the cave it actually lives in, surveyed by a hunter standing on it. Two more
beasts that lived inside Blackrock Mountain were doing the same thing; they now
name their zone and stay quiet about the rest rather than send you somewhere
there is nothing.

Every other trail was checked against real hunters' sightings before shipping.

### Found something the journal has never heard of? `/shiny share`

New zones arrive faster than any database can follow, and the hunter standing
in front of an unknown beast is often the only record that exists. Shiny Hunter
has always quietly noted those encounters — what it was, its family, and
exactly where you stood. Now you can copy that out and pass it on, and it comes
back to everyone in a later update.

Nothing is sent anywhere. It hands you the text; where it goes is your call.

## [0.29.1] — 2026-08-13

### Added

- A dossier can now name the sub-area a beast lives in, not just the zone.
  The zone gets you to the right map; the sub-area tells you where to look
  once you are on it, and a beast that lives in one named cave is a different
  search from one that roams a whole zone. The Kurken is the first entry to
  carry one — **Bastión Semprepino** — recorded by the player standing there.

## [0.29.0] — 2026-08-13

### Changed

- **The journal is no longer built on Blizzard's rare flag.** That flag says
  how a creature spawns, not whether it is worth collecting. The Kurken has a
  proper name and a skin nothing else wears, and is flagged Normal — so the old
  rule left it out, along with every beast like it. A named beast with a pet
  family belongs in a hunter's journal whatever its spawn behaviour.

### Added

- 632 entries, up from 616. Sixteen named tameable beasts the rare flag had
  excluded, among them The Kurken, Gara, Gon and Maximus.

### Fixed

- The tameability test was wrong and was dropping real entries. It read the
  page's "Tameable (Family)" line, which is simply absent on many pages —
  including The Kurken's, a beast this player had just tamed. The tooltip
  states both facts every time, so the rule is now: a Beast, naming a pet
  family, classified Normal or Rare. **A hunter cannot tame an elite**, which
  is what separates Gara from Elegon and The Kurken from Magmadar. Re-running
  the earlier scans with the correct rule recovered fifteen entries.

## [0.28.0] — 2026-08-13

### Added

- **616 rares, and every one of them has a portrait.** The 39 that drew a paw
  silhouette now show the beast: the per-NPC page states the display id
  outright, including for the creatures the client-data export does not carry.
  The earlier conclusion that the data did not exist was wrong — it was in a
  place nobody had looked.
- Twelve rares the catalogue never knew about, including **Isla Serpenteante**,
  a Midnight zone no public catalogue covers. Midnight coverage goes from 12
  entries to 24.
- Each new entry cleared four checks before it was written: Beast, Rare, a pet
  family, and a place. **A pet family is what makes a beast tameable** — of 50
  rare beasts found, only 11 have one. The other 39 are beasts a hunter can
  only kill, and a list that does not make that distinction is not a hunter's
  list.

## [0.27.0] — 2026-08-13

### Notes

- The in-world beacon still does not appear for a hunt set from inside a city,
  and it cannot: the client provides no navigation frame there, so there is
  nothing to anchor a marker to. Two attempts to relax the conditions were made
  and both reverted — the limits were never what hid it. The route card carries
  the guidance in that situation, as it always has.

### Added

- A travel network of Shiny Hunter's own, so a hunt across the world can say
  "take the portal to X" instead of "open the map". No other addon is
  required and none is consulted.

  The client will not answer this: `GetNextWaypointForMap` routes quests and
  tracked content and returns nothing for a waypoint an addon places, verified
  by asking at every level of the map hierarchy from a city up to the world.

- `/shiny portal` records a portal, boat or zeppelin **by travelling it**.
  Run it where you board, take the journey, run it again on arrival. Both ends
  are then facts observed on your client rather than something remembered, the
  same standard the sighting log and the display-id harvest already hold.

  Links you record guide you immediately, and fill the gaps the import leaves.

- The network ships with **199 travel links across 86 maps**, imported from
  Mapzeroth under its MIT licence, with its copyright notice carried in the
  generated file. That licence exists precisely so its work can be reused this
  way, and the alternative — asking every player to walk through every portal
  with a slash command — is not a reasonable thing to ask of anyone.

  Faction-restricted links are filtered to your own side. Standing a Horde
  hunter in front of an Alliance portal is a worse failure than saying nothing.

  Quel'Thalas is not in that data, so Midnight zones still need recording.

## [0.26.0] — 2026-08-12

### Added

- Every rare but four now has a trail. Coverage finishes at 600 of 604 with
  4,218 verified points, up from 203 when the day started. The last 35 were
  filed under "unknown zone" because their zone name exists in two
  expansions — Shadowmoon Valley is a zone in Outland and a different one in
  Draenor — and the source names the expansion it means, so the two published
  facts settle it without a guess.

  Three remain unfiled on purpose. Crystal Fang and the two Karazhan rares
  answer with a list of dungeon floor maps, where choosing wrong really would
  move the point.

### Fixed

- Hunts across the world now show the journey. Blizzard does route a waypoint
  through portals and boats, but it does not have the answer the instant the
  point is set, and it changes as you travel. The route was asked for exactly
  twice — on setting the hunt and a quarter of a second later — so it always
  came back empty and nothing ever asked again. A hunt on another continent
  never showed a single step, even once the client knew the whole route. It is
  asked every tick now, while a hunt is active.

### Fixed

- `Blizzard_MapCanvas.lua:280: assertion failed` is gone, and map pin tooltips
  work for the first time. The canvas asserts if a pin declares `OnEnter` or
  `OnLeave`, because it wires those itself from `OnMouseEnter` and
  `OnMouseLeave` on the pin mixin — so ours were both breaking the first pin
  of each template and being silently replaced by handlers that did not exist.
  Named after reading the assertion, having guessed at it twice.
- The hunt no longer disappears when the client hands the tracking arrow to
  something else. Super-tracking has one slot, and accepting a quest takes it
  from the beast you chose. The addon read that as "the hunt is over" and hid
  the route card and the beacon together, while the waypoint was still sitting
  on your map — which is exactly what "no waypoint appears" looks like from
  the outside. It now checks whether the waypoint is still ours, and takes the
  arrow back if it is.
- Fifteen beasts were filed on a sub-area map instead of the zone their
  coordinates are measured against. Stonecrag Gorge is not a zone: it is a
  small inset drawn inside Nagrand, and fourteen Draenor rares were pinned
  there while their points belonged to Nagrand — so every hunt for them
  pointed at empty ground. Skittering Broodmother had the same problem inside
  The Maw.
- Twenty-one entries showed a wiki page title rather than a creature name:
  "Grizzlemaw (wolf)", "Ghostcrawler (mob)", "Bonepicker (Blasted Lands)".
  The parenthesis exists to keep two wiki articles apart and the game never
  shows it. They now carry the name the client uses, which also corrects two
  the game has since recapitalised and one it renamed outright.

### Changed

- Beasts that share a name with their own colour variants now say which one
  they are. Madexx is five separate NPCs in Uldum with five different display
  ids — five distinct skins, five things to collect, one name — and listed
  plainly they looked like the same row printed five times. It is the only
  name in all 604 that repeats, and no entry is duplicated.
- Sightings no longer file every boar under "pending research". The page mixed
  two unrelated things: rares the catalogue is missing, which someone should
  act on, and the hundreds of ordinary skins that no catalogue will ever hold.
  Calling both "pending" promised work that will never be done and buried the
  handful of entries that matter. Rares are now listed one by one as catalogue
  candidates; ordinary skins become a count of how much of the world you have
  surveyed.
- An uncatalogued beast now records where it was met, not only what it was. For
  a zone no public source has catalogued — The Coiled Isle shipped with
  Midnight and has none — this log is the only record that exists, and a name
  without a place can never become a journal entry.

### Fixed

- Tracking a beast from another zone no longer drops the world beacon at a
  random spot on screen. When the destination is not in view the client keeps
  positioning its navigation frame anyway, pinning it to the nearest screen
  edge so its own arrow can point off-screen — and the beacon followed it
  there, claiming a beast was standing in the middle of your minimap. The
  beacon now appears only when the client is projecting a real world position;
  until then the route card carries the guidance, as it already did at range.

### Added

- Exact spawn coordinates for 363 more rares. The catalogue had 203 of 604 with
  a trail and the rest with a zone at best — not because the data is
  unpublished, but because the builder read the wrong field: the per-NPC source
  moved its spawn data, and a lookup that finds nothing said nothing. Coverage
  goes from 203 to 566, with 3,912 verified points.

  Coordinates are attached only to a map this catalogue had already resolved
  for that creature, or to one derived from entries that know both ids and all
  agree. A beast is never placed on a map by assumption.

### Removed

- Fifteen localization strings nothing referenced any more, in all six
  languages, plus a stale placeholder file that was shipping in every package.
- The "mark as captured" button. An entry is earned by taming the beast or by
  defeating it, and the addon watches for both. A button that let you assert
  either one turned the collection into a claim: a full journal proved nothing,
  and the entries that *were* earned were worth less for it.

  Correcting a tame the addon missed does not need your word. Visiting a stable
  master reconciles your whole stable against the catalogue from client data,
  so a capture we failed to see is still recoverable — and still evidence.

## [0.25.1] — 2026-08-12

### Changed

- The addon list shows Shiny Hunter's own emblem instead of a stock bear
  portrait. The artwork already shipped; nothing referenced it.
- The model frame used to read a missing display id is now live but parked off
  screen and transparent. It was hidden, and a hidden model has nothing to
  draw, so the client had no reason to load the creature — and an unloaded
  model cannot say which display it is.
- Every outcome of that read is now reported once per creature. "Nothing
  happened" was the one answer that could not be acted on.

## [0.25.0] — 2026-08-11

### Changed

- Updated for client 12.1.0. The TOC interface number is now `120100`, read
  from the installed client rather than assumed.
- The minimap button carries the hunter paw instead of a stock bear portrait —
  the same mark that labels a hunt on the world map.

### Added

- Packaging now backs the whole working tree up first, to a folder outside the
  game directory. The development folder is also the folder the game loads, so
  installing the addon from CurseForge overwrites it and deletes everything
  that does not ship. A backup kept inside `Interface/AddOns` would die in the
  same event it exists to survive.

## [0.24.3] — 2026-08-11

Packaging only, same addon as 0.24.0. The pinned packager reads its tokens
from GITHUB_OAUTH and CF_API_KEY; the workflow was passing the newer names it
only accepts on its default branch, so both tokens arrived empty and both
uploads were skipped without a word while the run reported success.

## [0.24.2] — 2026-08-11

Packaging only, same addon as 0.24.0. The CurseForge upload token was missing,
and the packager skips that upload in silence when it has no token, so two
tagged releases reached GitHub and never reached CurseForge.

## [0.24.1] — 2026-08-10

Packaging only. 0.24.0 published to GitHub and skipped CurseForge without
failing, because the project id was read from a repository variable that
defaults to zero — and zero tells the packager not to upload. The id is in the
project URL, not a secret, so it now lives in the workflow where it cannot be
forgotten. Same addon as 0.24.0.

## [0.24.0] — 2026-08-10

First public release since 0.21.5. It gathers everything from 0.22.0 to
0.23.5 — the blocked-action fix, passive detection, the facts learned from
your own client — plus the clean-up below.

### Fixed

- Tracking a beast or recording a capture no longer rebuilds the map pins on a
  closed world map. That was wasted work, and it is where Blizzard's pin pool
  raised `Blizzard_MapCanvas.lua:280: assertion failed`. The map still refreshes
  the moment it opens.

### Changed

- Diagnostics are a per-session tool now, not a saved preference. One
  `/shiny debug` typed months ago used to turn the chat frame into a log at
  every login afterwards. Every session starts quiet; the command is one line
  away when something needs watching.

### Removed

- Three localization strings left behind by the secure targeting button this
  client refuses, in all six languages.

## [0.23.5] — 2026-08-10

### Fixed

- The language explanation in Options no longer runs underneath the new command
  list. It has its own column now, as wide as the buttons below it.

## [0.23.4] — 2026-08-10

### Fixed

- Selecting a unit whose identity this client hides no longer throws
  "attempt to perform string conversion on a secret string value". The guard
  now sits at the single place that reads a GUID, so a future caller cannot
  forget it.

### Added

- The Options tab lists every slash command with what it does, translated with
  the rest of the interface. It reads from the same strings `/shiny help`
  prints, so the panel and the command can never disagree.

## [0.23.3] — 2026-08-10

### Changed

- Start-up no longer greets you with thirteen diagnostic lines. Which modules
  woke up and how many records loaded is not news to a player. The lines are
  still recorded, so `/shiny debug dump` answers what happened during start-up
  — the one moment you could not have had diagnostics enabled in time to see.

## [0.23.2] — 2026-08-10

### Changed

- Diagnostics no longer repeat themselves in chat. A line is printed only when
  it says something new for its category, so opening the world map stops
  burying everything under dozens of identical map-refresh lines.
  `/shiny debug dump` is unaffected and still holds every repeat.

## [0.23.1] — 2026-08-10

### Changed

- The journal card's empty brass plate now carries the outcome — **Captured**
  in green, **Defeated** in red. It had been blank since the secure targeting
  button this client refuses was removed.
- Card text is centred in the space beside the portrait instead of hugging its
  left edge.
- The card shows the creature's name as your own client spells it, like the
  rest of the catalogue.

## [0.23.0] — 2026-08-10

### Added

- Shiny Hunter now learns from your own client. Meeting a rare whose portrait
  or name the shipped data is missing records what your client says: its
  display id, and its name in the language you play in. 39 of the 604
  catalogued rares had no portrait, six of them in Eversong Woods; they fill
  in as you meet them. A stabled pet reports its display id the same way.
  Learned facts live in your saved variables, and verified shipped data always
  wins over them.
- A rare's nameplate badge now carries its name, in its rarity colour and a
  larger font. Ordinary skins keep the single quiet word they had: a world
  where every boar shouts teaches you to stop reading the badge.

### Notes

- Catalogue names were checked with a Lua-aware parser: all 604 are sound. The
  entry reported as broken in 0.22.0 is `"Chowdar"`, whose name genuinely
  contains quotation marks. The earlier report was a fault in the checking
  script, not in the data.

## [0.22.0] — 2026-08-10

Every change since 0.21.5 was re-applied one at a time and confirmed in game.

### Fixed

- The client dialog offering to disable the addon is gone. Its cause was a
  single refused event registration, `COMBAT_LOG_EVENT_UNFILTERED`, which this
  client reserves for Blizzard's own interface. One refusal raises the dialog
  twice, which is what made it look like two separate faults.
- Passive detection works again: walking past a beast, or hovering it, records
  it. Detection no longer lives inside a cosmetic module, so turning interface
  features off cannot take the journal down with them.
- Restored the skin-quality badges above tameable beasts.
- Defeat detection now watches the target through `UNIT_HEALTH` and
  `UNIT_FLAGS`, filtered to the target by the client rather than in Lua.

### Added

- Diagnostics report a restricted action by name, and a refused event by event
  name. Blizzard's own messages give neither.
- `Events:RegisterUnitEvent`, so unit events are filtered by the client instead
  of firing for every nameplate and group member on screen.

### Known gaps

- 39 of 604 catalogue rares have no verified display id and show a generic
  paw instead of a portrait, including 6 in Eversong Woods. The published
  client-data export does not carry these creatures yet, and a display id is
  never guessed.

## [0.21.5] — 2026-08-10

### Changed
- Replaced the minimap and addon metadata icon with a native Hunter pet icon,
  giving Shiny Hunter a clearer beast-companion identity at small sizes.

## [0.21.4] — 2026-08-10

### Fixed
- Field-guide cards are now vertically chained from the lower summary upward,
  rather than positioned with independent fixed offsets. The third step cannot
  overlap the automatic-features panel at any UI scale.

## [0.21.3] — 2026-08-10

### Fixed
- The Field guide's automatic-features panel is now anchored to the journal's
  lower content edge and uses a compact height. It no longer overflows below
  the frame at higher UI scales.

## [0.21.2] — 2026-08-09

### Fixed
- Field-guide cards now use one aligned text column. Removed the duplicate
  floating step numerals that overlapped the first line of each explanation.

## [0.21.1] — 2026-08-09

### Changed
- The in-world hunt marker now uses a warm quest-style beacon with a layered
  glow, a gold search emblem and the selected beast's portrait at its centre.
  The hunter target name sits below the emblem; the native waypoint retains
  distance and route guidance without duplicated text.

## [0.21.0] — 2026-08-09

### Added
- New in-journal **Field guide** tab explains the three-step hunt loop,
  automatic tracking, collection evidence and independent stable snapshot.
- New **Options** tab lets players follow the game-client locale or choose
  English (US/UK), Spanish, German, French, Italian or Brazilian Portuguese
  for Shiny Hunter itself. The journal rebuilds immediately after a change.

### Changed
- Localization is now registered as locale packs and applied from the saved
  setting, instead of being permanently chosen only while the addon loads.

## [0.20.0] — 2026-08-09

### Added
- The main journal, tracking and rare-ledger interface is now localized for
  German (`deDE`), French (`frFR`), Italian (`itIT`) and Brazilian Portuguese
  (`ptBR`) clients. English remains the safe fallback; Spanish continues to
  cover both `esES` and `esMX`.
- Locale packs are layered over the existing English key set, so untranslated
  secondary/debug labels remain readable instead of becoming missing strings.

## [0.19.3] — 2026-08-09

### Fixed
- Nameplate processing now ignores Retail Midnight secret values instead of
  converting protected GUIDs, names or family labels to strings. This prevents
  repeated `NAME_PLATE_UNIT_ADDED` errors while units enter view.

## [0.19.2] — 2026-08-09

### Fixed
- The map provider no longer force-refreshes while Blizzard's world-map canvas
  is still initializing at login. It now lets the normal map lifecycle refresh
  pins, preventing the Retail `Blizzard_MapCanvas.lua:280` assertion.
- Active-pet reconciliation logs a tame only when it newly records the rare,
  so already captured pets no longer flood the chat log after login.

Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project uses semantic versioning; while below 1.0, the minor number marks
a roadmap phase.

## [0.19.1] — 2026-08-09

### Fixed
- The native map provider no longer calls Blizzard's pin-pool removal API for
  a Shiny Hunter template before that template has acquired its first pin.
  This prevents the Retail 12.0.7 `Blizzard_MapCanvas.lua:280` assertion at
  login while retaining normal map-pin refreshes afterwards.

## [0.19.0] — 2026-08-09

### Added
- A named rare now completes its journal entry when it is either captured or
  defeated. `PARTY_KILL` records kills directly from the Retail client without
  an external addon dependency.
- Capture and kill evidence are stored independently. Dossiers, sightings and
  map tooltips distinguish `Captured`, `Defeated` and `Captured and defeated`.

### Changed
- Global and territory progress now counts unique recorded rares instead of
  requiring all 604 to remain simultaneously inside the 205-slot stable.
- SavedVariables schema 10 adds the per-character `killedRares` set.

## [0.18.12] — 2026-08-09

### Fixed
- Active-pet reconciliation now falls back to an exact globally unique rare
  name plus matching localized family when Retail replaces the wild NPC id in
  the tamed pet GUID. This recovers Ha'kalawe on `/reload` while rejecting
  shared names and family mismatches.

### Added
- Verified display IDs and family tokens for all five Harandar tameable rares.
  Their list portraits and 3D dossiers now have models, and stable scans can
  identify them by an unambiguous display ID.

## [0.18.11] — 2026-08-09

### Fixed
- Native map-pin XML now binds `OnLoad`, `OnEnter`, `OnLeave` and `OnClick` to
  the pin mixins. Markers are no longer passive images.

### Added
- Hovering a rare skull shows its name, localized family, collection state and
  known search-point count.
- Left-click reveals or hides its coloured search area. Right-click starts or
  stops autonomous tracking from the nearest known point.

## [0.18.10] — 2026-08-09

### Fixed
- Search-area pins now tolerate Blizzard's pool calling `OnReleased` before a
  new pin's first `OnLoad`. The route line is created lazily when acquired and
  released only when it exists.
- This prevents `NAVIGATION_CHANGED` from aborting the map provider before its
  automatic rare skulls are created.

## [0.18.9] — 2026-08-09

### Fixed
- World-map skulls and search areas now use Retail's managed `MapCanvas` data
  provider and pin templates. The previous frames were attached directly to
  `ScrollContainer.Child`; live testing showed that layer behind the visible
  Harandar map, so correct coordinates still produced no visible marker.
- Native pins remain aligned during map zoom and panning. Clicking a skull
  still toggles its coloured search samples and route.
- The `Shiny Hunter` maker's mark is moved from the cartouche's upper seam to
  its measured vertical centre.

### Independence
- The provider uses only Blizzard map mixins and Shiny Hunter's generated
  catalogue. No map library or other addon is loaded or queried.

## [0.18.8] — 2026-08-09

### Changed
- Harandar's five tameable rares now carry their complete currently published
  coordinate samples instead of one representative point: Rhazul 3,
  Ha'kalawe 12, Queen Lashtongue 3, Stumpy 4 and Oro'ohna 4.
- Selecting any of their automatic red skulls can therefore reveal a coloured
  search area or patrol trace, and native tracking receives every known sample.

### Data quality
- The points come from targeted Wowhead NPC metadata and were cross-checked
  against the same five local RareScanner records. The repeated generic point
  `47.2, 50.0` was rejected because it is attached to unrelated Harandar NPCs
  and does not describe any one beast's route.

## [0.18.7] — 2026-08-09

### Fixed
- A successful tame is no longer missed when Retail publishes the replacement
  pet GUID after the first 0.8 seconds. Exact rare ownership is checked over a
  bounded six-second sequence after the relevant pet and cast events.
- Reloading or entering the world now reconciles an independently catalogued
  rare that is already the active pet. This lets a newly tamed Rhazul repair
  its progress immediately after `/reload`, without manual marking.

## [0.18.6] — 2026-08-09

### Fixed
- Harandar now exposes map markers for its five independently catalogued,
  tameable rares: Ha'kalawe, Oro'ohna, Queen Lashtongue, Rhazul and Stumpy.
  Three records were missing coordinates and the other two used older,
  less precise points.
- The generated runtime catalogue remains self-contained; the map overlay does
  not load or query RareScanner.

## [0.18.5] — 2026-08-09

### Fixed
- Dropdowns no longer use the unsupported Unicode `▼` character, which the
  client font rendered as an empty square. They now share a brass-tinted,
  downward-facing `bag-arrow` texture from Retail's native atlas.

## [0.18.4] — 2026-08-09

### Fixed
- The collection summary now names the scope of its capture counter. A regional
  filter reads, for example, `604 total · In Quel'Thalas: 0 / 12 captured`;
  the all-regions view explicitly labels the corresponding figure `Global`.
  This separates filtered results, catalogue size and regional progress.

## [0.18.3] — 2026-08-09

### Added
- The Sightings page now has a persistent field-alert selector: `Ledger only ·
  604` limits cards and sounds to exact NPCs in the independent rare ledger;
  `All rare & exotic` restores alerts for other notable tameable beasts too.
- The preference affects only interruptive alerts. Every valid sighting keeps
  being recorded in the journal regardless of the selected scope.

### Fixed
- The collection search box now preserves `SearchBoxTemplate`'s own text-change
  handler, so its placeholder disappears while typing. Entered text also uses
  the journal's high-contrast ivory instead of the dark inherited font.

### Saved variables
- Schema 9 adds the account-wide `settings.alertScope` preference. Existing
  profiles default to the quieter 604-entry ledger mode.

## [0.18.2] — 2026-08-09

### Fixed
- Named rares are no longer marked captured merely because `Tame Beast`
  reported a successful spell event. The addon now waits for the player's pet
  GUID to confirm that the exact NPC really became the active pet, and clears
  pending captures after interruption, failure or timeout.
- Catalogued rares now trigger their encounter card and nameplate marker even
  when the client has not yet populated `UnitCreatureFamily`; family and model
  information safely fall back to the independent rare ledger.
- `Track beast` now starts the complete automatic patrol at the closest known
  point and keeps its coloured map trail visible. The same control changes to
  `Stop tracking` while that exact NPC is active.
- Regional progress selection now uses an explicit set instead of relying on a
  truthiness expression whose all-regions result was only correct by accident.
- Resetting SavedVariables while the journal is open now refreshes the active
  page as well as its header counter, so stale capture states do not remain on
  screen.

## [0.18.1] — 2026-08-09

### Changed
- `Colección` now contains the complete 604-creature named-rare catalogue and
  a 3D field dossier; the duplicate `Raros` tab has been removed.
- The catalogue filters by continent/region and continues grouping rows by the
  localized zone. The journal counter now measures exact named-rare captures.
- Territory cards are interactive: selecting one opens the collection already
  filtered to that region.
- Sightings now retain catalogued rare encounters per character, show their
  last observed zone and time, and open the corresponding dossier. Unknown
  family members remain in a clearly separated research queue.

### Saved variables
- Schema 8 adds `seenRares[npcID]` with the last observation time, map and
  player coordinates. Migration is additive and preserves all previous data.

## [0.18.0] — 2026-08-09

### Added
- Added an independent runtime ledger of 604 named tameable rares, including
  560 creature models, 548 mapped zones and 212 route-capable records after
  merging the addon's previously verified coordinates.
- Added a `Raros` journal page with instant search, a zone menu, portraits,
  exact NPC ids and direct multi-colour trail selection on Blizzard's map.
- Added exact per-character named-rare capture state. Successful Tame Beast
  casts record the NPC; stable scans safely backfill only unique display ids.

### Changed
- Territory seals now measure the complete named-rare ledger instead of the
  original six rare appearances.
- Catalogued rare NPCs receive encounter alerts and are no longer logged as
  unknown sightings, even when the client classifies their vignette as elite
  or normal rather than `rare`.

### Data provenance
- No RareScanner record, route, coordinate, texture or code is shipped or read
  at runtime. The standalone catalogue is generated from public tameable-family
  pages and factual Blizzard client metadata documented in `docs/data-sources.md`.

## [0.16.0] — 2026-08-09

### Added
- Added `hunter-bestiary-shell.png`, a 1024×640 transparent field-journal
  shell with a reinforced hide spine, bone toggles, restrained brass corners
  and a small turquoise tracking seal.
- Added `hunter-sighting-alert.png`, a distinct 768×256 transparent trophy
  notice with a portrait socket, claw-close seat and integrated action recess.

### Changed
- Replaced the generic `ButtonFrameTemplate` main window with the custom hunter
  journal shell, including its own drag surface, close control, content inset
  and title channel. The window is now 1160×720 and the list narrows to 330 px
  so the decorative spine does not steal space from the creature exhibit.
- Journal tabs now use brass-edged leather plates with a turquoise active rune.
  Inner panels are translucent enough to reveal the authored hide beneath.
- Rebuilt the encounter alert around its own 456×152 trophy plaque. Portrait,
  text, close action and secure target action sit in authored positions; the
  old yellow stripe, generic border, stock close button and red rectangle are
  gone.

## [0.15.12] — 2026-08-09

### Changed
- The turquoise patrol indicator now snaps to the five actual brass route
  details authored into the tracker PNG instead of moving along an approximate
  linear range between them.
- The shared three-slice coordinate calculation is used by both the world route
  instrument and the bestiary tracking plaque, keeping their live indicators
  aligned even though each renders the leather centre at a different width.

## [0.15.11] — 2026-08-09

### Changed
- Migrated the tracker asset from TGA to `hunter-tracker.png` while preserving
  its 1024×256 RGBA pixels and verified alpha channel.
- New project rule: generated interface artwork ships as transparent RGBA PNG,
  with no opaque exterior canvas or black background baked into the asset.

## [0.15.10] — 2026-08-09

### Art
- Replaced the tracker texture's opaque black exterior with genuine alpha
  transparency. The leather writing surface remains opaque; only the canvas
  outside the brass and compass silhouette disappears over the game world.
- The final project asset is an uncompressed 1024×256 RGBA TGA. Its built-in
  background-extraction prompt and conversion provenance are recorded beside
  it in `Assets/UI/README.md`.

### Changed
- Removed the temporary UV margin crop because the transparent asset is now
  fitted directly to its authored silhouette and should use its full bounds.

## [0.15.9] — 2026-08-09

### Changed
- The world route instrument is now 420×104 instead of 540×135, with tighter
  copy, a smaller target title and a progress rail recalibrated to the compact
  silhouette.
- Tracker artwork now crops the narrow opaque safety margin from the shipped
  TGA in UV space. The visible widget ends at its brass frame instead of
  exposing a rectangular black strip around the sides and bottom.

## [0.15.8] — 2026-08-09

### Fixed
- The exact-points button now receives its initial visible label before its
  font region is styled. Retail can return `nil` from `GetFontString()` when a
  bare button still has an empty label; the old unconditional call could stop
  the journal at the same point despite using the correct Font object.
- Multiline Lua failures now repeat their meaningful first line after the stack
  trace, so the concrete error remains visible in short chat windows.

## [0.15.7] — 2026-08-09

### Fixed
- Finished replacing string font names with Retail Font objects. The main
  `Track beast` button was the next construction failure after the exact-points
  control, so the journal could still stop while opening from the minimap.
- Applied the same correction proactively to the sighting alert's combat
  blocker and target button.

## [0.15.6] — 2026-08-09

### Fixed
- Opening the journal from the minimap button no longer aborts immediately
  after constructing its model viewer. The exact-points control now gives
  Retail the actual `GameFontNormalSmall` object instead of its string name.
- Retail's internal `ToDebugString` inspection is no longer reported as a
  missing localization key.
- Lazy window construction now reports a useful stack trace if a later UI
  component fails, rather than silently rebuilding partial viewers on every
  minimap click.

### Changed
- Removed the routine `model viewer created` debug line; successful widget
  construction no longer clutters the diagnostic channel.

## [0.15.5] — 2026-08-09

### Changed
- The route notification is no longer a generic black card. It is now an
  original hunter field instrument built around a teal tracking compass,
  tooled wyvern leather, aged brass and a live route needle. The asset is
  rendered as a three-slice so its authored end pieces never stretch.
- The detail view gains the same visual language in a dedicated field-tracking
  plaque below the model. One prominent `Track beast` action starts or stops
  the full automatic patrol; live progress moves along its brass route rail.
- Exact coordinates are collapsed by default behind `Show exact points`. The
  primary view now shows only hunting ground, recorded-trace count and patrol
  state, keeping raw data available without letting it dominate the exhibit.

### Art
- Added `Assets/UI/hunter-tracker.tga`, an original project texture generated
  for Shiny Hunter and converted to an uncompressed WoW-friendly 1024x256 TGA.
  Its provenance and final prompt are recorded beside the asset.

## [0.15.4] — 2026-08-09

### Added
- Selecting one coordinate now starts an automatic hunt for the appearance,
  rather than tracking an isolated point. Spawn samples are grouped into real
  search zones and ordered by nearest neighbour to reduce backtracking.
- Reaching a search zone starts a three-second observation window. If the
  tracked beast is not detected, the Blizzard waypoint automatically advances
  to the next zone and loops through the patrol. Detecting the target stops the
  route after the encounter alert has been rendered.
- The detail panel distinguishes the active zone from the other locations
  already included in the automatic patrol, and the route card shows progress,
  total zones and live distance.

### Changed
- The projected world beam is now shown only during the final approach. A map
  coordinate has no terrain height, so at long range Blizzard can project its
  X/Y direction onto an intervening cliff. Shiny Hunter now uses the honest
  route card at range instead of making that wall look like the destination.

## [0.15.3] — 2026-08-09

### Fixed
- Search-area points no longer remain invisible when Blizzard's world-map
  addon finishes loading after the map's first `OnShow`. Every refresh now
  explicitly reveals its overlay, including when a coordinate is selected
  while the map is already open.
- Alternative spawn points and the translucent bridges between nearby points
  are larger and more opaque, so a many-coordinate patrol cannot be mistaken
  for the single native Blizzard waypoint.
- Debug output now reports how many search points were drawn and on which
  UiMapID.

## [0.15.2] — 2026-08-09

### Added
- Rare and exotic hunter beasts now raise an original Shiny Hunter encounter
  card when their nameplate enters view or they are targeted. It includes the
  live localized name, family, portrait, sound and secure target action; each
  spawned GUID alerts only once per session.
- The encounter card also works for uncatalogued candidates; verified entries
  such as Aotona and King Krush use their catalogued portrait.
  Sound is now owned by this single alert path, preventing tracked hunts from
  ringing twice.
- The active hunt paints every verified coordinate for that appearance on
  Blizzard's world map. Nearby points merge into a translucent magenta search
  area; the selected point is gold and every spot is click-to-track.
- `tools/audit_hunter_catalog.py` inventories the complete tameable-family
  candidate graph from Warcraft Wiki's CC BY-SA API. It can compare names with
  a local RareScanner installation without importing its protected records.
- Ten verified rare spirit beasts joined the shipped bestiary: Ankha,
  Ban'thalos, Bloodgullet, Bulvinkel, Ghostcrawler, Karoma, Lightning Paw,
  Magria, Myonix and Pashya. Aotona also joins as the first bird-of-prey entry.
  Their patrol samples bring the database to 17 appearances, 17 creatures and
  188 locations.

### Research
- RareScanner declares `All Rights Reserved`. Its pet table describes battle-
  pet drops, not hunter pets, and its rare NPC table does not identify
  tameability. No code, textures, coordinates or database records were copied.
- Warcraft Wiki currently exposes 63 tameable family categories and 5,542
  unique candidate pages. The local rare-name intersection yields 633 review
  candidates; 600 have an NPC ID independently confirmed by the wiki. They
  must be grouped by appearance and verified in batches before shipping.

## [0.15.1] — 2026-08-09

### Fixed
- Tracking a spawn on another continent no longer leaves an invisible active
  state. A compact route card remains on screen until Blizzard can project the
  next waypoint into the world.
- The route card reads `C_SuperTrack.GetNextWaypointForMap` and displays the
  next travel-step description supplied by the client. This lets Blizzard name
  a portal, boat or map transition without maintaining a duplicate route
  network inside Shiny Hunter.
- The world marker is now a single narrow beam, diamond and pet name. Duplicate
  distance and ETA labels were removed because they overlapped Blizzard's own
  waypoint text.

### Added
- When a nameplate or selected target matches the appearance currently being
  tracked, a native WoW warning sound plays once for that spawned creature.
  The alert respects `soundEnabled` and has an eight-second global cooldown.

### Verification
- Static checks pass. Cross-continent travel descriptions, the simplified
  world marker and the tracked-creature sound still require an in-game test.

## [0.15.0] — 2026-08-09

### Added
- Every verified coordinate in `Dónde encontrarla` is now a selectable link.
  Selecting it creates a Blizzard user waypoint and super-tracks that exact
  spawn point; selecting the active coordinate again clears the route.
- `Navigation/NativeWaypoint.lua`: a dependency-free in-world beacon anchored
  to Blizzard's projected navigation frame. It shows the appearance name,
  live distance and an estimated arrival time while the player approaches.
- Hover help and an explicit `[Seguir]` / `[Siguiendo]` state make each spawn
  point independently actionable, including creatures with many coordinates.

### Architecture
- Navigation uses only `C_Map`, `UiMapPoint`, `C_SuperTrack` and
  `C_Navigation`. No external addon is detected, loaded or called.
- The marker's distance sampling is throttled to 0.12 seconds and its
  `OnUpdate` exists only while the marker is visible.
- The obsolete optional dependency declaration and planned external provider
  were removed.

### Verification
- Static Lua parsing, localization coverage and data validation pass. The
  world-space projection, distance, route clearing and cross-zone behaviour
  require confirmation inside World of Warcraft.

## [0.14.3] — 2026-08-09

### Fixed
- Detail text is clipped inside a mouse-wheel scroll region between the model
  and the fixed action buttons. Long coordinate lists can no longer leave the
  panel or draw underneath its controls.
- The favourite marker now uses the client-shipped gold star texture instead
  of a font glyph that rendered as an empty square on the Spanish client.
- Every pet read from the player's stable is shown in full colour and labelled
  as owned. A missing collection record is addon data debt, not an unknown pet.

### Changed
- The visible collection name is now **Hunter's Bestiary** / **Bestiario del
  cazador**. The earlier inspiration name has been removed from source and
  documentation.

## [0.14.2] — 2026-08-09

### Added
- A hunter bestiary presentation for the collection: stable catalogue numbers,
  real creature portraits sourced from each verified display ID, family and
  expansion on every card, and a larger exhibit-style detail view.
- Missing appearances are desaturated in both the list and 3D preview; collected
  appearances regain full colour. The state remains readable through text and
  does not rely on colour alone.
- A compact visual progress bar beside the existing collection counter.

### Changed
- The main window is wider and uses layered ink, leather-brown and gold panels
  instead of a single flat black inset.
- Tabs, filters, action buttons, list headers and selection states now share one
  client-native theme in `UI/Theme.lua`.
- Stable pets use their own display IDs for portraits. Uncatalogued stable pets
  are shown desaturated rather than with a generic family icon only.

### Verification
- Data validation and static Lua parsing pass. Exact layout, portrait masking
  and model desaturation still require confirmation inside World of Warcraft.

## [0.14.1] — 2026-08-09

### Fixed
- Skoll no longer falls back to “exact spawn points not verified”. The six
  precise coordinate pairs published by Wowhead's structured NPC tooltip are
  now stored under The Storm Peaks and generated into `Data/Locations.lua`.
- Source documentation distinguishes Wowhead's zone id from Blizzard's UiMapID;
  only the coordinate pairs cross between those two identifier systems.

## [0.14.0] — 2026-08-09

### Added
- Instant collection search over appearance name, family, expansion, tags,
  creature names, zones and subzones. Search documents are cached when the
  browser layout is built; typing performs no sorting or map API calls.
- Compact filters for collection status (including favourites), family,
  expansion and traits (rare, elite and exotic).
- Filter-aware family headers: empty groups disappear and each counter reflects
  only the matching appearances. A clear empty state replaces a blank list.
- One-button reset for the search and every active filter.

### Performance
- Filtering only rebuilds the data provider. The existing `WowScrollBoxList`
  continues to recycle visible rows rather than creating frames per result.

### Verification
- Static Lua validation and data validation pass. In-game confirmation is still
  required before this phase is considered delivered.

## [0.10.0] — 2026-08-09

**Seen.** The half of a field journal that a plain collection list leaves out.

### Added
- `Collection/SightingTracker.lua`. Target a pet the database knows and it is
  marked **seen** — tamed or not. You can walk past Loque'nahak at level 20,
  fail to tame it, and the journal remembers you found it.
- A new `SEEN` status between missing and collected, shown in the list in blue
  and stated in the detail panel.
- A sighting log: targeting a tameable beast the database does *not* know
  records its creature id, name and family. That is first-party data gathered
  by playing — exactly the candidate list the enumeration phase needs, with no
  external source and no licence attached to it.
- `/shiny sightings` reports the log.

### Changed — SavedVariables (schema 4 → 5)
- `seen` per character, `sightings` account wide. Additive; the migration step
  exists so the version chain does not stall.

### Notes on the implementation
- The creature id comes from splitting the target's GUID and taking the sixth
  field, the way RareScanner does it on this client. Anything whose GUID does
  not start with `Creature` is ignored.
- `UnitCreatureFamily` is **not** observed in use by any addon here, so it is
  capability-checked. It returns the localized family name or nil, which is the
  filter that keeps quest givers and critters out of the log. Without it the
  seen-marking still works and only the log stops.
- `UnitCreatureType` was rejected for that filter: it returns a localized
  string, so comparing it against a literal would break outside English.
- Seen is additive only. Nothing ever un-sees a pet.
- Cost per target change: one GUID split and one hash lookup. No polling.

## [0.9.0] — 2026-08-09

**The addon is now Shiny Hunter.** Renamed while nobody had it installed,
which is the only cheap moment to do it.

### Changed
- Folder, TOC, saved variables, window global and slash commands all renamed.
  `/hc` becomes **`/shiny`**, with `/shinyhunter` as the long form. `/sh` was
  rejected as too likely to collide with another addon.
- `ShinyHunterDB` replaces `HunterCollectionDB`.

### Added
- A `LICENSE`: free to download and use, **all rights reserved**. Redistribution,
  forks and derivative works need written permission. The addon ships as source
  because WoW addons must — the licence is what governs reuse, not secrecy.
- `## X-License` and a real author in the TOC, plus notes written for a public
  listing rather than for a work in progress.

### Consequence
- Saved data does not survive the rename. WoW names the saved-variables file
  after the addon folder, so the old file is orphaned and cannot be read by the
  new one. This affects six pets' worth of marks and nobody but the author, and
  it is precisely why the rename happens now rather than after release.
- **The TrinityCore route is closed.** GPL 2.0 data cannot go into an
  all-rights-reserved addon. The licence question is settled and the data plan
  is now verified batches plus what the addon can learn from play, neither of
  which needs anyone's permission.

## [Unreleased]

### Investigated
- TrinityCore's world database (TDB) as a bulk source for the NPC → display id
  mapping. Report in `docs/data-sources.md`. **No data incorporated.**
- Coverage is far better than assumed: the `master` branch declares support for
  **12.0.7.68974**, the exact build this addon targets, and its latest world
  database (`TDB1200.26021`, February 2026) is three times the size of the
  3.3.5 one. The earlier hypothesis that it would only cover old content was
  wrong.
- Licence is the blocker and remains unresolved. The code is GPL 2.0; the data
  dumps carry **no stated terms at all** in the README, the FAQ or the release
  notes. Two consequences need a human decision: GPL 2.0 is copyleft and would
  apply to the addon, and the EU sui generis database right can attach to bulk
  extraction from a compilation regardless of whether the individual facts are
  copyrightable.

### Noted
- Shiny Hunter declares **no licence at all**. That is a gap worth closing
  whatever is decided about TDB.

## [0.8.0] — 2026-08-09

The data pipeline, brought forward because hand-editing record files stops
scaling at around fifty entries and the collection is meant to reach a few
hundred.

### Added
- `database/hunter_pets.json` — single source of truth. Nests creatures inside
  appearances and locations inside creatures, because that is how a human edits
  it; the generator flattens it into the three flat record files.
- `tools/generate_database.py` — emits `Data/Appearances.lua`,
  `Data/Creatures.lua` and `Data/Locations.lua`. Refuses to write when the data
  does not validate, and is idempotent: a second run changes nothing.
- `tools/validate_data.py` — the cross-record checks of `Data/Validator.lua`,
  run outside the game. A dangling reference or a coordinate written as a
  percentage is now caught when the data is edited rather than after logging in.
- `tools/petdata.py` — shared loader, so the generator and the validator can
  never disagree about what the source file means. It reads the enum and family
  tokens out of `Data/Enums.lua` and `Data/Families.lua` rather than repeating
  them, so the two sides cannot drift apart.
- A `"pending": true` flag for candidates that have not been verified. The
  generator skips them instead of emitting guessed values.

### Changed
- The three record files are now generated and carry a "do not edit by hand"
  header. `Data/Families.lua` is **not** generated: it is complete and comes
  from the client's own `CreatureFamily.db2`.
- `docs/database-schema.md` now states what counts as collectible: notable
  appearances — spirit beasts, named tameable rares, and pets with a special
  obtaining condition. Ordinary family skins are out of scope, and that is a
  data decision rather than a schema one.

### Verified
- The generated files reproduce the six hand-written appearances exactly. The
  only differences are cosmetic: `0.30` renders as `0.3`, and locations are now
  grouped under their creature rather than split between coordinate and
  zone-only sections.
- Editorial notes in the JSON survive into the generated Lua as comments, so
  the "why" a reader needs is not lost to generation.

## [0.7.0] — 2026-08-09

A browser that looks like it belongs in the current game, using the family
icons the database gained in 0.6.1.

### Changed — list
- Rows are 36px and carry the family's own icon, the pet name, and the family
  name as a subtitle underneath it.
- The selected row is a tinted panel rather than a faint wash.
- Family headers carry their icon, their counter, and are **collapsible**.
  A collapsed family is still walked for its totals, so the counter stays
  correct while its rows are simply not emitted.

### Changed — detail panel
- A proper header: the pet's name on the left, the family with its own icon on
  the right, the way the game's own collection panels lay it out.
- The family name is no longer repeated in the line below; that line now
  carries specialization and expansion only.
- The pet's name turns gold when it is a favourite.

### Notes
- `PetList:Create` now takes a callbacks table rather than a single function,
  since the list has two things to report: selection and family collapse.
- Icons use the verified `IconFileID` values from `CreatureFamily.db2`. No
  atlas name has been used that was not observed in use on this client, which
  is why favourites are still shown by tint rather than by a star: an
  unverified texture draws nothing at all rather than failing loudly.

## [0.6.2] — 2026-08-09

### Fixed
- `/shiny validate` with debug enabled printed a dozen alarming-looking rejection
  warnings that came from the self-tests deliberately registering broken
  records. Fixture stores are now created quiet: expected rejections are still
  recorded so the tests can assert on them, they just no longer reach the debug
  channel looking like faults in the shipped data. A diagnostic channel that
  cries wolf is worse than none.

## [0.6.1] — 2026-08-09

Every hunter pet family, from the game's own data.

### Added
- All **61** hunter pet families, with verified `familyID`, icon file id,
  specialization and exotic flag. The list is not a judgement call: it is every
  row of `CreatureFamily.db2` whose `PetTalentType` is not -1, that value
  marking the families that are not hunter pets. The count matches an
  independent list exactly.
- Family names in both locales taken verbatim from the client's own table,
  including its `?locale=esES` export.

### Fixed
- Two hand-written Spanish family names were wrong and are now game data:
  "Bestia de espíritu" → **"Bestia espíritu"**, and "Demonisaurio" →
  **"Demosaurio"**. The second was visible in the stable UI all along.

### Changed
- The validator reports families without appearances as a single summary line
  instead of one warning each. The family table is complete while the
  appearance table deliberately is not, so most families having nothing yet is
  the expected state, and sixty warnings would bury the real findings.
- `Data/Families.lua` is a table plus a registration loop rather than sixty
  repeated literals. Every entry still goes through the same schema validation.

## [0.6.0] — 2026-08-09

The 3D model view. Taken before 0.5 because with six appearances a model can be
verified by looking at it, and a search box cannot.

### Added
- `UI/ModelViewer.lua` on `CreateFrame("PlayerModel")` and `SetDisplayInfo`:
  drag to rotate, mouse wheel to zoom, and a reset button.
- The detail panel shows the model at the top of the pane with the text
  flowing underneath, so a wide creature is not squeezed into a column.
- The main window grew to 620px tall to keep an eight-spawn source list from
  colliding with the buttons.

### Notes on the implementation
- An appearance with no verified display id shows a message, not an empty 3D
  frame. `Model:ClearModel()` is **not** used: it is not in use by any addon on
  this client, so it stays unverified. Hiding the frame achieves the same thing
  with verified behaviour.
- Drag rotation is the one place an `OnUpdate` is unavoidable, since it has to
  sample the cursor between mouse events. The script is installed on mouse down
  and removed on mouse up, and the handler also stops itself if the button is
  no longer held — a mouse-up outside the frame never reaches `OnMouseUp` and
  would otherwise leave it running every frame.
- `SetDisplayID` ignores a repeated id, so refreshing the panel after a
  favourite toggle does not reset a rotation the player just made.

## [0.4.2] — 2026-08-09

The display id gap is closed for the shipped data, and family ids and icons
now come from the game's own tables.

### Added — data
- Every appearance now carries its verified Blizzard display id:
  Loque'nahak 28010, Skoll 29673, Gondria 28871, Arcturis 31094,
  Humar the Pridelord 4424, King Krush 28052.
- Families carry their real `familyID` and `icon` from `CreatureFamily.db2`:
  Spirit Beast 46, Cat 2, Devilsaur 39.
- `tools/fetch_creature_data.py`, a bounded development tool for looking up
  display ids. It takes explicit ids only, refuses more than 25 per run, does
  no crawling, and sleeps between requests. The addon still never touches a
  network.

### Established
- `CreatureFamily.db2` carries `PetTalentType`: 0 Ferocity, 1 Tenacity,
  2 Cunning, and **-1 for families that are not hunter pets** (warlock demons,
  elementals). Confirmed by cross-checking about sixty families against an
  independent specialization list with no disagreement, which makes the full
  hunter family list derivable from game data rather than a judgement call.

### Consequences
- `/shiny validate` should now report 3 warnings instead of 9: the six
  "no display id" warnings are gone.
- The stable scanner has real data to match against. It will still recognise
  none of a typical stable, because the database holds six rares and not the
  spiders and scalehides most hunters actually carry — but the matching is now
  live rather than theoretical.
- The 3D model view is unblocked for phase 0.6.

### Sources tried and rejected, recorded in docs/data-sources.md
- `Creature.db2` looked ideal — it has `DisplayID` and `CreatureFamily`
  columns — but it is a 23,062 row table of pets and summons, not the world NPC
  catalogue. None of the six rares are in it, and it is unsorted, so a
  streaming early exit cannot work either.
- `CreatureCache.wdb` is no longer written by modern retail clients.
- The Wowhead tooltip endpoint has no display id, but does carry 20 spawn
  points for Loque'nahak against the wiki's 8 — a better coordinate source for
  later.

## [0.4.1] — 2026-08-09

The stable snapshot is now remembered, so the addon knows this hunter's pets
away from a stable master.

### Changed — SavedVariables (schema 3 → 4)
- `stableDisplayIDs`, a bare set of ids, became `stablePets`: the client's
  answer stored verbatim, with slot, display id, family name and pet name.
- The 3 → 4 migration converts the old set into snapshot entries carrying the
  display id alone. It cannot invent the fields the old shape never held, and
  the next stable visit fills them in. Nothing is discarded.
- `owned` is now derived from the snapshot rather than stored alongside a
  second copy of the same facts.

### Added
- `/shiny stable` falls back to the saved snapshot when there is no live read, and
  states when it was taken. Previously it reported an empty list, which read as
  "you have no pets" rather than "I cannot see them from here".

### Confirmed in game
- The stable **is** readable with the stable window open: 11 pets returned with
  their display ids. Whether it is readable with the window closed is still
  open; the fallback above makes that difference visible instead of silent.

## [0.4.0] — 2026-08-09

Stable detection, brought forward from phase 0.8: the stable turned out to be a
legitimate first-party source of the display ids the database is missing.

### Added
- `Collection/StableScanner.lua`. Reads the hunter's own stable through
  `C_StableInfo.GetStablePetInfo`, which returns a `displayID` per pet —
  exact and locale independent, unlike family names or the player's own pet
  names.
- Display ids read from the stable are matched against the database and the
  corresponding appearances are marked collected automatically.
- `/shiny stable`: reports whether the client answered, how many pets were read,
  how many were recognised, and lists every display id the database does not
  know. Those ids are verified values from the player's own client.
- `Data/Registry.lua` gained the `appearanceIDByDisplayID` index and
  `API:GetAppearanceIDByDisplayID()` — the bridge from what the client sees to
  what the journal calls it.
- The detail panel states "In your stable" when the last read saw the pet.
- Validator check and three self-tests for the display id index, including the
  clash case: a display id claimed by two appearances would mark the wrong pet.

### Changed — SavedVariables (schema 2 → 3)
- Character records gained `owned`, `stableDisplayIDs` and `stableScannedAt`.
  Purely additive; the migration exists so the version chain does not stall.
- **Ownership is stored separately from `collected`.** Ownership is whatever
  the last read saw; `collected` is the player's journal. Merging them would
  let a stale or partial read overwrite a mark the player made by hand.

### Two rules the scanner follows
- A read that returns nothing leaves everything untouched. Empty means "could
  not read", never "you own nothing".
- The scanner only ever **adds** to `collected`. A pet absent from a read may
  mean the read was partial; concluding the player released it would invent
  information and destroy a mark they cannot recover.

### Known limitations
- The full stable appears to be readable only while the stable window is open —
  see `docs/wow-api.md` for the evidence. Syncing is therefore opportunistic,
  and `/shiny stable` says so plainly instead of showing an empty list.
- The database still holds no display ids, so nothing will be recognised yet.
  Every pet in the stable will be reported as unknown, which is exactly the
  output needed to start filling the gap.

## [0.3.0] — 2026-08-09

The browser. The database is now visible, selectable and markable.

### Added
- `UI/PetList.lua`: virtualized list on Blizzard's `WowScrollBoxList` stack.
  Frames are recycled, so the number of live frames stays proportional to the
  visible area rather than to the size of the database.
- `UI/DetailPanel.lua`: the right hand pane — name, family, specialization,
  expansion, traits, requirements, collection status, and every known spawn
  point with its zone and coordinates.
- `UI/Browser.lua`: turns the database into list elements, grouped by family
  with per-family progress counters, and wires selection through to the detail
  panel.
- Favourite and collected toggles in the detail panel. Beyond the phase's
  stated scope, but `Collection/State.lua` had shipped in 0.1 with no way to
  exercise it: without these the browser's reaction to `COLLECTION_CHANGED`,
  the progress counter and saved-variables persistence could not be tested at
  all.

### Changed
- The main window's placeholder is gone, replaced by the list/detail split.
- Zone names are resolved through `C_Map.GetMapInfo(mapID).name` at display
  time, so they arrive already localized and are not stored in our database.
- Coordinates are converted from the canonical 0..1 to percentages in the
  detail panel only — the single "where a human reads them" boundary.

### Notes on the implementation
- Sorting and state reading are separated: `BuildLayout()` sorts families and
  appearances and runs once, `BuildElements()` walks that cached layout and
  reads only the volatile fields. Toggling a favourite therefore costs one walk
  rather than a re-sort of the database.
- The registry's index arrays are returned by reference, so the browser copies
  them before sorting; sorting in place would reorder the database itself.
- Favourites are shown by tinting the row name rather than with an icon: no
  icon atlas name has been verified, and an unverified texture draws nothing at
  all rather than failing loudly.
- Creature names are still not displayed. `creature.name` is English reference
  data, so a source is identified by where it is found until names can be
  resolved from the client.

## [0.2.0] — 2026-08-09

Data foundation. The model is now real, validated and covered by tests; the
database is deliberately tiny.

### Changed — SavedVariables (schema 1 → 2)
- Character records are now keyed by `UnitGUID("player")` instead of
  `"Name - Realm"`. The old key broke on a character rename and left records
  nothing could identify.
- The character is resolved at `PLAYER_LOGIN` rather than `ADDON_LOADED`: unit
  information is not guaranteed to be populated when saved variables first
  become available, so the old code could have produced a nil key.
- Each character record now stores `name`, `realm`, `class` and `lastLogin` as
  readable metadata alongside the opaque GUID.
- Migration 1 → 2 parks old records in `legacyCharacters` and adopts them onto
  the GUID key as each character logs in. Nothing is deleted.
- `Database:GetAllCharacters()` added, for the account-wide aggregates on the
  roadmap.

### Added — data model
- `Data/Enums.lua`: expansion, specialization, source-type, provenance and
  requirement-kind tokens, each with a localization key. No bare strings
  anywhere else.
- Coordinates are stored in **0..1**, the form every current Blizzard map API
  uses. Sources quoting percentages are converted once, in the data file.
- Extensible requirement system: a `kind` plus a free `params` table, with a
  per-kind parameter contract. Ten kinds defined; adding one is a single entry.
- Schema field constraints are declarative (`required`, `enum`, `min`, `max`,
  `element`), so type, range and enum checks share one code path.
- Facts are no longer duplicated across records: a creature has no family or
  locations of its own, and an appearance has no creature list. Those are
  reached through derived lookups and indexes.

### Added — registry and queries
- `ns.Data.API`: the single query surface, every call a hash lookup.
- Indexes built at registration for family, expansion, appearance, map,
  creature and location lookups. `creatureIDsByMap` is deduplicated.
- `Registry:NewStore()` / `RegisterInto()`, so tests exercise the real
  index-building code rather than a copy of it.
- `API:GetEffectiveRequirements()` merges family, appearance and creature level
  requirements without repeats.

### Added — validation
- `Data/Validator.lua` and `/shiny validate`: dangling references, orphans,
  invalid map ids, out-of-range or half-missing coordinates, contradictory
  level ranges, unknown expansion tokens, reference cycles and provenance.
  Errors and warnings are reported separately — a thin database is not a broken
  one.
- `Tests/DataValidation.lua`: 26 self-tests over throwaway stores and the
  shipped data, including the one-appearance-many-creatures relationship and
  map deduplication.

### Added — data (all `DATA_REAL_VERIFIED`)
- 3 families: Spirit Beast, Cat, Devilsaur.
- 6 appearances and 6 creatures: Loque'nahak, Skoll, Gondria, Arcturis,
  Humar the Pridelord, King Krush.
- 13 location records across 5 zones.
- 1 requirement: Beast Mastery, referenced by the two exotic families.
- Sources and licences recorded in `docs/data-sources.md`.

### Fixed
- The main window's progress counter was anchored underneath the template's
  close button and was invisible. It now sits above the content inset.
- Slash input with more than three words no longer falls through to opening the
  window.

### Known gaps
- **No Blizzard display id could be verified**, so `appearance.displayIDs` is
  empty everywhere and the future model panel has nothing to show. Reported as
  a warning per appearance.
- Blizzard numeric `familyID` values and family icons are likewise unverified
  and therefore absent.
- No shipped appearance has more than one creature. The relationship is
  supported, indexed and tested against a fixture; asserting it with real data
  needs display ids we do not have.

## [0.1.0] — 2026-08-09

First skeleton. Architecture only: no pet data ships in this version.

### Added
- Addon loads on Retail 12.0.7 (TOC interface `120007`).
- Private namespace and a small module registry with `OnInitialize` /
  `OnEnable` lifecycle, driven in explicit TOC order (`Core/Bootstrap.lua`,
  `Core/Init.lua`).
- `ShinyHunterDB` saved variables with defaults, `schemaVersion`, forward
  migrations, and read-only protection against data written by a newer build
  (`Core/Database.lua`).
- Settings access layer (`Core/Config.lua`).
- Shared event dispatcher and internal message bus over a single frame, with no
  `OnUpdate` anywhere (`Core/Events.lua`).
- Debug channel, off by default, with a ring buffer that captures start-up so
  `/shiny debug dump` can report it after the fact (`Core/Debug.lua`).
- Slash commands `/shiny` and `/shinyhunter`: open, `help`, `version`,
  `debug`, `debug dump`, `reset` with mandatory confirmation
  (`Core/Commands.lua`).
- Record schema and validator for families, appearances, creatures, locations
  and requirements (`Data/Schema.lua`).
- In-memory data registry with the indexes the browser will need, plus
  cross-reference checks at start-up (`Data/Registry.lua`).
- Collection state layer, fully separate from the static data: collected,
  pending, favourite, ignored, and progress aggregation
  (`Collection/State.lua`).
- Main window on `ButtonFrameTemplate`: movable, position persisted, closes
  with ESC, built lazily on first open (`UI/MainWindow.lua`).
- English and Spanish locales, with English as the fallback for any missing key
  (`Localization/`).
- Documentation: architecture, database schema, and a WoW API table recording
  how each call was verified and what remains unproven.

### Notes
- Zero pet records are registered in this version, by design.
- `Navigation/` and `Tests/` exist but are empty; they are reserved for phases
  0.7 and 0.12.

This mod has no related projects