diff options
| author | Jan Tuomi <jan@jantuomi.fi> | 2025-11-13 23:51:15 +0200 |
|---|---|---|
| committer | Jan Tuomi <jan@jantuomi.fi> | 2025-11-13 23:51:15 +0200 |
| commit | 1e1ff4a39635952513c20bdb002f2586a55152a8 (patch) | |
| tree | 7316bb01f57231c672c118332c9a7a9f5039a6db | |
| parent | c59c2179725a205743d6f5edf60ea0db866969e9 (diff) | |
Add pwa
| -rw-r--r-- | docs/index.144x144.png | bin | 0 -> 8761 bytes | |||
| -rw-r--r-- | docs/index.144x144.png.import | 40 | ||||
| -rw-r--r-- | docs/index.180x180.png | bin | 0 -> 11929 bytes | |||
| -rw-r--r-- | docs/index.180x180.png.import | 40 | ||||
| -rw-r--r-- | docs/index.512x512.png | bin | 0 -> 49018 bytes | |||
| -rw-r--r-- | docs/index.512x512.png.import | 40 | ||||
| -rw-r--r-- | docs/index.html | 3 | ||||
| -rw-r--r-- | docs/index.manifest.json | 1 | ||||
| -rw-r--r-- | docs/index.offline.html | 41 | ||||
| -rw-r--r-- | docs/index.service.worker.js | 166 | ||||
| -rw-r--r-- | export_presets.cfg | 10 |
11 files changed, 335 insertions, 6 deletions
diff --git a/docs/index.144x144.png b/docs/index.144x144.png Binary files differnew file mode 100644 index 0000000..cb86ad9 --- /dev/null +++ b/docs/index.144x144.png diff --git a/docs/index.144x144.png.import b/docs/index.144x144.png.import new file mode 100644 index 0000000..d9b6219 --- /dev/null +++ b/docs/index.144x144.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://nylqh0ydh5tb" +path="res://.godot/imported/index.144x144.png-92b83f3768c7cca659fbe2ac02cd6924.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/index.144x144.png" +dest_files=["res://.godot/imported/index.144x144.png-92b83f3768c7cca659fbe2ac02cd6924.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/docs/index.180x180.png b/docs/index.180x180.png Binary files differnew file mode 100644 index 0000000..4299b3e --- /dev/null +++ b/docs/index.180x180.png diff --git a/docs/index.180x180.png.import b/docs/index.180x180.png.import new file mode 100644 index 0000000..5a1583e --- /dev/null +++ b/docs/index.180x180.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhv3uwpmsc8qf" +path="res://.godot/imported/index.180x180.png-df2c9c60e7d0ad994df71f75ff8fc6c4.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/index.180x180.png" +dest_files=["res://.godot/imported/index.180x180.png-df2c9c60e7d0ad994df71f75ff8fc6c4.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/docs/index.512x512.png b/docs/index.512x512.png Binary files differnew file mode 100644 index 0000000..ec8786f --- /dev/null +++ b/docs/index.512x512.png diff --git a/docs/index.512x512.png.import b/docs/index.512x512.png.import new file mode 100644 index 0000000..cb923fb --- /dev/null +++ b/docs/index.512x512.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://co68onym5nd3x" +path="res://.godot/imported/index.512x512.png-9c95060c3a6daf64e19402e931238c81.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://docs/index.512x512.png" +dest_files=["res://.godot/imported/index.512x512.png-9c95060c3a6daf64e19402e931238c81.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/docs/index.html b/docs/index.html index b56ee9c..af6696a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -92,6 +92,7 @@ body { </style> <link id="-gd-engine-icon" rel="icon" type="image/png" href="index.icon.png" /> <link rel="apple-touch-icon" href="index.apple-touch-icon.png"/> +<link rel="manifest" href="index.manifest.json"> </head> <body> @@ -111,7 +112,7 @@ body { <script src="index.js"></script> <script> -const GODOT_CONFIG = {"args":[],"canvasResizePolicy":2,"emscriptenPoolSize":8,"ensureCrossOriginIsolationHeaders":true,"executable":"index","experimentalVK":false,"fileSizes":{"index.pck":737240,"index.wasm":38034280},"focusCanvas":true,"gdextensionLibs":[],"godotPoolSize":4}; +const GODOT_CONFIG = {"args":[],"canvasResizePolicy":2,"emscriptenPoolSize":8,"ensureCrossOriginIsolationHeaders":false,"executable":"index","experimentalVK":false,"fileSizes":{"index.pck":737240,"index.wasm":38034280},"focusCanvas":true,"gdextensionLibs":[],"godotPoolSize":4,"serviceWorker":"index.service.worker.js"}; const GODOT_THREADS_ENABLED = false; const engine = new Engine(GODOT_CONFIG); diff --git a/docs/index.manifest.json b/docs/index.manifest.json new file mode 100644 index 0000000..b31b976 --- /dev/null +++ b/docs/index.manifest.json @@ -0,0 +1 @@ +{"background_color":"#000000","display":"fullscreen","icons":[{"sizes":"144x144","src":"index.144x144.png","type":"image/png"},{"sizes":"180x180","src":"index.180x180.png","type":"image/png"},{"sizes":"512x512","src":"index.512x512.png","type":"image/png"}],"name":"MobileMetroidvania","orientation":"landscape","start_url":"./index.html"}
\ No newline at end of file diff --git a/docs/index.offline.html b/docs/index.offline.html new file mode 100644 index 0000000..ae5298a --- /dev/null +++ b/docs/index.offline.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>You are offline</title> + <style> +html { + background-color: #000000; + color: #ffffff; +} + +body { + 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: 2rem; +} + +p { + margin-block: 1rem; +} + +button { + display: block; + padding: 1rem 2rem; + margin: 3rem auto 0; +} + </style> + </head> + <body> + <h1>You are offline</h1> + <p>This application requires an Internet connection to run for the first time.</p> + <p>Press the button below to try reloading:</p> + <button type="button">Reload</button> + <script> +document.querySelector('button').addEventListener('click', () => { + window.location.reload(); +}); + </script> + </body> +</html> diff --git a/docs/index.service.worker.js b/docs/index.service.worker.js new file mode 100644 index 0000000..ddf416f --- /dev/null +++ b/docs/index.service.worker.js @@ -0,0 +1,166 @@ +// This service worker is required to expose an exported Godot project as a +// Progressive Web App. It provides an offline fallback page telling the user +// that they need an Internet connection to run the project if desired. +// Incrementing CACHE_VERSION will kick off the install event and force +// previously cached resources to be updated from the network. +/** @type {string} */ +const CACHE_VERSION = '1763070536|3676227673'; +/** @type {string} */ +const CACHE_PREFIX = 'MobileMetroidvan-sw-cache-'; +const CACHE_NAME = CACHE_PREFIX + CACHE_VERSION; +/** @type {string} */ +const OFFLINE_URL = 'index.offline.html'; +/** @type {boolean} */ +const ENSURE_CROSSORIGIN_ISOLATION_HEADERS = false; +// Files that will be cached on load. +/** @type {string[]} */ +const CACHED_FILES = ["index.html","index.js","index.offline.html","index.icon.png","index.apple-touch-icon.png","index.audio.worklet.js","index.audio.position.worklet.js"]; +// Files that we might not want the user to preload, and will only be cached on first load. +/** @type {string[]} */ +const CACHEABLE_FILES = ["index.wasm","index.pck"]; +const FULL_CACHE = CACHED_FILES.concat(CACHEABLE_FILES); + +self.addEventListener('install', (event) => { + event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(CACHED_FILES))); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil(caches.keys().then( + function (keys) { + // Remove old caches. + return Promise.all(keys.filter((key) => key.startsWith(CACHE_PREFIX) && key !== CACHE_NAME).map((key) => caches.delete(key))); + } + ).then(function () { + // Enable navigation preload if available. + return ('navigationPreload' in self.registration) ? self.registration.navigationPreload.enable() : Promise.resolve(); + })); +}); + +/** + * Ensures that the response has the correct COEP/COOP headers + * @param {Response} response + * @returns {Response} + */ +function ensureCrossOriginIsolationHeaders(response) { + if (response.headers.get('Cross-Origin-Embedder-Policy') === 'require-corp' + && response.headers.get('Cross-Origin-Opener-Policy') === 'same-origin') { + return 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, { + status: response.status, + statusText: response.statusText, + headers: crossOriginIsolatedHeaders, + }); + + return newResponse; +} + +/** + * Calls fetch and cache the result if it is cacheable + * @param {FetchEvent} event + * @param {Cache} cache + * @param {boolean} isCacheable + * @returns {Response} + */ +async function fetchAndCache(event, cache, isCacheable) { + // Use the preloaded response, if it's there + /** @type { Response } */ + let response = await event.preloadResponse; + if (response == null) { + // Or, go over network. + response = await self.fetch(event.request); + } + + if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) { + response = ensureCrossOriginIsolationHeaders(response); + } + + if (isCacheable) { + // And update the cache + cache.put(event.request, response.clone()); + } + + return response; +} + +self.addEventListener( + 'fetch', + /** + * Triggered on fetch + * @param {FetchEvent} event + */ + (event) => { + const isNavigate = event.request.mode === 'navigate'; + const url = event.request.url || ''; + const referrer = event.request.referrer || ''; + const base = referrer.slice(0, referrer.lastIndexOf('/') + 1); + const local = url.startsWith(base) ? url.replace(base, '') : ''; + 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); + if (isNavigate) { + // Check if we have full cache during HTML page request. + /** @type {Response[]} */ + const fullCache = await Promise.all(FULL_CACHE.map((name) => cache.match(name))); + const missing = fullCache.some((v) => v === undefined); + 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, isCacheable); + return response; + } 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 + return caches.match(OFFLINE_URL); + } + } + } + let cached = await cache.match(event.request); + if (cached != null) { + if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) { + cached = ensureCrossOriginIsolationHeaders(cached); + } + return cached; + } + // Try network if don't have it in cache. + const response = await fetchAndCache(event, cache, isCacheable); + return response; + })()); + } else if (ENSURE_CROSSORIGIN_ISOLATION_HEADERS) { + event.respondWith((async () => { + let response = await fetch(event.request); + response = ensureCrossOriginIsolationHeaders(response); + return response; + })()); + } + } +); + +self.addEventListener('message', (event) => { + // No cross origin + if (event.origin !== self.origin) { + return; + } + const id = event.source.id || ''; + const msg = event.data || ''; + // Ensure it's one of our clients. + self.clients.get(id).then(function (client) { + if (!client) { + return; // Not a valid client. + } + if (msg === 'claim') { + self.skipWaiting().then(() => self.clients.claim()); + } else if (msg === 'clear') { + caches.delete(CACHE_NAME); + } else if (msg === 'update') { + self.skipWaiting().then(() => self.clients.claim()).then(() => self.clients.matchAll()).then((all) => all.forEach((c) => c.navigate(c.url))); + } + }); +}); + diff --git a/export_presets.cfg b/export_presets.cfg index ca2025f..6f13fcc 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -3,7 +3,7 @@ name="Web" platform="Web" runnable=true -advanced_options=false +advanced_options=true dedicated_server=false custom_features="" export_filter="all_resources" @@ -32,11 +32,11 @@ html/head_include="" html/canvas_resize_policy=2 html/focus_canvas_on_start=true html/experimental_virtual_keyboard=false -progressive_web_app/enabled=false -progressive_web_app/ensure_cross_origin_isolation_headers=true +progressive_web_app/enabled=true +progressive_web_app/ensure_cross_origin_isolation_headers=false progressive_web_app/offline_page="" -progressive_web_app/display=1 -progressive_web_app/orientation=0 +progressive_web_app/display=0 +progressive_web_app/orientation=1 progressive_web_app/icon_144x144="" progressive_web_app/icon_180x180="" progressive_web_app/icon_512x512="" |
