[Major Feature] WebAssembly/Emscripten build target for browser deployment #158

Open
opened 2025-12-07 04:50:41 +00:00 by john · 0 comments
Owner

Vision

Compile McRogueFace to WebAssembly, enabling:

  • No-install web application — run games directly in browsers
  • Code portability — Python scripts transfer directly between web and desktop
  • Broader reach — accessible on any device with a modern browser
  • Future console support — abstract renderer also enables Nintendo Switch, etc.

Dependency Analysis

Dependency WASM Support Status Notes
libtcod-headless Ready Our fork No SDL deps, should cross-compile cleanly
SFML None Blocker Explicitly out-of-scope for SFML 3.x
VRSFML (fork) Yes Alternative Modern OpenGL ES 3.0+, Emscripten-ready
SMK Yes Alternative SFML-like API built for WASM
CPython Tier 3 PEP 776 Official support in 3.11+, formalized in 3.14
ImGui Mature Works Native Emscripten backend available

Major Technical Hurdles

1. SFML Replacement Required

SFML explicitly declined Emscripten support for 3.x (deferred to 4.x with potential Vulkan backend).

Options:

  • VRSFML — Emscripten-ready fork, removes legacy OpenGL, targets OpenGL ES 3.0+
  • SMK — Ground-up SFML alternative for WASM
  • Wait for SFML 4.x — Unknown timeline

2. Game Loop Architecture Change

Browsers require cooperative multitasking — no blocking while(true) loops.

// Current (blocking)
while (running) {
    processEvents();
    update();
    render();
}

// Emscripten (callback-based)
void mainLoop() { /* single frame */ }
emscripten_set_main_loop(mainLoop, 0, 1);

// VRSFML provides SFML_GAME_LOOP macro to abstract this

Requires refactoring GameEngine::run() to support both models.

3. Python-in-WASM Integration

CPython compiles to WASM (PEP 776, build guide), but with limitations:

Feature Browser Node Pyodide
subprocess/fork
threads WIP
file system MEMFS only IDB/Node
shared extensions WIP WIP
PyPI packages
sockets WebSocket

Key concerns:

  • Threading + dynamic loading together is experimental (Pyodide uses no-pthreads)
  • No subprocess/fork/popen (ENOSYS)
  • C++↔Python binding layer (McRFPy_API) needs adaptation
  • Binary size: ~4.5 MB compressed for minimal stdlib

4. Filesystem Virtualization

All file I/O must go through Emscripten's virtual filesystem:

  • Assets preloaded via --preload-file or async fetch()
  • scripts/ directory bundled into WASM
  • Save/load requires IndexedDB or cloud storage
  • Synchronous fopen() becomes async or pre-bundled

5. Asset Loading & Binary Size

Estimated bundle size:
- CPython WASM: ~10-15 MB
- Graphics library: ~2-5 MB
- Game code + assets: varies
- Total: 20-50+ MB potential download

Requires asset optimization strategy (lazy loading, compression, LOD).

Implementation Strategy

