Browser WebAssembly Port - #5106
Conversation
|
This is so cool! |
|
You don't need to worry about the graphics API thing. If I complete the Vulkan engine I will probably write a WGPU engine. |
|
If the commits don't create any regressions, I guess I could merge it as quickly as possible. The todos can be done in later PRs or by other contributors. But I would like a clear instruction on how to compile this in INSTALL.md. |
Personally I don't think using the same code as the Android version would be a good idea here, since Android is vastly different from the Emscripten environment. For example in WASM the threading implementation is very broken, which means a large amount of the networking logic has to be rewritten to use async APIs for it to work. I did borrow the audio patches from the Switch port though, since those allowed the audio processing to run in the main thread (because web audio cannot be run from a worker at all). Regarding the graphics issues, when I tried using the non-legacy renderer, I kept getting WebGL errors which I wasn't able to debug. You can try removing the stk-code/lib/irrlicht/source/Irrlicht/CIrrDeviceSDL.cpp Lines 544 to 546 in b8a53b9
Also, I did put compile instructions inside the README for the wasm directory, but I guess this got buried in the PR diff. |
|
Thanks for mentioning. Actually, I meant the Android code could handle the option of installing the full uncompressed game asset instead of forcing you to load that initially. I don't compile Android code so I don't know a lot tbh. |
|
And yes I found the instructions now, very thanks. Then I would approve the merge of this PR at any time when you feel free. |
|
I do think that I can incorporate what If I can get the assets compressed down to under ~200MB or so, then that amount of extra memory usage is more acceptable and we won't need to worry about the Emscripten virtual filesystem stuff. |
|
another task is to either strip out or parse the ANSI escape sequences |
stk_wasm_2.mp4I just made some improvements to the web interface. The most significant changes are that the game now fills the entire browser window, and the progress for the asset download is displayed. |
|
It's cool to have STK running in a web browser. But I have some concerns. The OpenGL ES 2 graphics mean that the game looks really crappy, and at the same time I get really terrible performance. Running the benchmark I got a steady FPS of 6 and the game was running at 50% of real-time-speed (it took 1m13s to complete instead of normally about 36s). I get something like 250FPS with a normal compiled version using Graphics 1. If someone is curious about STK, I'd prefer them to not play the web version as a way to test the game... I had a cursory look at the changes, most of it seem to be compiling logic and define guards, plus the webpage code. It seems to be relatively simple overall, but the maintenance burden still appears to be an open question. Especially as additional code would arguably be needed to disable the parts and options that don't work on the web version. |
|
to anyone that wants to try this you might wanna disable ublock origin as it blocks webassembly if youre using a hardened by default browser (e.g. librewolf, mulch, ungoogled-chromium, etc.) you may need to find a way to enable jit, webgl and wasm |
|
I managed to get the assets compressed down to 120MB, which is a large improvement over the 700MB download that was required before. The memory usage is also significantly lower since less asset data gets loaded into memory. The highest levels of compression cause the textures to be noticeably blurry sometimes, so I added an option to use higher resolution assets at the cost of a larger download. |
|
Hello, is there any progress on this? |
|
@CodingJellyfish I just merged the latest commits on the main branch with my changes. I'll probably be able to fix the networking problems by switching from the blocking libcurl APIs to the async ones. Once the networking is fixed I'll likely be fine with merging this PR. I don't have any experience in graphics programming so I can't fix the GLES 3 support, so someone else will probably have to do it later. |
…creen" This reverts commit e50c523.
|
I am happy to announce that STK in the browser with GL ES 3.0 is now working successfully, on my fork/branch. The demo is available up here https://stk.linuxcolorado.com/ I need more people to test playing the game in the browser, and online matches, then provide feedback on bugs, etc. my fork/branch is here https://github.com/vlouvet/stk-code/tree/wasm-gles3 and I will be making a separate PR for it soon, in order to not cross-request on this PR. I wanted to add this note for the sake of reference - and to thank @ading2210 for the hard work, without which my work would not have been possible. |
|
Thank you @vlouvet! This is the furthest we've gotten so far with GLES3 support. However, I had some issues with your demo. If you run the in-game benchmark, the kart isn't rendered correctly, and the game crashes with this error:
If you start a new race manually, it's fine though. |
|
@vlouvet Once everything is fixed I can add your changes to my PR and hopefully get it merged soon. There's a ton of AI generated changes in there and I can manually pick out the ones that are needed to make it easier to review. |
The in-game benchmark crashes on Firefox WebGL2 the moment the race
countdown hits "GO":
Uncaught TypeError: GLctx.disjointTimerQueryExt.createQueryEXT is not a function
at _emscripten_glGenQueriesEXT (supertuxkart.js:20:3666)
...
Reproduction reported by @ading2210 in PR supertuxkart#5106 review:
supertuxkart#5106 (comment)
What triggers it: WorldStatus::onPhaseChange() activates the profiler
when RaceManager::isBenchmarking() is true; the very first ScopedGPUTimer
then calls glGenQueries, which Emscripten's library_webgl.js dispatches
to GLctx.disjointTimerQueryExt.createQueryEXT. Firefox often refuses to
expose EXT_disjoint_timer_query_webgl2 (fingerprinting concern), so
disjointTimerQueryExt is undefined and the page tears down.
Guard ScopedGPUTimer construction/destruction and GPUTimer::elapsedTimeus
behind !defined(__EMSCRIPTEN__). CPU-side profiling still runs and the
benchmark completes; GPU-time breakdown is just unavailable on wasm,
which matches the broader story that Emscripten doesn't expose reliable
GPU timer queries anyway.
Also adds wasm/test_benchmark.sh as a regression check:
1. Parses the wasm IMPORT section and fails if any glGenQueries /
glBeginQuery / glGetQuery / TimerQuery symbols are imported.
2. Verifies the public deploy returns 200 with application/wasm.
3. Documents the manual browser repro.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@ading2210 thanks for the catch — fixed in 8c345939df. Root cause: WorldStatus::onPhaseChange() activates the profiler the moment the race countdown hits "GO" when RaceManager::isBenchmarking() is true. The very first ScopedGPUTimer after that calls glGenQueriesEXT, which Emscripten dispatches to GLctx.disjointTimerQueryExt.createQueryEXT. Firefox refuses to expose EXT_disjoint_timer_query_webgl2 (fingerprinting concern), so disjointTimerQueryExt is undefined and the page tears down with the TypeError you saw. A normal race start doesn't go through that path, which is why only the benchmark hit it. Fix: the three GPU-timer call sites in src/graphics/glwrap.cpp (ScopedGPUTimer ctor/dtor and GPUTimer::elapsedTimeus) are now guarded by #if defined(GL_TIME_ELAPSED) && !defined(EMSCRIPTEN). CPU profiling still runs; the benchmark just doesn't report a GPU-time breakdown on wasm — which matches the broader reality that Emscripten can't reliably expose GPU timer queries anyway. Verified at https://stk.linuxcolorado.com/ — benchmark replay completes cleanly now: [info] Profiler: Frame count '6123', Time (ms) '20335', Re-test whenever you have a minute. Hard-reload first since the old wasm is in browser cache. |
@vlouvet @ading2210 Please see https://supertuxkart.net/How_to_contribute_code#supertuxkarts-policy-on-ai-generated-code |
|
I understand the position of the project on A.I. generated code - and I did not mean to waste anyone's time, my apologies. I do hope that the work done so far on bringing STK to the browser recently can be of some use to someone in the project in the future. Additionally, I am happy to incorporating upstream changes into my fork/branch so that playing through the browser remains possible - even if it is through an unofficial port/fork. Thank you for the wonderful project. |
|
So if theres AI generated code on this PR now, doesn't that mean this PR has to be immediately closed and rejected? |
|
This PR remains untouched by AI. My original comment states that the work was on a separate for and branch and it not incorporated into this PR from what I can tell. Hope this helps clear this up @searinminecraft |
My bad, sorry for the misunderstanding |


Agreement
I ported SuperTuxKart to the web using Emscripten, and I think it would be worthwhile to have this merged upstream.
Here's a working demo: https://supertuxkart.pages.dev/
I tested this on Chrome 125 and Firefox ESR 115.
8mb.video-Q5u-I6rcrEhf.mp4
Working features:
TODO:
Webpage themingBetter compression for assetsCaveats:
The RAM usage is rather high because the assets are always loaded in memoryThere is a large ~700MB download required immediately