Skip to content

WasmPlayer: boot-time TypeError from dotnet.native.wasm interop (undefined style target) #2011

Description

@alexwarren

Summary

During testing of the new single-file embedded-game export (docs/wasmplayer-single-file-export.md, src/WasmPlayer/scripts/export-embedded.mjs, and the window.QuestVivaEmbeddedGame boot branch near wasm-player.js:1897), I found a reproducible-but-load-dependent console error during WasmPlayer boot:

TypeError: Cannot set properties of undefined (setting 'backgroundColor')
TypeError: Cannot set properties of undefined (setting 'color')
TypeError: Cannot set properties of undefined (setting 'fontFamily')
TypeError: Cannot set properties of undefined (setting 'fontSize')

The stack trace bottoms out inside _framework/dotnet.native.wasm (a generated JS-interop marshaling frame, not application JS) — so this is the .NET WASM runtime itself calling into JS to set 4 style properties together on an object reference that's undefined at that point.

The game still boots and plays correctly despite the errors (confirmed full playthrough works), so this looks non-fatal — but it indicates something in the WASM boot sequence assumes a DOM element (or JS interop handle) exists before it reliably does.

Investigation so far

All done via a local CDN stand-in (a python http.server with Access-Control-Allow-Origin: *, serving a Release AppBundle) and a separate origin serving generated single-file HTML exports, verified with browser dev tools.

  • Not specific to the new embedded-game boot path's code. Decoding the exact same .quest package bytes and loading them via the pre-existing ?url= boot path (network fetch, same origin) did not show the error, while the embedded path (bytes available synchronously via base64, no fetch delay) did, reproducibly, across multiple different game packages (a blank freshly-created draft AND examples/published.quest).
  • Not specific to game content. Same bytes reproduced the error whether generated via the Node CLI script (export-embedded.mjs) or via the AppShell in-browser TypeScript export path (exportSingleFile in src/AppShell/src/lib/editor-store.ts).
  • It is timing/load sensitive. An early, low-load test of published.quest via the embedded path passed completely clean (no errors). A later reload of the identical file under heavier concurrent system load (multiple dev servers + browser tabs running WASM boots simultaneously) reproduced the error consistently.

Working theory: the new embedded-game path is faster than every existing boot source (bytes are already in memory — no network round-trip — before startGame()/Bridge.Initialise() runs), which exposes a latent race that pre-existing (slower) boot sources rarely or never hit.

Where to look

  1. Search WasmPlayerBridge.cs / PlayerHelper.cs / GameQuery.cs for JS-interop calls that set background/foreground/font together. Grep hits so far (none obviously match a direct .style.backgroundColor = pattern on a quick read, so the actual call site is probably in the .NET WASM SDK's own generated JSImport marshaling glue, or somewhere not yet located):
    • JsSetBackground/JsSetForegroundWasmPlayerBridge.cs:354-357,714-723
    • IPlayer.SetFont/SetFontSizeWasmPlayerBridge.cs:780-782
    • PlayerHelper.cs's m_fontSize/SetFontSizePlayerHelper.cs:27-28,332-348
  2. Check whether initWasmPlayer (wasm-player.js:446) assumes something set up asynchronously elsewhere (the chrome.css <link> load, jQuery UI init in playercore.js's initPlayerUI, paper.js/grid canvas setup) has completed before Bridge.Initialise/Bridge.InitialiseWithSave (called at wasm-player.js:533-534, right after the synchronous swapInPlayerUi() call at line 530) starts executing game startup scripts that might reach this style-setting interop call.
  3. Confirm whether pre-existing fast boot sources (source=editor/source=local, delivered via BroadcastChannel with no network delay) can also reproduce this under load — if so it further confirms this predates the new embedded export feature entirely and is a general latent race, not something introduced by it.

Impact

Not currently blocking anything — the single-file export feature works correctly end-to-end despite this. Worth a dedicated root-cause pass since it suggests a real (if currently harmless) race in the boot sequence.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions