From 923fa2869f1c093bf705daf7da55a95dc07f9038 Mon Sep 17 00:00:00 2001 From: sucupira Date: Thu, 16 Jul 2026 21:05:22 -0400 Subject: [PATCH] app: refonte JWE v2 - SvelteKit 2 + Svelte 5 + MapLibre, 4 modes de jeu, API anti-triche, ecran Cas B 'Pwen blinde', i18n FR/GCF, PWA --- app/.gitignore | 7 + app/LICENSE | 28 + app/package-lock.json | 2140 +++++++++++++ app/package.json | 25 + app/src/app.d.ts | 12 + app/src/app.html | 14 + app/src/lib/components/GameMap.svelte | 421 +++ app/src/lib/components/LangSwitch.svelte | 43 + app/src/lib/components/PhotoPanel.svelte | 47 + app/src/lib/components/ResultPanel.svelte | 114 + app/src/lib/components/TimerRing.svelte | 87 + app/src/lib/components/WikiFiche.svelte | 182 ++ app/src/lib/i18n/fr.ts | 109 + app/src/lib/i18n/gcf.ts | 110 + app/src/lib/i18n/store.svelte.ts | 38 + app/src/lib/map/regions.ts | 16 + app/src/lib/map/style-oki.json | 3346 +++++++++++++++++++++ app/src/lib/server/lieux.ts | 152 + app/src/lib/stores/defi.svelte.ts | 32 + app/src/lib/styles/oki.css | 118 + app/src/lib/types.ts | 82 + app/src/routes/+layout.svelte | 82 + app/src/routes/+page.svelte | 258 ++ app/src/routes/api/guess/+server.ts | 51 + app/src/routes/api/lieux/+server.ts | 10 + app/src/routes/api/round/+server.ts | 18 + app/src/routes/api/wiki/[qid]/+server.ts | 81 + app/src/routes/explorer/+page.svelte | 261 ++ app/src/routes/jeu/[mode]/+page.svelte | 543 ++++ app/src/routes/jeu/[mode]/+page.ts | 12 + app/src/service-worker.ts | 64 + app/static/favicon.ico | Bin 0 -> 4286 bytes app/static/icon-maskable.svg | 5 + app/static/icon.svg | 5 + app/static/manifest.webmanifest | 25 + app/svelte.config.js | 12 + app/tsconfig.json | 14 + app/vite.config.ts | 6 + 38 files changed, 8570 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/LICENSE create mode 100644 app/package-lock.json create mode 100644 app/package.json create mode 100644 app/src/app.d.ts create mode 100644 app/src/app.html create mode 100644 app/src/lib/components/GameMap.svelte create mode 100644 app/src/lib/components/LangSwitch.svelte create mode 100644 app/src/lib/components/PhotoPanel.svelte create mode 100644 app/src/lib/components/ResultPanel.svelte create mode 100644 app/src/lib/components/TimerRing.svelte create mode 100644 app/src/lib/components/WikiFiche.svelte create mode 100644 app/src/lib/i18n/fr.ts create mode 100644 app/src/lib/i18n/gcf.ts create mode 100644 app/src/lib/i18n/store.svelte.ts create mode 100644 app/src/lib/map/regions.ts create mode 100644 app/src/lib/map/style-oki.json create mode 100644 app/src/lib/server/lieux.ts create mode 100644 app/src/lib/stores/defi.svelte.ts create mode 100644 app/src/lib/styles/oki.css create mode 100644 app/src/lib/types.ts create mode 100644 app/src/routes/+layout.svelte create mode 100644 app/src/routes/+page.svelte create mode 100644 app/src/routes/api/guess/+server.ts create mode 100644 app/src/routes/api/lieux/+server.ts create mode 100644 app/src/routes/api/round/+server.ts create mode 100644 app/src/routes/api/wiki/[qid]/+server.ts create mode 100644 app/src/routes/explorer/+page.svelte create mode 100644 app/src/routes/jeu/[mode]/+page.svelte create mode 100644 app/src/routes/jeu/[mode]/+page.ts create mode 100644 app/src/service-worker.ts create mode 100644 app/static/favicon.ico create mode 100644 app/static/icon-maskable.svg create mode 100644 app/static/icon.svg create mode 100644 app/static/manifest.webmanifest create mode 100644 app/svelte.config.js create mode 100644 app/tsconfig.json create mode 100644 app/vite.config.ts diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..68997aa --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,7 @@ +node_modules +build +.svelte-kit +.env +.env.* +!.env.example +.vite diff --git a/app/LICENSE b/app/LICENSE new file mode 100644 index 0000000..c05a2fa --- /dev/null +++ b/app/LICENSE @@ -0,0 +1,28 @@ +MIT License + +Copyright (c) 2026 ORGANISATION KA INTERNATIONALE (OKI) & contributeurs JWE + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +Note : les photographies affichées par l'application restent la propriété de +leurs auteurs respectifs et sont distribuées sous leurs licences Wikimedia +Commons (voir content/credits.md). Les extraits d'articles Wikipédia sont +sous licence CC BY-SA 4.0 (https://creativecommons.org/licenses/by-sa/4.0/deed.fr). diff --git a/app/package-lock.json b/app/package-lock.json new file mode 100644 index 0000000..b0582b5 --- /dev/null +++ b/app/package-lock.json @@ -0,0 +1,2140 @@ +{ + "name": "jwe", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "jwe", + "version": "2.0.0", + "dependencies": { + "maplibre-gl": "^5.1.0" + }, + "devDependencies": { + "@sveltejs/adapter-node": "^5.2.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.1.0", + "typescript": "^5.6.0", + "vite": "^6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mapbox/jsonlint-lines-primitives": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz", + "integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==", + "license": "MIT", + "engines": { + "node": ">= 22" + } + }, + "node_modules/@mapbox/point-geometry": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz", + "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==", + "license": "ISC" + }, + "node_modules/@mapbox/tiny-sdf": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz", + "integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mapbox/vector-tile": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.5.tgz", + "integrity": "sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/point-geometry": "~1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^4.0.2" + } + }, + "node_modules/@mapbox/whoots-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", + "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", + "license": "ISC", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@maplibre/geojson-vt": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz", + "integrity": "sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.1.0" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.10.0.tgz", + "integrity": "sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^1.0.0", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^3.0.0", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz", + "integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==", + "license": "BSD-2-Clause" + }, + "node_modules/@maplibre/mlt": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.12.tgz", + "integrity": "sha512-ZeK5w2TTeHOajcLaEQs1KZXw2V9wIKo1PmThlxlsHoXsQsYlBqLJzPOd6tJHRtGTChUY3DPPmjXRArYVvAbmZw==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0" + } + }, + "node_modules/@maplibre/vt-pbf": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.2.tgz", + "integrity": "sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==", + "license": "MIT", + "dependencies": { + "@mapbox/point-geometry": "^1.1.0", + "@types/geojson": "^7946.0.16", + "pbf": "^5.1.0" + } + }, + "node_modules/@maplibre/vt-pbf/node_modules/pbf": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz", + "integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==", + "license": "BSD-3-Clause", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "29.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.3.tgz", + "integrity": "sha512-ZaOxZceP7SOUW7Lqw5IRVweSQYWaeIPnXIGLiB690EBA3FGJTO40EEr2L5yZplJWsgTCogILRSpcAe7+U0Otdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", + "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.3.tgz", + "integrity": "sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.11.tgz", + "integrity": "sha512-LFuZUkjJ9iF7JZye/aG5XM0SFcQ5VyL0oVX4WJ9dc0Va3R3s0OauX1BESVCb+YN/ol8TAfqGDDAQsTG627Y5kw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-node": { + "version": "5.5.7", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.5.7.tgz", + "integrity": "sha512-uOfc9eVlI3A37RRSaKcgrheBYPrfJwC9VMqDp8x/O6tlKdcLLvHThSWD0KNIbjQ/d+7bwLGx3vx6aowAcRfd2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-commonjs": "^29.0.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.0", + "@rollup/plugin-replace": "^6.0.3", + "rollup": "^4.59.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.4.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.69.3", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.69.3.tgz", + "integrity": "sha512-cphwqMRcE19/9VkrIPr5qZhQ0SptSSDfDzRUpYHu9OJDFGuYBFyJzK+KQA27wB4YG32O/yF2QjBkDmTyo0vtCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.9", + "@types/cookie": "^0.6.0", + "acorn": "^8.16.0", + "cookie": "^0.6.0", + "devalue": "^5.8.1", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3 || ^6.0.0", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@sveltejs/load-config": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sveltejs/load-config/-/load-config-0.2.0.tgz", + "integrity": "sha512-1LgZ/qUqSoq+QorD83lk2hka79Px0wXNW2q5V1nZlxGhQgw1jrsIbVz5YiCeucVLo4XvFLjXukUaQjIiqowkcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.0.6" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/devalue": { + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.1.tgz", + "integrity": "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/earcut": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.2.3.tgz", + "integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==", + "license": "ISC" + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.13.tgz", + "integrity": "sha512-m8jH5hZgJE2RRUK/jjkGPcJEDAV+dYnZYFkosQaPTcE+Yw4xynXHOo6FUdwaWBtdR3b1MMa7wEDTSHeR2VWsGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "peerDependencies": { + "@typescript-eslint/types": "^8.2.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/types": { + "optional": true + } + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, + "node_modules/kdbush": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz", + "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==", + "license": "ISC" + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/maplibre-gl": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz", + "integrity": "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^1.1.0", + "@mapbox/tiny-sdf": "^2.1.0", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^2.0.4", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/geojson-vt": "^6.1.0", + "@maplibre/maplibre-gl-style-spec": "^24.8.1", + "@maplibre/mlt": "^1.1.8", + "@maplibre/vt-pbf": "^4.3.0", + "@types/geojson": "^7946.0.16", + "earcut": "^3.0.2", + "gl-matrix": "^3.4.4", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^4.0.1", + "potpack": "^2.1.0", + "quickselect": "^3.0.0", + "tinyqueue": "^3.0.0" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/murmurhash-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", + "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pbf": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.2.tgz", + "integrity": "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==", + "license": "BSD-3-Clause", + "dependencies": { + "resolve-protobuf-schema": "^2.1.0" + }, + "bin": { + "pbf": "bin/pbf" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz", + "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/potpack": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz", + "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==", + "license": "ISC" + }, + "node_modules/protocol-buffers-schema": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz", + "integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==", + "license": "MIT" + }, + "node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-protobuf-schema": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", + "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", + "dependencies": { + "protocol-buffers-schema": "^3.3.1" + } + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-cookie-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", + "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "5.56.6", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.6.tgz", + "integrity": "sha512-p4HDLDogGHKRKCrgckQHNs5PEfXkju6JI5jTywueaKJI5hAdjPohEhRtQ0M1SWC/+TA73SPln+r7srr+7e4nZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.10", + "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", + "acorn": "^8.12.1", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.8.1", + "esm-env": "^1.2.1", + "esrap": "^2.2.12", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.7.3.tgz", + "integrity": "sha512-DHdTCGX62R0fCxBEaT+USdASAnoaRBaaNczkRJl0K7o3WyoCeVUbVxo6fKqpOll/B+WMWCsiFK0eFrJSNBKZIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "@sveltejs/load-config": "^0.2.0", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte/node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/app/package.json b/app/package.json new file mode 100644 index 0000000..94dc567 --- /dev/null +++ b/app/package.json @@ -0,0 +1,25 @@ +{ + "name": "jwe", + "version": "2.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "start": "node build", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" + }, + "devDependencies": { + "@sveltejs/adapter-node": "^5.2.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.1.0", + "typescript": "^5.6.0", + "vite": "^6.0.0" + }, + "dependencies": { + "maplibre-gl": "^5.1.0" + } +} diff --git a/app/src/app.d.ts b/app/src/app.d.ts new file mode 100644 index 0000000..0d053c2 --- /dev/null +++ b/app/src/app.d.ts @@ -0,0 +1,12 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/app/src/app.html b/app/src/app.html new file mode 100644 index 0000000..cc0701d --- /dev/null +++ b/app/src/app.html @@ -0,0 +1,14 @@ + + + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/app/src/lib/components/GameMap.svelte b/app/src/lib/components/GameMap.svelte new file mode 100644 index 0000000..64a8375 --- /dev/null +++ b/app/src/lib/components/GameMap.svelte @@ -0,0 +1,421 @@ + + +
+ + +
+
+ {#each REGIONS as region (region)} + + {/each} +
+
+ + diff --git a/app/src/lib/components/LangSwitch.svelte b/app/src/lib/components/LangSwitch.svelte new file mode 100644 index 0000000..e4f07fd --- /dev/null +++ b/app/src/lib/components/LangSwitch.svelte @@ -0,0 +1,43 @@ + + +
+ {#each ['fr', 'gcf'] as l (l)} + + {/each} +
+ + diff --git a/app/src/lib/components/PhotoPanel.svelte b/app/src/lib/components/PhotoPanel.svelte new file mode 100644 index 0000000..bdbdd34 --- /dev/null +++ b/app/src/lib/components/PhotoPanel.svelte @@ -0,0 +1,47 @@ + + +
+ {photo.alt} + {#if revealed} +
{photo.credit}
+ {/if} +
+ + diff --git a/app/src/lib/components/ResultPanel.svelte b/app/src/lib/components/ResultPanel.svelte new file mode 100644 index 0000000..cc3bd89 --- /dev/null +++ b/app/src/lib/components/ResultPanel.svelte @@ -0,0 +1,114 @@ + + +
+
+

{result.score > 0 ? t().micro.bravo : t().micro.kiteSaYe}

+

+ {result.score} + {t().resultat.points} +

+ {#if result.distanceKm !== null} +

{t().resultat.distance} : {result.distanceKm} {t().resultat.km}

+ {/if} +

+ {result.nom} + {#if result.nom_creole && result.nom_creole !== result.nom} + · {result.nom_creole} + {/if} +
+ {t().resultat.commune} : {result.commune} — {t().regions[result.region]} +

+
+ + {#key result.nom} + 0 ? t().resultat.trouve : t().resultat.aDecouvrir} + /> + {/key} + + {#if creditPhoto} +

{creditPhoto}

+ {/if} + + {#if onsuivant} + + {/if} +
+ + diff --git a/app/src/lib/components/TimerRing.svelte b/app/src/lib/components/TimerRing.svelte new file mode 100644 index 0000000..49718b7 --- /dev/null +++ b/app/src/lib/components/TimerRing.svelte @@ -0,0 +1,87 @@ + + +
+ +
+ + diff --git a/app/src/lib/components/WikiFiche.svelte b/app/src/lib/components/WikiFiche.svelte new file mode 100644 index 0000000..ba7c496 --- /dev/null +++ b/app/src/lib/components/WikiFiche.svelte @@ -0,0 +1,182 @@ + + +{#if wiki === undefined} +
+

{t().explorer.chargerFiche}

+
+{:else if wiki} + +
+

+ {wiki.title} +

+ {#if tonPositif || tonNeutre} +

{tonPositif ?? tonNeutre}

+ {/if} + {#if wiki.thumbnail} + + {/if} +

{wiki.extract}

+ + {t().resultat.lireWiki} ↗ + +
+{:else} + +
+

{t().lacune.titre}

+

{t().lacune.texte}

+ + {t().lacune.cta} ↗ + +

+ {t().lacune.guide} + + {t().lacune.guideLien} ↗ + +

+
+{/if} + + diff --git a/app/src/lib/i18n/fr.ts b/app/src/lib/i18n/fr.ts new file mode 100644 index 0000000..5ece930 --- /dev/null +++ b/app/src/lib/i18n/fr.ts @@ -0,0 +1,109 @@ +const fr = { + app: { + titre: 'JWE', + sousTitre: 'Jeu de géolocalisation — Guadeloupe, Martinique, Guyane, La Réunion' + }, + regions: { + GUADELOUPE: 'Guadeloupe', + MARTINIQUE: 'Martinique', + GUYANE: 'Guyane', + REUNION: 'La Réunion', + TOUTES: 'Toutes les régions' + }, + modes: { + monument: 'Konnèt moniman', + monumentDesc: 'Reconnais le monument photographié et place-le sur la carte.', + lieu: 'Kote mwen ye ?', + lieuDesc: 'Une rue, un bord de mer, une forêt… devine où tu es.', + defi: 'Défi 5 rounds', + defiDesc: '5 lieux d’affilée, monuments et lieux mélangés.', + explorer: 'Aprann', + explorerDesc: 'Explore la carte librement et lis les fiches Wikipédia. Sans score.' + }, + accueil: { + choixRegion: 'Choisis ta région', + choixMode: 'Choisis ton mode', + options: 'Options', + timer: 'Minuteur (60 s, bonus de score)', + jouer: 'Jouer' + }, + jeu: { + charger: 'Chargement du lieu…', + erreur: 'Impossible de charger un lieu. Réessaie.', + reessayer: 'Réessayer', + valider: 'Valider ma position', + passer: 'Passer', + indice: 'Indice', + indicePenalite: '−10 % de score', + indiceRestant: 'indice restant', + indicesRestants: 'indices restants', + plusDIndice: 'Plus d’indice disponible', + poserMarqueur: 'Clique sur la carte pour placer ton marqueur', + round: 'Manche', + sur: 'sur', + difficulte: { + FACILE: 'Facile', + MOYEN: 'Moyen', + DIFFICILE: 'Difficile', + EXPERT: 'Expert' + } + }, + resultat: { + bravo: 'Bravo !', + score: 'Score', + points: 'points', + distance: 'Distance', + km: 'km', + trouve: 'Tu as trouvé ! Apprends-en plus sur ce lieu.', + aDecouvrir: 'Le lieu était ici. Apprends-en plus sur lui.', + lireWiki: 'Lire la suite sur Wikipédia', + commune: 'Commune', + region: 'Région', + suivant: 'Lieu suivant', + voirBilan: 'Voir le bilan', + rejouer: 'Rejouer', + retourAccueil: 'Retour à l’accueil' + }, + lacune: { + titre: 'Pwen blindé — Sa pa dokimanté', + texte: + 'Ce lieu existe, mais il n’a pas de page sur Wikipédia ni de fiche sur Wikidata. Pour nos régions, c’est un enjeu majeur : si nous ne documentons pas nos propres territoires, notre histoire et notre géographie disparaissent des cartes numériques et des bases de données mondiales (qui alimentent même l’intelligence artificielle).', + cta: 'Kontribyé sou Wikipédia', + guide: 'Besoin d’aide pour démarrer ? Suis le guide OKI « Comment contribuer à Wikipédia ».', + guideLien: 'Ouvrir le guide de contribution' + }, + defi: { + bilan: 'Bilan du défi', + scoreTotal: 'Score total', + partager: 'Partager', + telecharger: 'Télécharger l’image', + taPosition: 'Ta position', + positionReelle: 'Position réelle', + manche: 'Manche' + }, + explorer: { + titre: 'Aprann — Explorer', + filtrer: 'Filtrer par région', + chargerFiche: 'Chargement de la fiche…', + aucuneFiche: 'Sélectionne un marqueur sur la carte.', + fermer: 'Fermer le panneau' + }, + carte: { + ariaLabel: 'Carte de jeu. Flèches pour déplacer le marqueur, Entrée pour valider.', + sautRegion: 'Aller à la région', + zoomIn: 'Zoomer', + zoomOut: 'Dézoomer' + }, + micro: { + bravo: 'Bravo !', + kiteSaYe: 'Kité sa ye ?', + pwenBlinde: 'Pwen blindé' + }, + langue: { + fr: 'Français', + gcf: 'Kreyòl' + } +}; + +export default fr; +export type Dict = typeof fr; diff --git a/app/src/lib/i18n/gcf.ts b/app/src/lib/i18n/gcf.ts new file mode 100644 index 0000000..772c3d8 --- /dev/null +++ b/app/src/lib/i18n/gcf.ts @@ -0,0 +1,110 @@ +import type { Dict } from './fr'; + +const gcf: Dict = { + app: { + titre: 'JWE', + sousTitre: 'Jwé jéyolokalizasyon — Gwadloup, Matinik, Giyan, Léryinyon' + }, + regions: { + GUADELOUPE: 'Gwadloup', + MARTINIQUE: 'Matinik', + GUYANE: 'Giyan', + REUNION: 'Léryinyon', + TOUTES: 'Tout péyi yo' + }, + modes: { + monument: 'Konnèt moniman', + monumentDesc: 'Roukonèt moniman-an asou foto-a é mété’y asou kat-la.', + lieu: 'Kote mwen ye ?', + lieuDesc: 'On lari, on bodlanmè, on fowé… chwé kote ou yé.', + defi: 'Défi 5 rounds', + defiDesc: '5 koté youn dèyè ròt, moniman épi plas mélanjé.', + explorer: 'Aprann', + explorerDesc: 'Flanné asou kat-la é li fich Wikipédia yo. San pwen.' + }, + accueil: { + choixRegion: 'Chwazi péyi ou', + choixMode: 'Chwazi jan ou vlé jwé', + options: 'Règlaj', + timer: 'Kronomèt (60 s, bonus pwen)', + jouer: 'Jwé' + }, + jeu: { + charger: 'Nou ka chajé koté-la…', + erreur: 'Nou pa rivé chajé on koté. Éséyé ankò.', + reessayer: 'Éséyé ankò', + valider: 'Validé pozisyon mwen', + passer: 'Pasé', + indice: 'Endis', + indicePenalite: '−10 % pwen', + indiceRestant: 'endis ki rété', + indicesRestants: 'endis ki rété', + plusDIndice: 'Pa ni endis ankò', + poserMarqueur: 'Kwiké asou kat-la pou mété makò-a', + round: 'Mannèk', + sur: 'asou', + difficulte: { + FACILE: 'Fasil', + MOYEN: 'Mwayen', + DIFFICILE: 'Difisil', + EXPERT: 'Espè' + } + }, + resultat: { + bravo: 'Bravo !', + score: 'Pwen', + points: 'pwen', + distance: 'Distans', + km: 'km', + trouve: 'Ou trouvé ! Aprann pli plis asou koté sa-a.', + aDecouvrir: 'Koté-la té la. Aprann pli plis asou’y.', + lireWiki: 'Li swit-la asou Wikipédia', + commune: 'Komin', + region: 'Péyi', + suivant: 'Koté swivan', + voirBilan: 'Wè bilan-an', + rejouer: 'Rèjwé', + retourAccueil: 'Tounen an lakay' + }, + lacune: { + titre: 'Pwen blindé — Sa pa dokimanté', + texte: + 'Koté sa-a égzisté, men i pa ni on paj asou Wikipédia ni on fich asou Wikidata. Pou péyi nou, sé on zafè enpòtan anpil : si nou pa dokimanté pwòp téritwa nou, listwa épi jéwografi nou kay disparèt asou kat nimérik épi labaz donné lemonn yo (ki manm ka bay manjé a lintelijans atifisyèl).', + cta: 'Kontribyé sou Wikipédia', + guide: 'Ou bizwen èd pou koumansé ? Swiv gid OKI « Kijan pou kontribyé sou Wikipédia ».', + guideLien: 'Ouvri gid kontribisyon-an' + }, + defi: { + bilan: 'Bilan défi-a', + scoreTotal: 'Total pwen', + partager: 'Palé di moun', + telecharger: 'Téléchajé foto-a', + taPosition: 'Pozisyon ou', + positionReelle: 'Rèl pozisyon-an', + manche: 'Mannèk' + }, + explorer: { + titre: 'Aprann — Flanné', + filtrer: 'Triyé pa péyi', + chargerFiche: 'Nou ka chajé fich-la…', + aucuneFiche: 'Kwiké asou on makò asou kat-la.', + fermer: 'Fèmé pano-a' + }, + carte: { + ariaLabel: 'Kat jwé-a. Flèch yo pou déplasé makò-a, Antré pou validé.', + sautRegion: 'Alé o péyi', + zoomIn: 'Zoumé', + zoomOut: 'Dézoumé' + }, + micro: { + bravo: 'Bravo !', + kiteSaYe: 'Kité sa ye ?', + pwenBlinde: 'Pwen blindé' + }, + langue: { + fr: 'Français', + gcf: 'Kreyòl' + } +}; + +export default gcf; diff --git a/app/src/lib/i18n/store.svelte.ts b/app/src/lib/i18n/store.svelte.ts new file mode 100644 index 0000000..bfbc177 --- /dev/null +++ b/app/src/lib/i18n/store.svelte.ts @@ -0,0 +1,38 @@ +import { browser } from '$app/environment'; +import fr, { type Dict } from './fr'; +import gcf from './gcf'; + +export type Lang = 'fr' | 'gcf'; + +const dicts: Record = { fr, gcf }; +const STORAGE_KEY = 'jwe-lang'; + +let lang = $state('fr'); + +/** Dictionnaire courant — fonction réactive : lit le `$state`, donc les templates se mettent à jour. */ +export function t(): Dict { + return dicts[lang]; +} + +export function getLang(): Lang { + return lang; +} + +export function setLang(next: Lang): void { + lang = next; + if (browser) { + localStorage.setItem(STORAGE_KEY, next); + document.documentElement.lang = next; + } +} + +/** À appeler une fois au montage du layout : restaure la langue persistée. */ +export function initLang(): void { + if (!browser) return; + const saved = localStorage.getItem(STORAGE_KEY); + if (saved === 'fr' || saved === 'gcf') { + setLang(saved); + } else { + document.documentElement.lang = lang; + } +} diff --git a/app/src/lib/map/regions.ts b/app/src/lib/map/regions.ts new file mode 100644 index 0000000..2fbf44e --- /dev/null +++ b/app/src/lib/map/regions.ts @@ -0,0 +1,16 @@ +import type { Region } from '$lib/types'; + +/** Bornes de chaque région : [lonOuest, latSud, lonEst, latNord]. */ +export const REGION_BOUNDS: Record = { + GUADELOUPE: [-61.9, 15.8, -60.95, 16.55], + MARTINIQUE: [-61.25, 14.35, -60.75, 14.95], + GUYANE: [-54.7, 1.9, -51.5, 6.0], + REUNION: [55.15, -21.42, 55.9, -20.82] +}; + +/** Enveloppe union des 4 régions (≈ lon −63…57, lat −23…18) : interdit de sortir du terrain de jeu. */ +export const MAX_BOUNDS: [number, number, number, number] = [-63, -23, 57, 18]; + +export const MIN_ZOOM = 4; + +export const REGIONS: Region[] = ['GUADELOUPE', 'MARTINIQUE', 'GUYANE', 'REUNION']; diff --git a/app/src/lib/map/style-oki.json b/app/src/lib/map/style-oki.json new file mode 100644 index 0000000..6d98125 --- /dev/null +++ b/app/src/lib/map/style-oki.json @@ -0,0 +1,3346 @@ +{ + "version": 8, + "sources": { + "ne2_shaded": { + "maxzoom": 6, + "tileSize": 256, + "tiles": [ + "https://tiles.openfreemap.org/natural_earth/ne2sr/{z}/{x}/{y}.png" + ], + "type": "raster" + }, + "openmaptiles": { + "type": "vector", + "url": "https://tiles.openfreemap.org/planet", + "attribution": "© OpenStreetMap contributors" + } + }, + "sprite": "https://tiles.openfreemap.org/sprites/ofm_f384/ofm", + "glyphs": "https://tiles.openfreemap.org/fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "rgb(245, 239, 226)" + } + }, + { + "id": "park", + "type": "fill", + "source": "openmaptiles", + "source-layer": "park", + "filter": [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + "paint": { + "fill-color": "rgb(128, 178, 116)" + } + }, + { + "id": "water", + "type": "fill", + "source": "openmaptiles", + "source-layer": "water", + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "!=", + [ + "get", + "brunnel" + ], + "tunnel" + ] + ], + "paint": { + "fill-antialias": true, + "fill-color": "rgb(23, 94, 112)" + } + }, + { + "id": "landcover_ice_shelf", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "maxzoom": 8, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "==", + [ + "get", + "subclass" + ], + "ice_shelf" + ] + ], + "paint": { + "fill-color": "hsl(45, 40%, 96%)", + "fill-opacity": 0.7 + } + }, + { + "id": "landcover_glacier", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "maxzoom": 8, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "==", + [ + "get", + "subclass" + ], + "glacier" + ] + ], + "paint": { + "fill-color": "hsl(45, 40%, 96%)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + 1, + 8, + 0.5 + ] + } + }, + { + "id": "landuse_residential", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landuse", + "maxzoom": 16, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "residential" + ] + ], + "paint": { + "fill-color": "rgb(238, 228, 207)", + "fill-opacity": [ + "interpolate", + [ + "exponential", + 0.6 + ], + [ + "zoom" + ], + 8, + 0.8, + 9, + 0.6 + ] + } + }, + { + "id": "landcover_wood", + "type": "fill", + "source": "openmaptiles", + "source-layer": "landcover", + "minzoom": 10, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "wood" + ] + ], + "paint": { + "fill-color": "rgb(96, 156, 92)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 0, + 12, + 1 + ] + } + }, + { + "id": "waterway", + "type": "line", + "source": "openmaptiles", + "source-layer": "waterway", + "filter": [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + "paint": { + "line-color": "hsl(192, 60%, 38%)" + } + }, + { + "id": "building", + "type": "fill", + "source": "openmaptiles", + "source-layer": "building", + "minzoom": 12, + "paint": { + "fill-antialias": true, + "fill-color": "rgb(238, 228, 207)", + "fill-outline-color": "rgb(214, 200, 174)" + } + }, + { + "id": "tunnel_motorway_casing", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "brunnel" + ], + "tunnel" + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "rgb(216, 202, 176)", + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 5.8, + 0, + 6, + 3, + 20, + 40 + ] + } + }, + { + "id": "tunnel_motorway_inner", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "brunnel" + ], + "tunnel" + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "rgb(236, 226, 206)", + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 4, + 2, + 6, + 1.3, + 20, + 30 + ] + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 12, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "taxiway" + ], + true, + false + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(40, 30%, 80%)", + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.55 + ], + [ + "zoom" + ], + 13, + 1.8, + 20, + 20 + ] + } + }, + { + "id": "aeroway-runway-casing", + "type": "line", + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "runway" + ], + true, + false + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(40, 30%, 80%)", + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 11, + 6, + 17, + 55 + ] + } + }, + { + "id": "aeroway-area", + "type": "fill", + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 4, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "runway", + "taxiway" + ], + true, + false + ] + ], + "paint": { + "fill-color": "rgba(255, 255, 255, 1)", + "fill-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0, + 14, + 1 + ] + } + }, + { + "id": "aeroway-runway", + "type": "line", + "source": "openmaptiles", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ + "all", + [ + "match", + [ + "get", + "class" + ], + [ + "runway" + ], + true, + false + ], + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "rgba(255, 255, 255, 1)", + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.5 + ], + [ + "zoom" + ], + 11, + 4, + 17, + 50 + ] + } + }, + { + "id": "road_area_pier", + "type": "fill", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "MultiPolygon", + "Polygon" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "pier" + ] + ], + "paint": { + "fill-antialias": true, + "fill-color": "rgb(245, 239, 226)" + } + }, + { + "id": "road_pier", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "pier" + ], + true, + false + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "rgb(245, 239, 226)", + "line-width": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 15, + 1, + 17, + 4 + ] + } + }, + { + "id": "highway_path", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "path" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "rgb(236, 226, 206)", + "line-opacity": 0.9, + "line-width": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 13, + 1, + 20, + 10 + ] + } + }, + { + "id": "highway_minor", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 8, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "minor", + "service", + "track" + ], + true, + false + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(40, 30%, 80%)", + "line-opacity": 0.9, + "line-width": [ + "interpolate", + [ + "exponential", + 1.55 + ], + [ + "zoom" + ], + 13, + 1.8, + 20, + 20 + ] + } + }, + { + "id": "highway_major_casing", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 11, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "secondary", + "tertiary", + "trunk" + ], + true, + false + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "rgb(216, 202, 176)", + "line-dasharray": [ + 12, + 0 + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.3 + ], + [ + "zoom" + ], + 10, + 3, + 20, + 23 + ] + } + }, + { + "id": "highway_major_inner", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 11, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "secondary", + "tertiary", + "trunk" + ], + true, + false + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "#fff", + "line-width": [ + "interpolate", + [ + "exponential", + 1.3 + ], + [ + "zoom" + ], + 10, + 2, + 20, + 20 + ] + } + }, + { + "id": "highway_major_subtle", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "maxzoom": 11, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "secondary", + "tertiary", + "trunk" + ], + true, + false + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsla(40, 30%, 78%, 0.69)", + "line-width": 2 + } + }, + { + "id": "highway_motorway_casing", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "match", + [ + "get", + "brunnel" + ], + [ + "bridge", + "tunnel" + ], + false, + true + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "rgb(216, 202, 176)", + "line-dasharray": [ + 2, + 0 + ], + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 5.8, + 0, + 6, + 3, + 20, + 40 + ] + } + }, + { + "id": "highway_motorway_inner", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "match", + [ + "get", + "brunnel" + ], + [ + "bridge", + "tunnel" + ], + false, + true + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 5.8, + "hsla(40, 30%, 78%, 0.53)", + 6, + "#fff" + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 4, + 2, + 6, + 1.3, + 20, + 30 + ] + } + }, + { + "id": "highway_motorway_subtle", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "maxzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsla(40, 30%, 78%, 0.53)", + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 4, + 2, + 6, + 1.3 + ] + } + }, + { + "id": "railway_transit", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 16, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "class" + ], + "transit" + ], + [ + "match", + [ + "get", + "brunnel" + ], + [ + "tunnel" + ], + false, + true + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#dddddd", + "line-width": 3 + } + }, + { + "id": "railway_transit_dashline", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 16, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "class" + ], + "transit" + ], + [ + "match", + [ + "get", + "brunnel" + ], + [ + "tunnel" + ], + false, + true + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#fafafa", + "line-dasharray": [ + 3, + 3 + ], + "line-width": 2 + } + }, + { + "id": "railway_service", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 16, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "class" + ], + "rail" + ], + [ + "has", + "service" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#dddddd", + "line-width": 3 + } + }, + { + "id": "railway_service_dashline", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 16, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "==", + [ + "get", + "class" + ], + "rail" + ], + [ + "has", + "service" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#fafafa", + "line-dasharray": [ + 3, + 3 + ], + "line-width": 2 + } + }, + { + "id": "railway", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "!", + [ + "has", + "service" + ] + ], + [ + "==", + [ + "get", + "class" + ], + "rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#dddddd", + "line-width": [ + "interpolate", + [ + "exponential", + 1.3 + ], + [ + "zoom" + ], + 16, + 3, + 20, + 7 + ] + } + }, + { + "id": "railway_dashline", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 13, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "!", + [ + "has", + "service" + ] + ], + [ + "==", + [ + "get", + "class" + ], + "rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "#fafafa", + "line-dasharray": [ + 3, + 3 + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.3 + ], + [ + "zoom" + ], + 16, + 2, + 20, + 6 + ] + } + }, + { + "id": "highway_motorway_bridge_casing", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "brunnel" + ], + "bridge" + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "butt", + "line-join": "miter" + }, + "paint": { + "line-color": "rgb(216, 202, 176)", + "line-dasharray": [ + 2, + 0 + ], + "line-opacity": 1, + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 5.8, + 0, + 6, + 5, + 20, + 45 + ] + } + }, + { + "id": "highway_motorway_bridge_inner", + "type": "line", + "source": "openmaptiles", + "source-layer": "transportation", + "minzoom": 6, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "all", + [ + "==", + [ + "get", + "brunnel" + ], + "bridge" + ], + [ + "==", + [ + "get", + "class" + ], + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 5.8, + "hsla(40, 30%, 78%, 0.53)", + 6, + "#fff" + ], + "line-width": [ + "interpolate", + [ + "exponential", + 1.4 + ], + [ + "zoom" + ], + 4, + 2, + 6, + 1.3, + 20, + 30 + ] + } + }, + { + "id": "boundary_3", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "minzoom": 8, + "filter": [ + "all", + [ + ">=", + [ + "get", + "admin_level" + ], + 3 + ], + [ + "<=", + [ + "get", + "admin_level" + ], + 6 + ], + [ + "!=", + [ + "get", + "maritime" + ], + 1 + ], + [ + "!=", + [ + "get", + "disputed" + ], + 1 + ], + [ + "!", + [ + "has", + "claimed_by" + ] + ] + ], + "paint": { + "line-color": "hsl(35, 12%, 55%)", + "line-dasharray": [ + 1, + 1 + ], + "line-width": [ + "interpolate", + [ + "linear", + 1 + ], + [ + "zoom" + ], + 7, + 1, + 11, + 2 + ] + } + }, + { + "id": "boundary_2", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "filter": [ + "all", + [ + "==", + [ + "get", + "admin_level" + ], + 2 + ], + [ + "!=", + [ + "get", + "maritime" + ], + 1 + ], + [ + "!=", + [ + "get", + "disputed" + ], + 1 + ], + [ + "!", + [ + "has", + "claimed_by" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-color": "hsl(35, 12%, 55%)", + "line-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + 0.4, + 4, + 1 + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 3, + 1, + 5, + 1.2, + 12, + 3 + ] + } + }, + { + "id": "boundary_disputed", + "type": "line", + "source": "openmaptiles", + "source-layer": "boundary", + "filter": [ + "all", + [ + "!=", + [ + "get", + "maritime" + ], + 1 + ], + [ + "==", + [ + "get", + "disputed" + ], + 1 + ] + ], + "paint": { + "line-color": "hsl(35, 12%, 55%)", + "line-dasharray": [ + 1, + 2 + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 3, + 1, + 5, + 1.2, + 12, + 3 + ] + } + }, + { + "id": "waterway_line_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "waterway", + "minzoom": 10, + "filter": [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + " ", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Italic" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-size": 14 + }, + "paint": { + "text-color": "hsl(35, 12%, 52%)", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "water_name_point_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "water_name", + "filter": [ + "match", + [ + "geometry-type" + ], + [ + "MultiPoint", + "Point" + ], + true, + false + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Italic" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 0, + 10, + 8, + 14 + ] + }, + "paint": { + "text-color": "#495e91", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "water_name_line_label", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "water_name", + "filter": [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + "layout": { + "symbol-placement": "line", + "symbol-spacing": 350, + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + " ", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Italic" + ], + "text-letter-spacing": 0.2, + "text-max-width": 5, + "text-size": 14 + }, + "paint": { + "text-color": "#495e91", + "text-halo-color": "rgba(255,255,255,0.7)", + "text-halo-width": 1.5 + } + }, + { + "id": "highway-name-path", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 15.5, + "filter": [ + "==", + [ + "get", + "class" + ], + "path" + ], + "layout": { + "symbol-placement": "line", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + " ", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "map", + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 12, + 14, + 13 + ] + }, + "paint": { + "text-color": "hsl(30, 15%, 55%)", + "text-halo-color": "#f8f4f0", + "text-halo-width": 0.5 + } + }, + { + "id": "highway-name-minor", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 15, + "filter": [ + "all", + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "class" + ], + [ + "minor", + "service", + "track" + ], + true, + false + ] + ], + "layout": { + "symbol-placement": "line", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + " ", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "map", + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 12, + 14, + 13 + ] + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-width": 1 + } + }, + { + "id": "highway-name-major", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 12.2, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "primary", + "secondary", + "tertiary", + "trunk" + ], + true, + false + ], + "layout": { + "symbol-placement": "line", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + " ", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "map", + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 12, + 14, + 13 + ] + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-width": 1 + } + }, + { + "id": "highway-shield-non-us", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 11, + "filter": [ + "all", + [ + "<=", + [ + "get", + "ref_length" + ], + 6 + ], + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "network" + ], + [ + "us-highway", + "us-interstate", + "us-state" + ], + false, + true + ] + ], + "layout": { + "icon-image": [ + "concat", + "road_", + [ + "get", + "ref_length" + ] + ], + "icon-rotation-alignment": "viewport", + "icon-size": 1, + "symbol-placement": [ + "step", + [ + "zoom" + ], + "point", + 11, + "line" + ], + "symbol-spacing": 200, + "text-field": [ + "to-string", + [ + "get", + "ref" + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "viewport", + "text-size": 10 + } + }, + { + "id": "highway-shield-us-interstate", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 11, + "filter": [ + "all", + [ + "<=", + [ + "get", + "ref_length" + ], + 6 + ], + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "network" + ], + [ + "us-interstate" + ], + true, + false + ] + ], + "layout": { + "icon-image": [ + "concat", + [ + "get", + "network" + ], + "_", + [ + "get", + "ref_length" + ] + ], + "icon-rotation-alignment": "viewport", + "icon-size": 1, + "symbol-placement": [ + "step", + [ + "zoom" + ], + "point", + 7, + "line", + 8, + "line" + ], + "symbol-spacing": 200, + "text-field": [ + "to-string", + [ + "get", + "ref" + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "viewport", + "text-size": 10 + } + }, + { + "id": "road_shield_us", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "transportation_name", + "minzoom": 12, + "filter": [ + "all", + [ + "<=", + [ + "get", + "ref_length" + ], + 6 + ], + [ + "match", + [ + "geometry-type" + ], + [ + "LineString", + "MultiLineString" + ], + true, + false + ], + [ + "match", + [ + "get", + "network" + ], + [ + "us-highway", + "us-state" + ], + true, + false + ] + ], + "layout": { + "icon-image": [ + "concat", + [ + "get", + "network" + ], + "_", + [ + "get", + "ref_length" + ] + ], + "icon-rotation-alignment": "viewport", + "icon-size": 1, + "symbol-placement": [ + "step", + [ + "zoom" + ], + "point", + 11, + "line" + ], + "symbol-spacing": 200, + "text-field": [ + "to-string", + [ + "get", + "ref" + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-rotation-alignment": "viewport", + "text-size": 10 + } + }, + { + "id": "airport", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "aerodrome_label", + "minzoom": 11, + "filter": [ + "all", + [ + "has", + "iata" + ] + ], + "layout": { + "icon-image": "airport_11", + "icon-size": 1, + "text-anchor": "top", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 9, + "text-offset": [ + 0, + 0.6 + ], + "text-optional": true, + "text-padding": 2, + "text-size": 12 + }, + "paint": { + "text-color": "#666", + "text-halo-blur": 0.5, + "text-halo-color": "#ffffff", + "text-halo-width": 1 + } + }, + { + "id": "label_other", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 8, + "filter": [ + "match", + [ + "get", + "class" + ], + [ + "city", + "continent", + "country", + "state", + "town", + "village" + ], + false, + true + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Italic" + ], + "text-letter-spacing": 0.1, + "text-max-width": 9, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 9, + 12, + 10 + ], + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#333", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_village", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 9, + "filter": [ + "==", + [ + "get", + "class" + ], + "village" + ], + "layout": { + "icon-allow-overlap": true, + "icon-image": [ + "step", + [ + "zoom" + ], + "circle_11_black", + 10, + "" + ], + "icon-optional": false, + "icon-size": 0.2, + "text-anchor": "bottom", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 7, + 10, + 11, + 12 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_town", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 6, + "filter": [ + "==", + [ + "get", + "class" + ], + "town" + ], + "layout": { + "icon-allow-overlap": true, + "icon-image": [ + "step", + [ + "zoom" + ], + "circle_11_black", + 10, + "" + ], + "icon-optional": false, + "icon-size": 0.2, + "text-anchor": "bottom", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 7, + 12, + 11, + 14 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_state", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 5, + "maxzoom": 8, + "filter": [ + "==", + [ + "get", + "class" + ], + "state" + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Italic" + ], + "text-letter-spacing": 0.2, + "text-max-width": 9, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 5, + 10, + 8, + 14 + ], + "text-transform": "uppercase" + }, + "paint": { + "text-color": "#333", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_city", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 3, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "city" + ], + [ + "!=", + [ + "get", + "capital" + ], + 2 + ] + ], + "layout": { + "icon-allow-overlap": true, + "icon-image": [ + "step", + [ + "zoom" + ], + "circle_11_black", + 9, + "" + ], + "icon-optional": false, + "icon-size": 0.4, + "text-anchor": "bottom", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-max-width": 8, + "text-offset": [ + 0, + -0.1 + ], + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 4, + 11, + 7, + 13, + 11, + 18 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_city_capital", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 3, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "city" + ], + [ + "==", + [ + "get", + "capital" + ], + 2 + ] + ], + "layout": { + "icon-allow-overlap": true, + "icon-image": [ + "step", + [ + "zoom" + ], + "circle_11_black", + 9, + "" + ], + "icon-optional": false, + "icon-size": 0.5, + "text-anchor": "bottom", + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 8, + "text-offset": [ + 0, + -0.2 + ], + "text-size": [ + "interpolate", + [ + "exponential", + 1.2 + ], + [ + "zoom" + ], + 4, + 12, + 7, + 14, + 11, + 20 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_country_3", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "minzoom": 2, + "maxzoom": 9, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "country" + ], + [ + ">=", + [ + "get", + "rank" + ], + 3 + ] + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 6.25, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 3, + 9, + 7, + 17 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_country_2", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 9, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "country" + ], + [ + "==", + [ + "get", + "rank" + ], + 2 + ] + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 6.25, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 2, + 9, + 5, + 17 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + }, + { + "id": "label_country_1", + "type": "symbol", + "source": "openmaptiles", + "source-layer": "place", + "maxzoom": 9, + "filter": [ + "all", + [ + "==", + [ + "get", + "class" + ], + "country" + ], + [ + "==", + [ + "get", + "rank" + ], + 1 + ] + ], + "layout": { + "text-field": [ + "case", + [ + "has", + "name:nonlatin" + ], + [ + "concat", + [ + "get", + "name:latin" + ], + "\n", + [ + "get", + "name:nonlatin" + ] + ], + [ + "coalesce", + [ + "get", + "name_en" + ], + [ + "get", + "name" + ] + ] + ], + "text-font": [ + "Noto Sans Bold" + ], + "text-max-width": 6.25, + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 1, + 9, + 4, + 17 + ] + }, + "paint": { + "text-color": "#000", + "text-halo-blur": 1, + "text-halo-color": "#fff", + "text-halo-width": 1 + } + } + ], + "name": "OKI Caraïbes" +} \ No newline at end of file diff --git a/app/src/lib/server/lieux.ts b/app/src/lib/server/lieux.ts new file mode 100644 index 0000000..1424ffe --- /dev/null +++ b/app/src/lib/server/lieux.ts @@ -0,0 +1,152 @@ +import rawLieux from './data/lieux.json'; +import type { + Categorie, + Difficulte, + ExplorerLieu, + GuessResult, + Lieu, + Region, + RoundPlace +} from '$lib/types'; + +const lieux = rawLieux as Lieu[]; + +const REGIONS: Region[] = ['GUADELOUPE', 'MARTINIQUE', 'GUYANE', 'REUNION']; +const CATEGORIES: Categorie[] = ['MONUMENT', 'LIEU']; + +export const MAX_POINTS = 5000; + +/** Rayon (km) de la courbe de score selon la difficulté du lieu. */ +export const RAYONS: Record = { + FACILE: 50, + MOYEN: 15, + DIFFICILE: 5, + EXPERT: 1 +}; + +/** Distance haversine en km. */ +export function haversineKm(a: { lat: number; lon: number }, b: { lat: number; lon: number }): number { + const R = 6371; + const dLat = ((b.lat - a.lat) * Math.PI) / 180; + const dLon = ((b.lon - a.lon) * Math.PI) / 180; + const s = + Math.sin(dLat / 2) ** 2 + + Math.cos((a.lat * Math.PI) / 180) * Math.cos((b.lat * Math.PI) / 180) * Math.sin(dLon / 2) ** 2; + return 2 * R * Math.asin(Math.sqrt(s)); +} + +function parseRegion(value: string | null): Region | null { + return value && REGIONS.includes(value as Region) ? (value as Region) : null; +} + +function parseCategorie(value: string | null): Categorie | null { + return value && CATEGORIES.includes(value as Categorie) ? (value as Categorie) : null; +} + +export function getLieuById(id: string): Lieu | undefined { + return lieux.find((l) => l.id === id); +} + +/** Sélection aléatoire d'un lieu, avec filtres optionnels. */ +export function getRandomLieu(options: { + region?: string | null; + categorie?: string | null; + exclude?: string | null; +}): Lieu | null { + const region = parseRegion(options.region ?? null); + const categorie = parseCategorie(options.categorie ?? null); + const excluded = new Set( + (options.exclude ?? '') + .split(',') + .map((s) => s.trim()) + .filter(Boolean) + ); + let pool = lieux.filter((l) => !excluded.has(l.id)); + if (region) pool = pool.filter((l) => l.region === region); + if (categorie) pool = pool.filter((l) => l.categorie === categorie); + // Si tout a été exclu, on réessaie sans les exclusions (le jeu doit continuer). + if (pool.length === 0) { + pool = lieux; + if (region) pool = pool.filter((l) => l.region === region); + if (categorie) pool = pool.filter((l) => l.categorie === categorie); + } + if (pool.length === 0) return null; + return pool[Math.floor(Math.random() * pool.length)]; +} + +/** Anti-triche : ne garde que les champs publiques pour /api/round. */ +export function sanitizeRound(lieu: Lieu): RoundPlace { + return { + id: lieu.id, + nom: lieu.nom, + nom_creole: lieu.nom_creole, + categorie: lieu.categorie, + difficulte: lieu.difficulte, + photo: lieu.photo, + indices: lieu.indices + }; +} + +/** + * Scoring recalculé côté serveur : + * score = round(5000 × e^(−d/r)), r selon difficulté ; + * pénalité −10 % par indice ; bonus temps ≤ +20 % ; total plafonné à 5000. + */ +export function scoreGuess( + lieu: Lieu, + guess: { lat: number; lon: number }, + hintsUsed: number, + timeMs?: number +): GuessResult { + const distanceKm = haversineKm(guess, lieu.coordonnees); + const base = Math.round(MAX_POINTS * Math.exp(-distanceKm / RAYONS[lieu.difficulte])); + const penalises = base * Math.max(0, 1 - 0.1 * Math.max(0, hintsUsed)); + let total = penalises; + if (typeof timeMs === 'number' && Number.isFinite(timeMs) && timeMs >= 0) { + total += penalises * 0.2 * Math.max(0, 1 - timeMs / 60000); + } + const score = Math.min(MAX_POINTS, Math.round(total)); + return { + distanceKm: Math.round(distanceKm * 10) / 10, + score, + coordonnees: lieu.coordonnees, + commune: lieu.commune, + region: lieu.region, + nom: lieu.nom, + nom_creole: lieu.nom_creole, + wikidata_id: lieu.wikidata_id + }; +} + +/** Réponse « Passer » : la vérité est révélée, score 0, pas de distance. */ +export function skipResult(lieu: Lieu): GuessResult { + return { + distanceKm: null, + score: 0, + coordonnees: lieu.coordonnees, + commune: lieu.commune, + region: lieu.region, + nom: lieu.nom, + nom_creole: lieu.nom_creole, + wikidata_id: lieu.wikidata_id + }; +} + +/** Catalogue Explorer : coords arrondies à 0.05° (mode sans score, fiches autorisées). */ +export function catalogueExplorer(): ExplorerLieu[] { + return lieux.map((l) => ({ + id: l.id, + nom: l.nom, + nom_creole: l.nom_creole, + region: l.region, + commune: l.commune, + coordonnees: { + lat: Math.round(l.coordonnees.lat / 0.05) * 0.05, + lon: Math.round(l.coordonnees.lon / 0.05) * 0.05 + }, + categorie: l.categorie, + difficulte: l.difficulte, + wikidata_id: l.wikidata_id, + photo: l.photo + })); +} diff --git a/app/src/lib/stores/defi.svelte.ts b/app/src/lib/stores/defi.svelte.ts new file mode 100644 index 0000000..533e456 --- /dev/null +++ b/app/src/lib/stores/defi.svelte.ts @@ -0,0 +1,32 @@ +import type { Coordonnees, GuessResult, RoundPlace } from '$lib/types'; + +export interface MancheDefi { + place: RoundPlace; + guess: Coordonnees | null; + result: GuessResult; +} + +/** État du Défi 5 rounds — client uniquement, sans session serveur. */ +function creerDefiStore() { + let manches = $state([]); + + return { + get manches() { + return manches; + }, + get total() { + return manches.reduce((s, m) => s + m.result.score, 0); + }, + get termine() { + return manches.length >= 5; + }, + ajouter(manche: MancheDefi) { + manches = [...manches, manche]; + }, + reinitialiser() { + manches = []; + } + }; +} + +export const defi = creerDefiStore(); diff --git a/app/src/lib/styles/oki.css b/app/src/lib/styles/oki.css new file mode 100644 index 0000000..e09ca29 --- /dev/null +++ b/app/src/lib/styles/oki.css @@ -0,0 +1,118 @@ +/* Tokens OKI — doctrine « calm technology » : couleurs ancrées dans le territoire, + un seul accent fort (corail) réservé à l'action primaire (Von Restorff). */ +:root { + --oki-vert: #0b3d2e; /* vert profond — couleur principale de la marque */ + --oki-vert-clair: #17624a; + --oki-vert-doux: #e3efe7; + --oki-sable: #f5efe2; /* fonds */ + --oki-sable-fonce: #e7dcc4; + --oki-bleu: #175e70; /* bleu caraïbe profond */ + --oki-bleu-doux: #d9ecef; + --oki-corail: #e4572e; /* accent — action primaire UNIQUEMENT */ + --oki-corail-fonce: #c4441f; + --oki-encre: #22302a; + --oki-encre-doux: #5a6b62; + --oki-blanc: #fffdf8; + --oki-lacune-fond: #fdf3e3; /* panneau Cas B « Pwen blindé » — teinte distincte */ + --oki-lacune-bord: #d9a441; + + --oki-radius: 14px; + --oki-radius-petit: 9px; + --oki-ombre: 0 2px 10px rgba(11, 61, 46, 0.14); + --oki-font: + system-ui, + -apple-system, + 'Segoe UI', + Roboto, + sans-serif; +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} + +body { + font-family: var(--oki-font); + color: var(--oki-encre); + background: var(--oki-sable); + line-height: 1.5; +} + +button { + font-family: inherit; +} + +/* — Boutons — */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + border: none; + border-radius: var(--oki-radius-petit); + padding: 0.85rem 1.6rem; + font-size: 1.05rem; + font-weight: 650; + cursor: pointer; + text-decoration: none; + transition: background-color 0.15s ease; +} + +.btn:focus-visible, +a:focus-visible, +[tabindex]:focus-visible { + outline: 3px solid var(--oki-bleu); + outline-offset: 2px; +} + +/* Action primaire : le seul élément fortement coloré de l'écran */ +.btn-primaire { + background: var(--oki-corail); + color: #fff; + box-shadow: var(--oki-ombre); +} + +.btn-primaire:hover { + background: var(--oki-corail-fonce); +} + +.btn-primaire:disabled { + background: var(--oki-sable-fonce); + color: var(--oki-encre-doux); + cursor: not-allowed; + box-shadow: none; +} + +.btn-secondaire { + background: var(--oki-vert-doux); + color: var(--oki-vert); +} + +.btn-secondaire:hover { + background: #d2e5d9; +} + +.btn-tertiaire { + background: transparent; + color: var(--oki-vert-clair); + border: 1.5px solid var(--oki-vert-clair); +} + +.btn-tertiaire:hover { + background: var(--oki-vert-doux); +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/app/src/lib/types.ts b/app/src/lib/types.ts new file mode 100644 index 0000000..f6c3a7b --- /dev/null +++ b/app/src/lib/types.ts @@ -0,0 +1,82 @@ +export type Region = 'GUADELOUPE' | 'MARTINIQUE' | 'GUYANE' | 'REUNION'; +export type Categorie = 'MONUMENT' | 'LIEU'; +export type Difficulte = 'FACILE' | 'MOYEN' | 'DIFFICILE' | 'EXPERT'; + +export interface Coordonnees { + lat: number; + lon: number; +} + +export interface Indice { + niveau: number; + texte: string; +} + +export interface Photo { + url: string; + credit: string; + alt: string; +} + +/** Lieu complet — serveur uniquement, jamais exposé tel quel au client. */ +export interface Lieu { + id: string; + nom: string; + nom_creole: string; + region: Region; + commune: string; + coordonnees: Coordonnees; + categorie: Categorie; + difficulte: Difficulte; + wikidata_id: string | null; + photo: Photo; + indices: Indice[]; +} + +/** Lieu SANITISÉ envoyé par GET /api/round (aucune coordonnée, commune, région, wikidata_id). */ +export interface RoundPlace { + id: string; + nom: string; + nom_creole: string; + categorie: Categorie; + difficulte: Difficulte; + photo: Photo; + indices: Indice[]; +} + +/** Réponse de POST /api/guess : la vérité n'est révélée qu'après soumission. */ +export interface GuessResult { + distanceKm: number | null; + score: number; + coordonnees: Coordonnees; + commune: string; + region: Region; + nom: string; + nom_creole: string; + wikidata_id: string | null; +} + +/** Entrée du catalogue Explorer : coords arrondies à 0.05°, mode sans score. */ +export interface ExplorerLieu { + id: string; + nom: string; + nom_creole: string; + region: Region; + commune: string; + coordonnees: Coordonnees; + categorie: Categorie; + difficulte: Difficulte; + wikidata_id: string | null; + photo: Photo; +} + +/** Réponse normalisée de GET /api/wiki/[qid]. */ +export interface WikiSummary { + qid: string; + title: string; + extract: string; + url: string; + thumbnail: string | null; +} + +export type GameMode = 'monument' | 'lieu' | 'defi'; diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte new file mode 100644 index 0000000..6a2118f --- /dev/null +++ b/app/src/routes/+layout.svelte @@ -0,0 +1,82 @@ + + +
+
+ + +
+
+ {@render children()} +
+
+ + diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte new file mode 100644 index 0000000..bf4f59f --- /dev/null +++ b/app/src/routes/+page.svelte @@ -0,0 +1,258 @@ + + + + {t().app.titre} — {t().app.sousTitre} + + + +
+
+

