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

  1. On WG 2.4.1, confirm the uniquely named gui/gen_resources JSON is strict, mounted, and free of duplicate dotted IDs. On historical WG, confirm the resource-map JSON is discovered and the combined map validates.
  2. Confirm the matching native R.mods... accessor, or legacy itemID accessor, resolves to a non-negative numeric layout ID.
  3. Confirm the HTML, CSS, and JavaScript files exist in the runtime VFS.
  4. Confirm the correct account, lobby route, avatar, or battle-page context owns creation.
  5. Confirm windowsManager.getMainWindow() returns the current parent with a live proxy and WindowStatus.LOADED.
  6. In battle, confirm creation occurs after the battle page populated—not merely when the avatar became player.
  7. Confirm the Wulf window enters a live area and its content has not been destroyed.
  8. Confirm JavaScript observes engine readiness and DOM-built readiness.
  9. Confirm the intended model and DOM root exist.
  10. Confirm the authored panel dimensions are measurable and resizeViewPx runs.
  11. Confirm Python sees the intended positive window.size, not zero or a fallback square.
  12. Confirm saved-position loading did not complete before Settings.g_instance.userPrefs became available. If a delayed read succeeds, confirm the coordinates are reapplied to the already-created window.
  13. Confirm the global cursor, screen bounds, Wulf window.position, and window.size are converted into one coordinate space before hit testing and clamping.
  14. Confirm requested movement matches actual window.position and 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 packaged coui:// 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, and window.size agree.
  • 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

  1. Identify the loaded client build and embedded engine version independently from the vendor manual.
  2. Separate resource, window, frontend, model, layout and native-input readiness.
  3. Test API presence, actual operation and visible/audible output as separate criteria.
  4. For network/storage, distinguish packaged loads, loopback transport, recreation and full restart.
  5. Repeat normal closes, loading interruption and owner reconstruction; inspect callbacks and native topology.
  6. 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.