Files
healer-man/PLAYTEST_NOTES.md
T

1296 lines
74 KiB
Markdown

# Healer Man playtest notes
This file is the durable record of runtime behavior, regressions, and the
evidence required before calling a visual bug fixed. Update it whenever scene,
camera, input, physics, mob-rendering, or asset-loading code changes.
## 2026-08-16 responsive jump and natural teammate movement - COMPLETE
- Added the grounded single-jump path for Space and controller L3, including a
`7.2 m/s` launch, `100 ms` coyote time, `120 ms` input buffering, landing
lockout, upward-normal ground filtering, and blocked-input cancellation.
Player physics and the latest grounded navigation anchor are now reported
separately, so party breadcrumbs and recalls do not follow an airborne
player position.
- Player locomotion now presents rising, falling, and landing phases. The live
WoW human used its native jump pose while preserving the visible body and
equipped weapon; RuneWaker and fallback clip selection is covered by the
focused animation suite.
- Party members now derive stable movement personalities from member ID and
living-party rank. The runtime applies personalized trail distance, lateral
offset, comfort slack, speed, slow sway, stop/start hysteresis, combat
bearing, preferred range, and ally separation only when the candidate path
passes collision and floor-continuity checks. Breadcrumb centerline routing,
Stop, stuck recovery, role decisions, and blocked-route reporting remain the
fallback behavior.
- Focused verification passed 17 files / 117 tests:
`playerJump`, `inputManager`, `inputMath`, `store`, `combatAnimation`,
`partyMovement`, `partyNavigation`, `partyPathing`, `partyRuntime`, and the
complete `src/avatar` suite. The first full-suite attempts exposed a
pre-existing load-sensitive `30 s` timeout in the heavyweight RuneWaker
animation audit; the isolated test passed in `6.5 s`. Its two asset-audit
cases now use `60 s`, matching their actual full-suite workload more closely.
- Final `npm test`: **114 files / 656 tests passed**. Final `npm run build`:
**passed**, including TypeScript, 954 transformed Vite modules, and the KTX2
audit of 11,839 compressed textures with zero fallbacks.
- Production preview was exercised at `http://127.0.0.1:4174/`. At desktop
`1440 x 900`, Space produced a visible jump from rest and while moving; the
running capture shows the native raised-arm jump pose. Space pressed while
paused did not launch on resume. Five rapid Space presses during one airborne
cycle returned to a normal grounded pose rather than producing a double jump.
The entrance smoke route covered its sloped floor and low cavern roof without
visible clipping or a hidden avatar.
- In Defend, the companions settled at visibly different longitudinal and
lateral offsets. In Attack, tank, ranged, and melee actors held distinct
bearings; Brynn peeled to the right while the other roles retained separate
safe positions. Party health and combat activity continued updating. Stop and
Recall were then issued from the Thor companion display and the authoritative
command state updated correctly.
- The browser Thor preview displayed both the `960 x 540` main surface and
`620 x 540` companion surface. Entering as healer from the companion display,
Attack/Stop/Recall dispatch, Space jumping on the main display, and
right-mouse input with no pointer lock all worked. Runtime inspection found
one visible canvas, no loading screen, and no scene-error overlay.
- Console capture contains no errors. It contains two occurrences of the
project's existing third-party initialization deprecation warning, one per
desktop/Thor runtime load. The Vite preview host separately logged the known
optional `/content/manifest.json` proxy refusal because the auxiliary content
server on port 4173 was not running; the packaged dungeon still loaded and
played normally.
- Evidence is under `playtest-artifacts/2026-08-16-jump-party/`:
`desktop-running-jump-preview.png`, `desktop-varied-follow-preview.png`,
`desktop-varied-combat-preview.png`, `desktop-pause-jump-blocked-preview.png`,
`thor-jump-preview.png`, `thor-varied-combat-preview.png`,
`thor-repeated-jump-landing-preview.png`, and `preview-console.txt`.
- Coverage limits: no physical controller was connected, so L3 edge behavior
and removal of L3 clear-target are automated-test verified rather than
hardware verified. The entrance smoke route did not provide a deterministic
walk-off ledge or narrow doorway fixture; exact coyote timing and lateral
centerline fallback remain covered by their pure/navigation tests rather than
claimed as live edge-case evidence.
## 2026-08-01 all-dungeon v5 animation acceptance pass - COMPLETE
- The Blackhorn Silencer and Giant Assassin failures demonstrated that valid
files, finite tracks, expected clip names, and green Khronos validation do not
prove a correct skeleton pose. The v4 exporter repair changed the reflected-Z
quaternion conversion from `(x, y, -z, w)` to `(-x, -y, z, w)`. The v5 cache
identity retains that repair and invalidates the actor cache for complete cast
semantics: all exported cast-family clips must be preserved and reachable by
the runtime selector.
- The authoritative scope is 30 dungeon packages, 436 entity templates, 268
base actor configurations, and 322 runtime-referenced namespaced shipping
variants. The audit and visual-review unit is the 322 variant paths, not the
268 base configurations. Expected configuration is 321 native variants plus
one pose-only Mantarick mapping (Hall of Survivors template `102452`, asset
`judgement-light-pose`).
- `demon-stronghold-125` and `zurhidon-stronghold-124` are authoritative empty
copy zones and require explicit zero-row review entries. Sardo Castle's Rune
Warning Device (template `105758`, asset `rune-device-red`) is a native,
stationary actor whose missing locomotion clip is an approved source-faithful
exception; its other native animation families still require review.
- Required machine checks, run from `D:\Projects\HealerMan`, start with:
```powershell
npm run runewaker:audit:animation-inventory
npm run runewaker:audit:runtime-clips
npm run runewaker:audit:animation-readiness
npm run runewaker:audit:animations
```
The exact PowerShell that derives all 322 GLB inputs from
`runtime-clip-coverage.json`, runs Blender, generates contact sheets and review
pages, and compiles the human disposition is documented in
`scripts/runewaker-pipeline/POSE_AUDIT.md`.
- Blender numerically samples the bind pose plus the first, middle, and final
frame of every action. This can miss a defect between samples and cannot prove
semantics, timing, impact alignment, particles, audio, or encounter mechanics.
Every variant contact sheet therefore requires human review; suspicious
actors require `--render-mode all`, and every dungeon still requires an
in-browser combat pass covering idle, applicable locomotion, configured
attacks/casts, wound, death, transitions, and console/WebGL errors.
- **Rebuild result:** All 29 generic population recipes rebuilt green. Forsaken
Abbey's separate nine-actor package completed Khronos validation with zero
errors and zero warnings across all nine GLBs.
- **Inventory/runtime result:** The final inventory is green at 30 dungeons, 436
entity templates, 268 base actor configurations, and 322 runtime-referenced
variants with zero blockers. Runtime semantic near misses are zero. The only
required-family exceptions are the documented pose-only Mantarick and the
native stationary Rune Warning Device with no locomotion.
- **Pose result:** `artifacts/animation-audit/post-v5/summary.json` evaluated
44,305 poses for all 322 variants: 282 numeric passes, 40 accepted-warning
candidates, zero errors, zero failures, and 634 flagged samples. Those values
exactly match the visually reviewed v4 batch totals, so the v5 cast-semantics
rebuild introduced no aggregate numeric pose regression.
- **Offline browser result:** The packaged/offline catalog displayed all 30
RuneWaker dungeons as Ready. Pasper's Shrine and Hall of Survivors both loaded
their environments. The console contained only an unrelated library
deprecation warning; no asset, skeleton, animation, WebGL, or dungeon-load
error was observed.
- **Test boundary:** All 19 focused RuneWaker animation tests pass. Repo-wide
build/test gates remain blocked by the unrelated unfinished RoM class catalog
and missing Manastorm fixtures; those failures are not attributed to the v5
animation work.
## 2026-08-01 Pasper goatman quaternion-basis repair
- Reproduced the severe animated-pose deformation on Giant Assassin (template
`101039`), Giant Assassin Captain (`101045`), and Blackhorn Silencer
(`101053`). The first two use
`model/character/creature/goatman/act_fog_ferocity_03.ros`; the Silencer uses
`model/character/creature/goatman/act_fog_loster_03.ros`.
- The source-to-HealerMan position conversion reflects Z. The exporter had
incorrectly mapped rotations as `(x, y, -z, w)`. Applying the basis transform
`R' = S R S`, with `S = diag(1, 1, -1)`, requires
`(-x, -y, z, w)`. The corrected conversion is shared by skeleton bind
transforms and every sampled animation frame.
- Rebuilt Pasper's nine actors and validated all nine shipping GLBs with zero
Khronos errors and zero warnings. Then rebuilt all 29 generic dungeon actor
packages plus the separately handled Forsaken Abbey package; every package
completed its actor and Khronos validation stage green.
- Blender pose evidence is under
`artifacts/animation-diagnostics/fog-ferocity-03-runtime-clips` and
`artifacts/animation-diagnostics/fog-loster-03-runtime-clips`. The exact
runtime-selected one-handed idle, run, `1h_attack01`, and `1h_attack02` clips
retain coherent bodies, limbs, armor, and weapons at their first, middle, and
final samples. The corresponding pre-fix directories preserve the malformed
poses for comparison.
- Pasper's Shrine loaded in the local browser and the party entered combat. The
browser console contained no model-load, skeleton, or animation exceptions.
The automated camera remained at the entrance while the ordered party moved
ahead, so no browser screenshot of these specific goatmen is claimed; the
actor-specific Blender renders are the visual regression evidence.
- Added `blender/render-animated-actor.py` and documented the required visual
pose gate. Clip presence, semantic-family coverage, finite tracks, and
Khronos-clean files are not sufficient evidence of correct skeletal motion.
## 2026-07-31 Pasper's Shrine original skeletal-animation pilot
- Replaced the nine static Pasper combat packages with skinned GLBs generated
from their original GR2 skeletons and ACT-referenced RAS controls.
- The actors expose 20-24 clips each. Generated entity data marks all 12 Pasper
templates as native; combat selection covers attack variations, cast, wound,
and death in addition to stand/idle, walk, and run.
- Khronos validation passed all nine shipping GLBs with zero errors and zero
warnings. The focused animation/runtime/pipeline suites passed 19 tests. The
final full run passed 513 of 518 tests; its five unrelated failing assertions
cover missing Manastorm conversion inputs plus established Forsaken/Kalin
availability state, and the unrelated Manastorm compound-import suite still
has its pre-existing parser error. The production TypeScript/Vite build passed.
- The local Vite entry started at http://127.0.0.1:5173/. The in-app browser
controller timed out during connection and after a clean reset, before a tab
or screenshot could be obtained. No live visual result is claimed in this
entry; an interactive Pasper combat pass remains the final visual gate.
- Reproduction and remaining-dungeon rollout instructions:
scripts/runewaker-pipeline/ORIGINAL_ANIMATION_IMPORT.md.
## 2026-07-31 RuneWaker all-dungeon animation audit
- Three parallel read-only audits covered all 30 packaged RuneWaker instances.
- All 239 actor GLBs parsed successfully and contain zero native clips/skins.
- All 312 static-model entity definitions now select full procedural animation;
132 dynamic-display entities use explicit procedural proxy bodies.
- Automated coverage opens every referenced GLB, resolves all 4,094 spawn
references, and exercises finite idle, movement, attack/cast, wound, and
terminal death transforms.
- The audit exposed and fixed the generalized generator's missing procedural
mode and the runtime wrapper's missing wound-revision handoff.
- Focused command: npm run runewaker:audit:animations.
- Live Vite boot succeeded at http://127.0.0.1:4173/. The Codex in-app browser
connection timed out twice before a tab could be selected, so no new WebGL
screenshots were captured in this pass. Do not treat the automated results
as screenshot evidence.
- Detailed matrix:
scripts/runewaker-pipeline/RUNEWAKER_ANIMATION_AUDIT.md.
## Evidence rules
- `npm test`, `npm run build`, Android compilation, and APK signing prove logic
or packaging only. They do **not** prove that the Three.js Canvas renders a
dungeon before or after pointer lock.
- A pointer-lock fix is not verified without matching screenshots from the
running game plus browser console/runtime checks.
- `assetStatus === "ready"` is not enough. `ProductionDungeon` latches that
status after an initial frame; a later camera or frame-loop failure can still
leave the HUD over the Canvas clear color.
- The Canvas clear color is `#07110d`. A nearly uniform dark-green playfield
with a normal DOM HUD means the app shell is alive but the 3D view is not
producing visible geometry.
- Record what was actually observed. Mark unavailable platforms and missing
screenshots as unverified rather than inferring success from another test.
## Source and staging safety
- Installed game root: `C:\Users\phenom\Documents\Healer-Man`
- Current writable mirror:
`C:\Users\phenom\Documents\wow335a\dungeon-export-work\HealerMan\gameplay-ui-staging`
- Treat `.healer-man-staging` and
`dungeon-export-work\HealerMan\runtime-staging` as stale historical mirrors.
They contain older pointer-input/camera files and must not be bulk-copied over
the game.
- Before the pointer-lock transition patch on 2026-07-21, installed
`PlayerRig.tsx` matched the gameplay UI mirror at
SHA-256 `B918B24031DD7031F1EEBA75879E8291EABDE9AAB8A08223B9B392A105B4692A`.
Installed `inputManager.ts` matched the pre-patch mirror at SHA-256
`16D77BF075BD1355A23F81D019B8D34C7427026B113DBD257B4A7BE6FE53BF1F`.
- After the transition patch, the installed and staged hashes match:
`PlayerRig.tsx` is
`A2CD3D3951D99ECE05D99ACB3CAE53C412B075B01106DBAC0E37EC48B8AFC843` and
`inputManager.ts` is
`355A4AD7DE12AF777B4829428B32181F9511A8DF021102932036DAA643C3C716`.
- Compare source and destination hashes before and after every elevated copy.
Copy only the files intentionally changed. The installed root currently has
no Git history to rescue an accidental stale overwrite.
## Pointer-lock invariants that must remain intact
1. `GameScene.tsx` requests pointer lock on the Canvas itself.
2. `inputManager.ts` rejects non-finite mouse movement, clamps each event and
frame, clears the buffer on focus changes, and suppresses the complete
180 ms cursor-recentering burst after pointer lock begins.
3. `PlayerRig.tsx` repairs non-finite yaw, pitch, player translation, cast
distance, and camera boom state before they reach Three.js or Rapier.
4. `ThirdPersonCamera` uses the default `useFrame` priority. A positive priority
takes ownership of React Three Fiber's render loop; without an explicit
`gl.render(scene, camera)` call it produces the exact clear-color-plus-HUD
failure.
5. Errors thrown from a `useFrame` callback are not reliably surfaced by the
DOM `SceneErrorBoundary`. Browser `pageerror` and console capture are part of
the playtest, especially after adding new frame callbacks.
## Deterministic PC setup
Run the latest source, not an old Vite process or stale `dist` directory:
```powershell
npm run dev -- --host 127.0.0.1 --port 4173 --strictPort
```
Open `http://127.0.0.1:4173/` at `1440 x 900`. For a repeatable offline
character, run this in DevTools before reloading:
```js
const now = Date.now();
localStorage.setItem("healer-man.profile-database.v1", JSON.stringify({
version: 1,
accounts: [],
rosters: {
"offline-roster": [{
id: "character-playtest",
ownerId: "offline-roster",
name: "Remedy",
raceId: "human",
classId: "priest",
gender: "female",
appearance: { skinColor: 0, face: 0, hairStyle: 0, hairColor: 0, feature: 0 },
level: 10,
experience: 0,
talentRanks: {},
location: "Wailing Caverns Entrance",
createdAt: now,
lastPlayedAt: now,
}],
},
}));
sessionStorage.setItem("healer-man.session.v1", JSON.stringify({
kind: "offline",
ownerId: "offline-roster",
displayName: "Offline",
}));
location.reload();
```
## Required pointer-lock visual checklist
Store evidence under `playtest-artifacts/2026-07-21/` for this regression.
1. Select Remedy, click **Enter world**, and wait until `.loading-screen` is
gone and `.scene-shell canvas` is visible.
2. Confirm textured dungeon geometry is visible, not only `#07110d`.
3. Record pre-lock state: `assetStatus` is `ready`, `pointerLocked` is `false`,
and `playerPosition` plus `cameraYaw` are finite.
4. Capture the full window as `pointer-lock-before.png` and the Canvas crop as
`pointer-lock-before-canvas.png`.
5. Click the center of `.scene-shell`. Confirm
`document.pointerLockElement === document.querySelector(".scene-shell canvas")`.
6. Wait two animation frames and at least 500 ms. Confirm `pointerLocked` is
`true`, player/camera values remain finite, the WebGL context exists, and
`gl.isContextLost()` is `false`.
7. Capture the same views as `pointer-lock-after.png` and
`pointer-lock-after-canvas.png`.
8. Move the mouse, then hold `W` for about 250 ms. Capture
`pointer-lock-after-input.png`. This is required because a bad recenter event
can fail on the first post-lock input rather than on the click itself.
9. Press Escape, open and close a menu, reacquire pointer lock, and confirm the
dungeon remains visible.
10. Save console output as `pointer-lock-console.txt`. The pass condition is no
`console.error`, `pageerror`, `pointerlockerror`, or `webglcontextlost`
during the transition.
Visual pass criteria: all three full-window images show textured dungeon
geometry behind the HUD; the two post-lock images show a reticle; no loading or
scene-error overlay is present; the view changes after input without becoming
uniform dark green.
After the development-server pass, repeat against a fresh production build:
```powershell
npm run build
npm run preview -- --host 127.0.0.1 --port 4174 --strictPort
```
Use filenames ending in `-preview` for the production screenshots.
## Known evidence as of 2026-07-21
### Working or previously observed working
- Login/offline roster, character selection, and entering Wailing Caverns have
been observed working by the user.
- Before this regression, the user could see and navigate the dungeon and give
camera-clipping, pop-in, wall-material, mob, and performance feedback. This
proves that the extracted dungeon and runtime can render on this PC.
- The current source contains pointer-delta sanitization tests and finite camera
recovery guards.
- After the transition patch, `npm test` reported 109/109 tests passing and
`npm run build` completed successfully. An Android APK had been produced by
the preceding build, but has not yet been rebuilt from this patch.
- `scripts/probe-entrance.mjs` reported finite entrance camera geometry and a
visible shell hit. That static probe does not exercise React, pointer lock, or
the live frame loop.
### Not working or not yet verified
- User report: after entering Wailing Caverns, clicking the game to take focus
changes the 3D view to dark green while the HUD remains visible.
- No current before/after screenshots have yet demonstrated that the latest
source survives pointer lock. Until the required screenshots exist, this
regression remains open regardless of tests/build status.
- Browser console and WebGL context-loss evidence for the failing transition
has not yet been captured.
- The production preview answered HTTP 200 at `http://127.0.0.1:4174/`, but the
visual-test browser was not attached to this session. No screenshot was
captured, so the patch must not be called visually verified yet.
- The pointer-lock regression has not been visually rechecked in production
preview, the Android WebView, or the AYN Thor top display.
## Regression log
### HM-2026-07-21-POINTERLOCK-CLEARCOLOR - PATCHED, VISUAL VERIFICATION REQUIRED
**Reported:** 2026-07-21
**Symptom:** The dungeon is visible after character selection. Clicking the game
window to take focus leaves a dark-green Canvas with the UI still visible.
**Expected:** Pointer lock activates mouse look and the textured dungeon remains
visible and navigable.
**Important history:** Two earlier failure classes can create this symptom:
- A positive `useFrame` render priority can disable React Three Fiber's
automatic render call.
- A stale or malformed pointer-lock movement event can poison orbit/camera
state with non-finite values.
The prior input guard discarded only one transition event. Browsers can emit a
burst of recentering events, so later stale deltas could still rotate the camera
away from the rendered cavern. The patch discards the full 180 ms transition
burst and reads `pointerLocked` imperatively in the player frame, avoiding a
Rapier subtree reconciliation at lock acquisition. This is the leading cause,
but it remains a hypothesis until the required screenshots and runtime evidence
are captured. Recent mob/combat work also added more high-frequency `useFrame`
paths; an exception or WebGL context loss can create the same visible symptom.
**Patch files:** `src/game/inputManager.ts`,
`src/game/inputManager.test.ts`, `src/scene/PlayerRig.tsx`.
**Automated evidence:** 17 test files and 109 tests passed. The TypeScript/Vite
production build completed with 655 modules transformed. These results validate
the patch logic and bundle, not the rendered pointer-lock transition.
**Visual evidence status:** blocked on an attached visual-test browser. The
local production preview is running and ready for the checklist above; no
screenshots exist yet.
**Fix evidence required:** `pointer-lock-before.png`,
`pointer-lock-after.png`, `pointer-lock-after-input.png`, their Canvas crops,
`pointer-lock-console.txt`, finite runtime state, and a live WebGL context. Add
the exact root cause, changed files, commands, and screenshot hashes here once
verified.
### HM-2026-07-22-CAVERN-WHITE-CONTEXT - PATCHED, PC DEV/PRODUCTION VISUAL PASS
**Reported:** 2026-07-22, PC development runtime
**Symptom:** Wailing Caverns renders correctly, then the screen turns white.
**Expected:** The textured cavern, player, mobs, and HUD remain visible after
the first rendered frame and while pointer lock is active.
**Source diagnosis:** No application DOM layer, loading state, error state, or
Canvas clear color is white. The development root was wrapped in React
`StrictMode`; the installed R3F Canvas teardown schedules a forced WebGL
context loss after 500 ms, making the development-only effect replay a strong
timing match. No live context-loss event was captured, so this remains the
leading code-path diagnosis rather than visual proof. Two independent scene
lifecycle gaps were also confirmed: player physics could start while the
dungeon collider was still suspended, and the prior ready signal used the
renderer-global frame count rather than a post-mount dungeon frame.
**Patch:** The game root now mounts once in development. `GameScene` listens
for WebGL context loss/restoration, releases pointer lock, pauses simulation,
and displays a dark DOM recovery surface instead of leaving a blank Canvas.
Three's automatic restoration preserves the current Rapier world. If automatic
recovery fails, the explicit restart returns to the entrance and remounts at
DPR 1 with antialiasing and shadows disabled. The player and mob assets continue
preloading behind the loading surface, but the entire physics world and mob
simulation remain paused until the current dungeon/collider instance has
completed a rendered frame. This prevents a fall-through race without causing
a late GPU-upload burst at the first visible cavern frame.
**Files changed:** `src/main.tsx`, `src/scene/GameScene.tsx`,
`src/scene/DungeonEnvironment.tsx`, `src/scene/ProductionDungeon.tsx`, and
`src/styles.css`.
**Automated evidence:** 23 test files and 136 tests passed. The TypeScript/Vite
production build completed with 662 modules transformed. The entrance probe
reported finite camera geometry, a 6.099 m camera-to-target distance, and no
camera-to-target collision. The creature audit validated all 16 GLBs. The live
development server returned HTTP 200 for the page and updated scene module and
served both the recovery UI and readiness gate.
**Visual evidence status (updated 2026-07-22):** Edge/Chromium was attached at
1440x900 through Playwright. A fresh offline character entered the development
runtime and the rebuilt production preview; both showed textured Wailing
Caverns after a 12-second load/stability wait and remained rendered throughout
party-command and pause-menu checks. The post-entry captures had no `pageerror`
or console error. The original post-load white frame was not reproduced.
Native pointer lock, Android WebView, and the AYN Thor displays remain separate
unverified surfaces and must not be inferred from this pass.
### HM-2026-07-26-AVATAR-EQUIPMENT-RIGHT-DRAG - FIXED, PC VISUAL PASS
**Reported:** Playable character models and weapon/gear presentation had
stopped appearing as expected. Desktop right-mouse camera look also triggered
the browser's jarring Pointer Lock capture transition.
**Root cause:** The July 25 authentic-equipment integration left
`starterWeapons.tsx` and its tests in place but disconnected
`StarterWeaponAttachments` and `ApproximateStarterEquipment` from the shared
`CharacterModel`. As a result, valid character rigs rendered bare in the roster
and dungeon. Authentic item GLBs were also loaded inside the character's
top-level Suspense/error boundary, so one slow or broken optional gear model
could temporarily replace its entire wearer. Character-manifest loading used
one all-or-nothing `Promise.all`, allowing one optional race pack failure to
prevent every otherwise-valid race from resolving.
The camera transition was intentional browser behavior caused by
`GameScene.tsx` calling `requestPointerLock()` on every right-button press. The
browser controls that transition; it cannot be styled away.
**Fix:** The shared character renderer once again portals class-appropriate
starter weapons into the animated hand bones and supplies approximate gear on
loading/error fallbacks. Authentic client item models replace starter gear only
for their occupied hand. Each optional item model now owns an independent
Suspense and `AvatarErrorBoundary`, with the matching starter item as its local
fallback, so it cannot hide the body or unrelated gear. Character packs load
independently and merge whichever valid manifests are available.
Desktop camera look now uses bounded ordinary cursor deltas only while the
right button is held. It ends on release, lost pointer capture, blur, overlay
opening, or teardown. The normal gameplay path contains no
`requestPointerLock()` call, so no browser mouse-capture transition is invoked.
Without Pointer Lock, camera rotation naturally stops at the physical browser
window edge; the player can release, reposition the cursor, and continue.
**Regression protection:** Root `AGENTS.md` now makes the character/equipment
boundaries and popup-free right-drag behavior mandatory. New tests pin the
shared renderer integration, independent manifest failure behavior, occupied
hand replacement, per-item loading/error isolation, and unlocked right-drag
deltas. Existing asset audits still verify every playable rig, hand bone,
native equipment GLB, and texture.
**Automated evidence:** Focused avatar/input/store/respawn coverage passed 11
files and 53 tests. The complete suite passed 81 files and 504 tests. TypeScript
and Vite production build passed with 750 modules transformed. Because this
workspace is iCloud-synced, Vite now retains old hashed output instead of
recursively emptying `dist`; this avoids iCloud restoring an asset during
cleanup and causing `ENOTEMPTY`.
**Visual evidence:** The live 1440x720 PC development runtime showed the female
Human Priest body and staff in the roster, then the player plus four distinct
party character bodies and equipped silhouettes in textured Wailing Caverns.
An ordinary right-click produced no Pointer Lock prompt or scene transition,
and no application console error, avatar warning, or WebGL context loss was
captured. The one console warning was the existing third-party initialization
deprecation. Evidence:
- `playtest-artifacts/2026-07-26-model-input/roster-character-staff.png`
- `playtest-artifacts/2026-07-26-model-input/dungeon-equipped-party.png`
- `playtest-artifacts/2026-07-26-model-input/right-click-no-popup.png`
The browser-control surface can issue an atomic right-click but cannot hold the
right button while moving. Continuous drag rotation is therefore covered by
the input integration test; final feel across long drags remains a short manual
PC check.
## Entry template
```text
ID / status:
Date and platform:
Source/build identifier:
Observed symptom:
Root cause:
Files changed:
Commands and results:
Screenshots and hashes:
Console/runtime evidence:
Remaining unverified platforms:
```
## Gameplay implementation log
### HM-2026-07-21-COMBAT-PARTY-TALENTS - IN PROGRESS
**Requested:** Replace generic talent text with the local 3.3.5 talent text and
make learned talents affect gameplay; make Psychic Scream fear nearby enemies
for eight seconds; respawn a defeated player at the dungeon entrance; link
pack aggro; add one tank and three DPS companions; and play attack/death
animations for creatures.
**Authoritative local-data finding:** The extracted `Spell.dbc` contains the
talent names and descriptions. The generator was reading the standard string
field offsets, but this client uses a custom 239-field schema with six fields
inserted before the localized string blocks. The missing names were a parser
bug, not missing client assets.
**Combat-pool finding:** The current health, mana, XP, and combat-power curves
are explicitly prototype curves. Mana classes currently use a 100-point
percentage-style pool; these numbers are not exact 3.3.5 character-sheet
values. The client export was checked for base HP/MP tables, but those
server-side character-stat tables are not present in the resolved MPQ view.
Replacing the prototype pools accurately will require the matching 3.3.5
server database (class-level and race/class-level stats), plus the eventual
gear/stat model; they must not be presented as authentic yet.
**Staged and focused-tested so far:** Psychic Scream uses an eight-yard radius
and eight-second fear; hostile control starts combat; pulling any authored
`pack:member` wakes its surviving packmates; and death exits pointer lock and
resets the encounter/player position to the entrance. Full installed-project
tests, build, screenshots, and animation/party verification remain required
before this entry can be marked complete.
**Creature-animation finding:** All 16 browser creature GLBs had previously
been reduced to Stand and Walk by `prepareAnimatedCreatures.mjs`; the source
files were not generally missing. Eleven source creature exports also contain
exact `AttackUnarmed (ID 16 variation 0)` and `Death (ID 1 variation 0)` clips,
which are now restored in the staged browser assets. The five composite
humanoids (`druid-of-the-fang`, `lady-anacondra`, `lord-cobrahn`, `lord-pythas`,
and `lord-serpentis`) were themselves exported with animation IDs 0 and 4 only,
so they use bounded procedural attack and one-shot terminal death poses.
**Animation/fear staged behavior:** Attack clips resolve while an engaged mob is
in its attacking phase. Death has priority, plays once, clamps on its last
frame, preserves the corpse's combat position, and stops both mixer and proxy
root updates once settled. Active fear suppresses attack visuals and steers the
mob away from the player on the dungeon plane; stun/root still lock movement,
slows still apply, and the flee position is clamped to the mob's home leash.
The existing 95-unit population activation gate remains in place.
**Animation automated evidence:** The Three.js GLTF loader audit parsed all 16
staged GLBs and found 11 exact combat-clip models plus five explicit fallbacks.
The staging TypeScript app/node configurations passed `--noEmit`; the complete
Vitest suite passed 22 files and 131 tests using the staging-safe config loader.
This is logic/asset evidence only. Installed-project build, combat screenshots,
and live attack/death/fear observation remain required.
**Talent-data result:** The corrected custom-schema parser regenerated all 829
talent nodes and 2,243 rank spells from this client's DBC files. Visible names
and rank descriptions contain no generic fallbacks or unresolved tooltip
tokens. The talent panel shows both the learned rank and the next rank; the
SpellRadius table resolves values such as Circle of Healing's 15-yard radius.
All exact raw rank-effect metadata remains available to runtime systems.
**Talent-runtime coverage boundary:** 460 of 829 nodes currently yield at least
one common scalar modifier (damage, healing, mitigation, pools, regeneration,
cost, crit/haste, cast/cooldown, attributes, armor, range, duration, or threat).
This is partial coverage, not proof that every conditional clause or proc is
simulated. The other 369 nodes require triggered-spell, aura/proc, summon,
weapon-event, form, or active-ability systems. There are 151 one-rank
active/spell-granting rows. Faithful generic activation also needs DBC cost,
cast-time, range, and trigger payload generation plus friendly/party/dual
targeting metadata; the baseline action set now distinguishes hostile, friendly,
and self targets.
**Implemented scalar behavior:** Learned scalar modifiers are cached and now
feed max health/resource (including Stamina/Intellect), regeneration, costs,
direct and periodic damage/healing, shields, incoming mitigation, cast time,
cooldowns/groups, haste/GCD, range/AoE, and status/shield duration. Focused
tests prove concrete rank changes for Improved Frostbolt, Improved Fire Blast,
Twin Disciplines, Divinity, Convection, and Fel Vitality (21/21 passed).
Conditional/proc/stance clauses are not statefully triggered yet; crit uses a
deterministic expected-value benefit; armor is approximated; threat, flat-point
cost reductions, added periodic ticks, and learned active spells remain outside
this scalar layer.
**Party staged behavior:** A stable character-seeded roster now creates exactly
four AI companions: one Protection Warrior, Blood Death Knight, or Protection
Paladin tank and three unique non-tank DPS specs. All four attack an engaged
enemy. While alive, the tank redirects 70% of incoming health damage and can be
downed. PC frames are clickable; Thor frames are touch-selectable; D-pad
Up/Down cycles living allies. Baseline direct heals and healing-over-time spells
now route to a selected living ally, with the player as the no-selection fallback.
**Screenshot status (superseded 2026-07-22):** The first browser query exposed
no in-app backend, but an installed Edge executable was later attached through
Playwright. Current party/world evidence is recorded in the entry below. Native
pointer-lock, Android, and Thor checks remain outstanding.
**Installed-project verification:** The integrated project passed 23 test files
and 136 tests. The creature audit loaded all 16 GLBs (11 real combat-clip sets,
five procedural fallbacks). TypeScript and Vite production build passed with
662 modules transformed, and the live preview returned HTTP 200 for the new
bundle. Vite reports existing large-chunk warnings; this is a startup/bundle
optimization item, not a failed build.
**Thor/Android artifact from the preceding combat build:** `npm run android:apk`
completed after a fresh Capacitor sync and 98 Gradle tasks. Artifact:
`android/app/build/outputs/apk/debug/healer-man-0.1.0-debug.apk`, 108,315,663
bytes, SHA-256
`77B2BB53BD21FAA799F5BE15FE722399FB03B33983512BE8647694C9B5C5845B`.
This artifact predates the party-world command changes below.
### HM-2026-07-22-PARTY-WORLD-COMMANDS - IMPLEMENTED, PC VISUAL PASS
**Requested:** Make the four roster allies visible in the world; add Attack,
Defend, and Stop orders; make Attack advance toward the next boss while clearing
adds, Defend respond only to engaged enemies, and Stop hold the current world
positions; add pause-menu party management with current and future talents;
keep every ally at the player's level.
**Implementation:** Party command and boss-objective state now lives in the
low-frequency party store. Four procedural world actors keep their positions in
a render-loop registry, follow formation in Defend, freeze in Stop, approach
active targets at melee/ranged distance, and use the shipped Wailing Caverns
navigation GLB plus deterministic A* routing in Attack. A soft player tether
keeps the existing player-centric mob activation/leash system coherent; Stop is
exempt so it remains a literal hold order. Navigation loading is isolated behind
its own Suspense and error boundary, so an optional route-helper failure cannot
blank or suspend the dungeon Canvas.
**Interface:** The PC HUD exposes Attack/Defend/Stop with F1/F2/F3 shortcuts and
pressed state. The pause hub opens Party Management, where the four allies,
roles, live health/status, current legal talent ranks, and next three automatic
level choices are visible. The Thor companion snapshot and tactical panel expose
the same commands and named boss objective. World nameplates are hidden while a
menu is open, fixed at a small screen size, and stacked beneath the HUD.
**Automated evidence:** The full suite passed 28 files and 155 tests. New focused
coverage includes command acquisition/holding/range, deterministic roster level
sync, world-position registry and movement helpers, navigation welding/A*, all
22 supported specialization plans at every level 1-80, F-key mapping, and
dual-screen command dispatch. The final TypeScript/Vite build transformed 669
modules and emitted the 1,329.06 kB navigation GLB. The existing large-chunk
warning remains informational.
**Visual evidence:** At 1440x900 in the live development runtime, all four
companions and the command bar were visible over textured Wailing Caverns.
Attack moved the group into the entrance encounter and party/player health plus
mob health changed without `pageerror` or console errors. Stop appeared as the
selected HUD order, and all four members showed `HOLDING` in Party Management.
The level-1 panel showed future level-10/11/12 choices; the seeded level-10
production panel showed the current rank and level-11/12/13 choices. A first
capture exposed oversized nameplates leaking over the modal; the nameplates were
then reduced, placed below the HUD, hidden while paused, and the corrected dev
and production panels were recaptured cleanly. Fresh production entry remained
textured after 12 seconds with a Canvas present and zero post-entry console or
page errors.
**Remaining verification boundary:** The entrance encounter and menu flow were
visually exercised, but a complete manual walk through every boss route was not.
Late-dungeon navigation islands, native pointer lock, Android/Thor rendering,
and the full boss-by-boss Attack traversal remain manual follow-up coverage.
### HM-2026-07-22-FRIENDLY-TARGETING - IMPLEMENTED, PC INTERACTION PASS
**Requested:** Let the player mouse-click party members in the world or party
frames and use healing/support abilities on the selected teammate.
**Implementation:** Living world companions now have generous transparent
capsule hit targets. Their click handler stops both R3F and native DOM bubbling,
so selecting an ally does not also capture the mouse. Hostile and friendly
selection are mutually exclusive across world clicks, keyboard/controller
cycling, clear-target input, and the Thor companion channel. Party selection is
idempotent and clears automatically if the member is downed or removed.
Holy Light, Flash Heal, Healing Wave, and Rejuvenation now use 40-yard friendly
targeting. With no ally selected they intentionally target the player. Casts
snapshot the chosen recipient, revalidate that member's life, runtime presence,
and range on completion, and never put party IDs into hostile-target state.
Direct heals and per-recipient HoTs update party health without changing the
self-healing behavior of hostile hybrid attacks such as Death Strike.
**Interface:** A selected teammate gets the existing gold world/party-frame
selection treatment plus a green target frame with live health. Friendly action
slots carry an `ALLY` badge and accessible target wording.
**Evidence:** At 1440x900 in Edge/Playwright, clicking Garrick's party frame
selected him and left pointer lock off. Flash Heal displayed its cast bar,
restored Garrick from 157/217 to 217/217, and spent mana. Clicking Ash's actual
3D body switched both the target frame and selected party frame to Ash while
pointer lock remained off. The textured dungeon Canvas and all four companions
remained visible; no page error or white-screen regression occurred. The full
suite passed 28 files and 169 tests with a 15-second allowance for the existing
performance-heavy talent-plan audit. TypeScript and the production Vite build
passed with 669 modules transformed.
### HM-2026-07-22-PARTY-AVATARS - IMPLEMENTED, PC VISUAL PASS
**Requested:** Replace the four lightweight companion pawns with actual
characters that have races, genders, and randomized appearances.
**Implementation:** Every generated party member now owns a flat, serializable
`raceId`, `gender`, and five-value appearance record. Identity uses a dedicated
per-member PRNG stream keyed by the persistent player-character ID, party slot,
class, and specialization. It is varied between player characters but stable
across rerenders, level synchronization, combat resets, and re-entry. The race
selection respects the project's packed race/class catalog.
Party actors now use the same `CharacterModel` pipeline as the player: shipped
race/gender GLBs, skeleton-safe clones, composed skin/face/hair/feature textures,
Death Knight eye treatment, and Stand/Run animation. Each ally retains its own
Suspense/error boundary and procedural fallback, so one bad avatar cannot blank
the dungeon Canvas. Measured metrics for all 20 race/gender rigs drive each
nameplate, target ring, and transparent click capsule; this covers the 1.17 m
female Gnome through the 3.19 m male Troll. Party frames, target UI, pause-menu
management, and the Thor snapshot now expose race/gender identity.
**Asset evidence:** A direct loader audit covered all 20 character GLBs and
5,072 referenced model/texture URLs with zero missing files. Every rig had
finite geometry and animation tracks, matching appearance counts, required
material tokens, and valid Stand/Walk/Run clips.
**Visual evidence:** At 1440x900 in Edge/Playwright, the initial seeded party
rendered distinct Draenei, Night Elf, and Dwarf characters with visible body,
skin, hair, and feature differences. A second deterministic extreme party
rendered a male Troll, male Draenei, male Human, and female Gnome together.
There were no avatar loader warnings, page errors, WebGL context-loss reports,
or white-screen recurrence. Clicking the real Troll mesh selected Seraphin,
updated the green friendly target frame, and left pointer lock off. Party
Management displayed all four race/gender identities and preserved talent data.
**Automated evidence:** TypeScript passed. The full suite passed 28 files and
171 tests, including deterministic identity, valid appearance ranges, reset
stability, combat routing, and dual-screen propagation.
**Remaining boundary:** The shipped playable rigs currently provide the base
body/underwear, facial customization, and locomotion clips, but not equipped
armor/weapons or skeletal attack/death clips. The existing transform-based
attack/down motion remains. Android/Thor GPU performance with five animated
character rigs remains a separate native-device verification pass.
### HM-2026-07-22-CONTROLLER-ACTION-BINDINGS - IMPLEMENTED, AUTOMATED/NATIVE PASS
**Requested:** Replace the four-slot action bar with a complete controller
layout: Triangle/Circle/Cross/Square in their physical diamond, R1/R2, D-pad
Left/Right, L1 and L2 modifier layers, and a player-configurable binding menu.
**Implementation:** The combat runtime now owns 24 stable action bindings:
eight physical controls across Base, L1, and L2. Browser gamepads, the Android
controller bridge, and keyboard 1-8 with Shift/Alt all resolve through the same
semantic binding model. Modifier press/release ordering prevents a fast
L1/L2 transition from casting on a stale layer; native triggers use fallback
axes plus press/release hysteresis. Android system Back is distinct from Circle,
so it pauses gameplay or backs out of menus without firing a Circle ability.
**Interface:** Only the active eight-slot layer is shown over the playfield.
The four face buttons form the controller diamond, with separate shoulder and
horizontal D-pad groups. The pause menu's Ability Controls panel exposes the
same diagram, spatial D-pad navigation, current-assignment focus, empty or
duplicate bindings, safe reset confirmations, and immediate per-character
persistence. Friendly abilities continue to target the selected ally or self;
D-pad Up/Down cycles living party members plus the player. The PC and Thor
companion surfaces share the active layer and semantic binding commands.
**Automated/native evidence:** The full suite passed 33 files and 212 tests.
Coverage includes all 24 defaults, partial/corrupt save normalization,
per-character isolation, custom chord casting, modifier transition ordering,
native duplicate suppression, system/menu Back routing, self targeting, and
dual-screen dispatch. TypeScript and the production Vite build passed with 672
modules transformed. Android `:app:compileDebugJavaWithJavac --no-daemon`
completed all 43 tasks successfully; only the existing SDK XML/flatDir warnings
remained. A fresh production preview on an isolated local port returned HTTP
200 for both `/` and `/?layout=thor-preview`, then the preview process was
stopped.
**Current content boundary:** Every class currently exposes four runtime
abilities. Defaults therefore fill Cross, Square, Triangle, and Circle while
R1, R2, D-pad Left/Right, L1, and L2 slots begin empty. Players can reuse those
four abilities anywhere now; distinct assignments for all 24 slots require the
separate future expansion of the class ability catalogs and unlock progression.
No screenshot-based visual pass was possible in this session because no
connected in-app browser backend was available; responsive and accessibility
layout received static review, and fresh production entry was HTTP-smoke-tested.
### HM-2026-07-22-INPUT-HANDEDNESS - FIXED, AUTOMATED PASS
**Reported:** Keyboard A/D strafing and horizontal pointer-lock mouse look moved
in the opposite direction from the rendered third-person camera.
**Cause and fix:** Raw keyboard, mouse, and gamepad inputs already used standard
positive-right values. The shared +Z camera-relative transform supplied the
opposite screen-right vector, and positive horizontal look was added to yaw
even though this camera convention turns right by decreasing yaw. The movement
basis now uses the rendered camera's actual right vector, and a shared yaw
helper applies positive mouse/right-stick look in the matching direction.
Vertical look is unchanged. The correction also fixes left-stick strafing and
right-stick horizontal look.
**Evidence:** Focused input coverage passed 15 tests. New regressions verify
A/D at zero and nonzero camera yaw plus both horizontal look directions. The
full suite passed 33 files and 214 tests, and the production build passed with
672 modules transformed. A manual pointer-lock feel check remains device-side
because no connected browser backend was available in this session.
### HM-2026-07-22-SPELL-ICONS-STARTER-WEAPONS - IMPLEMENTED, PC VISUAL PASS
**Requested:** Use each spell's real client icon, equip the player and every
party member with a starting weapon, and replace the companions' repeated
whole-body thrusting with an attack that reads as an actual strike.
**Spell-icon result:** All 40 runtime abilities were joined through their
`dbcSpellId` to the local 3.3.5.12340 `Spell.dbc` and `SpellIcon.dbc` data. The
existing basenames were exact, including several non-obvious stock mappings,
but every URL pointed at a nonexistent `/assets/ui/spells/*.webp` directory.
The 39 distinct authoritative BLPs are now decoded into shipped 64x64 PNGs,
and the catalog serves those files. `scripts/export-spell-icons.mjs` provides a
dependency-free reproducible exporter for DXT1, DXT3, and DXT5 BLP2 sources.
The catalog audit pins all 40 DBC-id mappings and fails when an icon is absent
or empty.
**Equipment result:** No standalone weapon models or playable-character attack
clips were present in the browser asset pack; every race/gender rig contains
only Stand, Walk, and Run. A shared procedural equipment layer now supplies
swords, maces, staves, daggers, bows, and shields. Warriors use sword/shield,
Paladins and Shamans use mace/shield, Rogues dual-wield daggers, Hunters use a
bow, Death Knights use a runeblade, and cloth/Druid classes use staves. Weapon
scale is estimated in avatar-local space. Attachment discovers hands from the
named finger pivots instead of numeric bone IDs, which differ by skeleton; the
same class loadout is also rendered on the procedural loading/error fallback.
**Attack-motion result:** Party `nextActionAt` changes now create one stable
presentation pulse per real hit. Tanks no longer animate continuously merely
because their status is `guarding`, and the party wrapper no longer pitches or
bobs during attacks. Each pulse layers a short windup/strike/recovery onto the
right shoulder after the locomotion mixer, while the equipped weapon layer
adds bounded main-hand/off-hand or bow motion and returns exactly to rest. The
player receives the same one-shot presentation after a successful completed
ability. Combat simulation timing remains outside the render components.
**Automated evidence:** The focused icon/equipment/attack/party suites passed
4 files and 25 tests. The equipment audit reconstructs every one of the 20
shipped playable GLBs and resolves both hands. The complete suite passed 35
files and 224 tests with the established 15-second allowance for the heavy
level-1-through-80 party-talent audit. TypeScript passed. A clean Vite
production build transformed 674 modules; the existing large-chunk warnings
remain informational.
**Visual evidence:** At 1440x900 in Edge/Chromium, the roster preview showed
the Priest's staff attached to her hand. Fresh dungeon entry showed textured
Wailing Caverns, equipped player/party silhouettes, and the real Smite, Shadow
Word: Pain, Flash Heal, and Psychic Scream art on the controller action bar.
The successful captures are
`playtest-artifacts/2026-07-22-weapons/roster-staff.png` and
`playtest-artifacts/2026-07-22-weapons/dungeon-equipped-party.png`; neither
shows a loading/error surface or the prior white-screen failure.
The follow-up 1280x720 Edge/Playwright pass issued the real F1 Attack shortcut
and captured 25 frames from the pre-command state through two defeated entrance
adds. The sequence shows discrete arm/weapon actions on damage events, upright
rest poses between pulses, and no repeated pelvis pitch. Weapons remain bound
to moving hands throughout the advance. Evidence is in
`playtest-artifacts/2026-07-22-weapons/attack-contact-sheet.jpg` and the
individual `attack-frame-*.jpg` files. No page error, scene-error overlay,
white-screen recurrence, or WebGL context loss appeared. The log contains one
generic 404 plus software-WebGL and initialization deprecation warnings; none
prevented the dungeon, party, spell art, equipment, or combat from rendering.
**Remaining visual boundary:** A tank can briefly cross very close to the
player camera while the party leaves formation, making its shield dominate the
view for several frames. That is a companion separation/formation issue, not a
return of the old attack thrust. Native pointer lock, Android/Thor scale and
performance, and every race/class equipment silhouette remain separate
device-side checks. Re-exported authentic item models and native attack/cast
clips would be a future visual-quality upgrade over the current procedural
starter gear.
### HM-2026-07-22-MAIN-MENU-DUNGEON-BROWSER - IMPLEMENTED, AUTOMATED PASS
**Requested:** Add a main menu after character selection with Dungeons,
Manastorms, Roguelike RPG, Trials, Options, and Player Profile. Only Dungeons
needs to work initially and must open a dungeon list.
**Result:** Confirming a roster character now opens a dedicated mode hub
without initializing or resetting gameplay. Dungeons opens a separate browser
backed by a manifest-derived catalog. Wailing Caverns is the sole available
entry because it is the only complete runtime currently shipped; selecting it
activates the character, resets at the entrance, and mounts the 3D game. The
other five requested mode cards are visible, disabled, and marked Coming soon.
Back navigation follows dungeon browser to main menu to character roster, and
the in-game pause exit now returns to the main menu. Narrow PC layouts retain a
visible Continue button instead of hiding the only pointer-accessible action.
**Controller and companion behavior:** A/Enter confirms, directional input
navigates, and B/Escape backs out on both new top-screen views. The companion
display has explicit main-menu and dungeon states, so these shell phases never
fall through to a stale tactical HUD. Its roster Continue, dungeon launch,
change-character, and return-to-main-menu commands mirror the authoritative
top-screen transitions.
**Evidence:** Focused shell/catalog/dual-display coverage passed 3 files and 16
tests. The complete suite passed 36 files and 232 tests. TypeScript and the
production Vite build passed with 677 modules transformed; existing large
chunk warnings remain informational. The local development entry returned HTTP
200. Screenshot automation could not connect to the in-app browser backend in
this Windows sandbox, so responsive desktop/compact layouts received static
review rather than a claimed visual pass.
### HM-2026-08-01-RUNEWAKER-ALL-DUNGEONS - ACTIVE FIDELITY PASS
**Reported:** Every RuneWaker dungeon unexpectedly displayed Coming Soon, and
the imported actors did not consistently retain their original skeletons,
animations, appearances, or attacks.
**Catalog result:** The generated WoW availability refresh had replaced the
whole availability document and removed every RuneWaker key. Availability
generation now preserves non-campaign keys, and packaged RuneWaker definitions
fall back to their validated offline metadata when a key is absent. The live
dungeon browser showed all 30 RuneWaker packages as Ready. Evidence:
`artifacts/playtests/rom-dungeon-catalog-ready.png`.
**Native animation result:** The RuneWaker exporter now selects the largest
body GR2 hierarchy instead of a one-bone effects hierarchy, samples the ACT/RAS
motion set at 30 Hz, and maps skin weights from original OBJ positions to the
vertices Blender reordered or duplicated at seams. A complete audit accounts
for every recipe-referenced actor and rejects invalid GLBs or missing required
animation families. Dynamic paperdoll appearances are exported as exact
image-specific assembled actors instead of generic proxy bodies; the portable
appearance snapshot is checked into the build inputs so normal/offline builds
never connect to SQL.
For this historical rollout, the contract was expressed at the base-actor level
as 267 native actors, one documented pose-only actor, and no combat proxy actors.
The newer authoritative acceptance scope is the 322 namespaced shipping
variants recorded in the in-progress entry above.
Runtime population bindings were 435 native,
one pose-only, and zero proxy. The former eight actorless “bosses” were source
FX/door controllers (six invisible soul-ball effects and two dungeon doors),
not missing creature models; they are now deferred mechanics objects rather
than fake combat objectives.
**Combat-data result:** The portable RuneWaker spell catalog contains the
source assignments used by all dungeon population recipes. The generator only
executes positively classified direct-HP-damage families; buffs, summons,
heals, hooks, and unknown effects remain evidence rather than guessed gameplay.
The current cross-dungeon audit counts 388 source-backed executable attacks and
zero evidence-only spells entering runtime combat. Every entity still retains
a HealerMan basic fallback, so this is not yet a claim of formula-exact boss
state machines.
**Browser result:** Forsaken Abbey loaded from packaged files, rendered its
native population, and entered party combat with damage and XP progression;
captures are `artifacts/playtests/forsaken-abbey-native-population.png` and
`artifacts/playtests/forsaken-abbey-combat.png`. Pasper's Shrine initially
stopped at Blackhorn Nisorn because the source position was 5.25 meters outside
the retained navigation surface. Objective routing now projects a combat
approach point within the same six-meter rule used by the audit. The party
advanced, fought, took damage, and gained XP without console errors. Evidence:
`artifacts/playtests/paspers-shrine-route-fixed-combat.png`; the original
failure is retained as `artifacts/playtests/paspers-shrine-route-blocked.png`.
**Open fidelity boundary:** The source audit still reports disconnected ordered
boss routes in several packages and evidence for doors, phases, summons,
patrols, timers, interactions, and loot that has not been translated into
tested encounter state machines. Those items must remain explicit blockers or
review work; they must not be represented as a complete original game until
implemented and playtested instance by instance.
**Final production/offline verification:** The production build completed with
all 93 packaged paperdoll actor copies present in `dist`. The temporary
`HealerMan_RW_Objects_Paperdoll` forensic database was dropped and the manual
`MSSQL$HEALERMAN_RW` service was stopped before the browser check. From the
packaged production preview, offline login opened the RoM catalog with 30
available, 30 Ready, and zero Coming Soon entries; Forsaken Abbey then launched
into the 3D runtime with its population present. Evidence:
`artifacts/playtests/rom-dungeon-catalog-production-final.png` and
`artifacts/playtests/forsaken-abbey-production-final.png`. No browser error was
reported during dungeon launch. The log retained two earlier WebGL context-lost
messages from page transitions and one non-blocking initialization deprecation
warning.
**Historical automated scope:** TypeScript and the production build passed for
that rollout. Its RuneWaker animation audit reported 267 native base actors, one
pose-only base actor, and no configured combat proxies; required idle, movement,
attack, wound, and death animation-family gates were satisfied under the earlier
gate. It is superseded by the completed v5 all-variant verdict above. The
gameplay audit covered 30
dungeons, 8,199 source placement rows, 4,086 runtime static spawns, 436 runtime
entities, 61 boss objectives, and 824 executable attacks (436 basic fallbacks
plus 388 source-backed attacks). The full test run passed 87 files and 522
tests; its remaining three failures are pre-existing Manastorm fixture/parser
failures outside this RuneWaker work. The previously stale Forsaken Abbey test
was fixed and passes separately.
**Remaining source-fidelity work:** Thirty-one paperdoll appearances still need
their original dye-mask colors composited, although their geometry, base
textures, skeletons, skinning, and clips are authentic. Twenty-one optional
source RAS references are absent or non-GR2, while every required combat family
still passes. The navigation audit records 19 unreachable distance-derived
objective legs across eight packages; there are no preserved source-authored
orders, so unsafe permanent off-mesh links were not invented. Original
coefficient formulas and the evidenced door, phase, summon, patrol, timer,
interaction, loot, and modular-room state machines remain the next per-instance
implementation pass.
### HM-2026-08-01-ARROW-CAMERA-LOOK - PC KEYBOARD CAMERA PASS
**Requested:** On PC in the browser, make the arrow keys turn the camera when
playing with mouse and keyboard instead of a controller.
**Result:** WASD remains the keyboard movement cluster. Left/right arrows now
apply continuous camera yaw, and up/down arrows apply continuous camera pitch.
The pause controls and live HUD hint now describe arrows as camera input rather
than movement input. Controller left-stick movement and right-stick camera look
remain unchanged.
**Live browser evidence:** Wailing Caverns was launched from the offline roster.
Repeated right-arrow input changed the minimap heading from 244 degrees to 242
degrees; repeated left-arrow input then changed it to 247 degrees. Up/down arrow
passes visibly changed the vertical camera angle. The exploration counter stayed
at 0 m throughout, confirming arrow input did not move the player, and the
heading stayed at 247 degrees after a 600 ms release check. The updated camera
hint rendered in the dungeon and the browser console contained no errors.
**Pointer-lock boundary:** The in-app playtest browser does not expose the
Pointer Lock API, so `document.pointerLockElement` is undefined there and a
live null assertion or held-right-button automation is not possible on that
surface. No capture prompt appeared. The unchanged right-drag path remains
covered by `inputManager.test.ts`, including ordinary drag deltas and a null
pointer-lock assertion.
**Automated evidence:** `src/game/inputManager.test.ts` and
`src/game/inputMath.test.ts` pass 19 tests. TypeScript and the production Vite
build pass with 914 modules transformed; the existing large-chunk warnings
remain informational.
### HM-2026-08-01-RUNEWAKER-PLAYERS - RACES, CLASSES, AND DUAL CLASS
**Result:** The WoW/RoM content split is live across character creation,
persistence, roster summaries, party generation, Class Hall, the spellbook,
and combat. RoM ships Human, Elf, and male-only Dwarf plus the ten released
classes. Level 10 permanently fixes a race-eligible secondary; Class Hall swaps
the ordered primary/secondary orientation and its independent action bar.
Shared XP, automatic ranks, primary stats plus 10% secondary stats, role and
resource changes, equipment compatibility, and directional elite unlocks are
covered by the application tests. Existing WoW profiles migrate to storage v2
without losing their progression or bindings.
**Generator/audit:** `npm run runewaker:players:refresh` completed from the
RuneWaker source tables, strings, elite Lua, image metadata, and `interface.fdb`.
The portable catalog records source SHA-256 hashes and contains 269 ordinary
skill families plus 660 elite milestones across all 66 valid ordered pairs.
All 929 visible skills have an executable or explicit non-combat contract;
zero are unresolved. All 929 icon references resolve to 918 unique native PNGs.
The independently loadable `runewaker-v1` manifest contains five native rigs
(Human male/female, Elf male/female, Dwarf male), starter attachments, and
native idle/walk/run/attack/cast clip families. Khronos validation reported
zero errors and zero warnings for all five GLBs.
**Live controller/browser QA:** From the production preview, keyboard/controller
menu navigation moved from the default WoW Human race to the RoM category and
confirmed it with Enter. The draft reset to Taborean Human and exposed the
correct six-class pool. Dwarf creation enforced male gender and exposed
Warrior, Rogue, Mage, Priest, Warlock, and Champion. A native Dwarf Champion
rendered in creator and roster. The level-1 Class Hall showed its level-10 lock;
level-10 selection, irreversible confirmation, swapping, and both orientations
are covered by automated controller/persistence tests.
The same RoM character could select both the 54-dungeon WoW category and the
30-dungeon RoM category. Wailing Caverns and Forsaken Abbey both launched with
the native character, a rage pool, RuneWaker spell icons, and a same-category
RoM party. The tactical menu now says **Skills**, and its RoM view reported
Primary `2 / 18`, Secondary General `0 / 0`, Elite `0 / 0`, and automatic
rank progression for the pre-secondary level-1 Champion. Browser diagnostics
contained no errors. Expected renderer teardown messages and one non-blocking
initialization deprecation warning remain.
**Evidence:**
- `playtest-artifacts/2026-08-01-rom-dual-class/rom-roster-preview.png`
- `playtest-artifacts/2026-08-01-rom-dual-class/rom-character-wow-dungeon-preview.png`
- `playtest-artifacts/2026-08-01-rom-dual-class/rom-character-rom-dungeon-preview.png`
- `scripts/runewaker-pipeline/snapshots/runewaker-player-skill-audit.json`
**Final verification:** `npx tsc -b --pretty false` passed; Vitest passed all
95 files and all 549 tests; `npm run build` passed with 921 modules transformed.
Vite's existing large-chunk advisory remains informational.
### HM-2026-08-01-DUNGEON-ASSET-EVICTION - GLTF AND GPU LIFECYCLE
**Result:** Regular dungeon sessions now own their environment, collision,
navigation, and creature GLB URLs. Switching dungeons or leaving the gameplay
runtime clears those URLs from Drei's global `useGLTF` cache. Scene teardown
also deterministically disposes dungeon-owned geometries, cloned materials,
textures, creature skeletons, and bone textures, with identity-based
deduplication so shared resources are released once. Playable-character and
equipment assets remain cached because they are reused across every dungeon.
**Live browser evidence:** A fresh production-preview renderer loaded Auchenai
Crypts at 797.7 MB private / 856.6 MB working set. Returning to the main menu
released the outgoing scene and settled at 555.8 MB / 615.1 MB. Blackrock
Depths then loaded at 1,033.2 MB / 1,098.6 MB. Chromium initially retained that
allocator reservation after the Blackrock teardown, but loading Auchenai again
settled at 800.0 MB / 855.6 MB, effectively matching the first Auchenai load
instead of stacking both dungeon footprints. Leaving Auchenai a second time
settled at 592.5 MB / 651.5 MB. The environment, five-character party, HUD, and
minimap rendered correctly throughout. Browser diagnostics contained no GLB,
WebGL, or runtime errors; only the existing non-blocking initialization
deprecation warning remained.
**Verification:** The focused dungeon ownership, session-switch, invalid-switch,
and shared-resource disposal tests passed all 11 cases. The full Vitest run
passed 98 files and 556 tests. TypeScript, the 54-dungeon campaign audit, the
five-player import verifier, and `npm run build` all passed; the production
build transformed 923 modules. Vite's existing large-chunk advisory remains
informational.
### HM-2026-08-01-ROM-ABILITY-PRESENTATION - NATIVE ICONS AND CLIPS
**Result:** Runtime RoM abilities now consume the native icon path already
recorded in `romPlayerCatalog.generated.json` instead of replacing every skill
icon with its class emblem. RoM combat animation events now select native
RuneWaker character clips for casting/continuous casting, friendly buffs, bow
channel/release, melee weapon variations and specials, wounds, and death. WoW
characters retain the existing AnimationData-ID selector.
**Live browser evidence:** The saved Dwarf Champion rendered in the roster and
entered Forsaken Abbey with its body and starter weapon silhouette visible. All
eight live action slots resolved to distinct `/assets/ui/rom-spells/<id>.png`
assets (including Heavy Bash `589471.png` and Electrocution `589472.png`). The
ability control was exercised against a selected Ooze; the game correctly
reported that the target was out of melee range. Browser diagnostics contained
no errors. Native clip reachability for release/cast/bow/melee/wound/death is
therefore recorded by the focused automated selector test rather than claimed
from the out-of-range screenshot.
**Evidence:**
- `artifacts/playtest/rom-roster-preview-2026-08-01.png`
- `artifacts/playtest/rom-dungeon-heavy-bash-2026-08-01.png`
**Verification:** `src/game/combatAnimation.test.ts` and
`src/game/romPlayerCatalog.test.ts` passed all 11 tests; `npm test -- --run
src/avatar` passed all 28 avatar tests; `npm run build` passed with 921 modules
transformed. Vite's existing large-chunk advisory remains informational.
### HM-2026-08-01-WOW-CREATURE-ANIMATION-MEMORY - RUNTIME CLIP POLICY
**Result:** Shipped WoW dungeon creature GLBs now contain only animation
families requested by `MobPopulation`: stand, walk, run, and the highest-priority
available attack, cast, wound, and death families. Every variation in each
selected combat family is retained. The complete source GLBs remain untouched
under `HealerMan-Storage/pipeline-work/dungeons`, and all five-player, Epoch,
and Wailing Caverns packaging paths now apply the same policy to future exports.
The migration optimized 1,111 current dungeon creature GLBs. Source inventory
fell from 73,191 clips to 8,102 runtime clips. Runtime payload fell from
4,855,010,592 bytes to 2,963,934,636 bytes, saving 1,891,075,956 bytes (39%).
The 146-clip Auchenai reference model retained nine gameplay clips and fell
from 13,824,072 bytes to 7,650,004 bytes. Generated manifests record the source
clip count, runtime count, policy version, checksum, and post-policy semantics.
**Live browser evidence:** A fresh production-preview session opened the saved
Human Priest and entered Auchenai Crypts as healer. The environment and all five
character rigs rendered correctly. After moving inside the 95 m population
activation radius, the browser resource inventory confirmed optimized creature
displays 17932, 17924, and 17942 were loaded. Browser diagnostics contained no
errors; the existing initialization deprecation warning remains non-blocking.
After creature activation, the renderer settled at about 930 MB private / 989
MB working set and peaked at about 1.03 GB private / 1.09 GB working set. The
earlier pre-change two-dungeon pass peaked around 1.15 GB private / 1.2 GB
working set, so these measurements are directional rather than an identical
scene sequence.
**Verification:** The policy's four focused Node tests passed. The campaign-wide
WoW content test passed all 54 dungeons, the five-player verifier remained green
with only its three documented source blockers, mob/combat animation tests
passed all 18 cases, and `npm run build` passed with 921 modules transformed.
Vite's existing large-chunk advisory remains informational.
# 2026-08-14 — local-first content delivery and compact Android client
- Build under test: fresh full production `dist` served by `server/server.mjs`
at `http://127.0.0.1:4173`.
- Booted to the login screen and entered through **Play offline** without an
account-server request.
- Roster preview: the saved level 8 human female priest rendered her complete
body, hair, and starter staff silhouette. The procedural/error fallback did
not replace or hide the character.
- Downloads screen: the two-column local-first layout rendered without
clipping at the test viewport. Its local catalog request returned the
expected 404 because no generated `content/` volume was mounted for this
local smoke test; the screen retained the offline starter-content message.
- Dungeon smoke: entered Wailing Caverns as healer. The production cavern,
player body/equipment silhouette, four companion bodies, HUD, minimap, and
action bar were visible. No missing-GLB proxy or scene error appeared.
- Evidence reviewed during the browser run: login, roster-preview, Downloads,
and in-dungeon screenshots. Browser console contained no errors; one existing
third-party initialization deprecation warning was present.
# 2026-08-16 — CoA character-creation category
- Opened the offline roster and entered character creation in the live Vite
client. The header rendered distinct **WoW**, **RoM**, and **CoA** tabs without
clipping.
- The WoW tab showed only the eight standard WoW classes available to Human;
no custom CoA class appeared.
- The CoA tab reused the Azeroth race roster and showed the 16 custom CoA
classes available to Human, defaulting to Barbarian. The character body and
starter weapon silhouette remained visible while switching categories.
- In the production preview, the saved Human Priest rendered in the roster with
her full body and starter staff silhouette, then entered Wailing Caverns with
her body, staff, party, dungeon environment, and HUD visible.
- Browser diagnostics contained no errors.
- Evidence: `playtest-artifacts/character-create-wow-category-2026-08-16.png`
`playtest-artifacts/character-create-coa-category-2026-08-16.png`,
`playtest-artifacts/character-category-roster-2026-08-16.png`, and
`playtest-artifacts/character-category-dungeon-2026-08-16.png`.
- Verification: 71 focused catalog/store/repository/dungeon/ability/party tests
passed, all 28 avatar tests passed, and `npm run build` completed
successfully.
# 2026-08-16 — Deadmines party terrain following and vertical animation tolerance
- Entered The Deadmines as the saved Human Priest and selected **Attack**.
The player crossed 43 m of uneven mine-floor and rail terrain; the tank and
a damage companion remained visibly beside the player instead of waiting for
the 12 m stuck-recall threshold. All four companion world labels remained in
the live scene, and no automatic party recall was observed.
- The character maintained ordinary ground locomotion over small collision
height changes. Focused timing coverage confirms that terrain gaps shorter
than 100 ms neither enter the falling state nor trigger a landing animation,
while intentional jumps and sustained falls still present immediately/after
the grace period and land once.
- The saved roster preview rendered the complete Human body and starter staff;
the in-dungeon view rendered the player silhouette, nearby companions, the
Deadmines environment, and HUD.
- Browser diagnostics contained no errors. The existing third-party
initialization deprecation warning remained non-blocking.
- Evidence: `playtest-artifacts/party-terrain-roster-2026-08-16.png`,
`playtest-artifacts/deadmines-party-terrain-2026-08-16.png`, and
`playtest-artifacts/deadmines-party-follow-view-2026-08-16.png`.
- Verification: 38 focused party/pathing/jump/animation tests passed, all 28
avatar tests passed, and `npm run build` completed successfully with 954
modules transformed. The existing large-chunk advisory remains informational.