From bc7046180ac869de90bcf9a6ccf0a072e4ce0f5a Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 31 Jan 2026 14:36:22 -0500 Subject: [PATCH] Add Emscripten shell and pre-JS for browser compatibility - src/shell.html: Custom HTML shell with crisp pixel CSS (image-rendering: pixelated) and zoom prevention on canvas - src/emscripten_pre.js: Patches browser quirks that cause crashes: - Intercepts resize/scroll events to ensure e.detail is always 0 - Wraps window properties (innerWidth, outerWidth, etc.) to always return integers, fixing browser zoom crashes - CMakeLists.txt: Output as .html, include shell and pre-js files The pre-JS fix addresses "attempt to write non-integer (undefined) into integer heap" errors that occurred when users zoomed the browser via Ctrl+scroll or browser menu. Co-Authored-By: Claude Opus 4.5 --- CMakeLists.txt | 7 ++ src/emscripten_pre.js | 69 ++++++++++++++++++ src/shell.html | 162 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 src/emscripten_pre.js create mode 100644 src/shell.html diff --git a/CMakeLists.txt b/CMakeLists.txt index 265f910..49d3625 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,6 +269,10 @@ if(EMSCRIPTEN) --preload-file=${CMAKE_SOURCE_DIR}/src/scripts@/scripts # Preload assets --preload-file=${CMAKE_SOURCE_DIR}/assets@/assets + # Use custom HTML shell for crisp pixel rendering + --shell-file=${CMAKE_SOURCE_DIR}/src/shell.html + # Pre-JS to fix browser zoom causing undefined values in events + --pre-js=${CMAKE_SOURCE_DIR}/src/emscripten_pre.js ) # Add SDL2 options if using SDL2 backend @@ -288,6 +292,9 @@ if(EMSCRIPTEN) target_link_options(mcrogueface PRIVATE ${EMSCRIPTEN_LINK_OPTIONS}) + # Output as HTML to use the shell file + set_target_properties(mcrogueface PROPERTIES SUFFIX ".html") + # Set Python home for the embedded interpreter target_compile_definitions(mcrogueface PRIVATE MCRF_WASM_PYTHON_HOME="/lib/python3.14" diff --git a/src/emscripten_pre.js b/src/emscripten_pre.js new file mode 100644 index 0000000..a4b4108 --- /dev/null +++ b/src/emscripten_pre.js @@ -0,0 +1,69 @@ +// Pre-JS file for McRogueFace Emscripten build +// This runs BEFORE Emscripten's code, allowing us to patch browser quirks + +// Fix for browser zoom causing undefined values in resize events +// When browser zoom changes, some event/window properties can become undefined +// which causes Emscripten's HEAP32 writes to fail with assertion errors + +(function() { + 'use strict'; + + // Store original addEventListener + var originalAddEventListener = EventTarget.prototype.addEventListener; + + // Properties that Emscripten's uiEventHandlerFunc reads + // These need to be integers, not undefined + var windowIntegerProps = [ + 'innerWidth', 'innerHeight', + 'outerWidth', 'outerHeight', + 'pageXOffset', 'pageYOffset' + ]; + + // Ensure window properties return integers even during zoom transitions + windowIntegerProps.forEach(function(prop) { + var descriptor = Object.getOwnPropertyDescriptor(window, prop); + if (descriptor && descriptor.get) { + var originalGetter = descriptor.get; + Object.defineProperty(window, prop, { + get: function() { + var val = originalGetter.call(this); + // Return 0 if undefined/null, otherwise floor to integer + return (val === undefined || val === null) ? 0 : Math.floor(val); + }, + configurable: true + }); + } + }); + + // Wrap addEventListener to intercept resize/scroll events + EventTarget.prototype.addEventListener = function(type, listener, options) { + if (type === 'resize' || type === 'scroll') { + var wrappedListener = function(e) { + // Ensure e.detail is an integer + if (e.detail === undefined || e.detail === null) { + // Create a new event with detail = 0 + try { + Object.defineProperty(e, 'detail', { + value: 0, + writable: false + }); + } catch (ex) { + // If we can't modify, create a proxy event + e = new Proxy(e, { + get: function(target, prop) { + if (prop === 'detail') return 0; + var val = target[prop]; + return typeof val === 'function' ? val.bind(target) : val; + } + }); + } + } + return listener.call(this, e); + }; + return originalAddEventListener.call(this, type, wrappedListener, options); + } + return originalAddEventListener.call(this, type, listener, options); + }; + + console.log('McRogueFace: Emscripten pre-JS patches applied'); +})(); diff --git a/src/shell.html b/src/shell.html new file mode 100644 index 0000000..a1ab612 --- /dev/null +++ b/src/shell.html @@ -0,0 +1,162 @@ + + + + + + McRogueFace - WebGL + + + +

McRogueFace

+
Downloading...
+
+ +
+ + + {{{ SCRIPT }}} + +