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 @@ + + +
+ + +