Phase 1: Renderer Abstraction (see #157)

Create RenderBackend interface that decouples from SFML:

  • SFMLBackend — current desktop implementation
  • SoftwareBackend — for true headless (#157)
  • VRSFMLBackend or SMKBackend — for WASM

This is shared prerequisite work with #157.

Phase 2: VRSFML Evaluation

  • Build VRSFML and test browser demos
  • Assess API compatibility with current McRogueFace code
  • Identify required changes to rendering code

Phase 3: Python-in-WASM Prototype

  • Build minimal CPython for Emscripten
  • Test if McRFPy_API binding approach works
  • Evaluate Pyodide vs raw CPython Emscripten
  • This is the highest-risk unknown

Phase 4: Game Loop Refactor

  • Abstract main loop to support both blocking and callback styles
  • Test with Emscripten's emscripten_set_main_loop

Phase 5: Asset Pipeline

  • Implement Emscripten virtual FS integration
  • Bundle scripts and assets
  • Add async loading where needed

Phase 6: Build System

  • CMake configuration for Emscripten toolchain
  • CI/CD for WASM builds
  • Hosting/deployment strategy

Relationship to Other Work

  • Depends on #157 — Renderer abstraction is prerequisite
  • Benefits from libtcod-headless — Already SDL-free, should cross-compile
  • Enables future console ports — Same abstraction supports Switch, etc.

Scope Assessment

This is a v2.0+ project requiring:

  • 150+ files touched
  • New build system configuration
  • Potentially months of focused effort
  • Significant unknowns (especially Python integration)

The renderer abstraction work (#157) is the highest-leverage first step — it unblocks both headless and WASM paths.

References

## Vision Compile McRogueFace to WebAssembly, enabling: - **No-install web application** — run games directly in browsers - **Code portability** — Python scripts transfer directly between web and desktop - **Broader reach** — accessible on any device with a modern browser - **Future console support** — abstract renderer also enables Nintendo Switch, etc. ## Dependency Analysis | Dependency | WASM Support | Status | Notes | |------------|--------------|--------|-------| | **libtcod-headless** | ✅ Ready | Our fork | No SDL deps, should cross-compile cleanly | | **SFML** | ❌ None | Blocker | Explicitly out-of-scope for SFML 3.x | | **VRSFML** (fork) | ✅ Yes | Alternative | Modern OpenGL ES 3.0+, Emscripten-ready | | **SMK** | ✅ Yes | Alternative | SFML-like API built for WASM | | **CPython** | ✅ Tier 3 | PEP 776 | Official support in 3.11+, formalized in 3.14 | | **ImGui** | ✅ Mature | Works | Native Emscripten backend available | ## Major Technical Hurdles ### 1. SFML Replacement Required SFML [explicitly declined Emscripten support](https://github.com/SFML/SFML/issues/1494) for 3.x (deferred to 4.x with potential Vulkan backend). **Options:** - **[VRSFML](https://vittorioromeo.com/index/blog/vrsfml.html)** — Emscripten-ready fork, removes legacy OpenGL, targets OpenGL ES 3.0+ - **[SMK](https://github.com/ArthurSonzogni/smk)** — Ground-up SFML alternative for WASM - **Wait for SFML 4.x** — Unknown timeline ### 2. Game Loop Architecture Change Browsers require cooperative multitasking — no blocking `while(true)` loops. ```cpp // Current (blocking) while (running) { processEvents(); update(); render(); } // Emscripten (callback-based) void mainLoop() { /* single frame */ } emscripten_set_main_loop(mainLoop, 0, 1); // VRSFML provides SFML_GAME_LOOP macro to abstract this ``` Requires refactoring `GameEngine::run()` to support both models. ### 3. Python-in-WASM Integration CPython compiles to WASM ([PEP 776](https://peps.python.org/pep-0776/), [build guide](https://github.com/python/cpython/blob/main/Tools/wasm/README.md)), but with limitations: | Feature | Browser | Node | Pyodide | |---------|---------|------|---------| | subprocess/fork | ❌ | ❌ | ❌ | | threads | ❌ | ✅ | WIP | | file system | MEMFS only | ✅ | IDB/Node | | shared extensions | WIP | WIP | ✅ | | PyPI packages | ❌ | ❌ | ✅ | | sockets | ❌ | ❌ | WebSocket | **Key concerns:** - Threading + dynamic loading together is experimental (Pyodide uses no-pthreads) - No subprocess/fork/popen (ENOSYS) - C++↔Python binding layer (`McRFPy_API`) needs adaptation - Binary size: ~4.5 MB compressed for minimal stdlib ### 4. Filesystem Virtualization All file I/O must go through Emscripten's virtual filesystem: - Assets preloaded via `--preload-file` or async `fetch()` - `scripts/` directory bundled into WASM - Save/load requires IndexedDB or cloud storage - Synchronous `fopen()` becomes async or pre-bundled ### 5. Asset Loading & Binary Size ``` Estimated bundle size: - CPython WASM: ~10-15 MB - Graphics library: ~2-5 MB - Game code + assets: varies - Total: 20-50+ MB potential download ``` Requires asset optimization strategy (lazy loading, compression, LOD). ## Implementation Strategy ### Phase 1: Renderer Abstraction (see #157) Create `RenderBackend` interface that decouples from SFML: - `SFMLBackend` — current desktop implementation - `SoftwareBackend` — for true headless (#157) - `VRSFMLBackend` or `SMKBackend` — for WASM This is shared prerequisite work with #157. ### Phase 2: VRSFML Evaluation - Build VRSFML and test [browser demos](https://vittorioromeo.com/index/blog/vrsfml.html) - Assess API compatibility with current McRogueFace code - Identify required changes to rendering code ### Phase 3: Python-in-WASM Prototype - Build minimal CPython for Emscripten - Test if `McRFPy_API` binding approach works - Evaluate Pyodide vs raw CPython Emscripten - **This is the highest-risk unknown** ### Phase 4: Game Loop Refactor - Abstract main loop to support both blocking and callback styles - Test with Emscripten's `emscripten_set_main_loop` ### Phase 5: Asset Pipeline - Implement Emscripten virtual FS integration - Bundle scripts and assets - Add async loading where needed ### Phase 6: Build System - CMake configuration for Emscripten toolchain - CI/CD for WASM builds - Hosting/deployment strategy ## Relationship to Other Work - **Depends on #157** — Renderer abstraction is prerequisite - **Benefits from libtcod-headless** — Already SDL-free, should cross-compile - **Enables future console ports** — Same abstraction supports Switch, etc. ## Scope Assessment This is a **v2.0+ project** requiring: - 150+ files touched - New build system configuration - Potentially months of focused effort - Significant unknowns (especially Python integration) The renderer abstraction work (#157) is the highest-leverage first step — it unblocks both headless and WASM paths. ## References - [SFML WASM Issue #1494](https://github.com/SFML/SFML/issues/1494) - [VRSFML Emscripten Fork](https://vittorioromeo.com/index/blog/vrsfml.html) - [SMK - WASM Multimedia Library](https://github.com/ArthurSonzogni/smk) - [PEP 776 - Python Emscripten Support](https://peps.python.org/pep-0776/) - [CPython WASM Build Guide](https://github.com/python/cpython/blob/main/Tools/wasm/README.md) - [Python WASM Notes](https://pythondev.readthedocs.io/wasm.html) - [Pyodide](https://github.com/pyodide/pyodide) - [libtcod Emscripten Issue #41](https://github.com/libtcod/libtcod/issues/41) - [libtcod-headless fork](https://github.com/jmccardle/libtcod-headless)
john added the
Major Feature
system:rendering
priority:tier3-future
labels 2025-12-07 04:51:15 +00:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Reference: john/McRogueFace#158
No description provided.