Commit Graph
45 Commits
Author SHA1 Message Date
SamandClaude Fable 5.1 7a825111ab the world map's arrow shows on zone sheets, and UIParent goes stock
- the world map's arrow shows on every zone sheet, and alt-clicking a town jumps there: the stock file creates the player arrow as a `Model` child of `WorldMapFrame` and lays a zone sheet's explored-area overlays as ARTWORK textures on `WorldMapDetailFrame` — one `(strata, level)` bucket, where the draw layer outranks the frame — and benilla drew a model's scene at the frame's own layer-0 slot, so every overlay painted over it (the continent sheet has no overlays, which is why it was the only sheet with an arrow); wow-re's carve: a layer batch carries three sub-arrays — quads, the string batch, a render-callback list — that `0x76fb00` drains in that order, and `0x76d160` registers a model's callback only for layer 2 (`0x76d17f cmp ebx,2`), so a model's scene is ARTWORK content, neither a separate pass nor a layer-0 slot; a `ModelPane` quad now keys at the ARTWORK content rank, which re-orders the pet page's happiness icon (a sibling's BACKGROUND quad) under the pane's scene — the reference's own order, harmless because the bake is transparent where the model is not; a model against a LATER-linked ARTWORK font string in the same bucket is still ordered by link stamp, named not built; and the alt-click jump, which required the topmost frame under the cursor to be `WorldMapButton` itself while the stock file parents every POI icon and blip to that button, now walks up from whatever was hit to the button and takes its rect — the map's own chrome still answers nothing (1992)
- `UIParent` is the reference's own: `UIParent.xml` loads off the chain at its toc's slot, right after `WorldFrame.xml`, sourcing `UIParent.lua` and `LocaleProperties.lua` itself, and our `UIParent.xml` + `UiPanels.xml` — 3086 lines of transcribed `UIParent.lua` — are deleted; the one unbound verb the stock file ticks, `CheckReadyCheckTime`, was already 1989's; back from the reference: all sixty-six registered events and their arms (`PLAYER_CONTROL_LOST`/`_GAINED`, `RAID_ROSTER_UPDATE`, the trade-request pair, `PLAYER_SKINNED`, `GOSSIP_ENTER_CODE`), the ESC ladder as written — StaticPopup, the options window's Cancel, the game menu, `CloseMenus`, `SpellStopCasting`, `SpellStopTargeting`, `CloseAllWindows`, `ClearTarget`, else open — so ESC no longer clears a held cursor item or cancels the colour picker, two arms ours had grown that the reference does not have; the fade/flash/pulse kits walked from `UIParent`'s own OnUpdate in place of three 1×1 driver frames of ours, so a cinematic's `UIParent:Hide()` stops the walks as it does there; the managed bottom-stack positions without our `UIParent_RegisterManagedPositionListener` extension, which no shipped file registered any more; `LowHealthFrame`/`OutOfControlFrame`; and the `firstTimeLoaded` close on re-show; what stayed ours moved out — the window tab template and its OnUpdate settle (1004's async-measure adapter) and `BENILLA_FALLBACK_ICON` to `ScrollTemplates.xml`, 0561's bag verbs to `ContainerFrameAdapters`, the script log's slot row to its own file, `OptionsFrameCancel = OptionsFrameCloseButton` beside the two options aliases — and the Auction/Inspect/Macro/Talent panel rows, verbatim copies of the LoadOnDemand addons' own registrations, go; the reference also decides that the area spirit healer's dialog accepts on show with one CANCEL button, that losing control closes every window bar the reference's exceptions, and that the bottom-bar clearance reads the saved globals `SHOW_MULTI_ACTIONBAR_1`/`_2` rather than the bars' shown state; three integration binaries that kept private copies of the manifest loader use the shared one now (1988)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 19:30:54 +07:00
SamandClaude Fable 5.1 bc1a2428dd the loading screen lets nothing through, and the micro buttons go stock
- units could be hovered through the loading screen — the sword cursor gave it away: the world pick chain has no state gate, one of fifty-one input sites, so a gate per consumer is a rule that regresses; the cut is at the source instead — one `PreUpdate` system empties the button planes, drains the raw queues, zeroes the accumulators and blanks the window's cursor position while the cover is up (the alt-tabbed-away state every consumer already handles); a press under the cover never happened, a held button is released once, a gesture in flight is cancelled, and a wall test counts the channels; the reference does the same — its raise registers a veto stub (`0x406a50`) on five event-bus categories — and one gap closed with it: the reference parks the plain arrow and drops any item overlay before the screen goes up, where benilla kept a held item's icon over the loading art (1986, 1990)
- the micro-button row is the reference's own `MainMenuBarMicroButtons.xml`, our transcription deleted — no engine verb was missing, and the whole engine-side cost is one alias, `SoundOptionsFrame = OptionsFrame`, because the stock file reads the reference's three options windows and ours is the one window for all three; what the stock file brings back: `UpdateTalentButton`'s own −2 re-seat (the five buttons after the talent button sit 1 px further right — the reference's own pixel), the raw binding token in the hover label (`(C)`, `(SHIFT-P)`), the sixty-second talent-button pulse on a ding while the sheet is closed (0304's scope-out retired), the keyring arm, and "Abilities" on the spellbook hover for a character with no spells; `BenillaActionBarArt_SeatAbove` goes with the file — a child is born one level above its parent (`SetParent` `0x76ab65`), the seat it set by hand (1987)
- hovering the player arrow on the stock world map showed an empty tooltip: narrower than 4:3 the map is scaled under 1, and our `MouseIsOver` had dropped the reference's division by `GetEffectiveScale` as "always 1" — the frame getters answer in the frame's own units, `GetCursorPosition` in the screen's; the division is back, and the region getters divide by their owner's scale too; and the ready check times out: the stock `UIParent.xml` ticks `CheckReadyCheckTime` every frame, the one unbound name in that file's way, so the mechanism behind it is built — a 30 s deadline and a "has not answered" flag per roster entry, the leader getting no popup while members print "%s has initiated a ready check" and get it, and on expiry `RAID_MEMBERS_AFK` with the unanswered names or `READY_CHECK_NO_AFK`, the last answer closing the check at once (1985, 1989)
- a review of the floor grind closed eight stale-input and bypassed-side-effect siblings the gates had left open: a never-placed card places on a still frame, the dormant-emitter skip sits below the emitter's lifetime blocks, PVS changes (not only spawns) un-still the gates, the appear ramp's retirement and a far-side unmark come due, a host born under a parked camera is judged, the projection counts as a still input, a fresh palette range is zeroed, the stable feed runs once more after a close, the unit publisher's viewer query is filtered, solo UI materials are reused by key, and the draw-list cache compares exactly; and three doc links the chat window's stock move (1948) left dangling point at what replaced them — the colour table and the tell ring are the stock Lua's now — which is what had the doc-links gate (1925) red on main

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 21:01:38 +07:00
SamandClaude Fable 5.1 c965b5425d the tooltip and five windows go stock, and the battleground keeps score
- the tooltip is the reference's own file: `GameTooltip.xml` loads off the chain, ours is deleted, and every verb it calls was already bound, so this is a plain swap; retired with it: the `$parentThicken` plate fill that thickened the plate from the art's ~73% to ~84% opacity — the reference's plate is the raw `UI-Tooltip-Background` tint, and that is what ships; the one engine fact the transcription had been hiding: the reference's instance declares no size, and a frame with one anchor and no size resolves to NO rect under the reference's own layout law — our declared size had been a harness crutch (1968); and the dressing room goes stock with `<DressUpModel>` as a widget kind (factory `0x495c00`): a `PlayerModel` plus its own `Undress`/`Dress`/`TryOn`, where `Undress` strips the body and not the hands, and Close is read off the window since the stock OnHide queues nothing (1969)
- the mail window and the auction house are the reference's own: `MailFrame.xml` loads off the chain and brings the stationery picker, invoice pane and autocomplete ours had left out; the stationery family is built off wow-re's carve over a list computed off `Stationery.dbc` rows × the player's bags (`0x622270`, not the bank); the selection rides `CMSG_SEND_MAIL` field 6 and a send with none silently aborts; its two events fire where the client fires them (1970); `Blizzard_AuctionUI` loads on demand from the `AUCTION_HOUSE_SHOW` arm, and three root fixes its Lua surfaced: `GetAuctionItemClasses()` is static — read at the addon's load, before any session, so the class tree is a login-scoped push; `SetAuctionCompareItem` (`0x535d70`) on the vendor compare's one body; `NEW_AUCTION_UPDATE` resets the create form; its dressing-room pane shares the app's one room (1971)
- the battleground keeps score: `WorldStateFrame.xml` loads off the chain and ours is deleted; the stock file is three things where ours was one: the readout, the capture bars, and the battleground scoreboard this client never had, built off wow-re's round — `MSG_PVP_LOG_DATA` both ways (throttled to 5000 ms client-side, `0x4aa170`) and `CMSG_LEAVE_BATTLEFIELD`; eleven score verbs over a board the app pushes, where the filter is a SORT, not a compaction — team first, killing blows descending, deaths ascending, honor descending, name — so the filtered count shrinks while `GetBattlefieldScore` still reaches every wire row; `HIDE_OUTDOOR_WORLD_STATE` joins the options uvar block, a capture point is a bar, and the scoreboard and battlefield-minimap toggles become bound specs at the install's own `SHIFT-SPACE`/`SHIFT-M` (1972)
- the trade skill and craft windows go stock as `Blizzard_TradeSkillUI`/`Blizzard_CraftUI` on demand, from the reference's own UIParent arms; our two transcriptions are deleted; the four item-link verbs are built off wow-re's carve on the client's link builder (`0x52adb0`) — zero values on any miss, `GetTradeSkillReagentItemLink` raising Blizzard's own typo'd Usage, kept, and `GetCraftItemLink` the `|Henchant:` link in fixed white; `SetTextColor`'s channels coerce nil to 0 on FontString, Font and Button where ours had raised (1973); and the Inspect, Talent, Macro and Raid addons load on demand — `benilla.toc` lists no `Interface\AddOns` row, and below level 10 the talent addon is never even loaded; the gates walk every reached addon and found `Blizzard_GMSurveyUI`'s four engine verbs nothing answers, reachable only through `GMSURVEY_DISPLAY`, which nothing fires (1889; 1967)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:59:04 +07:00
SamandClaude Fable 5.1 f4951470a3 coins ride the cursor, and the trade window and combat text go stock
- coins ride the cursor: `MoneyFrame.lua`/`.xml` load off the player's chain, and the stock kit reads the cursor's coins at load, so the money cursor — payload mode 2, the copper at `[0xb4e2f0]` — is the engine's: `PickupPlayerMoney` puts coins on the cursor and the purse is never debited, and `CoinPickupFrame.xml`, the shift-click coin dialog nothing of ours had ever answered, joins; wow-re's round then set the law: the pickup raises on a non-number and refuses silently on zero, lost control and more than the purse; `AddTradeMoney` folds the coins into the offer as an absolute `CMSG_SET_TRADE_GOLD` gated on the purse; the send-mail setters and `GetCoinIcon` answer as the bytes do; the coinage-change reflex trims an offer the purse no longer covers; and the four send-mail pickup/drop verbs the stock table names do not exist in 5875, so they are not built (1962, 1965)
- the trade window is the reference's own file: `TradeFrame.xml` + `TradeFrame.lua` off the chain, ours deleted; `GameTooltip:SetTradePlayerItem`/`SetTradeTargetItem` (`0x5341e0`/`0x534410`) render the slot's item the way the loot slot's is, and `TRADE_PLAYER_ITEM_CHANGED`/`TRADE_TARGET_ITEM_CHANGED` — which the stock file repaints one slot on, and nothing had fired — fire per changed slot beside `TRADE_UPDATE`; the stock file brings the chain's own `MoneyInputFrame`, a TARGET_TRADE `SmallMoneyFrame`, `ItemButtonTemplate` slots and the enchant slot's own wording — "Item not yet modified" where ours had read "Will Not Be Traded"; the wire's enchant id is not carried into the slot yet, so the tooltip shows the item without its enchant (1966)
- the dialogs' verbs, as the bytes define them: nine of the ten stock `StaticPopup.lua` bindings 1960 had left named are built off wow-re's round with their packets, events and UIParent arms — the bare trade pair, `ForceLogout`, the instance-boot timer (whole seconds), the area spirit healer's accept/cancel/time, `AcceptBattlefieldPort` out of a three-slot queue `SMSG_BATTLEFIELD_STATUS` fills, `CancelMeetingStoneRequest`, and the pet trainer's pair as the talent wipe's twin, latch for latch — `SMSG_PET_UNLEARN_CONFIRM` latches and asks, `ConfirmPetUnlearn` sends behind the money gate, `CheckPetUntrainerDist` reads the leash; not built, named: the healer's proximity scan (`0x4923b0`: 20 yd to acquire, 22 to retain), so no healer is cached yet, and `ReplaceTradeEnchant`, which rides trade-slot enchant targeting this engine does not build (1963)
- the scrolling combat text is the reference's own `Blizzard_CombatText`, LoadOnDemand off the chain: our transcription is deleted, and the addon loads through `UIParentLoadAddOn` at the reference's own sites; the family's fourteen defaults move to the options file where the reference keeps them, because a LoadOnDemand addon cannot define the options that decide whether it loads (1964); and the Looking-for-Group pair is what the bytes define, correcting 1959's flag: `SetLookingForGroup` takes three (type, entry) pairs and a comment, packs each slot as `(type << 24) & entry` — an AND (`0x4e9713`), so every admissible input stores zero — and sends `CMSG_SET_LOOKING_FOR_GROUP` only when the commit changed something; `GetLookingForGroup` answers three nilable slot names then the comment, never 1|nil; and the stock 1.12.1 UI never calls either — both call sites sit in an XML comment (1961)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:58:15 +07:00
SamandClaude Fable 5.1 2fed249252 the chat and spellbook go stock, and hidden props park their meshes
- the chat window is the reference's own `ChatFrame.xml` and `FloatingChatFrame.xml`, run off the player's chain; our 2216-line transcription is deleted, the feed fires `CHAT_MSG_*` and the reference's `ChatFrame_OnEvent` prints — no app-side composition into the windows, no routing table, no whisper chime or flash of ours, and the transcribed edit-box machine (sticky type, tell ring, Tab cycle) retires with it; the verbs the two files call are built to the bytes — the whole `0x98` chat-window record and its eight verbs, the 94-entry chat-type colour registry, the language walk, the channel verbs as a command queue, the slash handlers' emote/roll/assist/uninvite/console/logging verbs; `chat-cache.txt` is written and read in the reference's whole grammar, the 68-entry message-group table in flag order and the no-file boot included, and the chat bindings and macro lines run through the reference's own arms (1948)
- the spellbook is the reference's own `SpellBookFrame.xml`; our 965-line transcription is deleted, and two quirks it reproduced by hand (the pet page ignores its page number, its arrows write the spell book's counter) now come from the reference's lines; one adapter remains because the reference's autocast shine is a `<Model>` that draws no pixels in this engine — the script puts the token-texture shine beside each button's model and carries it with the model's shown state; the nine spell-slot bindings (`GetSpellName`, `CastSpell`, `PickupSpell` and their kin) now parse their arguments the way the reference's shared marshaller `0x4b3ec0` does — a numeric arg 1, a mandatory arg 2, the index gated to [0, 0x400) with "Invalid spell slot in <Verb>" on a miss, "pet" matched without case — where ours raised mlua's own message on a negative id, answered nil for 0 and above 1024, and read the wrong book for "PET" (1952)
- a long-hidden world model part parks its `Mesh3d`: the entity path keeps the batches the retained pass declines resident — 5.3k hidden submeshes at any instant at the Stormwind auction house — and Bevy's sweeps walk every `Mesh3d` whether it draws or not, so a part parks after 30 consecutive hidden frames and unparks the frame its verdict turns visible; every world model part takes part, units' bodies included, while a booth's mirror parts stay out; interleaved pairs read an alone Stormwind 0.1–0.4 ms lighter, and `WOW_NO_MESH_PARK=1` is the A/B; the audio thread's realtime class was the standing suspect for the raid's `cpu_p99` spikes with sound on, and `WOW_AUDIO_NO_RT=1` across two interleaved Blackrock pairs read no difference, so the lever stays as an instrument (1949); and a no-merge prop batch now says which rule declined it — animated (1551 at the auction house) or transparent, not order-free (340) (1951)
- the probe reads CPU per thread across its window (user and system split, because a user-mode sampler never sees kernel time) and the main thread's CPU inside the app's frame beside its whole-frame CPU; together they place the vsync tax every player pays by default — cpu_ms 10.7 uncapped against 12.5 under vsync, alone in Stormwind, with no system growing and no thread spinning: it lands on the main thread, in user time, inside the schedules, the same systems each running slower, and a low-priority spinner holding one core busy erases it to the last decimal (vsync + spinner 10.18 against uncapped 10.17), which is frequency scaling — under vsync the cores idle deeper between frames and the next burst starts at a lower clock; nothing in the client is the cause and nothing in the client changes for it (1950)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:55:55 +07:00
SamandClaude Fable 5.1 fd595b7119 the quest windows go stock, and the 20 ms frames were mis-split pairs
- the quest giver's dialog and the quest log are the reference's own `QuestFrame.xml` and `QuestLogFrame.xml`, run off the player's chain at the reference's own toc seats; our 1366-line and 1999-line copies are deleted, and the verbs the stock files call are built — the four `GameTooltip` quest-item and reward-spell setters, the reward spell itself (parsed on all three packets and dropped by the model until now), and two verbs; the detail pane could never scroll because `UpdateScrollChildRect` measured a frame late where the reference's measure is synchronous, so it measures through the installed font engine now; and ten things the reference does that ours did not, each found by a test that had enshrined ours — a shift-click never selects, an empty log hides the whole detail pane and says "No Active Quests", the abandon confirm lives in the popup registry (1944)
- the quest bindings' law, read off the binary and folded back: no 1.12 packet carries a quest background material — `GetQuestBackgroundMaterial` (`0x502230`) forks on the dialog's SOURCE object, an item answering its template's PageMaterial, a GameObject its template data, a creature nil (FrameXML's "Parchment"), the id naming a `PageTextMaterial.dbc` row whose six words are nowhere in the binary; its twin `ItemTextGetMaterial` has the same body, so the reader window already held every piece and the giver's feed runs the same resolve; `QuestChooseRewardError` is game-error row `0x98`, and the row plays `igQuestFailed` first, which the verb now queues; the reward-spell getters' third return is `Spell.dbc` Attributes bit 5 (1161 of 22357 rows set — craft-cast spells set, `Pattern:` teaching spells clear), read off the catalog now (1946)
- the "20 ms frames" of a raid, chased to their number: the probe's worst frames now carry their churn (entities, assets, first-play sound decodes, live particles, the GPU reading) and in a Blackrock raid with sound on every one of those read flat; then the same window on the PACED clock — under vsync with pipelined rendering the raw delta is mis-split into long/short pairs that sum to exact refresh multiples, so an alone Stormwind leg read 115 of 300 frames over budget with cpu and gpu both at their means, while the paced clock read 0 skipped frames in every leg; what remains real in the raid is `cpu_p99` at 22–23 ms with sound on; and every submesh the streamer spawns now carries why it is an entity, counted per reason — 5.8k resident ADT-doodad submeshes at the Stormwind auction house, 5.3k of them hidden, three prop families the retained pass declines by rule, each riding every per-`Mesh3d` sweep for ~0.4 ms of the alone frame (1947)
- a raid's dozen voices cost the mixer ~1.5 ms of every 60 Hz frame: upstream kira spatializes every frame — normalizes, the attenuation curve and a dB→amplitude `powf` per frame per spatial track, two more `powf`s for the volume tween, ~1.7 M `powf`s a second at 48 kHz × 12 tracks for gains that change imperceptibly across a chunk — so kira 0.12.1 is vendored with one patch: the spatial gains and the volume × fade amplitude are evaluated at the chunk's two ends and interpolated across its ~10.7 ms, the granularity FMOD 3, the reference's own mixer, updates them at; nothing a listener can name changes (1945); and rig poses are evaluated in parallel over rigs — each reads its shared clips and writes only its own pose, and a raid's ~400 live rigs were 0.4 ms of one thread walked serially on the main thread's critical path (1947)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:55:12 +07:00
SamandClaude Fable 5.1 2f7cfcabf5 the action bars are the reference's own, and a gift can be wrapped
- the action-bar cluster is the reference's own: `MainMenuBar.xml`, `ActionBarFrame.xml`, `MultiActionBars.xml` and `BonusActionBarFrame.xml` run off the player's own chain, and our `ActionBar.xml` (2047 lines), `MultiBars.xml` and `StanceBar.xml` are deleted — three, since the stock bonus-bar file declares the shapeshift bar too; one engine verb, `ChangeActionBarPage`, fires `ACTIONBAR_PAGE_CHANGED` and nothing else; one load blocker: stock `MultiActionBars.lua` writes the options window's table from its OnLoad, the reference's own load-order hack, so our options window moves to the reference's toc slot; and ten things the reference does that ours did not: an empty button is HIDDEN while showgrid is 0, the bonus overlay sits one pixel right of the main buttons, every slide takes one frame more than its time, and `ActionButton_ShowGrid` ghosts EVERY ring, occupied included (1938)
- a gift can be wrapped: right-clicking wrapping paper fell through to plain use and sent `CMSG_USE_ITEM`, so nothing happened — you could receive a gift and never give one; the wrap is a displayed-cursor MODE plus a stashed slot, never a payload, so `CursorHasItem()` stays false and every stock gate on it stays shut: right-click arms it, a left-click on a bag slot sends `CMSG_WRAP_ITEM`, and the client applies no eligibility test — the server's `ERR_CANT_WRAP_*` reasons are the error line (1934); a duration-limited item counts down: `SMSG_ITEM_TIME_UPDATE` parks a deadline and the tooltip's `ITEM_DURATION` line runs the enchant countdown's bucket ladder, so "Duration: 1 days" is what the reference renders; an update for an item we do not hold is DROPPED, no queue (1933); and a renamed crowd-control refusal names its mechanic — "Can't do that while stunned" — off `SpellMechanic.dbc` (1943)
- a creature paths on a boat: `SMSG_MONSTER_MOVE_TRANSPORT` carries the transport's guid and deck-local coordinates, and is the attach/detach edge; a deck sample lands on the rider or nowhere, never as a world write a few yards from the map origin; and "there is no terrain under a boat" turned out wrong: the ground probe admits GameObject meshes — a boat's `.wmo` is a GameObject, so the probe hits the deck (1936); `MSG_MOVE_TIME_SKIPPED` is read, not dropped — the reference adds the lag to the observed unit's last-wire stamp, so dropping it scheduled their next packet `lag` ms late, a hitch for every player who stalled zoning in near us; and our own settle hold reports once (1935); and the tradeskill tool order was backwards — focus FIRST, so every two-tool recipe had read "Blacksmith Hammer, Anvil" for the reference's "Anvil, Blacksmith Hammer"; the focus's `hasTool` is 1.0 in the reference too (1942)
- the crowd's second sitting, instruments first: the probe line carries the tail — cpu p95/p99 and the six worst frames — because a mean under budget hides the one frame in twenty over it (raid legs railed at 16.67 with p95 at 18–20 ms) and whether that frame was work or a wait is the first question about a stutter, and the visible meshes are counted by lane; then two cuts — a terrain tile furnishes as 4×4 cells of 4×4 chunks, one mesh, one entity, one draw per 133-yd cell instead of per 33-yd chunk (a city horizon is over a thousand chunks a frame, and a cell changes nothing a pixel can see; Stormwind 10.55 → 10.32 `cpu_ms`), and an authored point light is our own `WorldPointLight`, not Bevy's `PointLight`, which was only a data carrier while Bevy ran its whole light lane over every lamp, ~2 % of the alone frame; the sitting's record is 1945, and the code says so (1945)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:54:27 +07:00
SamandClaude Fable 5.1 f0d1bacf0a the help window is the reference's own, and a ding carries nine gains
- the help window is the reference's own `HelpFrame.xml`, and ours was less than half its size, so this is mostly arrival: the category list, the per-category GM and harassment pages, the stuck page, the bug report, the PvP policy line; four things we had built go with the swap — one-click filing from Home, the Home unstick button, the downed-queue refusal message, and ticket abandonment, a capability loss rather than a look change, since `AbandonTicket` exists in neither the binding table nor the 1.12 FrameXML corpus and any return of it goes on top of the stock window; `GMSURVEY_DISPLAY` arrives with no producer, a real 1.12 event (`SignalEvent` `0x5e797b`) whose whole UI is a LoadOnDemand addon not on our chain; and the stock file needs two orderings ours did not, the micro-button row before its GM status ask and the buff frame before its repoll timer (1889, superseding 1687)
- the cast bar, the action-button regions and the font registry are the reference's own files too: our `CastingBar.xml` was `CastingBarFrame.xml` under another name, with the literal "Failed" where the reference reads the `FAILED` GlobalString (1886); `ActionButtonTemplate.xml` seats above our `ActionBar.xml` because the later-registered template wins, and it declares zero scripts, so the regions migrate while the handlers stay ours until `ActionButton.lua`'s verbs do (1887); `Fonts.xml` is manifest entry 0, all 51 fonts match by name, and its one real difference, `ITEM_QUALITY_COLORS`, moves to UIParent where the reference declares it (1888); the harnesses were the real cost — those reading our files off disk could not name a chain file and now read through the manifest's own rule — and the event-producer gate, having cried wolf at the cast bar's `SPELLCAST_INTERRUPTED` fired through a variable, now matches the fired tuple's shape
- of the 189 events benilla fires, three are not in the client — `BAG_UPDATE_DELAYED` (a Classic Era name), `LOOT_UPDATE` and `UPDATE_LOOT_ROLL` (invented here, no listener anywhere) — found against the reference binary's own string table, and a gate now fails any fire of a name the client cannot dispatch unless it wears a `BENILLA_` prefix (1883); two payloads the reference gives that we did not: `UNIT_HAPPINESS` carries its unit token, without which no `UNIT_*` consumer reads it, and `CHARACTER_POINTS_CHANGED` carries the point deltas `ChatFrame.lua` compares unguarded, so nil raised (1884); and `PLAYER_LEVEL_UP` carries all nine — level, health and mana gain, talent points (not on the wire: the client derives `(newLevel >= 10) ? 1 : 0` at `0x5e407c`) and the five stat gains — matched to the ding by level, a demotion's absent gains sent as zeros since a nil raises where a zero reads as no line
- the chain gap report could not run — one of its six probes had no player seated where a stock addon formats `UnitName("player")` at load, the other five each carrying an identical copy-pasted seed — and the repaired instrument prices each window's cost: 13 stock files load clean with nothing missing (the action bars, the cast bar, the fonts, the help, friends, game-menu and sound-options windows among them) and the near ones name their missing verb, with "loads clean" still not "swapped" (1885); and `UpdateNameplates`, recorded as the missing engine verb blocking the UIParent keystone, is FrameXML — defined in `UIOptionsFrame.lua`, absent from the binding table, its whole body four nameplate verbs that are already ours — so it is twelve lines transcribed into our options frame, the reference's own Show-then-Hide no-op included (1890 corrects 1878)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:50:36 +07:00
SamandClaude Fable 5.1 a8c9bc37a2 the audio crackle is gone, and a trainer answers a click as a trainer
- the audio crackle was our own stall sampler: `/usr/bin/sample` suspends every thread of the task for each of its snapshots, CoreAudio's realtime IO thread included, and coreaudiod times the client out — every HAL overload of the session sat inside a sample of our own process (three for three by timestamp), and the watchdog fires on exactly the stalls the crackle lands on (a desktop switch's `nextDrawable` block, a world entry's compile burst); in-frame sampling now waits for a run nobody can hear; and the output stream is ours — kira's renderer runs 256-frame chunks on a realtime render thread (time-constraint policy, joined to the device's IO workgroup) into a lock-free ring, the IOProc copies one device buffer and touches nothing else (≤ 0.01 ms), the device buffer goes 2048 → 512, a lost or changed default device rebuilds the stream (cpal's no-op error callback on macOS had paused it forever), a debug allocator aborts on any allocation inside either realtime path, and per-cycle meters name a skipped cycle's layer; `SoundBufferSize` is registered at the reference's own FMOD dial, and `audiowatch.py` puts the OS side — thread bands, coreaudiod's overload verdicts — on the same timeline
- right-clicking a trainer, questgiver, innkeeper, spirit healer, petitioner, tabard designer or battlemaster sent `CMSG_GOSSIP_HELLO` — eight of the reference's fourteen service arms collapsing into one packet, because the dispatch keyed on the CURSOR kind and Speak covers eight bits; the reference runs two structurally identical ladders over `UNIT_NPC_FLAGS` (one for the cursor at `0x482336`, one for the send at `0x5f0289`), so the ladder is transcribed, first match wins low to high: questgiver → `CMSG_QUESTGIVER_HELLO`, trainer → `CMSG_TRAINER_LIST`, petitioner → `CMSG_PETITION_SHOWLIST`, and the spirit healer and innkeeper send NOTHING on the click — they cache the guid and raise the confirm, whose Lua accept sends with a zero guid — both ghost-gated at entry, so a living player clicking a menuless spirit healer now gets exactly what the reference gives: nothing; the stable-master conjunct and the banker/auctioneer fork fall out of the bit order for free
- the -1 blood id is unfilled, not none, and the tests now name the creatures: -1 splits families that share a directory (QuillBoar beside QuillBoarWarrior, GnollMelee beside GnollCaster) and splits single creatures shipped under two rows (a Baby Murloc is both), so a "bloodless" reading would put non-bleeding quilboar beside bleeding quilboar warriors in one Razorfen room; `violenceLevel` 2 IS the reference's default — formatted out of a per-region cap table at `0x86c3f8`, and the one capped locale is koKR, whose green-blood row the table predicts from bytes alone; a spurt whose victim authors no attachment point is dropped, not relocated, and no creature-keyed suppression exists anywhere on the spurt path (ten stop conditions, none keyed on the creature)
- twenty dead copies of ours (`PanelTemplates_*`, `TabButtonTemplate`, `FauxScrollFrame_*`, `ScrollFrame_OnLoad`, `ScrollingEdit_*`) that a later chain entry had been shadowing are deleted under a gate that fails any such shadow, and deleting them turned 141 tests red on four bugs live since the kit swap: lists populated before showing (the reference gates every scroll-bar write on `IsVisible()`, so both arrows were dead on every faux list), every faux window wired to a `frame.updateFunc` the reference does not have (the bar moved, the list did not follow), a trainer pitch declared `local` where an `<OnVerticalScroll>` chunk cannot see it, and the armed-wheel guard bypassed by the template's own `<OnMouseWheel>`; nine faux windows (Skill, Craft, TradeSkill, Auction, QuestLog, Friends, ScriptLog) are still on `updateFunc` and their lists do not scroll until each is rewired

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:09:38 +07:00
SamandClaude Fable 5.1 46c7cf2b80 spells shake the camera, and the sound keeps playing in the background
- spells shake the camera: `SpellEffectCameraShakes.dbc` loads beside `CameraShakes.dbc` as the group table, `SpellVisualKit` field 14 is the shake column (58 of 1772 kits carry one — War Stomp, Thunder Clap, Kodo Stomp, the ~50 Knockdown/Slam/Charge impacts, every summon, Sapper Charge, Earthquake, Sapphiron's death), and the kit shake fires exactly once per play from the first effect node's one-time arm pass (`0x620e11`), the same leg that plays the kit sound one field over — the older "fires only if nothing else did" reading would have silenced every kit with a populated effect slot; `$SHK` markers fire from GameObject and DynamicObject hosts only (the titan chest, the bomb wagon); one deliberate deviation — the reference reads a bone-attached node's position twelve instructions before it is written, so 26 of its 58 shake kits shake at the world origin and are culled by the 80 yd cut, which is an uninitialised field, not a design; 21 of 24 presets now have a live producer, up from 6
- the sound keeps playing when the window loses focus, if you want it to: 1.12 mutes everything on `WM_ACTIVATE` and offers no way out, so benilla ships that as the default (`Sound_EnableSoundWhenGameIsInBG` "0") and puts an Audio-page checkbox on it — a gate appended LAST in the main-track chain, downstream of every tap, so an unattended capture still records; wow-re's round settled that music is not exempt and that it is a mute, not a pause
- a building's far side no longer draws through its own walls: the camera-inside leg has three passes and we had one and a half — Pass 2 admits an exterior-shell group only against a frustum clipped to ONE deferred window (we marked every such group visible against the full view, under a comment calling it a benign over-draw), and Pass 3, which we had none of, draws the 24 `0x10000` groups (14 in Stormwind, 6 across Dire Maul, Razorfen's four 450–520 yd shells) from anywhere, frustum-tested on both legs by byte-identical setup; there is no antiportal branch in 5875 and no such flag in its data (815/815 roots and 5220/5220 groups censused, no bit above 18 ever set)
- the macro window is the reference's own `Blizzard_MacroUI`, and `GlobalStrings.lua` — line 1 of the reference's own toc — was missing from our manifest entirely (the app loaded it out of band at startup, so the client was right and every harness that loaded the manifest was not); exactly one `<OnLoad>` runs, the most-derived, because `SetScript` releases the slot before it looks at the new body — which is why the reference re-states the template's width line in tab 1 and not tab 2

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:07:15 +07:00
SamandClaude Fable 5.1 b45bce8184 bindings answer the reference's shapes, and the panel kit goes stock
- four return shapes were wrong — `UnitPowerType` returns ONE value in 5875 (the Era `(type, "RAGE")` pair does not exist, and its miss arm pushes the NUMBER 0, which `UnitFrame.lua:122` indexes `ManaBarColor` with), `UnitName` returns `(name, server)`, `GetTexCoord` returns EIGHT (ours four — a shape that exists nowhere, with zero call sites in FrameXML, so only the binary could have caught it), `GetLootMethod` answers `freeforall` ungrouped — the fifth right-name-wrong-arity finding in two days, so wow-re's `binding-shapes.tsv` (1722 rows over all 82 registrar tables) is vendored and a gate probes every binding's arity against it: 313 probes, eight divergences (seven global, one widget); `GetBuildInfo` pushed a fourth value no 1.12 client does (458 corpus sites take one, the four that destructure a fourth read nil on the real client), `GetAddOnInfo` RAISES on a numeric index, `Model:GetFogColor` is a packed `0xAARRGGBB` dword with no unset state, and the five miss branches are the reference's exact tuples
- the panel-template kit is the reference's own `UIPanelTemplates` pair (our 18 templates were a strict subset — `TabButtonTemplate` and the `ScrollingEdit_*` family arrive, which unblocks the macro window and HelpFrame), and the swap found two structural facts: `FauxScrollFrameTemplate` is a `<ScrollFrame>` while every instance we declared was a `<Frame>` (fifteen elements across twelve files), and an instance `<OnLoad>` REPLACES the template's — four FriendsFrame lists set `updateFunc` in their own OnLoad, so `ScrollFrame_OnLoad` never ran and guild/friends/ignore/who had been silently painting nothing behind a `frame.offset or 0`
- the options widget kit (`OptionFrameBoxTemplate`, `OptionsButtonTemplate`, `OptionsCheckButtonTemplate`, `OptionsSliderTemplate`) comes off the chain too, giving back the reference's own per-widget hover; one template of ours stays because `UIOptionsFrame.xml` is not built here, and the lesson is general — when a file SHRINKS rather than dies, every harness that named it gains the chain entry beside it, not instead of it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:06:36 +07:00
SamandClaude Fable 5.1 7e3a67a02e the unit frames are the reference's own, and the water has motes in it
- the player, party, target and pet frames are the reference's own files (`BuffFrame`, `UnitFrame`, `CombatFeedback`, `PlayerFrame`, `PartyFrame`, `TargetFrame`, `PetFrame`, in the reference's toc order) — our 2741-line `UnitFrames.xml` and our `PartyFrame.xml` are deleted; four engine verbs built for them (`PartialPlayTime`, `NoPlayTime`, `UnitPlayerControlled`, `UnitIsCivilian`, each answering 1/nil), the whole-UI load bracketed in the counted sound-suppression scope `0x48fbf0` self-brackets (the reference fires a `PlaySound` during load and throws it away), and `GetBillingTimeRested` read off `SMSG_AUTH_RESPONSE`'s third billing field rather than hardcoded; the differences the stock files bring are pinned rather than papered — `PlayerFrame` never hides, an unresolved name is BLANK not "Unknown", the target frame has no numerals at all (a bar hover pops the unit tooltip instead)
- what the swap surfaced, each a hard break under the stock files: `UnitBuff`/`UnitDebuff` returned the Classic Era ten-value tuple, name first, where 1.12 returns two and three values TEXTURE first (`0x519500`/`0x5198f0`) — a raise twice per `UNIT_AURA` on any debuffed target, and all 184 corpus call sites bind the 1.12 shape; the power events are named per resource (`UNIT_MANA`/`RAGE`/`FOCUS`/`ENERGY`/`HAPPINESS` and their MAX twins) and we fired the Era pair, so no mana, rage or energy bar could live-update; `SetRaidTarget` is the engine verb and `SetRaidTargetIcon` the FrameXML toggle wrapper — we had registered the wrapper's name on the engine's body, so every raid mark in the unit popup raised
- the underwater drift cloud: the reference draws a fixed 4000-mote field whenever the camera eye is inside a liquid — not a particle system, nothing spawns, ages or dies; a population scattered once into a 30 yd camera-relative cube, advected by the camera's own motion plus a gust and wrapped, so the field stands still in the world; benilla had the murk and nothing in it; a dry frame commits no draw, and the submerged one is bounded by the reference's own 666-quad cap (633–644 of 4000 measured live, which is the expected survivor count of a uniform cube through the 90° cone — an independent check on population, distribution and cone at once)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:04:32 +07:00
SamandClaude Fable 5.1 6bafea0919 your character speaks its refusals, and clicks land on the right frame
- your character speaks its refusals: `VocalUISounds.dbc` gets an adapter, `sound::vocal` transcribes `0x4580f0`'s per-race table and `0x458250`'s play cycle — four plays of one line arm the annoyed variations, and the bus cap of one keeps the annoyed and ordinary lines from playing at once; a displayed message now carries its catalog RECORD, so its sound comes off the same row (tag 0x44 plays the named cue, anything else speaks the line), and 36 of the keys benilla raises have a voice — cast failures, inventory refusals, the quest/auction/petition lines, taxi, bank, stable, mail, the talent wipe; `EnableErrorSpeech` joins the CVars at the registrar's own default and the Audio page grows 1.12's fourth Sound checkbox with the dependency ours was missing (the master greys Ambience AND Error Speech, not Music); seven of the twelve taxi refusals turn out to be the YELLOW info line, not the red one they all took
- at equal (strata, level) the hit sweep takes the EARLIER-linked frame: `0x764aa0` inserts with a strict `ja`, so equal keys are appended, and `0x7660d0` sweeps each bucket from index 0 upward — the reverse of the reverse-draw-order walk we had, so draw order is unchanged and only the hit sweep reorders within a plane; the wheel becomes its own index, and the five full-area wheel-catcher Buttons (Craft, QuestLog, Skill, TradeSkill, Trainer) are deleted, since under the true tie law each would have swallowed its whole window's clicks — a bug the Skill window's own comment had already recorded once
- one rasterizer settle for the whole ground-decal family, and it is the measured one: the shipped client constructs `CGxDeviceD3d`, so the OpenGL arm holding the −4.0 slope factor is never executed (factor 0 on 2485 of 2485 captured `glPolygonOffset` calls), and every number derived from it was 256× too small; the reference groups the blob shadow with the selection RING and the footprints on their own at 10×, the reverse of ours — but ours is reversed-Z float where the bake residual is millimetre-scale and constant with distance, so `DECAL_RASTER` collapses to one value (32768: the ring and the reticle had been under their own conflict at 8192 and simply never walked on a slope)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:03:50 +07:00
SamandClaude Fable 5.1 cac6e88145 settings boot at 1.12's defaults, and a cold loot no longer errors
- a setting's default is the reference's, enforced: eight player-facing options booted at something a stock client does not — `UnitNameNPC`, `UnitNameOwn`, `nameplateShowEnemies`, `ChatBubblesParty`, `cameraDistanceMaxFactor`, `QUEST_FADING_DISABLE`, `SHOW_BUFF_DURATIONS`, `SHOW_COMBAT_TEXT` — each a defensible "turn this on so I can see it while you build it" on its day and invisible as a set; the CVar table grows a mandatory `Reference` column (Same / Overridden / Deviates-with-reason) that a test checks in both directions, the FrameXML saved-variable store is compared against the reference's own `UIOptionsFrame.lua` off the chain (which found `SHOW_COMBAT_TEXT`, declared inside a table walked by a loop where a grep could not see it), and the wow-re census of all 214 `CVar::Register` sites folded in — `WorldDetail` back to `same`, since `GetWorldDetail` reads only `SmallCull` and the reference's own slider reads Medium at boot
- looting on a cold item cache raised `LootFrame.lua:85: attempt to index local 'color'` out of the stock window: `GetLootSlotInfo` answered nil where the reference answers cache-miss SENTINELS — quality −1 (which is exactly why stock `UIParent.lua` builds `ITEM_QUALITY_COLORS` over `for i = -1, 6`), "" for a name in flight, `INV_Misc_QuestionMark` for a display-info miss — and four values on every leg (`mov eax,4` at `0x4c2d07` is unconditional); `GetLootRollItemInfo` takes its own miss tail (`nil, nil, 1.0, 1.0, nil`), `GetItemQualityColor(-1)` reads Common because the compare is unsigned, and the window now WAITS for every item template before opening as `0x4c1cb0` does — there is no repaint path in 1.12 to fall back on, so deferring IS the mechanism
- the coin row is quality 0 (grey), not white — `0x4c23a0`'s coin leg falls to `xor eax,eax` before the item-cache read — and its icon walks the reference's six-step ladder (`0x6c6307`: one icon per decade of copper; two of the six were not in our set at all, and the pairs do not fall where "highest nonzero denomination" put them)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:02:34 +07:00
SamandClaude Fable 5.1 c5df478c51 the buff bar goes stock, and gossip quests show their level
- the buff bar is the reference's own `BuffFrame.xml`, and the swap found an engine defect: an empty `<OnLoad>` in 1.12's XML is a BLANK that takes an inherited handler away again (seven such sites across four stock files), which our loader read as "none given" — so the two enchant slots would have painted the player's first buff in the corner and cancelled it on right-click; the first fix then had to be corrected at the bytes (`SetScript 0x7025c0` tests only NULL and empty, and nothing trims, so `<OnLoad>↵</OnLoad>` compiles to a valid empty function rather than storing nil, which any addon calling `GetScript` can observe); `SHOW_BUFF_DURATIONS` is applied once post-load because 1.12 leaves that to `UIOptionsFrame.lua`, which benilla does not build — without it the bar ships a 10px pitch error on every buff
- gossip quests come through the reference's four verbs — `GetGossipAvailableQuests`/`GetGossipActiveQuests` returning (title, level) PAIRS, with the two `Select*` verbs indexing into that list — replacing three invented names that sat on the beyond-1.12 exception list; the quest LEVEL was on the wire, parsed and dropped because the invented verb had nowhere to put it, and the reference's order (available before active, whatever the packet interleaved) comes with them
- eight more files off the chain as groundwork: `LocaleProperties.lua` (the gendered/plural `GetText` selector that eleven stock call sites read their words through — fifty lines of FrameXML that looked like an engine binding), `CinematicFrame.xml`, the UIMenu kit, the `UnitFrame.lua`/`CombatFeedback.lua` kits (the only two names blocking the stock player, party, target and pet frames), the money-input kit, and `ItemButtonTemplate.xml` — the base every bag, bank, merchant, loot, trade and mail slot inherits; `GetMerchantItemMaxStack` (on the wire the whole time, dropped) and the two trade item-link verbs join the engine
- two instruments for the migration: a gap report that reads a stock window's call sites against a LOADED VM and says which engine verbs it still needs (28 windows need none, the rest name 1–5), and the readiness probe's documented false positive — loading a stock window on top of our same-named one leaves `getglobal(name)` pointing at ours while the stock handlers run against theirs, so a failure inside a colliding name is a question, not an answer

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 16:58:47 +07:00
SamandClaude Fable 5 3d0bc38978 trades answer the reference's way, and the message catalog is a table
- an incoming trade request is answered by the reference's eight-leg ladder, not by reflex — before, `CMSG_BEGIN_TRADE` went back the same frame it decoded, so any player in range could put a window on your screen mid-cinematic, mid-loading, while mind-controlled, at an auctioneer, or from your own ignore list; three legs answer with something other than "busy" (the ignore list sends `CMSG_IGNORE_TRADE`, two legs send no packet at all), Block Trades ships as the CVar and options row it is in 1.12 with its refusal on the chat line the catalog says, and the consent popup that was built came back out — 1.12 signals the trade dialog from nowhere, so asking first would be a divergence every player and addon feels, and the reference's answer to an unwanted trade is already in the ladder
- the client's message catalog ships as a generated table instead of being read by eye: every refusal, notice and confirmation goes through one dispatcher taking only a message id into a 465-record registry, benilla names 163 of the keys, and the surface does not follow the key names — the byte-exact sweep settles 170 chat / 28 yellow / 267 red, none on the console arm, with the skill-up trio speaking CHAT_MSG_SKILL rather than system; a message's surface now comes from its record, not its call site, which found `ERR_SPELL_FAILED_NOTUNSHEATHED` painted red where the client paints it yellow (seventeen of our eighteen cast-fail overrides are red; that one is not, and nothing downstream could have known which id the dispatch chose) — and a new test walks the workspace's own source asserting every `ERR_` literal is a real catalog row, because an unresolvable key shows NOTHING and nobody files a bug about a toast they never saw
- starting an attack stands you up — the stand sits after the reference's attackability cluster and before any range logic, so an attackable target out of reach stands you, a friendly NPC does not, and re-issuing an attack you are already making stands you too; the rest of the intended build is proven unnecessary rather than deferred: bare ground cannot stand you on any client (its two requirements are mutually exclusive in both CVar configurations), gossip is proven not to stand, and the loot leg is unproven and left alone
- a kick returns you to the login screen again instead of the client reconnecting indefinitely and taking the account back off whoever kicked it: "nobody is here" is DECLARED now, never inferred — the login environment variables answer "log in without waiting for someone to type", which cannot answer "is anybody here?", so a run acts unattended only on `$WOW_UNATTENDED` (implied by a capture or rig run), with the doubt deliberately falling toward a loud probe timeout over a silent account fight; and the player-tests gate finally resolves the install that sourcing FrameXML off the chain has required, instead of failing red for its own reasons on any shell without `$WOW_DATA` exported

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:20:07 +07:00
SamandClaude Fable 5 c4f432d0c3 the world map blips are the reference's, and particles go untinted
- the world map speaks the reference's names: WorldMapTooltip is declared (six corpus addons index it; pfUI dies on it at file scope), the blackout frame takes the reference's spelling BlackoutWorld, and the four hand-written party blips become the reference's own unit-blip templates — all 44 blips as instances, each with its published $parentIcon, the name pfUI recolours group blips by class through; the 40 raid ones are declared but not positioned yet, named in the OUT list rather than faked
- the templates addons build their own buttons from are published: ItemButtonTemplate, ContainerFrameItemButtonTemplate and the bag-slot chain — most of the handler scripts were live the whole time (this client executes the reference's own container and paper-doll code off the player's patch chain), so what was missing was mostly declarations, not behaviour — the bank arm stays out and is named as the omission it is; OptionsFrameSliders becomes real, with the three Graphics rows reading it and re-reading on show, so an addon's write to a slider's bounds actually moves the slider; and the template census that had ranked these at "zero demand" learns to see a local bound to a literal — its table went from 3 rows to 7
- the bindings answer in 1.12's own shapes: Button:IsEnabled() answers the NUMBER 1 or 0 (0 is truthy in Lua, so the reference's own == 0 tests got false forever, and three of our files had hand-worked around the divergence rather than fixed it); the constructors' string arguments are four shapes, not one rule — pfUI passes a Button where a template name goes and the reference constructs the FontString and ignores it; SetInventoryItem returns THREE values, the reference's own paper doll destructuring repairCost; UnitIsVisible is object presence and nothing else (57 bytes, one branch, no distance — an out-of-range party member is exists-yes, visible-nil); the tapped pair reads the two dynamic-flags bits, and its repaint wire fires UNIT_FACTION on the tap bit — the half a passing predicate test never sees; UnitIsPartyLeader is two ORed legs covering disjoint failures (a held stranger leading their own party, and an out-of-range member with no object to read a flag from); and the four nameplate verbs take no argument and return zero values
- the ghost's wisps compose onto its body instead of over it — the four emitters drew at full strength over a body at alpha 0.5, and now inherit the instance alpha down the attachment chain the way the reference recomposes it per frame; the residual we had parked ("the wisps should inherit the tint too") is REFUTED at the bytes: a particle batch commits hardcoded white RGB, and even that never reaches the fragment — particles are never tinted, only the alpha crosses, applied to the alpha byte alone — so the shipped shader split was already right and no code changes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:15:16 +07:00
SamandClaude Fable 5 d245535e68 the HUD becomes UIParent's child, and cinematics fade through black
- the transcription had dropped parent= on 72 declarations the reference carries (37 to UIParent, 28 to the action bar's art frame, 7 more), so the HUD was a field of top-level frames and UIParent:Hide() reached almost nothing — which is why a cinematic had to hide the UI at the draw level and then special-case the pointer; both workarounds are deleted and the HUD hides through the reference's own route; restoring only the UIParent half would have been the dangerous part (draw order is one flat sort, so a partial restore lifts frames over the neighbours they carry), and manifest order turns out to be load-bearing — a parent name that doesn't exist yet is silently ignored, so UIParent.xml moves to the reference's own slot with a test that fails if anything declares a child first; the chat still drew over a fly-by after all that, because the reference parents the chat windows on their TEMPLATE, invisible to a name-for-name diff when both sides rename — two declarations fix it, and the sweep that replaces the method loads the whole shipped manifest, fires CINEMATIC_START and asserts the survivors are exactly three: 91 frames visible before, 3 after, and the count comes back on stop
- every cinematic boundary cuts through the reference's 0.25 s fade to black, and the next step hangs on the fade's COMPLETION, not a delay — the shot boundary is exactly where the reference does a blocking terrain load, so a delay-driven cut shows through a hitch and a completion-driven one cannot; and a fly-by now ends into black instead of a ~0.3 s loading cover: the reference raises no cover on that path, it holds black while the ground under the player loads back, so ours holds black while the stream catches up — budgeted, never an unbounded wait
- the death arc keeps its promises across a relog: the body's own state machine now dies with the session — re-entering the world as a ghost used to match no arm of the world-edge machine, so the corpse query never went out and "Resurrect Now" stayed down until the next death; and a corpse wears its owner's guild crest — the corpse descriptor carries the guild field and resolves through the same crest cache a living tabard does, where ours dressed the body crestless
- the char-select ghost gets its body kit: the screen resolves the state kit of the very "Ghost" aura a released ghost rides in the world — tint (140,185,253), alpha 0.5, and the Ghost_state wisp model at the body's attach point, pinned by a golden that decodes the row out of the shipped DBC; the airborne model is corrected before its fix lands — the address six comments called the gravity integrator is really the fall-velocity query, and a knockback is unsteerable because its launch PLANTS the forward bit, not because the arc is airborne (our guard was a velocity proxy, so a near-zero-speed knockback steered from frame 2); and the hover inspect card now decodes a picked part's mesh tag — alpha, rig slot, and both readings of the lighting payload side by side — turning a rebuild-and-two-probes hunt into a hover

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:13:31 +07:00
SamandClaude Fable 5 67c0c000fb the world redraws on resize, and terrain takes its DXT blocks
- the world froze on every resize or graphics change: the backdrop was resized by writing a fresh image through the existing handle, and a mutated `Image` is a whole new GPU texture while a material's bind group is captured once and never re-captured — so the camera drew into a texture the UI never sampled, and the last frame stretched over the window forever; a resized world target is now a NEW asset (publish, retire the old one, and the UI pass forgets materials for removed images so a window drag does not leak a 46 MB target per frame), and a resized capture now matches the native render bit for bit
- terrain tile layer arrays take the DXT blocks when the tile's whole layer set allows it — one array has one format, so eligibility is the tile's, not a texture's — and the install's own census says narrow is enough: 87 % of Azeroth's tiles and 92 % of Kalimdor's pass, layer bytes 1.57 GB → 0.63 and 2.23 → 0.76; the decode-tax comment is corrected on the way past — decoding costs 8x DXT1's bytes and 4x DXT3/DXT5's, not 4x and 2x
- Environment Detail is the reference's slider, not a dropdown — row 27 of 1.12's own slider table, with the readout keeping the stop names because a bare "1" means nothing to a player — and the shipped ground cover comes off High to Medium: the x3 clutter density had been matched to a configured install, and Medium is the nearest stop no sparser than what a fresh install draws on capable hardware
- Display Mode is modern Classic's two-entry dropdown — Windowed (Fullscreen) / Windowed, a boolean at Blizzard's own source, where the three-mode list is pre-8.0.1 folklore — riding `gxWindow` so saved configs keep meaning, with the label-against-value polarity pinned by the row's first test; the Multisampling row comes off the Graphics page for now (the CVar, the device clamp and the bindings all stay): with alpha-to-coverage set nowhere, MSAA touches polygon silhouettes only, and render scale on the same page measures four times the visual change

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:16:01 +07:00
SamandClaude Fable 5 3cc24f14be the world shrinks without the UI, and a party member keeps their face
- `renderScale`: the world renders into its off-screen target at a fraction — or a multiple — of the window while text, icons and frame art stay native; the logical viewport comes out arithmetically unchanged, so picking cannot see the scale at all, and every hand-written sampler takes the `log2(scale)` mip bias below 100 % and none above it, where the sharper mip is what makes supersampling work — measured here at 26x the world pixels for +0.02 ms, and reachable as a Render Scale row on the Graphics page (50–200 %), staged to Apply so a dragged slider rebuilds the world target once instead of thirty times a sweep
- a party member who walks out of range keeps their numbers and their face (B334): the client asks — `CMSG_REQUEST_PARTY_MEMBER_STATS` goes out on the despawn edge and for a roster member gained unseen, the same two edges the reference sends from — the record is snapshotted whole from the live descriptor at the moment the object deactivates, a never-seen member seats at the reference's 1/1 placeholder rather than an empty bar, and the raw-to-display divide happens at the read, so an out-of-range warrior stops reading ten times the rage; the portrait binds a guid-keyed bake cache built as a handover — the booth's own target image moves into the cache as its member streams out, so the face freezes with no copy and no flicker — and the self-review adds that a changed occupant is a re-bake and the record's dead/ghost bits are read
- a slider row's number sits on its label's line (B232): the readout hung off the control frame and inherited a +3 art nudge that exists to seat the groove texture — four pixels off on an eleven-pixel cap height at the reporter's geometry — so the nudge moves onto the two frames that draw the art, across eight rows on three pages, and the bar itself does not move a pixel; `$WOW_DPI` renders on a player's pixel grid, so a 1x reporter's screenshot and a capture from this 2x machine compare pixel-for-pixel

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:15:06 +07:00
SamandClaude Fable 5 45f001bbc5 the hover tax is pinned and cut, and a spell-less macro is a button
- a tooltip change costs ~1.3 ms — five whole-interface recomputes, each working as designed: the quad re-convert at 474 µs, the Lua tick at 287, the layout resolve at 200, bevy's `Assets<Mesh>` tax at ~270 and the mesh rebuild at 146 — pinned with new hover probes (a jitter dial, a `WOW_PROBE_HOVER_DUTY` duty cycle so run drift cancels, an `AssetChanged` tax meter), and the layout preamble's two whole-roster scans become lists maintained at the writer (52–83 µs → 1–11)
- the splice compared this frame's entries against last frame's by index, so one inserted highlight shifted the 160 entries behind it and read as "everything changed"; it now aligns on `z` — an identity, not a position — and a `Text` entry that writes only quads became spliceable, so a tooltip change re-converts 22 entries instead of 520 (`convert` +439 µs → +107), with `WOW_UI_SPLICE_VERIFY` running the full conversion behind every spliced frame: 0 mismatches over 1,078
- a spell-less macro is a usable action button, not the 0.4 grey — the reference's usable compute has a dedicated leg answering usable for the bound-spell zero, cross-checked at the bytes in the reference's disassembly — and the button's Name line is written unconditionally from `GetActionText` as the reference does, so the macro's name sits under its icon and a `/cast` of a spell the character does not know now greys, which is also 1.12's behaviour (B340)
- a capture bounds its run in wall-clock seconds, because a frame cap is no cap at the ~1 fps a starved `nextDrawable` leaves — 1800 frames is thirty minutes there — and the teardown backstop runs on every run as a liveness guarantee, carrying the exit code the run asked for; the Multisampling row reads Off / 2x / 4x, since "1x" contradicts the no-multisampling byte both of the reference's enumerators normalise to and the bit-depth prefix was identical on every row

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:13:58 +07:00
SamandClaude Fable 5 a0447c171d action-bar hover stops re-deriving, and multisampling asks the GPU
- hovering the action bars re-derived the whole layout graph and hovering bags did not: `GameTooltip:SetOwner(owner, "ANCHOR_NONE")` dropped the tooltip's anchors through the conservative whole-graph derive, and with `UberTooltips` at its shipped default every action-bar button routes through that arm while a bag slot anchors `ANCHOR_RIGHT` and never does — the arm now retargets to the empty target set, and derive frames fall from 15.9 % of hovered frames to 0.2 %
- `gxMultisample` clamps to what the GPU actually offers: Apple GPUs stop at 4x, so a typed 8 was a wgpu validation panic on frame one — the clamp intersects the supported counts of every format the client multisamples into and steps the request down the way the reference's device-init retry loop does, with a warning that says so
- the Multisampling dropdown lands on the Graphics page with the device's own stops, built from the same enumeration that clamps a typed value on the reference's three bindings (`GetMultisampleFormats`, `GetCurrentMultisampleFormat`, `SetMultisampleFormat`) — a fixed Off/2x/4x/8x ladder would put a crash on the menu of every GPU that stops at 4
- capture hardening: a run whose `$WOW_WIN` the display clamped is refused in ~2 s instead of producing a wrong-sized shot to diff, a capture never reads the OS pointer (a cursor resting over the window arms a hover and a tooltip that a cursor an inch to the left does not), and the stall sampler writes into `benilla-config` instead of a hand-built `~/Library/Logs` path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:13:27 +07:00
SamandClaude Fable 5 a60f723ad4 borderless fullscreen ships, and the 4x MSAA nobody chose is off
- the display mode is borderless fullscreen by default, and there is no exclusive mode at all — winit ignores exclusive on Wayland, X11's path cannot restore the desktop after a crash, macOS has none, and WoW itself dropped it in 8.0.1; 1.12's `gxWindow` row keeps its name, polarity and default with "0" redefined as borderless, read before the window exists so it is born in the player's mode (a window that does not fill gamescope's nested output is a documented input break, and the recorded workaround is "set the game to fullscreen"), `gxResolution` remembers the windowed size, and the Graphics page grows 1.12's own Windowed Mode checkbox
- the UI camera says `Msaa::Off` out loud, because silence there meant Bevy's default 4×: the world arrives on this camera as an already-resolved quad and everything it draws itself is axis-aligned rects, so four samples bought a 4× colour target, a 4× depth texture nothing ever writes, 4× the fill on every quad and a resolve — for a measured difference of MAE ≤ 0.024, all of it quad borders now drawn at their authored crispness, which is also the reference's hard-edged 8-bit direction
- `gxMultisample` is a real player setting, and it ships off — the reference's own default: the reference registers no literal, it formats field 21 of the `VideoHardware.dbc` row the GPU matched, a 193-row table that holds nothing above 2 anywhere and whose every 2004-era id misses a modern card, so the fallback rows answer and all of them hold 1; the setting persists, all three world-lane cameras read it on the reference's [1,16] scale rounded down the way its own retry loop steps, and `$WOW_MSAA` survives session-only
- two instruments for the tooltip hunt: `rebuild_ui_mesh` — which sorts, clips and re-splits every quad in the interface on any dirty frame — gets a meter carrying total/sort/split/write beside the script phases whose flat reading had stood as an alibi, and `WOW_PROBE_HOVER` sweeps the real cursor across named frames through the real pointer path, pressing nothing: the hover recorder records what a hand does, and this supplies the hand

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:12:37 +07:00
SamandClaude Fable 5 10874da37f clicks find their target, the booth eases off, and the map's lines go
- the world camera's pick regression: its off-screen render target carried `scale_factor: 1.0`, so on a Retina display the camera reported physical pixels as logical and a centred cursor cast its pick ray into the upper-left quadrant — unit and GameObject picks, the occlusion ray, chat bubbles and `world_to_viewport` all broke at once; the target now carries the window's real scale factor, re-stamped when dragging between displays changes it mid-session — and the perf pill's overlap dodge had the same disease in miniature (`GetBottom()` answers in WoW UI units, the pill lays out in window px), so it now answers a fraction of the screen and works at any window height
- `boothHalfRate` defaults back to half-rate: a body pane's off-screen booth pass rendered every frame reads +7.6 ms of GPU at 4K (~1.6 ms at 1600×900), on exactly the weak GPUs that felt the last snapshot — the doll's item effects keep full speed, since they key on the pacing regime rather than the camera's active bit, so only the 30 fps animation cadence returns, and full-rate stays one `SetCVar` away
- a spell cast by a GameObject arrives with caster guid 0 — vmangos writes the caster slot from a `Unit*` its GameObject constructor never sets — and the whole visual body was dropped at the guid lookup; the decode now reads an empty caster slot as the packet's first guid, which with no cast item IS the caster, so the Lightwell's click plays its impact kit (sound 3155 and the head flash) instead of only the aura glow that hid the miss, and the object stops being mislabelled a cast item
- the world map's black hairlines: a `SetTexCoord` crop is not a texture, and a POI icon magnified to 2.08 px per texel sampled half a texel past its crop into the neighbouring atlas cell — an opaque black row bleeding over a cell that is fully transparent (the empty cell is the reference's own zone-level substitution); `UiQuad::uv_clamp` now insets the sampling window half a texel per axis, so a crop renders as if its sub-rect were its own clamped texture, and `WOW_UI_PICK=x,y` names every quad under a pixel — it found this one in a single run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:09:56 +07:00
SamandClaude Fable 5 343e46fdde the chat tab's right-click menu, and Options gets its Chat page
- right-click a chat tab for its menu: background colour and alpha through the colour picker, font size — three of GetChatWindowInfo's nine values are real state now, persisted per character in benilla-config/chat, and the hover fade interpolates from the window's own stored alpha as the reference's guard does (the default look is unchanged, pinned)
- the Social page becomes the Chat page 1.12 has, in the reference's anchor order: Remove Chat Hover Delay and Detailed Loot Information join, and `showLootSpam` off collapses the roll chatter to the winner line with its number; Guild Member Alert is registered at the reference's default, off
- two guild-line defects found while settling that CVar: the sign-on line's fourth conjunct is a friends-list test (an ignored guildmate was silenced, a guildmate who is also a friend announced twice), and vmangos broadcasts your own sign-on, which benilla announced to you at every login

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:45:45 +07:00
SamandClaude Fable 5 ab235bad6e the target-of-target frame, and talents can be unlearned again
- the target-of-target frame and its option: 1.12's frame with its five display modes, fed one hop off the selected unit's own target field through the same read `/assist` runs, in four feeds (snapshot and transitions, the debuff buttons, the portrait booth, TargetUnit's click arm); ships off, as 1.12 does, on its own pair of saved globals
- talents can be unlearned again: the trainer's `MSG_TALENT_WIPE_CONFIRM` had no handler since the wipe flow was deferred, so the gossip line closed the menu and did nothing — the question is an NPC session (walking away retracts it), the popup shows the cost on the StaticPopup money variant, Accept answers it behind the client's own purse check
- Sprint's sparkles hang in the air behind you along the trail instead of collapsing into your torso: ride-vs-trail is the emitter's own file flag 0x10, not the host class — the finding wow-re returned eighteen days ago and nobody folded; the particle dump names the two flag bits it had been mis-reporting
- `/sleep` takes both movement masks (the strictest posture), correcting the day's sit gate which let you lie down on a lake bottom while `/sit` was refused; a Lua-driven selection (TargetUnit on an attackable token) starts the swing exactly as a click does, through the one select path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:40:16 +07:00
SamandClaude Fable 5 cf581aa2ac the auction house opens, the Honor tab lands, and a day of fixes
- the auction house end to end: right-clicking an auctioneer opens Browse/Bids/Auctions on the server's reply — search, the category tree from your own DBCs, the reference's 50-a-page pager, multi-key sorting (directions corrected at the bytes), bid/buyout, the sell slot with deposit and duration, cancel with its fee popup; prices sit on the reference's own money-frame kit in lined-up columns, the twenty auction messages split refusals-red / outcomes-to-chat, and a won or sold auction reads as a proper mail receipt — the window's Lua re-worded in our own terms after the overlap ratchet caught the first cut leaning on the reference's text
- the PvP honor system whole: the Honor tab and the inspect page over a real wire model, with current rank and highest-ever rank correctly two different fields
- a day of reported fixes: WASD survives a /logout re-entry, addon settings save on a window close and Cmd+Q (exactly once — a mac close could fire the tail twice), clams open again, random-enchant items name themselves on every surface, the loot window's rows hold their seats with legible counts, idle players stop sinking through building floors, the shooter re-pulls between Auto Shots, portraits loosen ~19% to the client's own aspect-1.0 matrix, and big creatures thump the camera off the CameraShakes table
- character select clicks like 1.12 — captions whiten on hover, buttons fire on release, Humans face straight ahead off the stage bone's real yaw, the facing is per-character, and hunter/warlock pets stand beside you at their family-ramp size with their own emitters (the imp's flames), the Voidwalker's sequence-hidden shackles culled
- the smaller player-facing set: nameplate on/off rows in Options with the CanAttack category gate (emissaries stop plating), the bonus bar slides up with igBonusBarOpen, the camera's framing height glides on a shapeshift, the open letter evicts the centre seat, the far-band fog hull stops printing a pale horizon stripe at low view distance, the guide arrow is gold with per-source rim art, error text fades through its shadow too, and /convertraid converts the party
- README: the auction house and PvP honor move out of "not built yet"

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:04:27 +07:00
SamandClaude Fable 5 f8e312d015 Terrain Distance returns to Graphics, and guards flag your map
- the Terrain Distance slider is back on Options → Graphics, in its 1.12 seat and range (177–777, live, no Apply) — and it now drives how much world is resident, not just how far you see: the streamer derives its resident and prefetch windows from farclip in the reference's own chunk units, pulling the ring in as you drag left and streaming it back one tile per frame as you drag right; the `WOW_TILE_RADIUS` env var, the debug panel's farclip slider and a dressed-up fog constant all retire into it
- ask a city guard for directions and the destination lands on your maps: `SMSG_GOSSIP_POI` becomes a red flag drawn through the same landmark path as towns and inns — an icon in place when near, competing for a rim arrow when off the edge — and the world map's landmark enumeration answers now, so the flag renders there too and names itself on hover
- the flag is one slot (new directions replace the last), drops itself within 10 yards of the destination, expires after the reference's own 480 seconds, and clears on any world entry; the rim-arrow rank rides the packet's own field, not a guessed constant

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:18:30 +07:00
SamandClaude Fable 5 348f55e37e four extra action bars as options, and the bottom band gets one owner
- the four extra action bars become per-character options, off by default, on a new Action Bars options page — the toggles ride the server's own byte (`CMSG_SET_ACTIONBAR_TOGGLES` into `PLAYER_FIELD_BYTES`), so a fresh character's zero is the default for free; turning the bottom-left bar off gives the stance bar its previously unbuilt unraised look, end-caps and 64×64 rings
- bag windows stop drawing straight through a raised bottom bar: the bottom band has ONE owner — the manage pass — the bag stack joins it through a listener seam, and a guard test walks all eight raisable-bar combinations across 24 bar/tenant pairs and refuses overlap
- the item-push card takes the reference's real geometry, closing the gap 0887 measured
- resizable addon windows stop at their bounds instead of pinning and walking across the screen: four per-frame f32s with 0.0 the disable sentinel, the clamp on the interactive drag only with the residual rebated out of the drag delta, `<ResizeBounds>` in XML honoured — and `SetFontString`'s three raises land exactly as the bytes have them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:12:19 +07:00
SamandClaude Fable 5 6b05373630 Quiver loads, teleports stop losing the city, the camera eases right
- Quiver works end to end (the reported nil-field error): 1.12's widget method tables are flat, so the 19 Region methods are ONE function per name — a frame's `GetHeight` IS the texture's — where we had two implementations behind two disjoint registries; `Button:SetFontString` and the Set/GetMin/MaxResize quad land with it, and the 219-addon survey moves loads-without-error 150 → 151 with every other addon byte-identical
- a teleport stops dropping you into a bare city: the reveal gate now waits on geometry that can actually draw (14 regions had sat undrawn for 630 ms with the cover already down), a relocating snap ≥100 yd raises the cover, and the pipeline warm pass runs once per process — a far same-map teleport's cover drops 3.8 s → 0.8 s
- the empty-world flash on a fully-resident teleport dies with it: the camera's world pose publishes before anything in Update reads it, so the visibility verdict stops being computed up to 644 yd from the eye — the lag reads 0 yd on every snap frame of every arm
- the camera follow becomes the engine's own curve — an edge-armed cosine smoothstep clamped to 0.1–2 s behind a 7-state input classifier, the enum 0/1/2 with Smart staying the default — and overlapping chat bubbles stack as whole cards, one frame level per bubble, nearest to the camera on top

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:10:46 +07:00
SamandClaude Fable 5 c9fe3d7a48 the camera follows again, /errors opens the log, cmangos lets you in
- the camera auto-follow returns, as a setting: Camera Following Style on the Controls options page — Smart (the default), Always, Never — so after an orbit drag the camera swings back behind you while you run; far sight still forces the chase off
- broken addons announce themselves: world entry prints "3 addon load failures — type /errors to see them", and the `/errors` window lists every script error this session with its traceback — 256 deduplicated rows, repeats collapsing onto a count — while the five load-failure classes that only ever hit the terminal (missing .toc, unparseable FrameXML, dependency cycles…) finally get a channel
- B opens the backpack alone, SHIFT-B opens all bags, F8–F11 toggle the individual slots — the reference's six bag commands instead of one command wearing every chord; and the Skills page gets its CLOSE button, with the ALL fold in the row font
- cmangos-classic logons work: `CMSG_AUTH_SESSION` now carries the real client's twelve secure-addon records (342 bytes, compressing to 130) — an empty addon block is a shape no client can send, and cmangos kicks for it where vmangos shrugs; Warden-enabled anticheat remains a separate wall

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:10:06 +07:00
SamandClaude Fable 5 a53a58128c opening a chest kneels you, and outdoors elects what it draws
- the loot kneel finally fires on a chest (the reported gap): a chest never sends `CMSG_LOOT`, so the client-local loot latch gains its second arm on `SMSG_SPELL_GO` with the loot response as an admission gate — you kneel before the window opens and hold it while it is up, like the reference
- the outdoor draw election lands: the 1.12 client elects every scene object per frame, and a unit behind you or in a room the portal flood can't see is neither drawn, animated nor particle-ticked — at the Goldshire pin drawn submeshes go 365 → 49 and live particles 569 → 138, camera stamp bit-identical; `WOW_NO_DRAW_ELECTION=1` reverts. No ms pricing yet — counts only, the machine was shared
- standing-NPC facing and docked transports go write-on-change instead of dirtying their transforms every frame
- the options window gets a ground: a black fill inside the rope drops the world's bleed-through onto the page from 40% to 12%, so the small text reads against snow and noon water

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:59:10 +07:00
SamandClaude Fable 5 d67737b51f show helm and show cloak work, and the minimap composites its interior
- show-helm / show-cloak preferences dress the world body at last: the preference is `PLAYER_FLAGS` 0x400/0x800 — a public descriptor field, so it dresses every player you can see — and equipment resolve now reads it in both places the helm resolves (geosets and attachments) and the one the cloak does; character select has honoured the same stored bit since day one, which is why the two disagreed
- the toggles reach the wire (`CMSG_TOGGLE_HELM`/`CMSG_TOGGLE_CLOAK`), the `ShowHelm`/`ShowingHelm`/`ShowCloak`/`ShowingCloak` script API exists, the dressing room follows the world, and Options → Interface finally has the two rows
- the minimap's interior draw starts compositing into the client's own 256² target, and the interior gate reads the client's indoor byte — the ground work for the black-lines fix that lands next
- `WOW_DRESS_CENSUS` reports what the wire asked for vs what is on the body

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:56:53 +07:00
SamandClaude Fable 5 39f5953a7e VSync joins the video options, the chat dock goes quiet
- VSync is a player setting on the Graphics page now — 1.12's own gxVSync, persisted like every other CVar — instead of a dev-HUD checkbox
- the perf HUD collapses to one surface that says everything once, at a deliberate, governed width; the badge stops crying wolf
- the idle chat dock stops repainting itself every frame — the fade applier gets the gate the reference carries twice over, and hovering still reveals the hidden tabs
- the tick can name who spent it: per-handler self/total attribution at the one seam where every handler fires

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:04:53 +07:00
SamandClaude Fable 5 b427860b35 dialogs come to the front, and the red line names what it needs
- dialogs carry the reference's toplevel bit, so the stack-split window opens above Bagnon instead of behind it
- the failure line fills its blank — "Requires Blacksmith Hammer", not "Requires" — and Opening casts stop printing a label the spell itself marks "no text"
- the pet bar's Attack/Follow/Stay tooltips name their keybinding, and typed text reaches the focused frame through the client's own delivery walk
- AtlasLoot parses again: our Lua keeps 5.0's compatibility semicolon

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 19:38:18 +07:00
SamandClaude Fable 5 047dd3444e the wheel binds, one AddOns screen, text at the true scale
- SetBinding accepts the mouse wheel — the refusal was ours, not the client's — so wheel-bound action buttons press and release like the real thing
- one addon load law: a single arbiter for "can this addon load, and why not", with the out-of-date version gate live
- one AddOns screen — the character-select list, wearing the authored reference layout: roster dropdown, per-character tri-state checkboxes, force-load; the ESC-menu panel is retired, since 1.12's own menu has no AddOns row
- the glyph atlas follows the window scale, so maximised text stops washing out and a title stops measuring wider than it draws; an unpositioned frame positions nothing, instead of landing at the screen origin

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 19:31:56 +07:00
SamandClaude Fable 5 d1140829d7 the interface code is ours: the transcription debt is paid
- forty files that carried the reference's literal Lua are rewritten as our own expression of the behaviour — worst identical run 61 lines down to 7 — and the README now says exactly that
- the overlap gate measures the code itself across all four reference corpora, and ratchets: the number may only go down
- a lost session ends at the login screen instead of silently re-authenticating and stealing the account back
- a building's skybox is a real model: Caverns of Time's white ceiling becomes its painted nebula and additive stars

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 19:21:03 +07:00
SamandClaude Fable 5 b5bc569156 the addon arc: the AddOns folder opens
- benilla loads real 1.12 addons from Interface/AddOns — TOC, XML and Lua through one loader, with per-addon saved variables, Bindings.xml and the lifecycle events addons expect
- both AddOns screens are in: the character-select list with per-addon enable state, and the ESC menu's in-game list
- the API surface is measured, not guessed — a corpus harness runs hundreds of real 1.12 addons and ranks exactly which globals, templates and verbs they demand
- the Lua dialect is the client's own, read off the binary — 5.0 semantics with the 1.12 additions, and UI source files are bytes, not UTF-8

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:18:31 +07:00
SamandClaude Fable 5 8cc4ffa188 mouse speed, zoom ceiling and bar numerals stop being constants
- Mouse Sensitivity and Max Camera Distance are real settings now, not frozen constants
- Status Bar Text is wired through: value/max numerals on the player and pet frames' bars, live the moment the switch flips
- Shift+W walks — a modified press falls back once to the bare binding, the reference's own two-probe lookup
- the steep-face response is horizontal only, ending the extra slide when jumping nearly straight at a slope

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 17:14:26 +07:00
SamandClaude Fable 5 9cb943a0b0 Interface and Social pages arrive, and slopes refuse the jump-climb
- the options window gains Interface, Action Bars and Social pages — buff durations, the action-bar lock and the social switches are live settings
- a saved switch is applied when it loads, not just restored to its row
- jumping at an unwalkable slope costs the jump instead of banking height up the hillside
- the airborne animation starts at the launch, not at the falling flag — and the saved camera pitch is verified against the reference

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 17:13:45 +07:00
SamandClaude Fable 5 8a502fe1d6 the client starts remembering: zoom, camera, filters, a Combat page
- minimap zoom and the camera's distance and pitch persist across sessions
- the trainer's point-filter is a saved variable now and survives a relog, resetting per packet like the reference
- the options window gains its Combat page, over rows that can write the UI's own saved globals
- the step-up is a rise, not a jump forward — and the descent cone's cap belongs to the body, on every leg

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 17:13:23 +07:00
SamandClaude Fable 5 a401e5c43d the dressing room opens, and the pet gets its paper doll
- ctrl-click an item to try it on: the dressing room dresses your double, and shift-click posts the item link to chat
- the pet tab lands in the character window: paper doll stats, family and diet, the right-click menu, and dropping food on the pet feeds it
- water-only spells refuse on dry land: aquatic form gates to swimming, client-side like the real one
- the macro icon picker's white squares get their art back, and option rows explain themselves on hover

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 16:02:21 +07:00
SamandClaude Fable 5 1f06d032dd the spellbook grows its pet tab, and the pet bar gets its keys
- the spellbook's pet tab lists what the pet knows, with autocast toggled right on the page
- pet ability cooldowns sweep on the pet bar, and the bar binds to 1.12's Secondary Action Button keys
- the options window scrolls its pages in a real trough with seated arrows, nothing overflows the frame anymore
- Esc un-queues a queued strike, and a hostile unit's frame stops showing buffs the real client hides

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 16:01:27 +07:00
SamandClaude Fable 5 8549f14dd6 footprints on snow and sand, and the drunk effect staggers in
- drink enough and the screen blurs and your walk meanders, the camera carried along with the stagger; the underwater blur ships in the same lane
- boots leave prints on snow and sand that fade away in about six seconds, paws and hooves included
- key bindings move into the Options window with the rest of the settings, and action buttons abbreviate their hotkeys the way the client does
- the pet bar rearranges by drag, a running pet spell shows its active icon and a click cancels it, and spell ribbons follow their verified physics

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 19:05:51 +07:00
SamandClaude Fable 5 3b6975fdef the pet gets its frame, flooded rooms fill, and macros really fire
- the pet gets its own unit frame beside yours, and an Attack order no longer latches as the standing command
- five rooms that always read bone dry hold their water now, the Deeprun Tram's flooded stretches among them
- macros fire through the client's own chat door, and the macro window fits its tabs and scrolls its icon chooser
- the options window grows a Nameplates page and its first dropdown, and the name-display switches apply live in the world

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 19:03:43 +07:00