Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Moderators: GZDoom Developers, LZDoom Developers, UZDoom Developers
Forum rules
Please be as descriptive as possible in your posts (list your hardware and operating system, the version of the source port you are using, any mods you are running and how they're being loaded, etc.)
This will help others to give you a solution!
Please be as descriptive as possible in your posts (list your hardware and operating system, the version of the source port you are using, any mods you are running and how they're being loaded, etc.)
This will help others to give you a solution!
-
HyperCrab2000
- Posts: 2
- Joined: Thu Feb 20, 2025 4:10 am
- Operating System Version (Optional): macOS
- Graphics Processor: Apple M1
Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
I'm curious if I can port GZDoom to WASM for a web browser and I figure the only real hurdle is WebGL, and so I played around with it and got stuck and I'm not sure what's going on so I hope someone can help out?
I'm trying to build GZDoom into WASM and run it in the browser. However, I'm not very familiar with C and the instructions don't seem to be very clear to me. Here's what I did.
I modified CMakeLists.txt to add this at the very top
cmake_minimum_required(VERSION 3.10)
set(BUILD_SHARED_LIBS OFF) # Disable shared libraries
set(BUILD_STATIC ON)
Changed this block
#Change for Emscripten
include(CheckSymbolExists)
if (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
check_symbol_exists(backtrace "execinfo.h" HAS_BACKTRACE)
if (HAS_BACKTRACE)
add_definitions(-DHAS_BACKTRACE)
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "MSYS")
set(NOX11 ON)
set(NO_GBM ON)
set(WIN32_PLATFORM ON)
if(CMAKE_C_COMPILER_ID MATCHES "MSVC" OR "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
set(WIN32_MSVC ON) #msvc or icl or clang-cl
endif()
endif()
#Emscripten
if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
set(STATICLIB ON)
endif()
Added this at the bottom
# Ensure the linker knows where to find libGL.a
link_directories(/Users/me/IdeaProjects/react-boilerplate/gzdoom-build/gl4es/lib)
# Define gzdoom and make sure it links AFTER GL is built
add_executable(gzdoom main.c)
# Make sure gzdoom depends on GL
add_dependencies(gzdoom GL)
# Link gzdoom against GL (the static library)
target_link_libraries(gzdoom /Users/me/IdeaProjects/react-boilerplate/gzdoom-build/gl4es/lib/libGL.a)
And added this main.c file because I needed an entry point I guess?
#include <stdio.h>
#include <stdlib.h>
// External function to initialize GL4ES
extern void initialize_gl4es();
int main() {
// Initialize GL4ES before any OpenGL functions are used
initialize_gl4es();
// Your WebAssembly application logic here
printf("GL4ES Initialized, now running WebAssembly app...\n");
return 0;
}
To build I ran this
emcmake cmake ..
emmake make -j$(sysctl -n hw.ncpu)
And finally this command:
emcc -s USE_WEBGL2=1 -s FULL_ES2=1 -s ALLOW_MEMORY_GROWTH=1 -s AUDIO_WORKLET=1 -s WASM_WORKERS=1 -pthread \
--preload-file ../doom2.wad@/doom/doom2.wad \
../main.c -L../lib -I../include -o gzdoom.html \
-s EXPORTED_FUNCTIONS="['_initialize_gl4es', '_main']" \
-s EXPORTED_RUNTIME_METHODS="['callMain']" \
../lib/libGL.a
Which gives me a .wasm file and an .html file I can serve using
python3 -m http.server 8080
However, when I do I see this:
LIBGL: Initialising gl4es
LIBGL: v1.1.7 built on Feb 20 2025 01:24:52
LIBGL: Using GLES 2.0 backend
LIBGL: Hardware test disabled, nothing activated...
LIBGL: Targeting OpenGL 2.1
LIBGL: Not forcing NPOT support
LIBGL: Not trying to batch small subsequent glDrawXXXX
LIBGL: Trying to use VBO
LIBGL: Force texture for Attachment color0 on FBO
LIBGL: Hack to trigger a SwapBuffers when a Full Framebuffer Blit on default FBO is done
LIBGL: Current folder is:/
LIBGL: Not using PSA (prgbin_n=0, notexarray=0)
GL4ES Initialized, now running WebAssembly app...
And nothing happens. What am I missing? GZDoom doesn't seem to be running and I see no console errors.
Apologies for not formatting this cleaner but I don't see a way of enabling BBCode for this post so I hope someone can help out? I'm stuck and I'm not sure what else to do.
I'm trying to build GZDoom into WASM and run it in the browser. However, I'm not very familiar with C and the instructions don't seem to be very clear to me. Here's what I did.
I modified CMakeLists.txt to add this at the very top
cmake_minimum_required(VERSION 3.10)
set(BUILD_SHARED_LIBS OFF) # Disable shared libraries
set(BUILD_STATIC ON)
Changed this block
#Change for Emscripten
include(CheckSymbolExists)
if (NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
check_symbol_exists(backtrace "execinfo.h" HAS_BACKTRACE)
if (HAS_BACKTRACE)
add_definitions(-DHAS_BACKTRACE)
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows" OR CMAKE_SYSTEM_NAME MATCHES "MSYS")
set(NOX11 ON)
set(NO_GBM ON)
set(WIN32_PLATFORM ON)
if(CMAKE_C_COMPILER_ID MATCHES "MSVC" OR "x${CMAKE_C_SIMULATE_ID}" STREQUAL "xMSVC")
set(WIN32_MSVC ON) #msvc or icl or clang-cl
endif()
endif()
#Emscripten
if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
set(STATICLIB ON)
endif()
Added this at the bottom
# Ensure the linker knows where to find libGL.a
link_directories(/Users/me/IdeaProjects/react-boilerplate/gzdoom-build/gl4es/lib)
# Define gzdoom and make sure it links AFTER GL is built
add_executable(gzdoom main.c)
# Make sure gzdoom depends on GL
add_dependencies(gzdoom GL)
# Link gzdoom against GL (the static library)
target_link_libraries(gzdoom /Users/me/IdeaProjects/react-boilerplate/gzdoom-build/gl4es/lib/libGL.a)
And added this main.c file because I needed an entry point I guess?
#include <stdio.h>
#include <stdlib.h>
// External function to initialize GL4ES
extern void initialize_gl4es();
int main() {
// Initialize GL4ES before any OpenGL functions are used
initialize_gl4es();
// Your WebAssembly application logic here
printf("GL4ES Initialized, now running WebAssembly app...\n");
return 0;
}
To build I ran this
emcmake cmake ..
emmake make -j$(sysctl -n hw.ncpu)
And finally this command:
emcc -s USE_WEBGL2=1 -s FULL_ES2=1 -s ALLOW_MEMORY_GROWTH=1 -s AUDIO_WORKLET=1 -s WASM_WORKERS=1 -pthread \
--preload-file ../doom2.wad@/doom/doom2.wad \
../main.c -L../lib -I../include -o gzdoom.html \
-s EXPORTED_FUNCTIONS="['_initialize_gl4es', '_main']" \
-s EXPORTED_RUNTIME_METHODS="['callMain']" \
../lib/libGL.a
Which gives me a .wasm file and an .html file I can serve using
python3 -m http.server 8080
However, when I do I see this:
LIBGL: Initialising gl4es
LIBGL: v1.1.7 built on Feb 20 2025 01:24:52
LIBGL: Using GLES 2.0 backend
LIBGL: Hardware test disabled, nothing activated...
LIBGL: Targeting OpenGL 2.1
LIBGL: Not forcing NPOT support
LIBGL: Not trying to batch small subsequent glDrawXXXX
LIBGL: Trying to use VBO
LIBGL: Force texture for Attachment color0 on FBO
LIBGL: Hack to trigger a SwapBuffers when a Full Framebuffer Blit on default FBO is done
LIBGL: Current folder is:/
LIBGL: Not using PSA (prgbin_n=0, notexarray=0)
GL4ES Initialized, now running WebAssembly app...
And nothing happens. What am I missing? GZDoom doesn't seem to be running and I see no console errors.
Apologies for not formatting this cleaner but I don't see a way of enabling BBCode for this post so I hope someone can help out? I'm stuck and I'm not sure what else to do.
-
dpJudas
- Posts: 3177
- Joined: Sat May 28, 2016 1:01 pm
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Well at this point you have two options.
First is to install the Web assembly DWARF debugging extension for Chrome and then pray the debugger can tell you something (unfortunately its very undeveloped and borderline useless).
Or you begin adding printf/cout statements in the code to see how far it gets before going radio silent.
Also try try turn off gl_multithreaded as I'm not sure how Webassembly can do multithreading at all (as far as I know the workers can't share memory with the main UI thread, but please correct me if I'm wrong about that)
First is to install the Web assembly DWARF debugging extension for Chrome and then pray the debugger can tell you something (unfortunately its very undeveloped and borderline useless).
Or you begin adding printf/cout statements in the code to see how far it gets before going radio silent.
Also try try turn off gl_multithreaded as I'm not sure how Webassembly can do multithreading at all (as far as I know the workers can't share memory with the main UI thread, but please correct me if I'm wrong about that)
-
Enjay
-

- Posts: 27597
- Joined: Tue Jul 15, 2003 4:58 pm
- Location: Scotland
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
I can't help with the main problem but, just for info:
New users on the forum have limited access to the BBCode options until a certain number of posts have been reached (I forget the number - it's not too high). This was a deliberate anti-spam/troll decision as we did have people turning up, creating an account and then abusing the features.HyperCrab2000 wrote: ↑Thu Feb 20, 2025 4:22 am Apologies for not formatting this cleaner but I don't see a way of enabling BBCode for this post...
-
dpJudas
- Posts: 3177
- Joined: Sat May 28, 2016 1:01 pm
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Just reply to my own comment about threads, it turns out that webassembly does support sharing memory between the threads now. However, you must enable it using HTTP headers (https://web.dev/articles/coop-coep):
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
-
milpool
- Posts: 2
- Joined: Mon Mar 13, 2023 4:06 pm
- Preferred Pronouns: He/Him
- Graphics Processor: ATI/AMD with Vulkan/Metal Support
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
I've been looking for an Emscripten port of GZDoom. Would trying to get LZDoom (or even ZDoom) to run on WASM be any easier?
-
ololoken
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Well, I made some progress with porting gzdoom to emscripten.
https://github.com/ololoken/gzdoom
build options: -DHAVE_VULKAN=OFF -DHAVE_GLES2=ON -DDYN_OPENAL=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC=ON -DHAVE_VM_JIT=OFF -DNO_GTK=ON -DDYN_GTK=OFF
Main problems as usual are texture formats, shaders and framebuffers. It definitely can work in browser, but requires expert's hand.
https://github.com/ololoken/gzdoom
build options: -DHAVE_VULKAN=OFF -DHAVE_GLES2=ON -DDYN_OPENAL=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC=ON -DHAVE_VM_JIT=OFF -DNO_GTK=ON -DDYN_GTK=OFF
Main problems as usual are texture formats, shaders and framebuffers. It definitely can work in browser, but requires expert's hand.
-
ololoken
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Ok, here is PoC https://turch.in/gzdoom.png gzdoom is running in browser.
There is still plenty of work:
1. statically link emscripten AL
2. fix textures formats handling
3. fix VATTR_BONESELECTOR
There is still plenty of work:
1. statically link emscripten AL
2. fix textures formats handling
3. fix VATTR_BONESELECTOR
-
ololoken
- Posts: 9
- Joined: Wed Dec 17, 2025 2:24 am
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Here is (semi-)working gzdoom: no sound, some textures remain broken
https://turch.in/gzdoom+freedoom/index.html
repo: https://github.com/ololoken/gzdoom
milpool, HyperCrab2000 we can collaborate our efforts
https://turch.in/gzdoom+freedoom/index.html
repo: https://github.com/ololoken/gzdoom
milpool, HyperCrab2000 we can collaborate our efforts
-
Riax
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
ololoken wrote:
> Here is (semi-)working gzdoom: no sound, some textures remain broken
>
> https://turch.in/gzdoom+freedoom/index.html
>
> repo: https://github.com/ololoken/gzdoom
>
> milpool, HyperCrab2000 we can collaborate our efforts
Hello ololoken,
impressive work, compiled your project and it seems to be pretty stable, except the obvious zmusic issues and occasional stutters.
I have been working on a GZDOOM WASM port for the past couple of months, since March of this year, and I got to a state where it ran somewhat smoothly but I stopped due to a lack of motivation.
I would be down for a collab, as I could use this for personal needs. If youd like, you can add me on Discord; cochcetepomnedpc
-Riax
> Here is (semi-)working gzdoom: no sound, some textures remain broken
>
> https://turch.in/gzdoom+freedoom/index.html
>
> repo: https://github.com/ololoken/gzdoom
>
> milpool, HyperCrab2000 we can collaborate our efforts
Hello ololoken,
impressive work, compiled your project and it seems to be pretty stable, except the obvious zmusic issues and occasional stutters.
I have been working on a GZDOOM WASM port for the past couple of months, since March of this year, and I got to a state where it ran somewhat smoothly but I stopped due to a lack of motivation.
I would be down for a collab, as I could use this for personal needs. If youd like, you can add me on Discord; cochcetepomnedpc
-Riax
-
ololoken
- Posts: 9
- Joined: Wed Dec 17, 2025 2:24 am
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
@Riax yep, there is problem with synchronisation of AsyncBackgroundProc in oalsound.cpp and rest code.
You can try to rid of AsyncBackgroundProc and build with -pthread support, I'm sure it will fix stability issue.
You can try to rid of AsyncBackgroundProc and build with -pthread support, I'm sure it will fix stability issue.
-
ololoken
- Posts: 9
- Joined: Wed Dec 17, 2025 2:24 am
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Well I hope sound is not source of crashes anymore.
Build at https://turch.in/gzdoom+freedoom/index.html is updated. Let's think someone will have enough time to test it.
@Riax unable to find you on discord, try ping me turch.in1878
Build at https://turch.in/gzdoom+freedoom/index.html is updated. Let's think someone will have enough time to test it.
@Riax unable to find you on discord, try ping me turch.in1878
-
Riax
- Posts: 1
- Joined: Sat Dec 20, 2025 12:27 pm
- Preferred Pronouns: He/Him
- Operating System Version (Optional): Arch, Fedora, Windows 10
- Graphics Processor: ATI/AMD (Modern GZDoom)
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
ololoken wrote:
> Well I hope sound is not source of crashes anymore.
> Build at https://turch.in/gzdoom+freedoom/index.html is updated. Let's
> think someone will have enough time to test it.
>
> @Riax unable to find you on discord, try ping me turch.in1878
Hi, perfect, runs very well on Chromium-based browsers when loaded in cache.
I would love to discuss this further with you, I have sent you a friend request on Discord. My nick is adam, "cochcetepomnedpc" is my tagline. (without "")
> Well I hope sound is not source of crashes anymore.
> Build at https://turch.in/gzdoom+freedoom/index.html is updated. Let's
> think someone will have enough time to test it.
>
> @Riax unable to find you on discord, try ping me turch.in1878
Hi, perfect, runs very well on Chromium-based browsers when loaded in cache.
I would love to discuss this further with you, I have sent you a friend request on Discord. My nick is adam, "cochcetepomnedpc" is my tagline. (without "")
-
ololoken
- Posts: 9
- Joined: Wed Dec 17, 2025 2:24 am
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Let's continue ITT.
Remaining big issue is not working weapons in mods like brutal doom and ashes 2063
In brutal mod works only melee attacks, machine gun, bfg and daemonic flamethrower.
In ashes I can zoom with rifles, attack melee and that's it.
I guess it's somehow connected to reload weapon logic in zscript, but I have no ideas how to debug it. Any ideas?
@dpJudas @Enjay
Remaining big issue is not working weapons in mods like brutal doom and ashes 2063
In brutal mod works only melee attacks, machine gun, bfg and daemonic flamethrower.
In ashes I can zoom with rifles, attack melee and that's it.
I guess it's somehow connected to reload weapon logic in zscript, but I have no ideas how to debug it. Any ideas?
@dpJudas @Enjay
-
ololoken
- Posts: 9
- Joined: Wed Dec 17, 2025 2:24 am
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
Small update.
I've found root cause: A_JumpIfInventory
A value returned ResolveState() is ignored. Internally state is resolved properly both for indexes and string literals, but it just ignored and next state is executed without jumping.
Where I can find info where does vm handle jumps?
I've found root cause: A_JumpIfInventory
A value returned ResolveState() is ignored. Internally state is resolved properly both for indexes and string literals, but it just ignored and next state is executed without jumping.
Where I can find info where does vm handle jumps?
-
Jay0
-

- Posts: 98
- Joined: Tue Aug 21, 2018 9:31 pm
- Preferred Pronouns: She/Her
- Graphics Processor: ATI/AMD with Vulkan/Metal Support
- Location: Brazil
Re: Emscripten + GZDoom = WASM for a Web Browser, but I'm stuck
the jump issue isn't from emscripten, it's because GZDoom master's VM is currently broken due to this commit, i'd recommend switching your upstream to UZDoom instead, that's where most devs other than graf (me included) went (as for the reason, you can find it here)ololoken wrote: ↑Sat Dec 27, 2025 8:08 pm Small update.
I've found root cause: A_JumpIfInventory
A value returned ResolveState() is ignored. Internally state is resolved properly both for indexes and string literals, but it just ignored and next state is executed without jumping.
Where I can find info where does vm handle jumps?