Failure modes
| Symptom | Likely cause | Correction |
|---|---|---|
| No overlay appears | The context or parent was queried before the correct view-ready event. | Create hangar windows on lobby-view loaded and battle windows after the battle shared page populates. |
Battle window becomes DESTROYED with no area or size |
It attached to the outgoing lobby parent, or raw content failed before readiness. | Move creation to the populated battle page, then verify VFS files and content status. |
AttributeError for setPayload or another setter |
A hand-written property registered storage but not a Python setter. | Implement the matching _set* method wrapper with the correct index.
|
| Only the first character of each row is visible | Auto-sized content was measured inside an unsized or one-pixel native surface. | Use matching fixed CSS and native dimensions or measure independently. |
| A colored value overlaps the following row | Spans wrapped or overflowed. | Use explicit fields and a non-wrapping flex row with hidden overflow. |
| Window vanishes after returning from battle | The lobby context was selected before the reconstructed main window reached loaded status. | Re-resolve the current main window with a bounded token-guarded retry. |
| Window disappears or duplicates after replay rewind | The seek invalidated its page, entity, model, callback, or listener owner, and recovery reused stale state or installed a second layer. | Tear down at rewind start, invalidate the generation, and rebuild once from the current replay context after rewind finish. |
| Panel cannot reach a screen edge | The view retained a fallback native surface larger than the visible panel. | Publish the exact size after engine, DOM, and layout readiness. |
| Border is missing on the right or bottom | CSS and native dimensions disagree. | Use one border-box panel and identical surface dimensions. |
| Moving immediately after load logs an undefined area or ID | The window has not joined a Wulf area. | Move only after the post-resize ready command. |
| DOM changes disappear after navigation or filtering | The native React tree rerendered. | Use a scoped idempotent observer and repeat decoration safely. |
| Model changes never reach JavaScript | The listener was registered too late, on the wrong model, or without an initial render. | Render once, subscribe after engine readiness, and retain the callback identity. |
| Every overlay starts centered or at its default although position keys still exist | The first preference read ran before Settings.g_instance.userPrefs was
ready, and the load guard permanently accepted the fallback.
|
Retry preference readiness for a bounded period, mark loading complete only after a
successful read, cast readInt defaults to int, and
immediately reapply restored coordinates.
|
| The panel is visible under the cursor but will not drag, or it clamps toward the bottom-right | Physical screen pixels were mixed with the scaled coordinate space used by the Wulf main window. | Derive the current conversion from the loaded main window, perform cursor tracking
and screen clamping in physical pixels, then convert the final target back before
window.move().
|
Diagnostic workflow
- On WG 2.4.1, confirm the uniquely named
gui/gen_resourcesJSON is strict, mounted, and free of duplicate dotted IDs. On historical WG, confirm the resource-map JSON is discovered and the combined map validates. - Confirm the matching native
R.mods...accessor, or legacyitemIDaccessor, resolves to a non-negative numeric layout ID. - Confirm the HTML, CSS, and JavaScript files exist in the runtime VFS.
- Confirm the correct account, lobby route, avatar, or battle-page context owns creation.
- Confirm
windowsManager.getMainWindow()returns the current parent with a live proxy andWindowStatus.LOADED. - In battle, confirm creation occurs after the battle page populated—not merely when the avatar became player.
- Confirm the Wulf window enters a live area and its content has not been destroyed.
- Confirm JavaScript observes engine readiness and DOM-built readiness.
- Confirm the intended model and DOM root exist.
- Confirm the authored panel dimensions are measurable and
resizeViewPxruns. - Confirm Python sees the intended positive
window.size, not zero or a fallback square. - Confirm saved-position loading did not complete before
Settings.g_instance.userPrefsbecame available. If a delayed read succeeds, confirm the coordinates are reapplied to the already-created window. - Confirm the global cursor, screen bounds, Wulf
window.position, andwindow.sizeare converted into one coordinate space before hit testing and clamping. - Confirm requested movement matches actual
window.positionand remains clamped to the screen.
When a view disappears, sample windowStatus, window.area, window.content,
content view status, and window.size after short delays. A destroyed window with no
area, content, or size proves that CSS and placement are downstream of the real failure.
Review checklist
- The feature has a unique WG 2.4.1 native declaration filename and
R.mods...ID, or a unique historical WG resource-map key, plus an entrance and packagedcoui://path. - The chosen pattern matches the requirement: native-view injection or standalone panel.
- WG 2.4.1 validates the native accessor directly; only the historical WG lookup waits for helper validation. Either path treats an invalid ID as a disabled feature.
- An injected child attaches after parent load, attaches once, and follows the parent lifecycle.
- A standalone window has the current loaded main window as parent and uses a panel-sized overlay surface.
- Hand-written model properties include explicit setters.
- The initial model is complete, and later transactions begin after JavaScript readiness.
- JavaScript renders once, listens for later changes, and cleans up its listener identity.
- Engine, DOM, layout, scaling, and native resizing happen in the correct order.
- CSS dimensions,
resizeViewPx, Python hit testing, andwindow.sizeagree. - Physical screen pixels and Wulf main-window coordinates are converted explicitly rather than compared directly.
- Battle creation is anchored to the populated battle page rather than the earlier avatar transition.
- Garage-only visibility follows the lobby route, not merely account presence.
- DOM augmentation is scoped, idempotent, and resilient to React rerenders.
- Observers, callbacks, windows, hooks, and input handlers have explicit teardown.
- Saved placement uses bounded preference-readiness retries, sets its loaded guard only after
a successful read, passes integer defaults to
readInt, and reapplies delayed results. - Private models, generated DOM classes, state paths, and view methods are marked version-sensitive and verified against the target build.
Diagnostic checklist
Most Gameface failures fall into one of four buckets: resource resolution, model readiness, host sizing, or lifecycle ownership. Debug in that order before rewriting the UI.
| Symptom | Check first | Likely owner |
|---|---|---|
| Blank window | Wulf host exists, coui:// URL resolves, the resource for the target WG version
declaration is loaded, and HTML is packaged.
|
Resource registration and host view. |
| HTML loads but JavaScript does not run | Script path, case sensitivity, console errors, bundling target, cached stale asset. | Gameface resource root. |
| JavaScript runs but model is missing | Model name, creation order, window.model versus
window.subViews, destroyed view.
|
Python view model owner. |
| Model never updates | Transaction/update call, listener registration, stale Python reference, route ownership. | View model and lifecycle owner. |
| Zero-size window | Host dimensions, CSS root size, layout calculation, scale and resolution events. | Wulf host and layout. |
| Appears only after resize | Initial layout timing, missing size invalidation, delayed content measurement. | Layout readiness. |
| Duplicate window after battle | Old reference cleared, destroy event handled, init callback cancelled, route transition tested. | Lifecycle cleanup. |
| Wrong drag coordinates | Interface scale, CSS pixels vs client pixels, viewport clamp after resolution change. | Input and layout owner. |
| Disappears after replay rewind | Replay invalidated entities/model data, listeners rebuilt, duplicate prevention still active. | Replay lifecycle. |
Capability evidence workflow
- Identify the loaded client build and embedded engine version independently from the vendor manual.
- Separate resource, window, frontend, model, layout and native-input readiness.
- Test API presence, actual operation and visible/audible output as separate criteria.
- For network/storage, distinguish packaged loads, loopback transport, recreation and full restart.
- Repeat normal closes, loading interruption and owner reconstruction; inspect callbacks and native topology.
- State failed, unresolved and untested criteria separately from passes.
Use frontend capabilities, media results, transport/storage boundaries, native resize/input checks and workload measurement to select a narrow test. A successful desktop preview does not establish client rendering, and an empty native topology does not prove heap leak freedom.
Cross-layer acceptance matrix
Define separate criteria for a registered resource, created native surface, loaded frontend, delivered initial model, later revision, DOM reconciliation and native input. Then test normal closing, native-parent retention, closing during loading and context reconstruction. Count owned listeners/callbacks and native surfaces as well as checking visible output.
For injected controls, test localization and a native rerender; for staged calculations, distinguish observed revision from applied revision; for retained parents, verify child-slot detachment and independent frontend cleanup. See Communication and Updates and retained-parent detachment.