Web Build Crash Fixes (JS/WASM)


Posting a bit more info here in case it saves someone else some time.

Got the web build (-target:js_wasm32) stable after hitting two totally separate crashes. Here’s what broke and what I changed.

1) Startup crash: core:os not supported on JS/WASM

What happened
The game would start booting, then immediately die with an Odin runtime error pointing at core:os being “not yet implemented” for the JS target. The browser console would then spiral into loader failures and eventually a WASM trap.

Why it happened
settings_save.odin was calling core:os directly (os.read_entire_file, os.write_entire_file). Those procedures simply aren’t implemented for JS/WASM in Odin, so the build was guaranteed to abort as soon as settings I/O ran.

The annoying part: the project already had the right abstraction in place. utils.odin exposes read_entire_file / write_entire_file with per platform implementations:

  • Native: delegates to core:os

  • Web: uses fopen/fread/fwrite against Emscripten’s virtual FS
    …but settings_save.odin bypassed it.

Fix
settings_save.odin now uses the existing wrappers instead of importing core:os:

  • removed import "core:os"

  • swapped os.read_entire_file(...)read_entire_file(...)

  • swapped os.write_entire_file(...)write_entire_file(...)

Result
Web build can get past init again. This fixes the crash; persistence still depends on how Emscripten FS is mounted/synced in the actual deployment.

2) Gameplay crash: Aborted(alignment fault) from RNG

What happened
After settings stopped killing the build, gameplay would crash shortly after starting with:

Uncaught RuntimeError: Aborted(alignment fault)

Stack trace pointed straight into RNG usage (7 bag shuffle / refill_and_shuffle) via rand.int_max(...).

Why it happened
WebAssembly traps on unaligned 64 bit memory access. Odin’s default RNG (core:math/rand) keeps 64 bit state internally, and in this configuration the RNG state ended up being touched in a way that triggered an unaligned 64 bit read/write  instant WASM abort.

Fix approach
Stopped calling rand.* from gameplay code and added a tiny platform RNG layer:

  • Native builds: keep using core:math/rand

  • WASM builds: use a simple 32 bit xorshift (u32 state only) to avoid any 64 bit alignment issues

Code changes
Added two platform files with the same API:

  • source/random_web.odin (#+build wasm32, wasm64p32)

    • xorshift32-backed

    • web_rand_init(), game_rand_int_max, game_rand_int31_max, game_rand_float, game_rand_float_range

  • source/random_default.odin (#+build !wasm32 and !wasm64p32)

    • wrapper around core:math/rand with the same functions

Then in game.odin:

  • call web_rand_init() from game_init() (no-op on native)

  • replaced all gameplay RNG calls rand.*game_rand_*

Result
No more alignment fault during gameplay. 7 bag shuffle and other RNG heavy bits run cleanly on the web build now.

Leave a comment

Log in with itch.io to leave a comment.