From 1e1ff4a39635952513c20bdb002f2586a55152a8 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Thu, 13 Nov 2025 23:51:15 +0200 Subject: Add pwa --- docs/index.144x144.png | Bin 0 -> 8761 bytes docs/index.144x144.png.import | 40 ++++++++++ docs/index.180x180.png | Bin 0 -> 11929 bytes docs/index.180x180.png.import | 40 ++++++++++ docs/index.512x512.png | Bin 0 -> 49018 bytes docs/index.512x512.png.import | 40 ++++++++++ docs/index.html | 3 +- docs/index.manifest.json | 1 + docs/index.offline.html | 41 +++++++++++ docs/index.service.worker.js | 166 ++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 docs/index.144x144.png create mode 100644 docs/index.144x144.png.import create mode 100644 docs/index.180x180.png create mode 100644 docs/index.180x180.png.import create mode 100644 docs/index.512x512.png create mode 100644 docs/index.512x512.png.import create mode 100644 docs/index.manifest.json create mode 100644 docs/index.offline.html create mode 100644 docs/index.service.worker.js (limited to 'docs') diff --git a/docs/index.144x144.png b/docs/index.144x144.png new file mode 100644 index 0000000..cb86ad9 Binary files /dev/null and b/docs/index.144x144.png differ 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 new file mode 100644 index 0000000..4299b3e Binary files /dev/null and b/docs/index.180x180.png differ 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 new file mode 100644 index 0000000..ec8786f Binary files /dev/null and b/docs/index.512x512.png differ 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 { + @@ -111,7 +112,7 @@ body { + + 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))); + } + }); +}); + -- cgit v1.3