{t().app.titre}

+

{t().micro.kiteSaYe}

+

{t().app.sousTitre}

+
+ +
+

{t().accueil.choixRegion}

+
+ {#each REGIONS as r (r)} + + {/each} + +
+
+ +
+

{t().accueil.choixMode}

+
+ {#each modes as m (m.id)} + + {/each} + + + {t().modes.explorer} + {t().modes.explorerDesc} + +
+
+ +
+

{t().accueil.options}

+ +
+ +
+ +
+
+ + diff --git a/app/src/routes/api/guess/+server.ts b/app/src/routes/api/guess/+server.ts new file mode 100644 index 0000000..99c2ed0 --- /dev/null +++ b/app/src/routes/api/guess/+server.ts @@ -0,0 +1,51 @@ +import { json } from '@sveltejs/kit'; +import { getLieuById, scoreGuess, skipResult } from '$lib/server/lieux'; +import type { RequestHandler } from './$types'; + +interface GuessBody { + id?: unknown; + lat?: unknown; + lon?: unknown; + hintsUsed?: unknown; + timeMs?: unknown; + skip?: unknown; +} + +/** + * POST /api/guess { id, lat, lon, hintsUsed, timeMs? } + * → score recalculé serveur + vérité du lieu (révélée seulement ici). + * `skip: true` révèle la réponse avec un score de 0 (bouton « Passer »). + */ +export const POST: RequestHandler = async ({ request }) => { + let body: GuessBody; + try { + body = (await request.json()) as GuessBody; + } catch { + return json({ erreur: 'Corps JSON invalide' }, { status: 400 }); + } + + if (typeof body.id !== 'string') { + return json({ erreur: 'id manquant' }, { status: 400 }); + } + const lieu = getLieuById(body.id); + if (!lieu) { + return json({ erreur: 'Lieu inconnu' }, { status: 404 }); + } + + if (body.skip === true) { + return json(skipResult(lieu)); + } + + const lat = Number(body.lat); + const lon = Number(body.lon); + if (!Number.isFinite(lat) || !Number.isFinite(lon) || Math.abs(lat) > 90 || Math.abs(lon) > 180) { + return json({ erreur: 'Coordonnées invalides' }, { status: 400 }); + } + const hintsUsed = Math.max(0, Math.floor(Number(body.hintsUsed) || 0)); + const timeMs = + typeof body.timeMs === 'number' && Number.isFinite(body.timeMs) && body.timeMs >= 0 + ? body.timeMs + : undefined; + + return json(scoreGuess(lieu, { lat, lon }, hintsUsed, timeMs)); +}; diff --git a/app/src/routes/api/lieux/+server.ts b/app/src/routes/api/lieux/+server.ts new file mode 100644 index 0000000..f850351 --- /dev/null +++ b/app/src/routes/api/lieux/+server.ts @@ -0,0 +1,10 @@ +import { json } from '@sveltejs/kit'; +import { catalogueExplorer } from '$lib/server/lieux'; +import type { RequestHandler } from './$types'; + +/** GET /api/lieux → catalogue Explorer (coords arrondies à 0.05°, mode sans score). */ +export const GET: RequestHandler = () => { + return json(catalogueExplorer(), { + headers: { 'Cache-Control': 'public, max-age=300' } + }); +}; diff --git a/app/src/routes/api/round/+server.ts b/app/src/routes/api/round/+server.ts new file mode 100644 index 0000000..9a74a91 --- /dev/null +++ b/app/src/routes/api/round/+server.ts @@ -0,0 +1,18 @@ +import { json } from '@sveltejs/kit'; +import { getRandomLieu, sanitizeRound } from '$lib/server/lieux'; +import type { RequestHandler } from './$types'; + +/** GET /api/round?region=&categorie=&exclude=id1,id2 → lieu aléatoire SANITISÉ. */ +export const GET: RequestHandler = ({ url }) => { + const lieu = getRandomLieu({ + region: url.searchParams.get('region'), + categorie: url.searchParams.get('categorie'), + exclude: url.searchParams.get('exclude') + }); + if (!lieu) { + return json({ erreur: 'Aucun lieu disponible pour ces critères' }, { status: 404 }); + } + return json(sanitizeRound(lieu), { + headers: { 'Cache-Control': 'no-store' } + }); +}; diff --git a/app/src/routes/api/wiki/[qid]/+server.ts b/app/src/routes/api/wiki/[qid]/+server.ts new file mode 100644 index 0000000..7bc6173 --- /dev/null +++ b/app/src/routes/api/wiki/[qid]/+server.ts @@ -0,0 +1,81 @@ +import { json } from '@sveltejs/kit'; +import type { WikiSummary } from '$lib/types'; +import type { RequestHandler } from './$types'; + +const USER_AGENT = 'JWE-OKI/2.0 (https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/JWE; contact OKI)'; +const TTL_MS = 24 * 60 * 60 * 1000; // 24 h + +const cache = new Map(); + +interface WbEntity { + labels?: { fr?: { value: string } }; + sitelinks?: { frwiki?: { title: string } }; +} + +interface WbResponse { + entities?: Record; +} + +interface RestSummary { + title?: string; + extract?: string; + content_urls?: { desktop?: { page?: string } }; + thumbnail?: { source?: string }; +} + +/** GET /api/wiki/[qid] → extrait Wikipédia FR normalisé (404 si pas de sitelink fr). */ +export const GET: RequestHandler = async ({ params, fetch }) => { + const qid = params.qid; + if (!/^Q\d+$/.test(qid)) { + return json({ erreur: 'Identifiant Wikidata invalide' }, { status: 400 }); + } + + const cached = cache.get(qid); + if (cached && cached.expires > Date.now()) { + return json(cached.summary, { headers: { 'Cache-Control': 'public, max-age=3600' } }); + } + + const headers = { 'User-Agent': USER_AGENT, Accept: 'application/json' }; + + // 1. Wikidata : sitelink frwiki (+ libellé fr en fallback) + const wbUrl = `https://www.wikidata.org/w/api.php?action=wbgetentities&ids=${encodeURIComponent(qid)}&props=sitelinks%7Clabels&sitefilter=frwiki&languages=fr&format=json`; + let entity: WbEntity | undefined; + try { + const res = await fetch(wbUrl, { headers }); + if (!res.ok) throw new Error(`wikidata ${res.status}`); + entity = ((await res.json()) as WbResponse).entities?.[qid]; + } catch { + return json({ erreur: 'Wikidata injoignable' }, { status: 502 }); + } + + const titre = entity?.sitelinks?.frwiki?.title; + if (!titre) { + // Pas de page Wikipédia FR → le front bascule sur l'écran « Pwen blindé ». + return json({ erreur: 'Pas de page Wikipédia en français' }, { status: 404 }); + } + + // 2. Wikipédia FR : résumé de l'article + let data: RestSummary; + try { + const res = await fetch( + `https://fr.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(titre)}`, + { headers } + ); + if (res.status === 404) return json({ erreur: 'Article introuvable' }, { status: 404 }); + if (!res.ok) throw new Error(`wikipedia ${res.status}`); + data = (await res.json()) as RestSummary; + } catch { + return json({ erreur: 'Wikipédia injoignable' }, { status: 502 }); + } + + const summary: WikiSummary = { + qid, + title: data.title ?? titre, + extract: data.extract ?? '', + url: data.content_urls?.desktop?.page ?? `https://fr.wikipedia.org/wiki/${encodeURIComponent(titre)}`, + thumbnail: data.thumbnail?.source ?? null + }; + cache.set(qid, { expires: Date.now() + TTL_MS, summary }); + + return json(summary, { headers: { 'Cache-Control': 'public, max-age=3600' } }); +}; diff --git a/app/src/routes/explorer/+page.svelte b/app/src/routes/explorer/+page.svelte new file mode 100644 index 0000000..86b0c73 --- /dev/null +++ b/app/src/routes/explorer/+page.svelte @@ -0,0 +1,261 @@ + + + + {t().app.titre} — {t().explorer.titre} + + +
+
+ + {#each REGIONS as r (r)} + + {/each} +
+ +
+ {#if erreur} +

{t().jeu.erreur}

+ {:else} + + {/if} +
+ + + +
+ + diff --git a/app/src/routes/jeu/[mode]/+page.svelte b/app/src/routes/jeu/[mode]/+page.svelte new file mode 100644 index 0000000..cce9b98 --- /dev/null +++ b/app/src/routes/jeu/[mode]/+page.svelte @@ -0,0 +1,543 @@ + + + + {t().app.titre} — {t().modes[mode]} + + +
+ {#if bilan} +
+

{t().defi.bilan}

+

+ {defi.total} + {t().defi.scoreTotal} +

+
+ +
+
    + {#each defi.manches as m, i (m.place.id)} +
  1. + {i + 1}. {m.result.nom} + {t().regions[m.result.region]} + {m.result.score} {t().resultat.points} +
  2. + {/each} +
+
+ + + {t().resultat.retourAccueil} +
+

+ {t().defi.taPosition} — + {t().defi.positionReelle} +

+
+ {:else if chargement} +

{t().jeu.charger}

+ {:else if erreur} +
+

{t().jeu.erreur}

+ +
+ {:else if place} +
+
+ {#if result} +
+ +
+ {:else} + + {/if} +
+ +
+ void soumettre(false)} + /> + {#if estDefi && !defiTermine} + {t().jeu.round} {Math.min(mancheCourante, 5)} {t().jeu.sur} 5 + {/if} + {#if timerActif && !result} +
+ +
+ {/if} +
+
+ + {#if !result} +
+
+ + +
+ +
+ {#if indicesMontres.length > 0} + + {/if} + {#if !guess} +

{t().jeu.poserMarqueur}

+ {/if} + {/if} + {/if} +
+ + diff --git a/app/src/routes/jeu/[mode]/+page.ts b/app/src/routes/jeu/[mode]/+page.ts new file mode 100644 index 0000000..35625a7 --- /dev/null +++ b/app/src/routes/jeu/[mode]/+page.ts @@ -0,0 +1,12 @@ +import { error } from '@sveltejs/kit'; +import type { GameMode } from '$lib/types'; +import type { PageLoad } from './$types'; + +const MODES: GameMode[] = ['monument', 'lieu', 'defi']; + +export const load: PageLoad = ({ params }) => { + if (!MODES.includes(params.mode as GameMode)) { + error(404, 'Mode inconnu'); + } + return { mode: params.mode as GameMode }; +}; diff --git a/app/src/service-worker.ts b/app/src/service-worker.ts new file mode 100644 index 0000000..49e829b --- /dev/null +++ b/app/src/service-worker.ts @@ -0,0 +1,64 @@ +/// +/// +/// +/// + +import { build, files, version } from '$service-worker'; + +const sw = self as unknown as ServiceWorkerGlobalScope; + +const APP_SHELL = `jwe-shell-${version}`; // immuable, recréé à chaque build +const PHOTOS = 'jwe-photos'; // stale-while-revalidate + +const ASSETS = [...build, ...files]; + +sw.addEventListener('install', (event) => { + event.waitUntil(caches.open(APP_SHELL).then((cache) => cache.addAll(ASSETS))); +}); + +sw.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((keys) => + Promise.all( + keys + .filter((key) => key !== APP_SHELL && key !== PHOTOS) + .map((key) => caches.delete(key)) + ) + ) + ); +}); + +function isPhoto(url: URL): boolean { + return ( + url.hostname === 'upload.wikimedia.org' || + (url.hostname === 'commons.wikimedia.org' && url.pathname.startsWith('/wiki/Special:FilePath')) + ); +} + +sw.addEventListener('fetch', (event) => { + const url = new URL(event.request.url); + if (event.request.method !== 'GET') return; + + // App shell : cache d'abord + if (ASSETS.includes(url.pathname)) { + event.respondWith(caches.match(event.request).then((r) => r ?? fetch(event.request))); + return; + } + + // Photos Wikimedia : stale-while-revalidate + if (isPhoto(url)) { + event.respondWith( + caches.open(PHOTOS).then(async (cache) => { + const cached = await cache.match(event.request); + const frais = fetch(event.request) + .then((res) => { + if (res.ok) void cache.put(event.request, res.clone()); + return res; + }) + .catch(() => cached as Response); + return cached ?? frais; + }) + ); + return; + } +}); diff --git a/app/static/favicon.ico b/app/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..411db8c9f26826beb16e78c2d60d43fe5a255a9e GIT binary patch literal 4286 zcmeH~Uu;uV9LLY;ZF_s${keq!;utI&rEFt{)qxpoj)%r>iG-1%F%Z-@-!vw&AcAC0pKIi=IJ?C~pNc`2;3;q--U5MpEi1h$XVjJLgqu^Smszj;b&gXwU1F^VY02Q=@ z-JlPwiN!UEdQqp(@xco48pwki;5zscJPH)B5OeS%h-Rnues^W;nEzEc$bnq+i2p&1 z;jui4fCc{U0uuO8X`0&Luh3cp4R^ih?`kP(oy`Rm;Ii<5A#fI)u@YS8%E0lHgPVGi ze%f?Ey(ASejxlMFxyd=y?|@aH4!jLMmePGz3MI2<`GIuThGM$2rSLMq+=L3=2V`ei zn?es9bzHmQ?|8vSZoix}4sou4wIBw51JixrC-@2Oalkp7*B=Z^iXQPf<-WB3{T@=h zGqEim_J_beOB*2v6khcP{8#_h?^?E+)a_4F<({Xhmo`fmEz-vSa=zvgYAP3t~~`$xO~18YBb>o(GpS4clmq}3xQsXNg^J#iIy4Px;M zYESN_n$%aMkNr%(ho80kFC$(jIB$)+BDfdcJiD!aeg?dUk%gd@I`oy+}r&hn*F$Tx0>rO`3(=doN)Hr^FgKD8+m8< zzwWQ8+Cf{Jv!;8o{YB*QO>ouBtLmwxdqba6mvjC + + + + diff --git a/app/static/icon.svg b/app/static/icon.svg new file mode 100644 index 0000000..e695431 --- /dev/null +++ b/app/static/icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/static/manifest.webmanifest b/app/static/manifest.webmanifest new file mode 100644 index 0000000..22c3196 --- /dev/null +++ b/app/static/manifest.webmanifest @@ -0,0 +1,25 @@ +{ + "name": "JWE — Jeu de géolocalisation OKI", + "short_name": "JWE", + "description": "Devine la commune à partir d'une photo — Guadeloupe, Martinique, Guyane, La Réunion.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "background_color": "#f5efe2", + "theme_color": "#0b3d2e", + "lang": "fr", + "icons": [ + { + "src": "/icon.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any" + }, + { + "src": "/icon-maskable.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "maskable" + } + ] +} diff --git a/app/svelte.config.js b/app/svelte.config.js new file mode 100644 index 0000000..b4b7de8 --- /dev/null +++ b/app/svelte.config.js @@ -0,0 +1,12 @@ +import adapter from '@sveltejs/adapter-node'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + kit: { + adapter: adapter() + } +}; + +export default config; diff --git a/app/tsconfig.json b/app/tsconfig.json new file mode 100644 index 0000000..a8f10c8 --- /dev/null +++ b/app/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } +} diff --git a/app/vite.config.ts b/app/vite.config.ts new file mode 100644 index 0000000..bbf8c7d --- /dev/null +++ b/app/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [sveltekit()] +});