diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html index ef19c0032ec..51a996d4a6d 100644 --- a/misc/dist/html/editor.html +++ b/misc/dist/html/editor.html @@ -9,8 +9,8 @@ - - + + @@ -24,211 +24,7 @@ Redot Engine Web Editor (___GODOT_VERSION___) - +
Important - Please read
- - - - - +
+ +
+
+ + +
+
+ + +
@@ -345,14 +147,18 @@

Important - Please read

- + - - + diff --git a/misc/dist/html/manifest.json b/misc/dist/html/manifest.json index b799ea00031..6b651cbaa76 100644 --- a/misc/dist/html/manifest.json +++ b/misc/dist/html/manifest.json @@ -3,7 +3,7 @@ "short_name": "Redot", "description": "Multi-platform 2D and 3D game engine with a feature-rich editor (Web edition)", "lang": "en", - "start_url": "./godot.editor.html", + "start_url": "./redot.editor.html", "display": "standalone", "theme_color": "#202531", "icons": [ diff --git a/misc/dist/html/service-worker.js b/misc/dist/html/service-worker.js index 4f82d8be349..6bf91433e1d 100644 --- a/misc/dist/html/service-worker.js +++ b/misc/dist/html/service-worker.js @@ -11,13 +11,13 @@ const CACHE_NAME = CACHE_PREFIX + CACHE_VERSION; /** @type {string} */ const OFFLINE_URL = '___GODOT_OFFLINE_PAGE___'; /** @type {boolean} */ -const ENSURE_CROSSORIGIN_ISOLATION_HEADERS = ___GODOT_ENSURE_CROSSORIGIN_ISOLATION_HEADERS___; +const ENSURE_CROSSORIGIN_ISOLATION_HEADERS = typeof ___GODOT_ENSURE_CROSSORIGIN_ISOLATION_HEADERS___ === 'undefined' ? false : ___GODOT_ENSURE_CROSSORIGIN_ISOLATION_HEADERS___; // Files that will be cached on load. /** @type {string[]} */ -const CACHED_FILES = ___GODOT_CACHE___; +const CACHED_FILES = typeof ___GODOT_CACHE___ === 'undefined' ? [] : ___GODOT_CACHE___; // Files that we might not want the user to preload, and will only be cached on first load. /** @type {string[]} */ -const CACHABLE_FILES = ___GODOT_OPT_CACHE___; +const CACHABLE_FILES = typeof ___GODOT_OPT_CACHE___ === 'undefined' ? [] : ___GODOT_OPT_CACHE___; const FULL_CACHE = CACHED_FILES.concat(CACHABLE_FILES); self.addEventListener('install', (event) => { @@ -50,13 +50,12 @@ function ensureCrossOriginIsolationHeaders(response) { const crossOriginIsolatedHeaders = new Headers(response.headers); crossOriginIsolatedHeaders.set('Cross-Origin-Embedder-Policy', 'require-corp'); crossOriginIsolatedHeaders.set('Cross-Origin-Opener-Policy', 'same-origin'); - const newResponse = new Response(response.body, { + + return new Response(response.body, { status: response.status, statusText: response.statusText, headers: crossOriginIsolatedHeaders, }); - - return newResponse; } /** @@ -81,7 +80,7 @@ async function fetchAndCache(event, cache, isCacheable) { if (isCacheable) { // And update the cache - cache.put(event.request, response.clone()); + await cache.put(event.request, response.clone()); } return response; @@ -99,8 +98,8 @@ self.addEventListener( const referrer = event.request.referrer || ''; const base = referrer.slice(0, referrer.lastIndexOf('/') + 1); const local = url.startsWith(base) ? url.replace(base, '') : ''; - const isCachable = FULL_CACHE.some((v) => v === local) || (base === referrer && base.endsWith(CACHED_FILES[0])); - if (isNavigate || isCachable) { + const isCacheable = FULL_CACHE.some((v) => v === local) || (base === referrer && base.endsWith(CACHED_FILES[0])); + if (isNavigate || isCacheable) { event.respondWith((async () => { // Try to use cache first const cache = await caches.open(CACHE_NAME); @@ -112,8 +111,7 @@ self.addEventListener( if (missing) { try { // Try network if some cached file is missing (so we can display offline page in case). - const response = await fetchAndCache(event, cache, isCachable); - return response; + return await fetchAndCache(event, cache, isCacheable); } catch (e) { // And return the hopefully always cached offline page in case of network failure. console.error('Network error: ', e); // eslint-disable-line no-console @@ -128,9 +126,8 @@ self.addEventListener( } return cached; } - // Try network if don't have it in cache. - const response = await fetchAndCache(event, cache, isCachable); - return response; + // Try network when not in cache. + return fetchAndCache(event, cache, isCacheable); })()); } else if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) { event.respondWith((async () => { @@ -143,7 +140,7 @@ self.addEventListener( ); self.addEventListener('message', (event) => { - // No cross origin + // No cross-origin if (event.origin !== self.origin) { return; } diff --git a/misc/dist/html/styles.css b/misc/dist/html/styles.css new file mode 100644 index 00000000000..d23e78f2e34 --- /dev/null +++ b/misc/dist/html/styles.css @@ -0,0 +1,242 @@ +*:focus { + /* More visible outline for better keyboard navigation. */ + outline: 0.125rem solid hsl(220, 100%, 62.5%); + /* Make the outline always appear above other elements. */ + /* Otherwise, one of its sides can be hidden by tabs in the Download and More layouts. */ + position: relative; +} + +body { + touch-action: none; + font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + margin: 0; + border: 0 none; + padding: 0; + text-align: center; + background-color: #141111; + overflow: hidden; +} + +a { + color: hsl(205, 100%, 75%); + text-decoration-color: hsla(205, 100%, 75%, 0.3); + text-decoration-thickness: 0.125rem; +} + +a:hover { + filter: brightness(117.5%); +} + +a:active { + filter: brightness(82.5%); +} + +.welcome-modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: hsla(0, 0%, 0%, 0.5); + text-align: left; +} + +.welcome-modal-title { + text-align: center; +} + +.welcome-modal-content { + background-color: #241f1f; + box-shadow: 0 0.25rem 0.25rem hsla(0, 0%, 0%, 0.5); + line-height: 1.5; + max-width: 38rem; + margin: 4rem auto 0 auto; + color: white; + border-radius: 0.5rem; + padding: 1rem 1rem 2rem 1rem; +} + +#tabs-buttons { + /* Match the default background color of the editor window for a seamless appearance. */ + background-color: #241f1f; + display: flex; +} + +#tabs-buttons > div { + display: flex; +} + +#tab-game { + /* Use a pure black background to better distinguish the running project */ + /* from the editor window, and to use a more neutral background color (no tint). */ + background-color: black; + /* Make the background span the entire page height. */ + min-height: 100vh; +} + +#canvas, #gameCanvas { + display: block; + margin: 0; + color: white; +} + +/* Don't show distracting focus outlines for the main tabs' contents. */ +#tab-editor canvas:focus, +#tab-game canvas:focus, +#canvas:focus, +#gameCanvas:focus { + outline: none; +} + +.redot { + color: #e0e0e0; + background-color: #3b3943; + background-image: linear-gradient(to bottom, #403e48, #35333c); + border: 1px solid #45434e; + box-shadow: 0 0 1px 1px #2f2d35; +} + +.btn { + appearance: none; + color: #e0e0e0; + background-color: transparent; + border: 1px solid #e0e0e0; + padding: 0.5rem 1rem; + margin: 0; + position: relative; + cursor: pointer; +} + +.btn:not(:disabled):hover { + color: #e0e1e5; + border-color: #666c7b; + z-index: 1; +} + +.btn:active { + border-color: #241f1f; + color: #241f1f; +} + +.btn:disabled { + color: #aaa; + border-color: #141111; + cursor: default; +} + +.btn.tab-btn { + padding: 0.3rem 1rem; +} + +.btn.close-btn { + padding: 0.3rem 0.6rem; + font-weight: 700; +} + +.btn-tab > .btn { + border-color: #141111; +} + +.btn-tab.active > .btn { + background-color: #141111; +} + +/* Status display */ + +#status { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + display: flex; + justify-content: center; + align-items: center; + /* don't consume click events - make children visible explicitly */ + visibility: hidden; +} + +#status-progress { + width: 366px; + height: 7px; + background-color: #38363A; + border: 1px solid #444246; + padding: 1px; + box-shadow: 0 0 2px 1px #1B1C22; + border-radius: 2px; + visibility: visible; +} + +@media only screen and (orientation: portrait) { + #status-progress { + width: 61.8%; + } +} + +#status-progress-inner { + height: 100%; + width: 0; + box-sizing: border-box; + transition: width 0.5s linear; + background-color: #202020; + border: 1px solid #222223; + box-shadow: 0 0 1px 1px #27282E; + border-radius: 3px; +} + +#status-indeterminate { + visibility: visible; + position: relative; +} + +#status-indeterminate > div { + width: 4.5px; + height: 0; + border-style: solid; + border-width: 9px 3px 0 3px; + border-color: #2b2b2b transparent transparent transparent; + transform-origin: center 21px; + position: absolute; +} + +#status-indeterminate > div:nth-child(1) { + transform: rotate(22.5deg); +} + +#status-indeterminate > div:nth-child(2) { + transform: rotate(67.5deg); +} + +#status-indeterminate > div:nth-child(3) { + transform: rotate(112.5deg); +} + +#status-indeterminate > div:nth-child(4) { + transform: rotate(157.5deg); +} + +#status-indeterminate > div:nth-child(5) { + transform: rotate(202.5deg); +} + +#status-indeterminate > div:nth-child(6) { + transform: rotate(247.5deg); +} + +#status-indeterminate > div:nth-child(7) { + transform: rotate(292.5deg); +} + +#status-indeterminate > div:nth-child(8) { + transform: rotate(337.5deg); +} + +#status-notice { + margin: 0 100px; + line-height: 1.3; + visibility: visible; + padding: 4px 6px; +} diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py index 8fcabb21c74..34d7937aad7 100644 --- a/platform/web/emscripten_helpers.py +++ b/platform/web/emscripten_helpers.py @@ -45,7 +45,7 @@ def create_engine_file(env, target, source, externs, threads_enabled): def create_template_zip(env, js, wasm, worker, side): - binary_name = "godot.editor" if env.editor_build else "godot" + binary_name = "redot.editor" if env.editor_build else "redot" zip_dir = env.Dir(env.GetTemplateZipPath()) in_files = [ js, @@ -64,7 +64,7 @@ def create_template_zip(env, js, wasm, worker, side): out_files.append(zip_dir.File(binary_name + ".worker.js")) # Dynamic linking (extensions) specific. if env["dlink_enabled"]: - in_files.append(side) # Side wasm (contains the actual Godot code). + in_files.append(side) # Side wasm (contains the actual Redot code). out_files.append(zip_dir.File(binary_name + ".side.wasm")) service_worker = "#misc/dist/html/service-worker.js" @@ -72,26 +72,27 @@ def create_template_zip(env, js, wasm, worker, side): # HTML html = "#misc/dist/html/editor.html" cache = [ - "godot.editor.html", + "redot.editor.html", + "styles.css", "offline.html", - "godot.editor.js", - "godot.editor.audio.worklet.js", - "godot.editor.audio.position.worklet.js", + "redot.editor.js", + "redot.editor.audio.worklet.js", + "redot.editor.audio.position.worklet.js", "logo.svg", "favicon.png", ] if env["threads"]: - cache.append("godot.editor.worker.js") - opt_cache = ["godot.editor.wasm"] + cache.append("redot.editor.worker.js") + opt_cache = ["redot.editor.wasm"] subst_dict = { "___GODOT_VERSION___": get_build_version(), - "___GODOT_NAME___": "GodotEngine", + "___GODOT_NAME___": "RedotEngine", "___GODOT_CACHE___": json.dumps(cache), "___GODOT_OPT_CACHE___": json.dumps(opt_cache), "___GODOT_OFFLINE_PAGE___": "offline.html", "___GODOT_THREADS_ENABLED___": "true" if env["threads"] else "false", } - html = env.Substfile(target="#bin/godot${PROGSUFFIX}.html", source=html, SUBST_DICT=subst_dict) + html = env.Substfile(target="#bin/redot${PROGSUFFIX}.html", source=html, SUBST_DICT=subst_dict) in_files.append(html) out_files.append(zip_dir.File(binary_name + ".html")) # And logo/favicon @@ -101,7 +102,7 @@ def create_template_zip(env, js, wasm, worker, side): out_files.append(zip_dir.File("favicon.png")) # PWA service_worker = env.Substfile( - target="#bin/godot${PROGSUFFIX}.service.worker.js", + target="#bin/redot${PROGSUFFIX}.service.worker.js", source=service_worker, SUBST_DICT=subst_dict, ) @@ -111,6 +112,8 @@ def create_template_zip(env, js, wasm, worker, side): out_files.append(zip_dir.File("manifest.json")) in_files.append("#misc/dist/html/offline.html") out_files.append(zip_dir.File("offline.html")) + in_files.append("#misc/dist/html/styles.css") + out_files.append(zip_dir.File("styles.css")) else: # HTML in_files.append("#misc/dist/html/full-size.html") @@ -118,11 +121,13 @@ def create_template_zip(env, js, wasm, worker, side): in_files.append(service_worker) out_files.append(zip_dir.File(binary_name + ".service.worker.js")) in_files.append("#misc/dist/html/offline-export.html") - out_files.append(zip_dir.File("godot.offline.html")) + out_files.append(zip_dir.File("redot.offline.html")) + in_files.append("#misc/dist/html/styles.css") + out_files.append(zip_dir.File("styles.css")) zip_files = env.InstallAs(out_files, in_files) env.Zip( - "#bin/godot", + "#bin/redot", zip_files, ZIPROOT=zip_dir, ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}", diff --git a/platform/web/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js index fe99f55141e..d4c3f27b9bc 100644 --- a/platform/web/js/libs/library_godot_input.js +++ b/platform/web/js/libs/library_godot_input.js @@ -47,6 +47,9 @@ const GodotIME = { ime_active: function (active) { function focus_timer() { + if (!GodotIME.ime) { + return; + } GodotIME.active = true; GodotIME.ime.focus(); } @@ -54,7 +57,7 @@ const GodotIME = { if (GodotIME.ime) { if (active) { GodotIME.ime.style.display = 'block'; - setInterval(focus_timer, 100); + setTimeout(focus_timer, 100); } else { GodotIME.ime.style.display = 'none'; GodotConfig.canvas.focus();