Commit Graph
100 Commits
Author SHA1 Message Date
SamandClaude Fable 5 6e3a67e039 your corpse answers the mouse, and a cinematic's last holes close
- a corpse is a body you can hover, cursor and click: it enters the same ray pass as units with the winner switched on type at publish (the reference's own shape — one trace over every object), the cursor classifier is transcribed whole (lootable-by-me → the pickup cursor, grayed by range; else the insignia leg behind the learned-skill latch; your own body falls through to the clear), and right-click is "not mounted AND lootable" → CMSG_LOOT; CORPSE_FIELD_FLAGS bit 5 is the PvP insignia flag, not "reclaimable" as an old note had it; the widening also caught that a GameObject anywhere on screen could steal the click from a nearer corpse, and that a left-click on a body cleared your target as if you had clicked ground
- the cinematic sweep closes eleven holes: a shot plays its sequence band's WIDTH, not its end — two shipped fly-bys band away from zero and ran long with their opening frames frozen (the Night Elf intro measured 102333 → 102000 ms); CMSG_NEXT_CINEMATIC_CAMERA announces every shot, the first included — the old "between shots" reading meant it was sent NEVER, since every 1.12 sequence row carries exactly one camera; the ack invariant is stated once (one CMSG_COMPLETE_CINEMATIC per accepted trigger, over-acking tolerated, under-acking never — a dropped ack despawns the world around you until relog); the hardware cursor hides for the shot; and the music cut lands in the frame that starts it — it was one frame late, exactly long enough for a first login's zone fanfare to start under the narration and be stamped as played
- RunBinding exists, and a fly-by stops handing the world its mouse: CinematicFrame's OnKeyDown hands the SCREENSHOT chord back to its binding through RunBinding, a global we never had, so every press during a fly-by raised and took no picture; and the mouse was fully live under a shot — right-drag turned the character, clicks picked targets through the flying camera, both buttons walked the body — so the pointer now reads as over the UI while a shot plays
- AdvanceTime and ReplaceIconTexture are carved off the bytes: AdvanceTime really is a no-op in the reference (its one reachable call is mov eax,1; ret), ReplaceIconTexture is a material swap over a model's type-14 texture slots that stores nothing on the widget, and SetModel(nil) RAISES — the "documented clear" our binding claimed was invented, not read; and the addon roster now says WHOSE package is short when a .toc names files the folder doesn't hold — nine of the corpus's twenty-nine load failures are the addon's own manifest, which the real client also shrugs off ("Couldn't open %s", carry on), so they stop reading as our defects

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:55:36 +07:00
SamandClaude Fable 5 f6f2af3da9 the combat log's wire completes, and PlayerModel is its own class
- the combat log's last eight wire bodies decode — PARTYKILLLOG, SPELLINSTAKILLLOG, PROCRESIST, SPELLORDAMAGE_IMMUNE, SPELLDISPELLOG, DISPEL_FAILED, ENCHANTMENTLOG, SPELLLOGEXECUTE — each layout read off vmangos's own writer and pinned by a byte-exact golden (DISPEL_FAILED carries no count, the list runs to the end of the body; SPELLLOGEXECUTE's POWER_DRAIN row is (amount, power, multiplier), verified at the client's bytes as well as the server's); with the eleven chat types that were waiting on them, 44 chat types become 55 — 29 sentence families, the death pair and the aura rows riding descriptor diffs because 1.12 has no "unit died" opcode, plus the six trailers ((glancing), (30 blocked), (12 absorbed) and kin) that had been missing from every family; also corrected: the durability-death line was going to the red error frame with hard-coded English, and SMSG_SPELLNONMELEEDAMAGELOG lacked its split-damage branch and its blocked wording
- PlayerModel is its own frame kind: SetUnit, RefreshUnit and SetRotation were published on Model, but they belong to the <PlayerModel> method table (0x84f1fc), and the client's lookup chains derived → base only, so a plain <Model> can never reach them — they got there from a strings scan read as ownership, and a strings hit answers whether a name EXISTS, not who owns it (SetUnit's one pooled string is referenced by the PlayerModel and GameTooltip tables and by no Model entry); the new PlayerModel → Model → Frame → Region chain unblocks CreateFrame("PlayerModel"), which is how pfUI builds every unit-frame portrait — and through pfUI, pfQuest and ShaguDPS
- a nil where a number goes is four shapes, not one law: a census of all 408 widget-registrar entries found 62 numeric positions that validate-or-raise, 43 that gate then stage an alternate, 64 that silently coerce to 0.0 and 5 that gate then store nothing — so SetMaxLetters(nil) completes and stores 0, "no limit" (the argument COUNT is checked exactly, the type is not), and the backdrop colour setters are asymmetric on purpose: a nil r/g/b channel is 0.0 but a nil alpha is OPAQUE, and reading every nil as 0.0 would have turned those borders transparent; both setters now also quantize ×255 into the packed 0xAARRGGBB byte quad the client actually stores, so 0.09 reads back as 23/255
- two more addon-killers: LIGHTYELLOW_FONT_COLOR_CODE was the one missing line of Fonts.xml's seven-line colour block (aux-addon concatenates it at file scope and died on its own first line), and the guard now enumerates the whole block l.4-20 instead of the names an earlier round had noticed absent; and the unit frames publish the reference's names — 1.12 has no *PowerBar anywhere, every bar is ManaBar and the colour table is ManaBarColor (8 of the top-20 addons read it by name), so ManaBarColor is the published table our own bars index into, with 22 more regions renamed to the reference's own

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:54:58 +07:00
SamandClaude Fable 5 b46cb7e338 the chat dock exists, and alt-arrow keys are declined not swallowed
- the chat dock is a list, not a hardcoded pair: DOCKED_CHAT_FRAMES, SELECTED_DOCK_FRAME and the FCF verbs — DockFrame, UnDockFrame, DockUpdate, SelectDockFrame, SaveDock, SetTabPosition, Close and the button-side trio — are transcribed from FloatingChatFrame.lua, and every "for i = 1, 2" moved to what it meant, the dock or every window; the dock seeds at load from the window record's own docked byte handed to FCF_DockFrame, whose first line IS the reference's early return — transcribing the function that answers the way the reference answers, where an empty stub "because we have no dock" would have been the bandaid; its unconditional re-lock cannot clobber an unlock you saved, because the stored look is applied last; pfUI's RefreshChat now runs end to end
- ignoreArrows is alt-arrow mode, and the arrow is DECLINED, not swallowed: the reference's edit-box handler returns unconsumed on an arrow key, so the walk carries it past the box and it runs TURNLEFT — the whole feature is steering while the chat box holds focus, where the old reading left the arrows dead; holding Alt resumes the caret; SetAltArrowKeyMode and its getter land with the reference's own quirk that a missing argument enables while nil disables (the getter answers 1 or nil, never a boolean), SetIgnoreArrows turns out not to exist in 1.12 and is unpublished, and the binding pass gets a named four-key exemption rather than a hole, because the handler consumes every other path
- pfUI's square minimap is actually square: Minimap:SetMaskTexture makes the disc's mask state instead of a load-time constant — write-only from Lua, as shipped, no invented getter — where an empty path restores the round default and a failed load keeps the current mask and warns, because either mistake would otherwise hand a mistyped path a silently square map that looks like a feature; and MiniMapBattlefieldFrame grows the Border and Shine regions beside its icon, on the reference's own layers — icon on BACKGROUND, ring on ARTWORK above it, the only order a ring around an icon can draw in — which pfUI hides unguarded to sit the icon flush

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:51:11 +07:00
SamandClaude Fable 5 ac74c98c15 knockback is a jump the server aims, and tabards wear their guild crest
- knockback is a jump whose seed came off the wire, not a server spline: SMSG_MOVE_KNOCK_BACK's four floats are exactly the MovementInfo jump tail in a different order (speedZ down-positive — a rising launch carries a negative value, the sign vmangos's own source marvels at), flown at the same take-off site as the keyboard jump and acked with the post-launch pose, which the server matches float-for-float within 0.01 before relaying to anyone; it is the one take-off that seeds BOTH axes, absolute in world XY, so it skips the arm that would hand the momentum back to a held key and reduce the whole knockback to a hop; root refuses it silently, a seated player stands up first, no MSG_MOVE_JUMP goes out — that packet is the keyboard's, and vmangos logs a jump at knockback speed as an overspeed cheat — and MSG_MOVE_KNOCK_BACK turns out not to be dead: an observed knockback replays as the arc it is
- your guild crest reaches your tabard: the three GuildEmblems layers — background, border, emblem, on both torso tiles — belong to no equipment slot, so the body composite never wrote those cells and every guild wore the Guild Tabard's own default art; the install is gated on a display flag only seven of 29,604 rows set, of which exactly one is worn by any item — which is why every battleground and Argent Dawn tabard keeps its own art; the five wire indices are signed, because an undesigned guild carries −1 in all five and the client refuses to paint on the first −1 (unguarded, the commonest guild state on a young realm would have worn a blank tabard); the emblem keys the skin cache, so two guilds in the same tabard display cannot lend each other crests; and a guild tabard's background hides the bra where a plain tabard does not — it is a cutout, 79.5% opaque off the shipped art, and what shows at the sides is bare skin
- a fly-by is framed by the world camera, not the M2 camera record's fov: a census of every reader shows the record's fov and clip planes reach only the portrait and Model-frame paths — nothing on the cinematic path reads any of the three — so fifteen of the sixteen shipped shots were rendering at HALF their intended vertical FOV, visibly over-zoomed on every race intro but the Undead; the fix is a deletion, and it dissolves a standing puzzle: the authored 0.22 and 27.8-yard "clips", which would render the dwarf intro's mountains as empty sky, are not clips at all on this path — two floats nobody consumes look exactly like that
- 104 of Onyxia's lava traps stood on an interior floor classified as outdoors, taking the day/night sun inside a windowless lair: a GameObject's light node anchors at its model's AUTHORED bounding-box centre, and the trap's box reaches 98.42 yd past its bind pose — the anchor sits ~40 yd under the chamber floor, where a downward ray finds nothing above it to claim; the reference recovers with a 1000-yd upward retry at the claim itself, which benilla had only at the colour sample, so the verdict was decided before any colour was read; all 104 now classify interior, beside the 26 rocks and 119 eggs that always did — and the drowned-corpse pose came back from its cross-check confirmed at the bytes (a strict liquid-depth test at exactly two-thirds of a yard, Dead or Drowned), with the two reference-side notes it contradicted corrected over there

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:50:50 +07:00
SamandClaude Fable 5 f3ecb5c968 a cinematic holds your body, and all seven chat windows exist
- a cinematic holds the body while the camera flies: the streaming focus follows the eye — a Tauren's intro opens 1741 yards from the body — so the body's own ground unloaded under it and it fell (z=59.4 to −62 in four seconds, the server yanking it back); it now takes the same hold a teleport takes, released when the focus comes home to a resident tile, and the loading screen stops covering the fly-by, because "the player's ground is missing" is not a load while the eye is deliberately elsewhere; the letterbox measurement prints as an ordinary info line, and scripts/cine.sh plays any one cinematic and prints what the client did to the world while the camera was away
- a cinematic cuts the zone music: the reference asserts exactly what /console EnableMusic 0 asserts, through the same setter — a cut, not a fade, the music pump dead for the duration, resume at +3.000 s — and benilla asserts the runtime flag, never the CVar, or quitting during a 102-second intro would save your music off for good; ambience is deliberately untouched (it has the analogous flag and the cinematic never writes it); the narration has no category at all — its flags route it around every volume slider but not around the Enable Sound Effects gate, so unchecking that silences it — and the listener follows the cinematic camera for the duration
- addons can walk a UI they did not build: GetChildren/GetNumChildren/GetRegions/GetNumRegions land — the basis of the whole reskin genre, and the wall four of the twenty most-installed 1.12 addons died on: pfUI drew nothing before and now paints 495 quads, ShaguDPS 71 → 566, pfQuest 3 → 498 — with the reference's own quirks: the title region is NOT in the list (its creation path never reaches the region linker), hidden regions are returned and counted, oldest first; the Model widget gets its Lua surface (SetModel, SetSequence and siblings, read out of the shipped image, where SetRotation and SetFacing are two names for one slot); and the Minimap carries the nine engine-created Model children no XML declares, built before the frame descent, the ninth being the player arrow Questie indexes as ({Minimap:GetChildren()})[9]
- all seven chat windows come from one template, tabs and scroll buttons included — whether a window is shown has nothing to do with whether its globals resolve, and pfUI reads every piece of that furniture for all seven, unguarded; isDocked only on windows 1 and 2 (the chat-cache's own DOCKED byte), SELECTED_CHAT_FRAME seated beside DEFAULT_CHAT_FRAME (the window you last picked vs the one FrameXML prints to), and the four per-window fields ChatFrame_OnLoad seats; two more one-name walls fell — a Button's label answers to its second spelling NormalText, which KLHThreatMeter's column headers die without, and ABANDON_QUEST_WITH_ITEMS is declared because a dialog table is read at load whatever the client later shows, leaving Questie with zero errors of ours — and the addon harness gains --probe/--eval, one addon's VM answering a question in ~5 s instead of a 90 s corpus run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:50:08 +07:00
SamandClaude Fable 5 4ad8718b2a your corpse is your own dead body, and particles take the room's light
- corpses render: a corpse create spawned a real entity, latched its guid for the reclaim send, and drew nothing — one missing EntityKind variant folded it into the catch-all and four downstream lanes then failed by default, not even the debug cube fired; the reference forks once, on the bones flag: a fresh body builds a character composite from the corpse's OWN appearance bytes and 19 item slots through the same compositor a living player is dressed by (its own hide-helm/hide-cloak bits honoured, the ranged slot never dresses, and weapons never dress because the client looks a packed display word up as a guid — we reproduce the outcome, not the dead lookup), while a bone pile takes its race and sex's DeathSkeleton, sixteen of which ship; the pose is one settled arm — Dead, or Drowned when the body lies more than 0.66666669 yd under a liquid surface — and a corpse is not a unit, so clicking one no longer sends a selection for a guid no unit owns
- a lit particle takes its MODEL's committed light node, not the sky's: indoors the reference lights an object's particles from the object's own node — the footprint's baked floor colours on the fixed interior axis plus the room's placed lights — never the day/night sun; a particle quad carries exactly one normal, world up, one constant per draw, so the whole node collapses to three floats, published off the same fold the model's mesh renders from so a mesh and its own particles can never disagree about the room they stand in; in Onyxia's Lair the 78 lit falling-rock emitters on the 26 anchors that classify interior now take the room's light
- and that lit lane is FIXED FUNCTION, not the mesh's soft SH curve: the shipped client null-binds both shader slots for a particle batch and re-zeroes the shader mask at the head of every batch, so a model and its own particles share the same committed light words and legitimately differ in the curve applied to them — the mesh's wrapping lobe against the hardware's max(N·L, 0) is 0.900 vs 0.869 on the key axis, up to the three nearest room lights arrive diffuse-only under GL's own 1/(0.7d + 0.03d²) falloff (a light at or below the emitter cannot reach it at all), and the clamp sits on the product, never the multiplier, because it is GL that clamps the lit vertex colour
- the cinematic letterbox has no aspect test in it: CinematicFrame.lua's if guards a recompute, not whether there are bars — below 4:3 the reference's bar textures simply stand at their declared 1024x128 on the client's native 1024x768 sheet, which is height/6, the same formula evaluated at exactly 4:3 — so one expression covers every window shape, min((h − min(w/2, h))/2, h/6): a 2:1 picture when wide, bars at 4:3 too; and a shown keyboard frame swallows EVERY key, not the ten names the host used to feed it — you could walk around underneath your own intro; the proof is the reference's own handler, which has to RunBinding("SCREENSHOT") by hand to get one key back; ESC still skips, and a W already held when the shot starts keeps running, which is faithful too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 19:49:15 +07:00
SamandClaude Fable 5 c827813351 cinematics play, and a lit particle stops brightening as you turn
- cinematics play: `SMSG_TRIGGER_CINEMATIC` resolves through `CinematicSequences.dbc` → `CinematicCamera.dbc` → a `Cameras\*.m2` whose camera record is an eye path, a look-at path and a roll — cubic tracks with the full step / linear / Bézier / Hermite dispatch the bone loops collapse to step-or-linear (every shipped fly-by is Bézier), planted at the row's origin and facing (`Rz(+facing)`, checked against vmangos's own waypoint table: 8.5 yd mean on the human path, 154 with the other sign); FOV is per shot (the Undead intro authors 90°, the rest 45°), roll is authored around whole turns, the flight ends at the sequence band's end, a trigger arriving before the loading cover lifts is latched and started when it does, ESC skips through `CinematicFrame`'s own `OnKeyDown` (`StopCinematic` has zero native callers), and every path acks — natural end, ESC, or an unresolvable trigger immediately, as before; `.debug play cinematic <id>` replays any of them
- a cinematic hides the HUD — `UIParent:Hide()` reaches nothing here because the HUD frames are not its children, so the ALT-Z draw-level hide is used and the letterbox moves out of FrameXML onto Bevy UI nodes where that hide cannot reach it, recomputed per frame (bars only wider than 4:3, the picture cropped to 2:1) — and the restore only un-hides a UI this module hid
- a lit particle's normal is world up, one constant per draw, not camera-facing: Onyxia's always-on floor haze read about four times brighter from a level camera than from above because the shader dotted a to-eye normal against a fixed light; the reference uploads row 2 of the view matrix — world +Z carried into eye space — on every vertex and carries the light into the same frame, so the rotation cancels; 400 lit emitters (the waterfalls, chimney and campfire smoke, Westfall dust, Dun Morogh snow) stop brightening and dimming as you turn
- the `play` profile drops ThinLTO — rustc #86049 was intermittently poisoning the incremental link with `_anon.<hash>.llvm.<id>` symbols promoted by an earlier compile (48 unresolved across 7 codegen units; 1065 such symbols → 0 after) — and `benilla-formats` stops taking `image` with default features, which had been compiling a complete AV1 encoder into a crate that writes two PNGs: 499 → 466 workspace crates

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:24:50 +07:00
SamandClaude Fable 5 6710b31a82 scrolling chat brings lines back, and Onyxia's lava traps spurt again
- every chat scroll re-arms the displayed lines' fade — up, down, top, bottom, page up/down, and a no-op scroll at the bottom too, which is what clicking the arrows on an already-at-bottom chat does; a line at alpha 0 was unreachable for the rest of the session (play two minutes and the chat was empty and stayed empty), because "scrolling off the bottom freezes all fade countdowns; nothing un-fades" had been read as a law about the class when it was a finding about one function's gate; the displayed set only, never the whole ring, with the frame's current defaults, as the reference's re-arm writes them; there is no hover reveal — the scroll re-arm is the whole mechanism; and the fade ramp reads the un-rounded countdown, not the stored f32
- the GameObject animation arm rolls a variation: Onyxia's 104 lava traps and 26 falling rocks author Stand twice — a 29491 : 3276 chain whose second take is the `LAVALUMP2` ember burst — and the arm is issued with `variationIdx = −1`, a weighted random walk of the alias chain, where we resolved the chain head every time (215 emitters, every one at live = 0); and a resting substate re-arms itself through the model's completion callback, so the roll is re-taken every window for ever (~867 ms for the traps) — 45 emitters firing and 1299 live particles at +25 s, a standing field rather than a one-time flurry; 72 of 1582 GameObject models author such a chain (the fish schools, the AQ fireflies, the plague cauldrons, lanterns, mugs) and every one was playing take 1 of N; `benilla-extract goanimscan` censuses it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:23:44 +07:00
SamandClaude Fable 5 55b40b5257 names persist, the GM notice is a toast, and the target reads Dead
- the name cache persists to `benilla-config/cache/<realm>.tsv`, because the reference's `namecache.wdb` / `petnamecache.wdb` do and that is why it never sees the races we lost every time — unstabling a pet raised `Usage: SetText("text")` off an unresolved `UnitName("pet")`; the header carries magic, format, build, locale and realm and any mismatch discards the file (no checksum, no TTL: eviction is explicit only, via `SMSG_INVALIDATE_PLAYER`, decoded now and never sent by vmangos), negatives persist too, written on a 10 s debounce and at exit; a stable list also seeds the pet-name cache from the names it already carries
- `SMSG_NOTIFICATION` is the red UIErrorsFrame toast, not a chat line — `.gm on` printed twice because vmangos sends both a system message and a notification and both were rendered as chat; the stand-in dated from before the errors frame existed; `SMSG_AREA_TRIGGER_MESSAGE` moves with it on the yellow arm (its handler ends `xor edx,edx` — flag 0 — where the notification's is flag 1)
- the target frame's dead text is the GlobalString `DEAD` = "Dead" resolved through `text=` like the target-of-target frame, not the key typed into `SetText` in caps, and it takes `UnitIsConnected` so a disconnected player does not read as dead; a shipped-script sweep now refuses any key-shaped literal handed to a text sink; and the Help window is one click deep — Home's button opens the ticket text box, Auto-Unstuck sits beside it, and a ticket files as category 0, which a GM's queue names "Unknown" (a guard added days earlier refused 0 on reasoning from the enum rather than from the function that reads it)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:23:05 +07:00
SamandClaude Fable 5 0cd0a28942 edit boxes take focus the way 1.12 does, and the stable shows its pets
- the caret was a wedge in the line: it sat in flow, four units wide, so focusing a login box shoved its text right by one caret and a caret parked mid-word opened a gap; it is a zero-width seam now with the bar drawn as an overlay (a 0×26 seam and a 5×26 bar at the same x, off a node probe), the way the reference anchors its caret quad over the FontString; a blurred box collapses its selection so only the box holding the keyboard shows one; and a dialog answers only keys pressed while it was already on screen — ENTER on an empty form used to open the error dialog and close it in the same frame
- `autoFocus` defaults ON in the reference (the ctor leaves flags = 1, and every one of the ten `autoFocus` attributes in the shipped chain is an opt-out), showing an autoFocus box focuses it after its `OnShow`, and hiding the focused box releases the keyboard — the "never focuses on show" note we had transcribed came from a `call`-only census that missed a tail `jmp`; the loader's flag loop could only ever turn a flag on, so `autoFocus="false"` was a no-op, fixed before the default flipped or it would have grabbed exactly the ten boxes the reference exempts; and the EditBox does fire generic `OnChar` with the spliced string, on every typed or pasted character and never on `SetText`
- the stable master's portrait was a black disc (its session was missing from the `"npc"` token chain — the third window to ship that way, so the test is now exhaustive over every `impl NpcSession` and names the one you forgot) and its model pane draws the selected pet: a stabled pet is a database row with no world entity, so a `PortraitStandIn(display_id)` — an entity that exists only to be mirrored — feeds the existing booth code unchanged; plus the registrar's two service rows were hidden by an inherited attribute, a charter's tooltip carries the guild name and master on line 3, and the Help window drops three strings pointing at a company that stopped answering

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:22:27 +07:00
SamandClaude Fable 5 dbf9d8057b a full realm is a queue to wait in, and the login dialog is centred
- a full realm answers with `AUTH_WAIT_QUEUE`, and it used to be read as a refusal; the grammar is length-branching exactly as the reference's handler has it, so both mangos body shapes parse; the estimate is the reference's own 8-sample ring — divide before multiply, signed, no timer — whose displayed figure climbs while the queue is silent, pinned by a test so nobody "fixes" it; the dialog is the ordinary status dialog relabelled `CHANGE_REALM` (which cancels back to the login screen: no realm list exists yet), and cancelling actually leaves the queue — the IO thread used to keep its place and walk on into character select on admission
- the stable master, corrected against the binary: a stabled-pet drag rides the shared cursor at payload mode 10 (the mode census had that row's label wrong), a plain click always returns 1 and a drop always nil, the summoned pet dropped on an occupied stable slot swaps (STABLE was refused whenever both bought slots were full, silently), an unpurchased slot takes nothing, the stabled→summoned fork reads the live pet guid not the row, the client itself sends `MSG_LIST_STABLED_PETS` on the interact leg, `PET_STABLE_SHOW` fires on every list, the selection is a petNumber and every list clears it, and result codes 2–7 do nothing at all
- the login dialog's text is centred (a FontString with no `justifyH` is CENTER, and `GlueDialogText` has none), the fifteen-year-dead "see www.worldofwarcraft.com" clauses are cut at the clause, the Login click sound is unconditional (the reference plays `gsLogin` before it checks the boxes), dialog buttons play `gsTitleOptionOK`, the realmlist button's `gsClick` never existed and is `gsLoginNewAccount`, and focusing a login box selects it — a stated divergence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:21:50 +07:00
SamandClaude Fable 5 1fd736759e guild charters: the registrar, the charter, and the twelve verbs
- founding a guild: fourteen opcodes, eight goldens (four mutation-checked), twelve engine globals, `GuildRegistrarFrame` and `PetitionFrame` — `CMSG_PETITION_BUY` is a 72-byte frame the server reads two fields of and drops in silence if short, `allowedGender` is the family's one u16, a signature is a 12-byte stride not 8, and `MSG_PETITION_DECLINE` writes the charter guid and reads the decliner's — same width, opposite meaning
- two sessions, not one: the registrar is an NPC session (closed by walking away — its show event is one of the fourteen callers of the interact latch, so the registrar turns to face you) and the charter is bound to an item guid you carry across the city; right-clicking a charter in your bags opens it, keyed on template flag `0x2000` (item 5863 has no on-use spell and no quest, so every existing item-use arm declined it)
- the byte carve came back and rescored six named guesses — three confirmed, two corrected, one refuted: `PETITION_SHOW` is deferred until every signer name has resolved (the window never paints blank rows), `ClosePetition` on somebody else's charter sends `MSG_PETITION_DECLINE` ("sends nothing" had been chosen on principle and was wrong half the time), and founding a guild is silent — no `ERR_GUILD_FOUNDER_S`, the reference emits no text at all; the four success ids go to chat and the five refusals to the red error frame, three paraphrased strings are now the shipped ones (a sweep asserts all fifteen), and the `npc` unit token had never been fed — the registrar's name banner was blank; `WOW_PROBE_CHARTER=1` drives gossip → buy → open → rename → destroy live, 10/10

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:21:00 +07:00
SamandClaude Fable 5 57b61de04b GM tickets are in, and a login failure shows the string 1.12 shows
- GM tickets, end to end: five request/answer pairs, the seven Help-window bindings, three events and `GMTicketCategory.dbc` — the ten categories `HelpFrame.lua` keys 1..10 live in a DBC nothing here had ever opened (the four `TICKET_TYPE` strings feed a dropdown 1.12 never gave a frame); the category is one byte on the wire (a u32 would shift the map id and position and file every ticket at a garbage spot), and `UPDATETEXT` carries it too, which vmangos stores and cmangos swallows as the first character of the text — faithful to the client, the divergence recorded
- the engine re-asks for the ticket after a create or update succeeds and on a status push (the ask opcode has three callers in the reference, two of them engine legs with no idempotence guard) — which is why the shipped FrameXML registers no handler for the three response opcodes and still repaints; without that leg the form stays a form for ten minutes; `UPDATE_GM_STATUS` is a signed passthrough (`0xFFFFFFFF` → −1), the five ticket verbs drain through one ordered queue because call order is wire order, and the Help micro button — drawn, hovering and a no-op since the micro menu landed — is live
- a typed wrong password reads the reference's long "check the spelling of the account name and password" (0x04 and 0x05 share one jump-table arm — the client cannot say "wrong password", and the lockout cmangos's header describes does not exist in the binary), unknown codes read "Disconnected from server" rather than "Authentication failed", and every realmd row of the old map was in the wrong one: the two login-status enums have two key tables and two dialog paths, and a server source can only ever verify the codes, never which string the client draws for them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:20:24 +07:00
SamandClaude Fable 5 c0b7a613a9 the stable master is in, and master loot hands drops to the raid
- the stable master: `MSG_LIST_STABLED_PETS` both ways, the four mutations answered by one result byte, two slots priced from `StableSlotPrices.dbc` (500 and 50000 copper — the cap falls out of the data, corroborated by vmangos's `MAX_PET_STABLES` and the reference's `NUM_PET_STABLE_SLOTS`), rows seated by slot never by position (a petless hunter's list starts at a stabled row), slot 0 read from the wire because a dismissed pet has a row and no live unit, a re-list after every success because no result carries one, and `GetPetIcon` reading `CreatureFamily.dbc`'s icon column — which ships `Ability_Druid_CatForm` for both warlock families, asserted as shipped
- master loot: `CMSG_LOOT_MASTER_GIVE` (the slot is a byte here where the roll family's is a u32) and `SMSG_LOOT_MASTER_LIST`; the click gate is the wire's slot-type byte and nothing else — the reference never asks who the master looter is — so a MASTER row fires `OPEN_MASTER_LOOT_LIST` instead of a take and auto-loot skips every non-ALLOW row; the candidate array is bucketed by raid subgroup into blocks of five (a dense list would have filed every candidate under the wrong "Group N"), an unresolved name is nil so `UPDATE_MASTER_LOOT_LIST` has something to repaint, and a give re-checks the row is still MASTER before sending; found on the way: a master looter in another raid subgroup lit the crown on your own portrait
- `SetLootMethod` takes its third (threshold) argument; the reference's silent reset to Uncommon when it is absent is flagged and not adopted; the stable's model pane draws nothing yet — a stabled pet is a database row with no world entity, and a booth that renders from a bare display id is the next arc

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:19:45 +07:00
SamandClaude Fable 5 86ecbca9f7 a failed dial says which failure, and the sword reads the at-war bit
- "Unable to connect" now says which: an address that does not resolve reads the reference's "Invalid Login Server", a resolved address nothing answers on reads "Login Server Down", and each names the `host:port` actually dialed — resolution and connection are two operations now (a DNS failure surfaces as `Uncategorized` on macOS, so no error kind could tell them apart), and every address a name carries is tried, `localhost` → `::1` then `127.0.0.1` included
- a typed wrong password shows the login dialog instead of exiting the client, and the two auth-result enums — realmd's and the world server's — are split so a code is read against the family that sent it, with the world server's own refusal text shown for its codes
- the world cursor's fork is `CanInteract` and `CanAttack`, not a reaction-rank threshold: a Cenarion Circle NPC with no gossip showed the sword at neutral (and TAB acquired it, and right-click attacked it) because one predicate implemented twice read the standing where the binary reads the at-war bit in the player→unit direction; one byte-verified `CanAttack` is shared by the cursor, TAB, pet attack orders, `UnitCanAttack` and the action-button usable gate, the service ladder falls out to a plain pointer instead of the attack leg, and `/reaction` prints the at-war bit and the branch verdict

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:18:29 +07:00
SamandClaude Fable 5 1a051806ad a realmlist button on the login screen, and a roadmap in the README
- the logon address is the reference's own `realmList` CVar — name, `host[:port]` form and the "Address of realm list server" prompt read straight out of `WoW.exe`'s string table — persisted in `benilla-config/config.toml` and edited on the login screen: a Realmlist button in the slot `AccountLogin.xml` already reserves under the Quit stack, the current address in grey beneath it, opening the reference's own `hasEditBox` glue dialog; before this the address was `$WOW_HOST` read once at process start with no way to change it; one text field and no saved list (every client at this scale ships one field), a pasted `SET realmlist "…"` line is accepted, and the default is `localhost` because the retail host has not resolved since 2019
- the README's "Not built yet" becomes "Where it's going": what done means, no dates, and one list in probable order — the remaining basics (battlegrounds, guild charters, the stable master, meeting stones, GM tickets, master loot, cinematics), addons / options / performance as ongoing, the no-brainer VanillaFixes- and SuperWoW-class fixes, playable downloads with Linux first; not planned: other expansions, Warden
- a UI region's span comes from its content and the owner-edge fallback is deleted: the reference's resolver core has no parent pointer at all, a FontString floors at one unit on both axes, a texture takes its texel span, and a region resolves from its own anchors and span or not at all — a live census over 8772 rects: 0 stopped resolving, 923 FontStrings shrank (842 to exactly 1×1 — empty labels that had been the whole screen, or an inverted rect), 0 textures moved; and `Region:GetWidth`/`GetHeight` are the same virtual getters the resolver calls (authored value wins per axis, natural width, wrapped height, texel span for art), so a script reads the number its rect was built from

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:18:00 +07:00
SamandClaude Fable 5 66747179a1 effects ride the lift with you, and a long frame keeps you on the deck
- a rider's effects are stored in the deck's frame: standing still on the Thunder Bluff lift, a weapon enchant's streak hung four yards below the blade and through the floor, because its edges were laid down in world space while the car climbed out from under them — the reference folds the transport matrix (translate · Rz(facing), NULL on the ground) into the emitter at birth and back out at draw, so committed content rides the deck and only a boundary re-expresses it; a `RideFrame` on the rider's model, inherited down the parent-model chain the way the reference copies the transport pointer to every child each frame, one fold at birth, one at draw, one at the boundary — ribbons take it unconditionally, world-mode particle clouds take it, model-mode clouds never see it; measured on the car: streak 4.2 yd → 0.00 over a 49 yd climb, while the same rider thrown off the top streaks 0.9 → 24.8 yd on the way down
- switching away from the window while riding a lift dropped you through it: a collider moved in `Update` is invisible to `Update`'s own spatial queries until the next physics step, so on a 1 s frame the deck descended 7 yd with its broad-phase box left behind, the ground probe found nothing under the feet, and the second long frame's clamped 250 ms of gravity put them under the deck; avian's own `update_moved_collider_aabbs` now runs inside the transport chain right after the deck moves (0.03 ms p50, flat across scene density), and `WOW_STALL` injects long frames on demand, since a probe window is never throttled by the OS
- `WOW_TRAIL_CENSUS` prints each live ribbon trail's world-space spread beside its spread on the deck — the pair that separates "not riding" from "riding but not folded"; it first matched zero trails in every scene by requiring a component trails deliberately never carry, recorded rather than quietly fixed, because an instrument answering a confident zero cost an afternoon

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:17:25 +07:00
SamandClaude Fable 5 693c26d9c4 held weapons pick, book images size to their art, the panel opens again
- a unit's pick geometry is every model chained to it — body, held items, mount — one candidate per root resolving to the same unit, which is how the reference registers its pick (it walks the attachment tree and registers each model); Naxxramas' floating weapons could only be selected by their name plate before (no body, no candidate), and every armed unit gains its gear as clickable surface (our own body 12 → 21 tested parts); the broad phase stays the body's sphere, so a very long polearm on a small body is the named residual
- the selection ring's writer has two branches and we had transcribed one: a model whose stand box is degenerate (zero extent in x and y) rings at the literal 1.2 × scale — 2.7 yd under a trigger creature — instead of `sqrt(0.5·sqrt(dx²+dy²))` = 0 clamped to an invented 0.05 floor; both invented fallbacks are gone
- an HTML book image with no width/height is its art's texel square (one texel = one FrameXML unit, bit-for-bit the `<AbsDimension>` converter), not the rest of the page — *A Treatise on Military Ranks* drew its crest twice too big and stretched to the page's aspect; a texture-size oracle answers off the same decoder the renderer draws with, and an unfloated height-less `<IMG>` reserves its art's height in the flow; 797 shipped textures swept, exactly two zero-size axes move and neither is visible
- the dev debug panel killed the client on open with "Attachments have differing sample counts": Bevy's 2-D depth texture is keyed on the render target alone, so two Camera2ds on one window at different MSAA counts cannot both be valid, and the egui overlay camera had silently kept the default 4× after the player-UI camera went to Off; it now says `Msaa::Off`, and a preflight check reports any two 2-D cameras that disagree on a shared target, every run

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:16:04 +07:00
SamandClaude Fable 5 cbf77812d7 the cave hides the lake, the lifts come back, the bolt gets its width
- from inside a building the open-world water outside draws only through a doorway you can see, as terrain and trees already did — the Caverns of Time lake is gone from the cavern's ceiling: there was never a second visibility lane for open-world liquid (the old deferral said "it already has an authority"; a sweep of every visibility writer found none, so Bevy's frustum test was the lake's only gate), an ADT liquid layer is tagged exterior scene at spawn and the existing window cull owns it, one 33 yd chunk layer at a time — which the reference's bytes then confirmed is its unit too (`CChunkLiquid`, reachable only from the per-window walk, a sealed room's supply discarded not deferred); a building's own pool also rides the Map Objects toggle now, so switching buildings off no longer leaves the canals hanging in the air
- the Thunder Bluff elevators and every other Kalimdor lift were invisible for the whole session whenever you logged in on that continent: the lift arm snapshotted the current map one stage before the login frame had written it, so every lift compared itself against map 0 and hid as off-map — a lift carries no map at all now (it is only ever streamed to players standing on its own map), the off-map term stays for the boats it was written for, and `WOW_LIFT_CENSUS` prints each transport's arm state, cycle and visibility (13 transports, 11 hidden → 0)
- the lightning across Razorgore's room and Chain Lightning's mob-to-mob hop drew as hairlines: the chain renderer took each hop's cross-section as the world-horizontal perpendicular, where the reference takes `(−d.y, d.x, 0)` in eye space — the ribbon is view-plane aligned and keeps its authored 2 × halfWidth yards at every angle, so a long level beam watched from its own plane no longer thins to a line (the "a hop seen end-on genuinely collapses" note was wrong and is gone)
- a display that names a model builds even when it draws no batch — Naxxramas' Unholy Axe / Swords / Staff are an invisible stalker holding a Monster weapon, and the held weapon had nowhere to hang; the same gate was keeping 43 emitter-only GameObjects dark (house and blacksmith smoke, Ironforge's lava steam, Stratholme's embers, every firework), and a name sits at the authored PlayerName attachment instead of at the feet; and a vendor's foot-shuffle on turning to you now blends the whole way in and runs to its own clip window — a 500 ms step on 1100 of 1130 shipped shuffle records — where the latch had tested the gap left against a band sixty times too wide, and nothing ever ended the step

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 17:15:08 +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 5b62b89320 trilinear ships on, and every line of text rounds once
- the texture filter is the reference's policy — two globals, one process-wide mode, no per-texture override — registered as real CVars every sampler reads: the hardcoded trilinear + aniso 8 at five sampler sites had been read off an apitrace of an install whose `Config.wtf` set `anisotropic "16"`, a configured value taken for a default; and `trilinear` ships ON, because the registrar's `"0"` is not what a fresh install renders at — first-launch hardware detection overwrites sixteen video CVars from its hardware table, both rows a real GPU can reach set trilinear, and the reference's own `gx.log` on this machine names that row — while `anisotropic` is not among the sixteen, so anisotropy stays off
- the MSAA device clamp ran before the config was read, so a saved `gxMultisample = 8` carried from a machine that offers it still killed the render thread on one that stops at 4; the ceiling is now a property of the write itself, covering the config file, `SetCVar`, the dropdown and any writer added later — and an empty device list is no opinion, so headless runs pass through
- one line, one rounding: at a fractional display scale the per-glyph snap's f32 round-trip moved half-pixel ties by an ulp, so caps and ascenders rounded up while x-height letters stayed — the letters left the baseline, the thing the reporter photographed; the line's two anchors now round once and each glyph adds integer device-pixel offsets, so a line cannot be anything but flat at any scale, proven over 15,680 layouts — and `$WOW_DPI`'s size guard, which compared a physical request against the logical size and refused every non-1x run, now reads the unit it is denominated in
- a test that panics while holding `ENV_LOCK` no longer poisons the tests behind it — one missing knob resource had reported as twelve red tests, eleven naming the mutex and none naming the bug; there is nothing for the poison to protect, since the guard's `Drop` restores the environment during the panicking test's own unwind

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:15:45 +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 d1931eed1d instruments for motion at the glass, and a macro hovers to its name
- the jitter meter measures the palette and the pixels, not just the pose: `pal` probes the rows the vertex stage actually blends (the old bone columns read a matrix the GPU never sees), `SCREEN` carries them to viewport pixels by the shader's own arithmetic, `camrot` watches the camera's rotation where only its translation had been vouching for "bit-stable", and `WOW_JITTER_RAW` dumps one bone's series unaggregated — rotations too, since a translation can be smooth while its frames are not
- `WOW_FIXED_DT=<ms>` pins the animation advance so a screenshot burst measures the render rather than its own stall — arming on the wall clock, because during load the app runs ~385 updates a second and a pinned clock reached "90 seconds" in 14 s, photographing an empty world
- `benilla-visual flow` estimates the whole window's motion by least squares over every pixel (noise floor 0.0000 px on static regions, and its brightness-constancy limit is measured and stated: invalid on a lit deforming body), `edge` reads a silhouette's sub-pixel crossing renormalised against the lighting with an honest ±0.5 px floor, `WOW_TWIST_GAP` pins a yaw gap so the body counter-twist is exercised at all — every earlier "removing it changed nothing" had measured a pass that never ran — and `WOW_DITHER` adds the dither the frame's 8-bit output has never had, off by default because the reference's framebuffer was undithered
- hovering a MACRO action slot shows one white line, its name — the reference's macro leg renders exactly that and no more, in its "normal" white, where ours was a `_ => Ok(())` from before macros shipped; and `WOW_MSAA=8` is refused with a loud warning instead of panicking the render thread, through one parser both world-camera spawners now share

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:14:35 +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 ee8f9ddfa0 the login scene frames its art, char select remembers, DXT stays DXT
- the glue scene widens only as far as its art goes: none of the seven login dioramas is drawn wider than about 3:2 — measured per texel by `benilla-extract glueextent`, which rasterises every batch into the camera's own tan-space, painting where the reference's alpha-key test passes — so the frame zooms down to the reference's own 16:9 opening (never tighter) and pillarboxes past the aspect the art cannot fill, instead of showing the clear colour past the backdrop's slanted edges; 4:3 stays byte-identical
- the character screen opens on whoever you last logged in as: the reference's `lastCharacterIndex` CVar, written at Enter World and only there — clicks and arrow keys never touch it, which is what makes the value mean "last logged in" rather than "last clicked" — restored on every character-list rebuild and clamped into range
- spam-hovering tooltips stops costing 2 ms: two write sites gave up naming their node and re-derived the whole layout graph (1,812 µs against the ledger's 44, on 919 of 1,262 resolves) — the wrap pin now touches the one region it wrote, and re-pointing a tooltip at the button under the cursor retargets the node's edges in place instead of throwing the cached graph away
- two corrections off the project's first GPU-bound report (a Steam Deck at 94% GPU busy on 8.4 W of a 15 W budget, the memory-stall signature): `farclip` ships the reference's registered 350 instead of the clamp's 777 — the value also sizes terrain residency, so 777 streamed, held and drew 4.8× the area — and BLP textures upload WoW's own DXT blocks verbatim the way the reference does, instead of decoding to RGBA8 at 8× the bytes of DXT1; the terrain slider still reaches 777, and the lanes that read texels on the CPU (terrain arrays, the character-skin compositor) stay decoded and say why

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:11:59 +07:00
SamandClaude Fable 5 b344fc4938 Levitate walks on water, the doll takes a snapshot, the pose keeps time
- Levitate over water, whole: hover stacks on the water-walk surface, so the body rests exactly a yard above the waterline — the reference's own arm undoes the ground snap and descends by max(L−1.0, 0); casting it while swimming launches you clear of the water, because `SetHover(true)`'s handler calls `CMovement::Jump` before it ever sets the flag — a jump that, unlike Space's, is not refused for a hovering body; and aiming below −37° drops the liquid layers out of the walk mask, which is the reference's own way back into the water and the piece whose absence made the mode a one-way door
- walking no longer sinks a Levitator: the step-down snap's no-hit leg — right on land, where it is the frame that leaves a ledge — could not see water, since liquid is queried rather than swept, so every walking frame stepped down a cone's worth while the hover climb hauled it back; the arithmetic closes with no free parameters (descent 0.24355 yd a frame, climb 0.11667, net −0.12688 against a measured −0.12687), settling 0.88 yd under the hover line until the keys were released
- the pose advances on the PRESENTATION cadence, not the CPU loop: under vsync a frame reaches the eye only on a refresh boundary, but the measured delta absorbs the render thread's back-pressure wait, so two frames shown 16.67 ms apart get advanced 26.4 and 8.0 — the whole skeleton lurching at once, up to 91 of 117 bones past a quarter pixel in one frame; `Time<Virtual>` is re-split to a delta snapped to the estimated refresh with the remainder carried, engaging only while the stream looks vsync'd so a real stall stays visible — found once the jitter meter probed a point at each bone's flesh radius and logged the animation clock beside the wall clock, the two channels it had been blind in
- the character doll is a snapshot you edit, not a mirror you follow: the reference re-takes a model widget's copy on becoming visible, a change of dress, a manual sheath toggle or a resize — the combat auto-draw is not one of them, so a bow drawn in combat stays off the character sheet; and a portrait bake now waits for its PIPELINES too, not just its textures — off macOS a cold pipeline variant skips its batch silently, a one-shot still keeps the hole for the session, and which piece goes missing is which variants lost the race: the hair's alpha-key, the body's opaque, a glow card

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:11:32 +07:00
SamandClaude Fable 5 d6953c936f the missing bra, the robe's hem, and a doll that puts its arrow down
- the missing bra: the underwear section's CharSections row spends BOTH of its texture columns and the body compositor read only the first — the pelvis — so a bare-chested female composited panties and then bare skin above them; the second column is torso art authored on all eight female race rows and no male row, which is how the male-only regression test stayed green over the missing half, and the new test is byte-exact — the composite's torso tile must equal the shipped BLP's mip 0 verbatim
- underwear is the tile's FALLBACK, not an under-layer: the reference tests a prefix of a tile's equipment cells and skips the underwear blit entirely when any is occupied, while cells past the prefix stack on top of an underwear that was allowed to draw — so a shirt or chest suppresses the bra, trousers the panties, but a belt never hides the panties and a plain tabard never hides the bra; benilla blitted underwear first and equipment over it, which coincides on most gear and is still the wrong law
- a robe outranks footwear on the lower-leg tile: the equipment stacking table is a DEFAULT that two of the eight layer choosers overrule, and the robe bit lifts a chest to cell 4 over a boot's 3, so sandals stop repainting a robe's hem; and `_U` outranks the gendered file — the reference probes the universal name first and patches the gender letter in only on a miss (43 of 7944 shipped basenames carry both, and on those the gendered art is dead), which closes the bare-skin ring a shorter `_F` pant file left below the knee; `benilla-extract charatlas` prints the blits in order with the file each region resolved to, reading the same `equip_blits` law the compositor walks
- a model widget edits its copy the way the reference does: fifteen attach ids reset off every duplicate — blood, breath, the nameplates, the spell hands, and the nocked arrow — and the hand grips arm from attachment occupancy, where ours sat hardcoded open under a comment claiming the pane sheaths its weapons (it never did); the character doll stops drawing a hunter's arrow and closes the hand around the bow, and the booth bake log now names its attach ids (`at=[2,35] grip=[false,true]`), which is also the reset's retest readout

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:10:55 +07:00
SamandClaude Fable 5 69bcd3bb6b gear rides the rig, water walking answers the keys, and a jitter meter
- an attached model's frame rides its wearer's rig: composed as bone-offset-plus-world-root every frame, a helm at Elwynn's ~9500-yard coordinates lands on a 0.98 mm f32 grid (exactly 2^-10 yd) and snaps whole steps against a body that moves exactly — the plumed helm, both pauldrons, the sword and the shield, 0.83 px of hop at a fully zoomed-in close-up; each attachment now holds one rigid palette frame composed in the rig's own space, the world position added back camera-relative in the vertex stage, so nothing on the path is ever a big-plus-small sum — the property the reference keeps by injecting its view matrix once, at the root of the attachment tree
- a rider composes through the rig's own frame, not the unit's: `joints_root` re-points at the saddle's seat anchor the moment a character mounts, so reading the host entity's transform would have placed a mounted rider's helm and weapon by the gap between its feet and its saddle — pinned by a test whose seat is offset far enough that the wrong frame misses by 6 yards
- the water-walk surface is GROUND, not a post-step clamp: stepping onto water with Levitate up froze the last land velocity in — the mover classified every over-water frame airborne (liquid is queried, never swept) while the clamp reported grounded, so the body ran on at full speed through every key release; the reference has no water-walking code path at all — the flag just ORs the liquid layers into the same swept query that finds terrain — so the surface now feeds the same grounded classification the colliders do, and the clamp stays as the resolve half
- `WOW_JITTER`, a motion-jitter meter: the camera, the unit root and the pose sampled every frame as first AND second differences — Δ² tells a slow idle from per-frame noise at two orders' distance — with every reading also in pixels at the subject's own distance, because the same millimetre is 0.03 px across a courtyard and 0.8 px pressed against the camera

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:10:29 +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 db86a9c7ad the zone counters line up, and the ballista shine holds still
- the world-state readout — the top-centre counters a battleground or Silithus keeps up — takes the reference's real geometry: every icon those rows name is a sprite authored into the upper-left corner of a power-of-two canvas (`AllianceTower` is 16×16 of ink at (3,2) in a 32×32 file), nothing anywhere crops it, and the reference compensates geometrically — a 42×42 slot hung 6 units off the row's left edge with the label seated 10 above its centreline, taken as one system; our snug 20×20 box stripped exactly that compensation, so the art drew at half size floating away from its own `0/200` label — and an empty icon column now reserves its rect instead of sliding the text left, which straightens the readout's left edge
- the dynamic icon is a second slot, not a swap: `Icon` and `DynamicIcon` feed two different regions and shipped content never mixes them, so the flag is a 32×32 button off the row's right edge with an ADD-blend flash overlay pulsing 0.5 s in / 0.5 s out, lit only at `uiState == 2` — the flag-taken value; before, any non-zero state replaced the static art, which fires on the ordinary state 1 and hid a faction shield that should never have moved, and the pulse's alpha ramp is now pinned by a test, not just its art
- the dev cost pill yields the band: the readout is the game, the pill is scaffolding, and a stock 1.12 UI has no free corner to move house to — so it steps below whatever the readout draws, reading `WorldStateAlwaysUpFrame:GetBottom()` on its own 4 Hz cadence and only while it is drawing, rather than mirroring the frame's row pitch in Rust; the probe's cost is stated at the site (an edge read settles the layout — up to one graph solve, ~47 µs, four times a second)
- the Hearthglen ballista's bolt heads and shields stop flickering: a shine layer is a second batch over its base's own triangles, and ours split the pair across lanes — the base rode the retained lane's f64 CPU bake while the env-mapped, additive, no-depth-write shine stayed on the entity path's f32 GPU rotate, and a few ULPs between coplanar surfaces turns the depth test into a per-pixel coin flip re-rolled by every camera move; a batch now names the M2 skin section it draws, neither member of a shared section diverts into a consolidator (depths equal by construction), and a corpus census bounds the cost — 1,080 of 9,691 models draw a section more than once, 264 such sections across 221 `World\` doodads — with toggling pixels at the pin dropping 0.26% to 0.14%, matching the consolidators-off arm bit-for-bit

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:07:21 +07:00
SamandClaude Fable 5 462602c44b the world becomes the UI's backdrop, and recipe rows go white on hover
- every translucent UI pixel over the 3D world composited in the wrong space: the world lane and the UI lane each blend in gamma bytes the way the reference's fixed-function device does, but the one blend that mixes them — the UI camera's finished image onto the sRGB swapchain — ran in linear, so a chat tab whose body is black at alpha 102/255 left the scene at 77.5% of its brightness instead of 60%, and the dock's hover glow (an ADD with no plate under it) read as a lozenge floating on grass; the world camera now renders to an off-screen image drawn as the first quad of the UI pass, so every UI blend over the world is the same blend as every UI blend over UI — after, the selected tab plate lands at 0.593–0.600 of the bare scene against 0.60 predicted, and bare-world pixels move at most 1 LSB
- the backdrop image is un-encoded `Rgba16Float`, because the UI arc composites in gamma and takes its one decode at the end — pre-encoding would land a second encode in that chain, and quantizing un-encoded values to 8 bits is the banding collapse measured long ago; and hiding the UI keeps the world: the toggle used to retire every batch in the pass, which would now be a black screen — hidden means the two UI lanes draw nothing while the backdrop, which is the world, still draws, with the no-world glue screens pinned on the old behaviour
- a button's highlighted label is its own font instance: the client swaps which of three embedded instances the label reads — it never merges colour across states — so the `highlight_color.or(normal_color)` fallback is gone, and `LockHighlight()` now enters the label, not just the highlight texture (the reference blanks a recipe row's highlight texture to "" and then locks the row it selected — with nothing left to pin, the lock's only possible effect is the label, and that is the white text on a selected recipe)
- tradeskill, craft and class-trainer rows read white on hover and on select: all three windows carried the row name as a child FontString no per-state font can reach, behind a "no engine method" note that was true when written and stale ever since — the name is now the button's own `<ButtonText>` under the base template's `<NormalFont>`/`<HighlightFont>`/`<DisabledFont>` trio, and the windows call `SetTextColor`/`LockHighlight`/`UnlockHighlight` where the reference calls them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:06:05 +07:00
SamandClaude Fable 5 73826ca3d7 casting a hunter shot starts Auto Shot, and the ping wears its real art
- Serpent Sting starts Auto Shot in play: the chain built earlier the same day never fired because the in-flight record was armed only for the cast classes it refuses on, and every hunter shot is a ranged attack — the reference records every commit and discriminates at the gate; two tests now run the real ladder and reproduce the shipped symptom
- the minimap ping is MinimapPing.mdx, measured: three additive quads — a 12 px spinner on the model's global clock, a static core, and a ring expanding 3→32 px on an 833 ms loop — the interim art was ~3× too big and missing the ring the eye actually reads
- a mouse release goes to the frame that took the press and nothing else — the reference's up handler reads the capture alone and never the hover frame, so a press over open space delivers no release to whatever the cursor wandered onto (corrects the morning's fallback)
- `WOW_MOVE_TRACE_TAGS=use` traces a right-click end to end (the cursor decision, the use packet, the spell-go answer), and the first headless hover capture parks the cursor on a chat tab so the reveal can be measured against the bare scene

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:50:40 +07:00
SamandClaude Fable 5 f8421c1545 the colour wheel draws, chat windows move, and the minimap ping returns
- the colour picker can pick a colour: the hue disc and the value strip are engine-generated pixels (no BLP in the chain is a wheel), reproduced from the reference's own lattice — a hard-cut circle at a literal V = 1.0, the brightness marker moving over a disc that never dims
- chat windows move and resize once unlocked (Lock/Unlock Window on the tab menu; the reference's own 296×75 to 608×400 bounds), the border textures doubling as the grips, and the placement is remembered per character in benilla-config/layout; both windows ship locked, as 1.12's reset leaves them
- the minimap ping is back and pinned: one world point the engine draws, the click converted in the right unit (the old path was ~27% off at 1080p), and no 10-yard auto-clear — that was the gossip marker's rule, and walking to your own ping was deleting it
- the Lightwell can be clicked: a billboard card is a world root with no parent hop, so the hit resolved to nothing and the whole shaft published a null mouseover; casting a hunter shot chains Auto Shot through `Spell.dbc`'s modalNextSpell column (the mechanism nobody had read — the next snapshot carries the seam that makes it fire in play); tradeskill list rows stop tooltipping (that hover was ours, not Blizzard's), and OnMouseUp goes to the frame that took the press

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:49:16 +07:00
SamandClaude Fable 5 eaabe372f7 the Lightwell stands up, and stealth openers start your swing
- the Lightwell has its shaft: a billboard card kept only the x of its bone's scale, so a bone animated non-uniformly (the well's 8.8 × 8.8 × 37.6 light column) collapsed into a squat blob drowning the bowl — 32 models and 49 bones in the corpus were losing their stretch the same way, mage Teleport's six bones at ×11 among them; `bbscan` grew the column that finds them
- Backstab, Garrote, Ambush, Cheap Shot, Shred, Ravage, Pounce and one Judgement start your auto-attack on the spell's hit, as the reference does — the "no spell carries that bit" the deferral rested on was a proof by absence over ten rows; the census now covers the shipped file's 36
- Quiver's range rung reads right: the interact-distance map held players only, so a mob "target" answered a constant at every distance; it holds every unit now, with the inspect refusal riding the entry
- the craft and tradeskill reagent slot is the reference's QuestItemTemplate (147×41, the name plate, the count on the icon) — its base template lives in the Blizzard addons, not FrameXML, which is why the first cut was hand-rolled

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:47:48 +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 1c5db5c2c1 landmarks and the Plaguelands towers on the map, no ultrawide crop
- the world map's landmarks: city icons and the Eastern Plaguelands towers, from AreaPOI.dbc through the reference's own three gates (level flags, exploration, world state) — the tower rows are one per (tower, owner, state), so the server flipping a world state swaps which icon exists; and the always-up PvP readout ("Towers Controlled: n") over a new WorldStateUI.dbc loader, the init clearing the table on a zone change as the client does
- the character-select scene holds its authored 4:3 view box: the diagonal-FOV relation was fed the display's aspect, so every extra pixel of width came out of height (1.55× zoom at 21:9, head and feet gone) — now width grows and height never shrinks; the reference does the same and is wrong on the same panel
- a trail particle is stored in world space and drawn raw: Sprint's trail was welded to the chest bone (turn and it swings, run and it wobbles) because the trail was faked by subtracting translation inside a bone-local store; the correction machinery deleted itself, gravity is plain world down, and the emitters' live attach frame is retired
- the spellbook can shrink: `SMSG_REMOVED_SPELL` had no handler, so a talent wipe took the points back and left every rank drawn; and the chat dock's hover driver rides a frame the dock cannot hide, so selecting the Combat Log no longer freezes the tab alphas

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:43:04 +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 9e83e6608d the Combat Log tab exists, and black portraits get their faces
- the chat dock's second tab, Combat Log, exists — 44 combat chat types had been routed into a window with no tab, no rect and no border art; both tab labels resolve from the install's GlobalStrings, the docked window keeps its anchors out of UIParent's managed-position pass, and the reveal fade reads whichever window is selected
- the Fire Roc and Dredge Crusher portraits show a face instead of black: a skinned booth part was frustum-tested against its bind-pose box while the camera is aimed at its Stand — a flat-authored bird posed itself six units above the box every frame; eleven creature models (harpies, wind serpents, the battle standards) had the same empty bake, and `WOW_BOOTH_LOG` now says where the posed skeleton is, not only the camera
- you cannot sit down while swimming: the client's one stand-state setter reads the live movement flags against `0x20000f` (the four direction bits plus SWIMMING) and returns before the packet is built; standing up never reads it, so the water stays escapable

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:37:10 +07:00
SamandClaude Fable 5 ac2ed34735 the combat log speaks, and the swim line follows your native form
- the client synthesises its combat-log chat lines: 44 chat types over 34 GlobalString families from 7 packets, the reference's own four hops (classify both endpoints → chat type → string key → format), text resolved out of the player's own GlobalStrings — so damage meters and Quiver's TranqAnnouncer have something to parse; wow-re's byte round corrected six gates (owner is charmed-by then created-by, "party" is your subgroup, friend-or-foe is CanAttack, the range gate, the miss defaults, the damage-shield chat type)
- the collision prism follows the NATIVE display, not the rendered one: a druid in bear form keeps the druid's swim, splash and wade lines and a morph keeps the human's — worst divergence on shipped data 0.72 yd (tauren moonkin), the sign flipping by form
- the creature swim gate is on both legs: a unit that loses its flag mid-water is driven out of swim at any depth, as the reference drops a charmed creature to the seabed on the next tick

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:35:32 +07:00
SamandClaude Fable 5 b3a156f090 plate armor rings like plate, and sea giants walk the seabed
- a plate-wearing player's incoming hits stop sounding like a punch on meat: the victim's impact column comes from the chest armor's material (plate, chain, else flesh), the clang follows the defending item's class and material (a wooden shield rings wood, an unarmed parry is silent), and Material.dbc's Flags column gets one home instead of three interim readings
- a creature swims only if the server said it may: the reference tests three unit flags before starting a swim, and a Shore Strider carries none, so it wades chest-deep with its legs working instead of gliding — the collision height the triage suspected was right to the float; the height also takes the reference's max() floor over the display scale
- a second nudge of the rotate arrow inside a half-run blend no longer stacks fades: the client refuses the snapshot past the halfway mark and lets the older pose finish on its own window

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:34:09 +07:00
SamandClaude Fable 5 a8ab442d27 every melee hit makes a sound, and footsteps get their armor foley
- every connecting melee swing makes a sound: the reference splits its swing sound in two — a miss whoosh by handedness, and for a landed hit, parry, block, immune or deflect the WeaponSwingSounds2 kit picked by the swinging hand's weight class, a DBC column (ItemSubClass.WeaponSwingSize) this crate had carried unread; deflect and absorb get their real kits after three weeks as silent stubs
- a footfall is two sounds: the terrain step and the armor foley of your chest piece's material — chain, plate and leather rustle, cloth is silent by data; on the real 1.12.1 files every creature model's foley material is 0, so the foley you hear in the reference is your own, and that is what ships
- the paper doll's turn cross-fades at both ends instead of cutting — the reference plays every turn clip blended over the incoming clip's own authored blend time (0.25 s into a shuffle, 0.5 s back to Stand on HumanMale), and the outgoing clip keeps running under the fade rather than freezing, which corrects a "universal snapshot law" an earlier record had over-generalised; `m2seq` prints the blend column that settles such questions

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:31:38 +07:00
SamandClaude Fable 5 c6c7516a3b party members show on the world map, and the leader wears the crown
- party members appear on the world map at their position and hovering names them — the party wire has carried each member's zone and coordinates since the group arc; the blip and the minimap dot read one shared position so they can never disagree, and the member's zone picks which continent the position belongs to
- the player's own frame wears the leader crown and the master-looter icon, with the reference's own asymmetry (the crown asks IsPartyLeader, the member frames compare a leader index)
- a party member outside your local area gets the generic race/sex portrait instead of an empty circle — their race and sex ride the name query, and nothing had asked for a member we never see; the roster now warms that cache, which also fills the raid grid's class column
- right-clicking a member who is nowhere near grays Trade, Inspect, Duel and Follow: the reference's bindings answer nil for a unit the object manager does not hold (carved this session), where ours defaulted "absent = in range" for exactly the farthest member; and the group-invite popup's background is measured faithful — the plate draws at the BLP's own 60% alpha

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:30:24 +07:00
SamandClaude Fable 5 9e76f121f8 master volume moves ahead of the limiter, and mute NPCs greet you again
- the master volume was applied after the limiter, so turning the game down scaled the pumping with it — two full-scale copies at master 0.25 came out at half the level they should, the limiter ducking 6 dB on a mix that was never going to clip; the master is now the first effect in the chain
- six creature displays with a body loop could never say hello: one `source` tag answered three questions (ownership, the greeting latch, the bark latch), so any looping sound on a unit held its greeting latch for life — the latch is its own marker now, and a server-pushed object sound silences that unit's own grunts and barks while it plays, the reference's AISOUNDDESC registry
- the attacker's exertion grunt fires from the attack packet, not the animation tag (the tag drives the victim's injury vocal only), with the reference's per-class chance tables read out of the binary; the voice cap can no longer steal a latch-holding channel and turn a pet's aggro roar into a repeat generator
- fmod.dll itself read end to end: there is no hidden headroom in its mixers (full-scale sum, one clip) and the reference never steals a voice — every WoW channel is a stream at the one priority the allocator refuses to take; what the two unvoiced melee legs are blocked on is named precisely

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:27:52 +07:00
SamandClaude Fable 5 03fedf1375 the paper doll steps its feet round, and the Raid Info button behaves
- rotating the paper doll plays the reference's turn-in-place shuffle instead of spinning it like a turntable — ShuffleLeft/Right picked by direction off the same scalar `SetRotation` is handed, a 100 ms expiry, a frequency-weighted idle variation on the way back; wow-re's re-derivation caught the pair inverted in the prose (the doll was stepping into its turn), and a display with no shuffle stays standing rather than freezing mid-turn
- the doll's item effects run at full speed: the half-rate booth render (our pacing, not a cull) was skipping the emitter tick with the frame; measured off the reporter's side-by-side clip the skeletal clock was never slow, only the 30 fps cadence, so `boothHalfRate` now defaults off
- the Raid Info button follows the server's answer: `UPDATE_INSTANCE_INFO` fires per packet as the client does (the reference discards the first), so a character bound to nothing ends with a grey button over an empty panel instead of a live button over nothing; the panel's scroll bar sits centred on the trough drawn behind it
- an inspected player's gear keeps the template's bind line, stated as deliberate — there is no item object to read a bound flag from, which is what the reference prints for the same reason

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:26:45 +07:00
SamandClaude Fable 5 5a12410f5b raid tab art is back, set bonuses fit, and 12 voices bound the mix
- the mix is bounded the way the reference's is: FMOD gave 1.12 exactly twelve software channels and nothing else limits a priest buffing five people — ported as a 12-voice ceiling (a probe capture read 42 live voices at +13 dBFS, the limiter pumping 13 dB to hold it), plus same-kit copies started in one frame capped at two, since five sample-aligned Fortitudes are one sound +14 dB; `$WOW_SOUND_PROBE` records the mix before and after the limiter with a timeline, F9 stamps the moment
- the raid tab draws its window art again — its four corner textures were written with single backslashes, which Lua drops silently, and a sweep now reads every archive path a shipped Lua chunk names; a drag whose release never arrives (pointer left the window, a second press) ends instead of gluing the frame to the cursor for the rest of the session, and `WOW_PROBE_DRAG` drives any UI drag headlessly in a live client
- the item tooltip fits its set bonuses again: an emptied line kept its last measured height forever (a pooled cell with no way to say "empty"), and the two blank rows above the set block are the reference's own literal (a space and a newline) — a whole row each, not the empty string
- an equipped BoE or BoP piece reads Soulbound: the bind line reads the item's own flags through the client's bound predicate instead of the template's bonding, one predicate shared with the enchant cursor's bind confirm

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:25:07 +07:00
SamandClaude Fable 5 eeb607e5e6 the raid tab lands, and sounds take the reference's voice buses
- the social window's fourth tab, Raid: the eight-subgroup grid over the roster, drag a member between subgroups, Convert To Raid, promote / demote assistant, uninvite, Ready Check with its popup, and the Raid Info flyout on the new `CMSG_REQUEST_RAID_INFO` / `SMSG_RAID_INSTANCE_INFO` wire (byte-golden against vmangos, an empty answer decoding as an empty list); `raid1`..`raid40` unit tokens, and `/partytest raid` stages a roster for a solo look
- an imbue pressed with an empty weapon hand says "Your weapon hand is empty" instead of raising a cursor — the attribute bit has two readers in the reference and the second is the error (corrects the day's first cut)
- sounds route onto the reference's own voice buses with its per-bus caps (the 0x87ce60 table, pinned as bytes): weapon impacts and clangs share four voices, footsteps six, the attacker's grunt one, the victim's injury two — so a pack swinging together makes about a dozen voices where it made dozens

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:22:17 +07:00
SamandClaude Fable 5 915ebc0119 the login theme rides the loading screen, and the mix gets a limiter
- the login theme no longer cuts off the instant the loading screen appears: it plays through the whole load and hands over on a 3 s fade once the world is ready, as the reference does — the stop sat on the same edge that raised the cover, and the reference never calls its music-stop on the enter-world path at all
- the mix had no headroom: every WoW sound is mastered to full scale, so five party-wide Fortitudes in one frame asked for 5× and clipped hard ("dirty, like a speaker breaking") — a stereo-linked look-ahead limiter now holds the output, a meter reports the peak the mix asked for, `SoundOutputLimiter 0` A/Bs it, and the 3D voice ceiling is named at 512 instead of inherited from the backend at 128
- a shaman's Rockbiter / Flametongue / Frostbrand / Windfury Weapon casts straight onto the equipped weapon on the press — no item cursor, no click — the reference's own `Attributes & 0x200` read; stones, oils and poisons still raise the cursor
- the nameplate category's player arm is pinned to the bytes (CanCooperate is faction-group-mask equality) and `/reaction` prints the one number it turns on: a GM-mode character plates as an enemy on a test realm because faction 35's mask is zero, exactly as 1.12 does

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:04:59 +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 6aa78bc468 the shapeshift cloud both ways, and the Honor tab
- druids get the shift cloud back in both directions, by the reference's own mechanism: every shapeshift aura add *or* remove arms a one-slot pending-morph latch that the model-swap rebuild drains and replays — which is why shifting out (a client-side cancel the server sends no visual for) puffs at all, and why a GM morph or a revive correctly shows nothing; the first fix that merely let one-shot effects survive the swap's teardown produced the right pixels for the wrong reason and is superseded
- the honor system lands whole: the Honor tab on the character window, the honor page on inspect, and thirteen missing Lua bindings over a real wire model — session/yesterday/this-week/last-week kills, lifetime HKs and DKs, rank progress and badge art
- the load-bearing find: your current rank and your highest-ever rank are two separately-streamed fields, and the one we already had was the wrong one for anyone who ever de-ranked; a binary cross-check corrected five display details after the build, down to the rank title never being gendered

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:22:13 +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 9bd2609740 windows take turns, the gossip page waits, the shot bar counts down
- the UIPanel registry is re-derived from the reference's bytes: the readable-item page finally registers, so a note or letter closes when a gossip window opens instead of interleaving with it line for line; the character sheet takes its real pushable-2 seat (an NPC window slides it over instead of replacing it), and the spellbook, quest log, talents and character sheet open for dead players again — a refused open now says "You can't do that when you're dead." instead of doing nothing
- the gossip window waits for its greeting: the first packet carries only the options and a text id, and we used to show the frame with a blank page for the round trip the text needed — the menu now exists only once the text has answered, a mid-flight click is refused, and a revisit is instant off the cache
- a bag slot whose stack count changes on the server now fires `ITEM_LOCK_CHANGED` just ahead of its `BAG_UPDATE` — the one signal 1.12 hunter addons use to detect a spent arrow — so Quiver's auto-shot bar drains per shot instead of pinning at 100%; a swap or create deliberately does not fire it, so rearranging bags can't read as a shot
- the outdoor minimap tiles' gamma byte reaches the screen exactly once — the ordinary decode arm learns the same skip the fast path already had

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:17:03 +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 b3dbd5d6ab speech you don't know arrives scrambled, and a GPU crash dies
- opposite-faction speech garbles client-side now, the way 1.12.1 actually does it: the wire carries plaintext plus a language id, and the client substitutes per word — a word survives iff `SStrHash(word) % 300 < skill` (300 copies verbatim) — reimplemented from `0x49b560` over the LanguageWords pool, 35 golden vectors passing; a Horde character also stops seeing a spurious `[Orcish]` tag on every line of their own faction's chat, and the talk gesture reads the plaintext, not the garbled line
- a mid-session wgpu validation crash is gone: `NoIndirectDrawing` rides the camera's spawn instead of a per-frame sweep — 18 cameras were being flagged after spawn, and one whose first extraction beat the sweep latched indirect buffers forever; the census now reads zero late inserts with the direct-draw optimisation fully intact
- the 20-yard overhead-name cap is withdrawn: it read the V-key nameplate frame's law onto the overhead name lane, which the bytes show carries no distance term at all — a distant name just gets small; V-plates keep their 20 yd, which is correctly theirs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:06:27 +07:00
SamandClaude Fable 5 b15902b135 six lanes stop paying for the idle crowd, and Print Screen lands
- Print Screen takes a screenshot to `benilla-config/Screenshots/` (F13 on macOS), shows the reference's "Screen Captured" line, and the line never appears in the file — the capture defers one frame so the hidden confirmation's quads rebuild first; and the rule it surfaced is now hard law: benilla never writes anything into the WoW install
- six per-frame taxes now skip when their inputs are settled: water foam asks a spatial index (a dry unit is one hash miss, was a ~2.2k-surface scan per unit), an idle remote stops its capsule sweeps at the fixed point, hover picks stop allocating ahead of the ray-sphere reject, an unchanged unit's loadout is not re-derived, and the ground-shade walk stops re-asserting the world — settled inputs produce bitwise-identical outputs, each lane fenced by its own test; ms pricing still waits on a quiet machine
- overhead names take the V-plates' 20-yard cap, read at the bytes (this one is wrong and reverts in the next snapshot — the law belongs to the other nameplate system)
- the calendar lifts out of the `date()` global into its own module

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:04:55 +07:00
SamandClaude Fable 5 7171a4997c bogus form requirements, the hover jump, and mining at skill 1
- priest tooltips drop their bogus red lines ("Requires Shadowform" on Psychic Scream and Inner Fire, "Requires Spirit of Redemption" on Flash Heal): `Spell.dbc`'s Stances mask is an allow-list, not a requirement, when `AttributesEx2` bit 19 is set — 244 of the 522 masked spells carry the waiver, and the tooltip now consults the same gate the cast validator already did; Charge's "Requires Battle Stance" still asserts
- a hovering mover refuses the jump, silently — no packet, no toast — exactly as `CMovement::Jump` does: the HOVER test sits ahead of the swim select, so a levitating swimmer can't breach either; the old gate refused on ROOT only
- opening a lock gates on your skill, never your level: mining with 1 Mining no longer appears to open a 300 vein only to be bounced by the server — the client-side "Requires Mining ≥N" refusal fires with no packet sent, and the level term rides the skill block through the same clamp the reference uses
- the Mod/Mod2x fade was never a deviation — preset 5 IS the identity-lerp, byte-exact, five comment sites re-lawed with no behaviour change; and the garble word pool (`LanguageWords.dbc`) loads, the first hop of the language scramble that lands next

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:03:19 +07:00
SamandClaude Fable 5 a76530ab62 the minimap's black lines close out, and shared water cells draw once
- the Stormwind/Orgrimmar minimap lines are gone, at the cause: a group's boundary tile is authored 1.0 yd larger on that side alone, so touching groups overlap by 2 yd — without the bleed a LINEAR-filtered silhouette loses ≈0.38 texel at every abutment and the black clear reads through as a dashed line; with it, disc black goes 4.49% → 3.69% and no lines, inside the reference's own band
- the tile sampler stays LINEAR but filters in gamma space (`GL_SKIP_DECODE_EXT`, as the reference's trace has it) — a terrain underlay and a NEAREST sampler both reproduced the symptom and were both retracted as wrong once wow-re refuted them
- the canal-surface line in the world was a second defect: Stormwind's canal groups genuinely overlap (14,416 lattice points claimed wet twice), so the translucent sheet composited twice — the MLIQ `0x80` shared-tile gate now resolves each shared cell to one owner at load, pixel-identical and zero double-claimed points, not one wet point lost
- the interior composite is probeable headless now: `WOW_MM_PROBE` synthesises the minimap slot server-less, and an offline rebuilder reproduces the defect and the fix from the shipped art

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:01:55 +07:00
SamandClaude Fable 5 35a7c870ba a 6.3 MB-a-frame copy dies, and the ghost portrait comes back alive
- the rig-palette copy-on-write copies the live prefix, never the capacity: ~6.3 MB of memcpy per frame — paid everywhere, however few rigs were awake — becomes the ~250 KB actually live, ~25× smaller and observationally identical
- a frozen model-particle pool stays hidden (spell shards were drawing through walls and the cull forever), and a parked rig's animation event tracks fall silent like the reference's — except MORE_AUDIBLE creatures, so off-screen combat stays audible while the rest of the world goes properly quiet
- an automatic dismount no longer keeps the mount's run speed on foot (the reported `.tele` repro): a mover's speeds stage for the whole drain instead of being written live mid-teleport
- a dead character's portraits show the living face again: the ghost death-screen pass was leaking into every portrait bake — all eight portraits, paper doll, inspect, dress-up — because the death gate was the one combine lane with no per-view scale; post-fix the bake reads MAE 0.000 against the living control while the world still goes steel-blue on release

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 18:00:31 +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 6d1e13d147 there are three water renderers, and WMO water gets its two
- WMO water stops running the terrain-liquid program: the material key names WHICH renderer a pool takes, and the two WMO arms land — Blackfathom Deeps' interior pools take their authored per-vertex opacity and the material's own body colour (34, 38, 57 there — the dark blue-grey in the reference shot) instead of coming out opaque and daylit on the zone's river swatch
- the exterior WMO arm bands at sub-17, not sub-16 — teal, not olive — which is what the Stormwind canals actually read as
- a hole corner's authored height no longer counts as a height, and a corpus-wide instrument reports which WMO water arm every pool takes
- the ADT/Felwood golden sweep is bit-identical: open-world water is provably untouched

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:55:04 +07:00
SamandClaude Fable 5 8709dd6bc9 dark overcast skies, a talk gesture, and NPCs that face you
- the Tainted Scar sky reads its dark red overcast instead of almost pure white: a light-band row with no keyframes now commits the client's own constant — black for colour rows, +0.0 for scalars — instead of an invented neutral-daytime palette; Blasted Lands authors cloud density 0.85, so the cloud gradient IS the sky there, and sky pixels go `rgb(255,255,255)` → `rgb(145,55,25)` while the terrain control stays bit-identical and the blessed capture sweep holds MAE 0.000
- an NPC you interact with turns to face you and holds the bearing while the window is open — client-side, a per-frame facing-goal chain whose smoother halves the remaining angle each frame (π settles in 8–9 frames); the server sends nothing, and a patrolling guard or a creature in combat is unaffected
- sending a chat line plays the talk gesture, like every 1.12 client: a say reads its last byte (`?` question, `!` exclamation, else talk), a yell always shouts, a laugh-word laughs — five gestures resolved from Emotes.dbc flag bits, and talking stows a drawn weapon
- a standing capture viewpoint pins the Tainted Scar sky for regression

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 17:52:20 +07:00
SamandClaude Fable 5 d88aa932fe README: the addon folder is benilla-config/AddOns, as the code names it
- the addon line's folder is corrected to `benilla-config/AddOns/` beside the executable — the name `local_state` actually uses, not the decision record's original

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:15:14 +07:00
SamandClaude Fable 5 37193940ef README: addons load from benilla/AddOns beside the executable
- the README's addon line names the real folder — `benilla/AddOns/` beside the executable, the one local-state folder everything else of benilla's lives in — not the install's `Interface/AddOns`

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:14:06 +07:00
SamandClaude Fable 5 784822af46 README: what works, what is partial, and what is not built yet
- the "Not built yet" paragraph catches up with the last two weeks: guilds, the pet bar, fishing, the dressing room, macros and key bindings are in, and the list is now battlegrounds and honor, the auction house, and the unfinished half of addon support
- third-party addons are stated as partial: AtlasLoot and Bagnon run, and the addon API fills in as more addons are tried
- the UI line names the guild, macro and key-binding windows among the classic windows it drives

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:11:35 +07:00
SamandClaude Fable 5 a047a31aea the troll gate stops flickering, the signpost lands, the chair holds
- a fix16 animation key is signed: Zul'Farrak's troll gate was drawing its burnt twin inside the intact one (a −1.0 key read as +1.0, so the cull never fired) — 24 two-state models stop showing both states, 65 fade curves lose an over-bright tail
- a GameObject is placed by its quaternion, not its facing: the Ravenwind arm of the Feralas signpost comes down from mid-air onto the post, and 1,411 visible spawns — 123 of them chairs — take their authored tilt; the inspector shows it
- sitting in a chair holds: a jumpless fall puts nothing on the wire until it lands and heartbeats on the ordinary 500 ms deadline, so the stalled frames inside the chair's collider no longer send the moving flag that stood you back up; and the use cursor greys past the chair's own 3.0 yd reach
- README's "Not built yet" catches up: guilds, the pet bar, fishing, the dressing room, macros, key bindings and addons are in

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:10:13 +07:00
SamandClaude Fable 5 d2b3492cd5 the walking tax banded, and the minimap stops rewriting the world
- a panning UI batch rides its Transform instead of rewriting its mesh, minimap tiles emit unclipped (the mask shader already zeroes the corners), and the blip layer's origin snaps to half a logical pixel — steady UI mesh writes while moving drop from ~183/s to 10–14/s, and three minimap quads stop arming change detection over ~40k world meshes
- the classify twin GC comes off the despawn edge: a part despawn schedules the full walk behind a 2 s deadline instead of running it that frame — 12–22 full walks a second while walking, gone
- the walking tax measured and banded at Goldshire: parked 10.7 → moving 14.1 ms/frame of process CPU, ~+2.5 after the two fixes above
- WOW_PART_CHURN and WOW_MESH_HOLDERS count part spawn/despawn frames and name which entities hold a churning mesh; the capture rig's `at:` pin learns a facing

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:09:00 +07:00
SamandClaude Fable 5 ed8bf36625 the perf pill leaves egui, and the field store goes flat
- the perf pill is ~25 quads on the player-UI pass — `{fps} fps {cpu} ms` and nothing else — so the egui lane sleeps whenever no dev panel is open, instead of the collapsed pill paying ~1 ms for egui's whole per-frame train
- the pill is the whole HUD: the expanded readout, the spike arrow and the spike-detection engine behind it are removed; a >250 ms hitch still logs
- WOW_CPU_CENSUS=<at>:<secs> — a per-thread CPU census that sums to the process total exactly, user/sys split; in Lower Blackrock Spire the main thread is ~41% of ~14.5 ms, the render thread ~17%, the compute pool ~25%, Metal's own workers ~12%
- the object field store goes flat: the wire's presence mask plus a dense value array replace a BTreeMap, so 5–10k descriptor probes a frame are two array indexings — the main thread ~0.5 ms/frame lighter at the same pin

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:07:34 +07:00
SamandClaude Fable 5 e34600ff27 the client boots with no install, and the idle egui lane goes quiet
- with no WoW install the client boots to the login screen instead of panicking on frame one: three world systems demanded install-gated resources their own startup never inserts
- `WOW_DATA=` — set and empty — means there is no install, in any build; the cursor says "no client data" once instead of thirty-one times
- the per-frame `bevy_egui pass output has not been prepared` ERROR is gone: a gated context runs an empty pass itself, so the idle lane keeps its savings and the log stays silent
- ECS diagnostics name their system in a dev build — no more `<Enable the debug feature to see the name>` in a panic

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:06:09 +07:00
SamandClaude Fable 5 0af70dc8c7 the paper doll animates again, and the char-select plaza stops pulsing
- the paper doll and the character-select stage animate again: a staged rig is fenced off the world's frustum parker, which had been freezing every booth half a second after its bake
- the char-select plaza stops pulsing dark and bright after a geared relog: the off-world lane now carries its authored batch order, so a ground decal and the street under it stop swapping on a sort tie re-broken every frame
- the perf HUD goes on a diet: two small numbers and a bare arrow, drawn from a 4 Hz snapshot instead of the live meters
- a missing file in a player's addon manifest logs WARN, not ERROR — a broken third-party package is the addon's defect, not the client's

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:04:09 +07:00
SamandClaude Fable 5 85d62fec73 the paper doll goes half rate, and the parked frame diets
- the paper doll joins the collapsed rig lane and its body panes render every other frame while open, the pose still evaluating at full rate (boothHalfRate CVar) — the open character window's cost at Goldshire ~+2.7 → ~+1.0 ms
- the parked frame's idle diet: avian's dynamics pipeline goes (the world has zero dynamic bodies), the hidden dev overlay stops drawing an empty pass, and a unit's swim state is re-checked only when it moved — 12.8–13.3 → 12.0 ms parked at Goldshire
- the UI tick stops sweeping the whole frame arena three times over: OnUpdate frames and the message and cooldown kinds live on registries kept at their one write site — idle tick 530 → ~195 µs a frame
- the WOW_MEGA_STATIC bracket retires, past its recorded condition now that the retained pass carries its own

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:02:44 +07:00
SamandClaude Fable 5 5360a44f89 event-driven UI feeds, and the character window's cost lets go
- the eight heaviest UI feeds — spellbook, party, character, bags, talents, units, pet, player — rebuild only when an input moved instead of every frame: 216 → 12 µs a frame parked
- the character window's cost settles once it closes: enchant countdowns feed by the second instead of firing an inventory event into all 20 slots every frame, the paper-doll booth parks with its camera, and a window hidden under the cursor fires OnLeave so its tooltip goes with it — the reference's hover-hide law
- the walk stops paying for finished work: the loading-screen tally's per-placement walk latches off once the world is ready, the settled placement spawner is one integer compare, and billboards stop dirtying every card's transform
- never-rendering hierarchy nodes — rig anchors, joints, doodad hosts — keep the hide chain but leave the per-camera visibility sweep: 25,198 → 18,026 swept entities at Goldshire

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 19:01:11 +07:00
SamandClaude Fable 5 447e92aed5 three parked costs burned, two schedules go single-threaded
- the sun flare's terrain-occlusion march re-prices 2 grid cells a frame instead of 768 height queries, the retained pass's published regions go behind an Arc instead of two memcpys, and a unit's splash line is re-read only when its pose changed — −0.66 ms parked at Goldshire, pixels bit-identical
- PostUpdate and the render extract schedule run single-threaded by default — ~620 mostly no-op systems were paying the multi-threaded dispatch premium — −0.90 ms parked at Goldshire, −0.8 walking in Lower Blackrock Spire; WOW_MT_POSTUPDATE and WOW_MT_EXTRACT are the levers back
- GltfPlugin, AntiAliasPlugin and GilrsPlugin leave the boot — machinery for types nothing makes, 31 systems a frame fewer
- WOW_SCHED_CENSUS lists every schedule's systems with their executor-relevant flags, both worlds — the inventory the flips were priced against

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:59:48 +07:00
SamandClaude Fable 5 6f2d7e8a63 the retained static-world pass ships on by default
- the retained pass pays its churn debts: one shared texture-array pool with each layer encoded once, re-bakes that wait for a quiet window, killed placements leaving the draw runs — VRAM flat at 76 MB parked at Goldshire where it had climbed past 127, GPU 4.2 → 2.0 ms
- a building's furniture joins the pass in its own per-building region, so a prop's arrival never re-bakes the walls — submeshes 28,367 → 7,747 at the Stormwind gates, and Lower Blackrock Spire reads its first win, −0.37 ms
- WOW_STATIC_GX defaults on: negative at all four pins, −1.36 ms walking at Goldshire and −0.76 at the Stormwind gates; WOW_STATIC_GX=0 restores the entity path byte-for-byte

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:58:25 +07:00
SamandClaude Fable 5 4510607e91 the static world gets a retained draw pass, dark behind a flag
- behind WOW_STATIC_GX=1, never-fade doodads leave the per-entity renderer for one cross-material draw per 133-yard cell, pixel-identical to the entity path at the 1/255 floor
- WMO group geometry joins the pass with the portal flood as CPU range selection — in Lower Blackrock Spire the entity lane's WMO draws drop 33 → 0, no leak
- the fading doodads ride it too: a doodad inside its feather band is punched out of the retained draw and respawned as an ordinary entity, so the fade is the current look by construction
- correctness banked, performance not yet: the first legs read +2.36 ms at the Stormwind gates and +7.27 parked at Goldshire — per-cell texture arrays rebuilt on every re-bake are the priced cost, WOW_GX_PERF=1 meters the lane

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:56:36 +07:00
SamandClaude Fable 5 4080d4feff the static merge defaults on, and the fence pop is gone
- every run now merges the static world: never-fade doodads and interior props bake into per-cell blobs, −0.42 ms at the Stormwind gates and ~−0.2 at Goldshire; WOW_STATIC_MERGE=0 opts out
- the fading doodads stay individual — one translucent draw per cell depth-killed whatever feathered behind it, the lamppost popping in behind a Goldshire fence — and WOW_MERGE_FADERS=1 keeps the dev lane
- merged blobs sort at their own centre instead of the world origin, and their pipeline variants pre-warm so no blob compiles live mid-walk and steps the fade
- roaming converges on the parked shape: a quiet cell re-bakes its fragments into one blob, and a doodad straddling two tiles hands off to a loaded neighbour when its owner tile unloads

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:55:03 +07:00
SamandClaude Fable 5 352b90a1ae the static world merges into per-cell blobs, behind a flag
- behind WOW_STATIC_MERGE=1, never-fade doodads, fading doodads and interior props bake into one mesh per 133-yard cell and material — −0.99 ms at the Stormwind gates, a wash in Lower Blackrock Spire, GPU flat
- the merged faders fade in-shader on the reference's own fading draw state, so the ramp is as smooth as an individual doodad's
- interior props carry their light-probe slot per vertex, and the arrival cover waits for every unbaked blob so a reveal never shows a hole
- a merge census (WOW_MERGE_CENSUS=1) prices each population before it is built — WMO group geometry merges nothing and stays individual

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:53:51 +07:00
SamandClaude Fable 5 deae999024 liquids keep time in the shader, and the frame is measured CPU-bound
- water and lava keep time in the shader: the 24 Hz CPU tick that re-uploaded every liquid material is gone, −0.28 ms at the Stormwind gates, and lava scrolls smoothly instead of stepping
- static transform tracking is pinned on — the adaptive check spent two full scans a frame to say yes in a world where movers are 1–3% of the rows
- WOW_MEGA_STATIC merges static geometry per material and 133-yard cell — an experiment lever, priced at −1.15 ms CPU for +0.3 ms GPU at the Stormwind gates
- WOW_GPU_MS times the whole frame on the GPU and reads 2.2 ms against 17.4 CPU at the Stormwind gates: the frame is CPU-bound, so the work ahead is on the CPU side

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:50:55 +07:00
SamandClaude Fable 5 820c406049 the interface labels announce their writes, and the idle tick goes quiet
- a text write names its own label, so the per-frame measure sweep drains a short ledger instead of hashing every font string twice — ~0.3 ms a frame at the Stormwind gates, gone
- the idle interface tick stops re-writing settled state: buff durations and the weapon-enchant frame write only on change, and the fade and unit-popup drivers park until woken
- the interface extract skips a hidden region before cloning its row, not after
- WOW_UPLOAD_BUDGET=<MB> brackets the arrival burst's upload pacing — a lever for measuring world entry, not a fix yet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 18:48:12 +07:00
SamandClaude Fable 5 8522c65937 the lava bubbles move again, and the bonfire keeps its wood
- Blackrock Mountain's lava bubbles animate at last: their sprite's flip-book channel was baked from a sequence they never play — UV and tint loops now bake per sequence, and a placement whose sequences disagree gets its own material
- a bonfire's logs were vanishing while its flame burned on: a body planted just under its own floor now claims the room above it, and the flame card and fire sound follow the body's cull instead of outliving it
- a WMO prop's animation host stops being cull-tested as an object in its own right
- WOW_TILE_RADIUS's doc now states its real default, 2, and why

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:27:28 +07:00
SamandClaude Fable 5 802845981f the Rookery eggs hatch, and the bubble finds its height
- UBRS's Rookery eggs hatch on approach now: the trap's despawn-anim packet was silently dropped and the entity freed the instant the destroy landed — the packet is parsed, and the reference's refcount pin holds the egg alive through its 2.7 s burst before it goes
- the AQ drakes' crawl is the server's doing: vmangos flies cyclic paths at walk speed, and the client's ride measures exact against the wire — the motion is inspectable now, down to a per-spline trace
- the chat bubble sits at the height 1.12 gives it: a latched constant from the model's stand box, replacing the posed-attachment anchor the RE just refuted
- the trigger-creature render gate folds back from the binary, byte citations corrected

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:26:18 +07:00
SamandClaude Fable 5 287b109773 the bubble's pale lines, and the trigger NPC finally hides
- the pale lines through the speech bubble were its backdrop atlas bleeding across its own slices under magnification; the slices now inset, verified per row against the real backdrop bytes
- a bubble that never appears can say why: all seven silent refusals report themselves under the bubble trace
- the invisible trigger creature goes invisible at last — there is no server flag to consume; its model is authored empty, and the black slab people kept meeting was our own placeholder cube. a display that names a model now draws exactly what that model builds, including nothing
- a census probe lists which streamed entities are standing as placeholder cubes, and on which displays

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:22:57 +07:00
SamandClaude Fable 5 76f316d040 the creature vocal gates fold back from the binary
- fidget vocals play through the reference's three gates byte-exact — the chance roll, the mute classes, the routing — replacing the interim guesses that shipped with the sound lane
- the owl's constant screech is a proven negative: the reference fires the wing-flap on every animation loop too, and a live count measured ours at exactly the authored rate — so the report stays open as an A/B question, not closed as a fix
- every fired animation event key can be traced now, the asking half of the sound instrument
- the worktree janitor names the dead claim it cannot reap instead of skipping it silently

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:22:00 +07:00
SamandClaude Fable 5 d3c1a501de buffed stats go green, and the bear stops stacking its roar
- gear and buff bonuses finally render green in the character sheet, tooltips naming the unbuffed base — the stat-split fields are int on the wire and were decoded as float, which rounded every bonus to zero
- the bear pet's aggro roar played 63 times in two minutes and stacked into a phasing growl; it now plays through the reference's per-unit voice channel, where a live bark drops the next
- the chat bubble stops jittering: its anchor lagged the body by a frame, and it now snaps to the device pixel grid like the nameplate under it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:06:24 +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 5ce93810b0 the autocast shine squares up, and a pill watches the tail
- the shine's stars size by the screen diagonal instead of a frozen 4:3 constant, so a widescreen window stops blobbing them
- each button's shine wears its own authored geometry: the spell book's 36x36 model rect at 1.22 scale, not the pet bar's — and its autocast brackets reach the button's corners with the glow sharing their centre
- one deliberate deviation, recorded as such: the spell book's shine borrows the pet button's rim ratio, because the reference's own washes out there
- the perf HUD gains a pill that measures frame cost and its tail, and latches the spike that would otherwise scroll away

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:03:18 +07:00
SamandClaude Fable 5 2381df5a58 the layout graph is maintained, and the shine draws for real
- the interface's layout graph is maintained as anchors change instead of rediscovered from scratch: 1.48 ms per mutated frame becomes 34 µs, and end to end a running cast now costs +0.14 ms where it cost +4.33
- the autocast shine draws its authored population — 1200 particles through the star's own projection, spinning as the model says
- the shine is clipped to its own widget: the model frame installs its rect as the viewport, so nothing it draws leaves the button

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:01:46 +07:00
SamandClaude Fable 5 e4b6776b81 the autocast shine stops eating frames, sunken NPCs surface
- the pet bar's autocast shine cost +4.25 ms a frame for one button: its 92 script-side SetPoints forced two whole-roster anchor solves every frame — the shine now draws from a native lane, re-measured at +0.03 ms with what is drawn bit-faithful to before
- an NPC that spawned under its own floor — a cellar wolf, a pet at login — now measures its ground clamp from the server's seat instead of its own last answer, and climbs out
- a running cast cost ~4 ms a frame in layout gate walks; a mutated frame now takes one walk, not three, and the settled interface is pinned at zero

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 17:00:19 +07:00
SamandClaude Fable 5 970cac46c2 material animation stops touching assets: one shared table
- a drawn animated material — scrolling texture, pulsing tint — is never mutated again: the animation rides delta rows in a shared region of the light buffer, folded branch-free in the shader, with zero as identity
- the churn that came with mutating assets dies by construction — no per-material modified ratchet, no far-twin re-inserts — and capture parity is bit-exact
- the portal flood's answer goes compare-then-write, clearing the ground for a static-visibility lane
- the single-threaded PostUpdate probe answered: cheaper on mean cpu, parked on a tail-latency class, kept as a documented lever

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:58:39 +07:00
SamandClaude Fable 5 4ff2a8ebcf performance night: the interface splices and the walks go filtered
- a single animating entry — the resting blink, a sweeping cooldown — now re-converts alone and stitches into last frame's interface quads instead of dragging the whole batch through conversion, and the staleness sweep stops allocating
- two physics levers measured and flipped: entity clusters and the pre-step transform propagation both default off, −0.28 and −0.40 ms at the Stormwind gates
- the per-frame hygiene basket: env lookups cached once, both mouseover walks filtered by archetype instead of touching every streamed object, ground-shade cards resolve to their nearest shaded root, the nameplate steady frame stops allocating and stops dirtying transforms
- new meters for what remains: an animation memo-sizing counter and a lever that prices the physics stack's rate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:56:48 +07:00
SamandClaude Fable 5 49ba9d599b the bevy 0.19 excursion: graded 5.5 ms slower lane-for-lane, rolled back
- the full bevy 0.19 / avian 0.7 / egui 0.35 port landed and rendered at visual parity, then profiling matched the lanes honestly: +5.5 ms against 0.18 in our scenes, priced to three named buckets — so it was reverted the same day, with the pins mapped for a future release
- back on 0.18 the client is faster than 0.18 ever ran here, keeping both performance days' wins
- what the hunt left behind: the material-animation scan visits only rows that can be registry keys, and a capture that settles on an all-black image now says EMPTY instead of grading it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:54:09 +07:00
SamandClaude Fable 5 a626e29c39 performance day two: the resting interface stops rebuilding itself
- the resting player's blinking status glow was rebuilding the whole interface's batches every frame — a run whose bytes didn't move is no longer rewritten, worth 1.17 ms at Stormwind
- doodad skeletons collapse into the pose buffer and parked rigs skip the model pass; doodad and prop hulls weld into batched trimeshes
- the Update schedule runs on the single-threaded executor by default, measured faster than the multithreaded one for this frame
- a parked camera stops claiming to move every frame

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:52:00 +07:00
SamandClaude Fable 5 21e3fc4f06 the performance hunt, day one: the frame sheds 1.85 ms
- UI layout solves what moved, not what exists — hovering a full bag no longer re-solves the whole interface
- world albedo textures stop keeping a second copy of themselves in RAM
- collision gets a coarse grid for oversized slabs (32x fewer triangles tested), idle units stop re-asking the ground every frame, and anchors spawn on first consumer instead of by the thousand
- aura and loot watchers scan when the store changes rather than on the clock, and static-transform tracking and plate reaping join the sweep

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:49:54 +07:00
SamandClaude Fable 5 38d8502bb7 addon-screen polish, and item glows return to the paper doll
- every glue-screen string renders its colour markup — the addon tooltip included, which used to print its |cff… codes raw
- the addon list's scroll knob finally drags, on one shared slider law: press anywhere on the track and the knob warps under your cursor and follows, exactly as 1.12's slider behaves
- item effects survive the character sheet and dressing room again — a booth bake is premultiplied by construction and is no longer premultiplied twice, which had been erasing every glow hanging in the space beside the model
- the login one-shot announcements wait for the in-game UI to exist before they fire

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:47:33 +07:00
SamandClaude Fable 5 77b54ab3cc glyphs at their true size — the ladder that scrambled text is gone
- text rasterizes every glyph at its exact on-screen size, on demand — the fixed size ladder and its rescale-after-snap are gone, the machinery that left names scrambled and lines off their baseline after a window resize
- the worldport ack now rides the load's completion the way the real client sends it, and the near-teleport echo stands alone as the whole handshake
- a floating combat number whose anchor leaves the screen is destroyed rather than dragged to the border, and a trailing line break ends its line instead of opening a new one
- entering the world, the loading cover provably presents before the UI builds behind it, holds the world's audio while it is up, and fails closed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:45:34 +07:00
SamandClaude Fable 5 dfa369127c the same-continent teleport fall is found and fixed
- a teleport between cities on one continent could release you before the destination had streamed in and drop you under the map — the residency publish now waits for the snap and names the tile its facts are about, so the loading screen provably holds until the ground is real
- nameplates stop jittering: plates of units you cannot see no longer shove the visible ones around, and the snap rides the correct pixel grid
- unit-name text takes its first fix — a string fits the width its own measure reported, and a re-bake reaches the screen
- books and plaques render through a real SimpleHTML widget inside a real ScrollFrame — strict parse, per-element fonts, block layout, and a scroll range measured from the whole subtree

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:43:01 +07:00
SamandClaude Opus 5 9a184d3476 the guild window opens: roster, ranks, notes and the message of the day
- the social window's third tab is live — the roster in both its views, the member card with its promote/demote/remove verbs, the rank editor's thirteen permissions, the guild information board, and the invite, leave, kick and note dialogs behind them
- setting your hearthstone at an innkeeper now asks before it takes and says so afterwards, and the innkeeper's gossip lines get their own icons back
- unavailable talents grey out, and every greyed icon in the client now goes through the same luminance fold the original used
- the buff tooltip's remaining-time line reads gold with the client's own hour/minute ladder, the macro editor takes a shift-click to paste a spell, trainer rows repaint after a purchase, and a long book page stops flickering its ellipsis

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 17:38:54 +07:00