From ca8a3d1b92d8947552993bde294d1c950e2bc9e0 Mon Sep 17 00:00:00 2001 From: Liam Warfield Date: Sat, 10 Jan 2026 14:09:37 -0700 Subject: [PATCH] web: add loading screen while WASM fetches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shows a themed spinner overlay while the large WASM bundle downloads, improving perceived load time on slower connections. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- gui/Dioxus.toml | 2 +- gui/public/loader.js | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 gui/public/loader.js diff --git a/gui/Dioxus.toml b/gui/Dioxus.toml index 288a146..571a2c6 100644 --- a/gui/Dioxus.toml +++ b/gui/Dioxus.toml @@ -23,7 +23,7 @@ watch_path = ["src", "assets"] # CSS style file style = [] # Javascript code file -script = [] +script = ["loader.js"] [web.resource.dev] # serve: [dev-server] only diff --git a/gui/public/loader.js b/gui/public/loader.js new file mode 100644 index 0000000..1a86cfc --- /dev/null +++ b/gui/public/loader.js @@ -0,0 +1,65 @@ +// Loading screen that displays while WASM loads +(function() { + // Create and inject loader styles immediately (head exists) + var style = document.createElement('style'); + style.textContent = + '.wasm-loader {' + + 'position: fixed;' + + 'top: 0;' + + 'left: 0;' + + 'width: 100%;' + + 'height: 100%;' + + 'background-color: oklch(0.15 0.01 338.64);' + + 'display: flex;' + + 'align-items: center;' + + 'justify-content: center;' + + 'z-index: 9999;' + + 'transition: opacity 0.3s ease-out;' + + '}' + + '.wasm-loader.hidden {' + + 'opacity: 0;' + + 'pointer-events: none;' + + '}' + + '.wasm-spinner {' + + 'width: 48px;' + + 'height: 48px;' + + 'border: 4px solid rgba(123, 173, 159, 0.2);' + + 'border-top-color: #7bad9f;' + + 'border-radius: 50%;' + + 'animation: wasm-spin 1s linear infinite;' + + '}' + + '@keyframes wasm-spin {' + + 'to { transform: rotate(360deg); }' + + '}'; + document.head.appendChild(style); + + function init() { + // Create loader element + var loader = document.createElement('div'); + loader.className = 'wasm-loader'; + loader.innerHTML = '
'; + document.body.appendChild(loader); + + // Watch for Dioxus to mount content in #main + var observer = new MutationObserver(function(mutations, obs) { + var main = document.getElementById('main'); + if (main && main.children.length > 0) { + loader.classList.add('hidden'); + setTimeout(function() { loader.remove(); }, 300); + obs.disconnect(); + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + } + + // Wait for body to exist + if (document.body) { + init(); + } else { + document.addEventListener('DOMContentLoaded', init); + } +})();