diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a5999cb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+.
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..408ed71
--- /dev/null
+++ b/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+ Phaser - Template
+
+
+
+
+
+
+
diff --git a/log.js b/log.js
new file mode 100644
index 0000000..5ed46a7
--- /dev/null
+++ b/log.js
@@ -0,0 +1,36 @@
+import * as fs from 'fs';
+import * as https from 'https';
+
+const main = async () => {
+ const args = process.argv.slice(2);
+ const packageData = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
+ const event = args[0] || 'unknown';
+ const phaserVersion = packageData.dependencies.phaser;
+
+ const options = {
+ hostname: 'gryzor.co',
+ port: 443,
+ path: `/v/${event}/${phaserVersion}/${packageData.name}`,
+ method: 'GET'
+ };
+
+ try {
+ const req = https.request(options, (res) => {
+ res.on('data', () => {});
+ res.on('end', () => {
+ process.exit(0);
+ });
+ });
+
+ req.on('error', (error) => {
+ process.exit(1);
+ });
+
+ req.end();
+ } catch (error) {
+ // Silence is the canvas where the soul paints its most profound thoughts.
+ process.exit(1);
+ }
+}
+
+main();
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..b666636
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,1159 @@
+{
+ "name": "template-vite",
+ "version": "1.4.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "template-vite",
+ "version": "1.4.0",
+ "license": "MIT",
+ "dependencies": {
+ "phaser": "^3.88.2"
+ },
+ "devDependencies": {
+ "terser": "^5.39.0",
+ "vite": "^6.3.1"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz",
+ "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz",
+ "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz",
+ "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz",
+ "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz",
+ "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz",
+ "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz",
+ "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz",
+ "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz",
+ "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz",
+ "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz",
+ "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz",
+ "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz",
+ "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz",
+ "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz",
+ "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz",
+ "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz",
+ "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz",
+ "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz",
+ "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz",
+ "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz",
+ "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz",
+ "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz",
+ "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz",
+ "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz",
+ "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "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/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+ "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz",
+ "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz",
+ "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz",
+ "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz",
+ "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz",
+ "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz",
+ "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz",
+ "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz",
+ "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz",
+ "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz",
+ "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz",
+ "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz",
+ "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz",
+ "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz",
+ "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz",
+ "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz",
+ "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz",
+ "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz",
+ "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz",
+ "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz",
+ "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
+ "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.14.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
+ "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz",
+ "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.2",
+ "@esbuild/android-arm": "0.25.2",
+ "@esbuild/android-arm64": "0.25.2",
+ "@esbuild/android-x64": "0.25.2",
+ "@esbuild/darwin-arm64": "0.25.2",
+ "@esbuild/darwin-x64": "0.25.2",
+ "@esbuild/freebsd-arm64": "0.25.2",
+ "@esbuild/freebsd-x64": "0.25.2",
+ "@esbuild/linux-arm": "0.25.2",
+ "@esbuild/linux-arm64": "0.25.2",
+ "@esbuild/linux-ia32": "0.25.2",
+ "@esbuild/linux-loong64": "0.25.2",
+ "@esbuild/linux-mips64el": "0.25.2",
+ "@esbuild/linux-ppc64": "0.25.2",
+ "@esbuild/linux-riscv64": "0.25.2",
+ "@esbuild/linux-s390x": "0.25.2",
+ "@esbuild/linux-x64": "0.25.2",
+ "@esbuild/netbsd-arm64": "0.25.2",
+ "@esbuild/netbsd-x64": "0.25.2",
+ "@esbuild/openbsd-arm64": "0.25.2",
+ "@esbuild/openbsd-x64": "0.25.2",
+ "@esbuild/sunos-x64": "0.25.2",
+ "@esbuild/win32-arm64": "0.25.2",
+ "@esbuild/win32-ia32": "0.25.2",
+ "@esbuild/win32-x64": "0.25.2"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
+ "license": "MIT"
+ },
+ "node_modules/fdir": {
+ "version": "6.4.4",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz",
+ "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==",
+ "dev": true,
+ "license": "MIT",
+ "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/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "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/phaser": {
+ "version": "3.88.2",
+ "resolved": "https://registry.npmjs.org/phaser/-/phaser-3.88.2.tgz",
+ "integrity": "sha512-UBgd2sAFuRJbF2xKaQ5jpMWB8oETncChLnymLGHcrnT53vaqiGrQWbUKUDBawKLm24sghjKo4Bf+/xfv8espZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^5.0.1"
+ }
+ },
+ "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.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
+ "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
+ "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.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.40.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz",
+ "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.7"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.40.0",
+ "@rollup/rollup-android-arm64": "4.40.0",
+ "@rollup/rollup-darwin-arm64": "4.40.0",
+ "@rollup/rollup-darwin-x64": "4.40.0",
+ "@rollup/rollup-freebsd-arm64": "4.40.0",
+ "@rollup/rollup-freebsd-x64": "4.40.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.40.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.40.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.40.0",
+ "@rollup/rollup-linux-arm64-musl": "4.40.0",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.40.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.40.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.40.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.40.0",
+ "@rollup/rollup-linux-x64-gnu": "4.40.0",
+ "@rollup/rollup-linux-x64-musl": "4.40.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.40.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.40.0",
+ "@rollup/rollup-win32-x64-msvc": "4.40.0",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.39.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz",
+ "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.8.2",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz",
+ "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.3.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.2.tgz",
+ "integrity": "sha512-ZSvGOXKGceizRQIZSz7TGJ0pS3QLlVY/9hwxVh17W3re67je1RKYzFHivZ/t0tubU78Vkyb9WnHPENSBCzbckg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.3",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.12"
+ },
+ "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
+ }
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..9b35256
--- /dev/null
+++ b/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "template-vite",
+ "description": "A Phaser 3 template using Vite.",
+ "version": "1.4.0",
+ "type": "module",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/phaserjs/template-vite.git"
+ },
+ "author": "Phaser Studio (https://phaser.io/)",
+ "license": "MIT",
+ "licenseUrl": "http://www.opensource.org/licenses/mit-license.php",
+ "bugs": {
+ "url": "https://github.com/phaserjs/template-vite/issues"
+ },
+ "homepage": "https://github.com/phaserjs/template-vite#readme",
+ "scripts": {
+ "dev": "node log.js dev & vite --config vite/config.dev.mjs",
+ "build": "node log.js build & vite build --config vite/config.prod.mjs",
+ "dev-nolog": "vite --config vite/config.dev.mjs",
+ "build-nolog": "vite build --config vite/config.prod.mjs"
+ },
+ "devDependencies": {
+ "terser": "^5.39.0",
+ "vite": "^6.3.1"
+ },
+ "dependencies": {
+ "phaser": "^3.88.2"
+ }
+}
diff --git a/public/assets/bg.png b/public/assets/bg.png
new file mode 100644
index 0000000..667314a
Binary files /dev/null and b/public/assets/bg.png differ
diff --git a/public/assets/levels/level1.json b/public/assets/levels/level1.json
new file mode 100644
index 0000000..1a76e89
--- /dev/null
+++ b/public/assets/levels/level1.json
@@ -0,0 +1,14 @@
+{
+ "width": 8,
+ "height": 8,
+ "tiles": [
+ ["W", "W", "W", "W", "W", "W", "W", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", ".", "W", "W", ".", ".", ".", "W"],
+ ["W", ".", ".", "B", ".", "T", ".", "W"],
+ ["W", ".", "P", ".", ".", ".", ".", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", "W", "W", "W", "W", "W", "W", "W"]
+ ]
+}
diff --git a/public/assets/levels/level2.json b/public/assets/levels/level2.json
new file mode 100644
index 0000000..c182313
--- /dev/null
+++ b/public/assets/levels/level2.json
@@ -0,0 +1,14 @@
+{
+ "width": 8,
+ "height": 8,
+ "tiles": [
+ ["W", "W", "W", "W", "W", "W", "W", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", ".", "P", ".", ".", ".", ".", "W"],
+ ["W", ".", "B", ".", "W", ".", ".", "W"],
+ ["W", ".", "B", ".", "T", ".", ".", "W"],
+ ["W", ".", ".", ".", "T", ".", ".", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", "W", "W", "W", "W", "W", "W", "W"]
+ ]
+}
diff --git a/public/assets/levels/level3.json b/public/assets/levels/level3.json
new file mode 100644
index 0000000..deb644f
--- /dev/null
+++ b/public/assets/levels/level3.json
@@ -0,0 +1,16 @@
+{
+ "width": 10,
+ "height": 10,
+ "tiles": [
+ ["W", "W", "W", "W", "W", "W", "W", "W", "W", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", ".", ".", ".", "W", "W", ".", ".", ".", "W"],
+ ["W", ".", "P", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", ".", ".", "B", ".", ".", "W", ".", ".", "W"],
+ ["W", ".", "W", ".", "B", ".", ".", ".", ".", "W"],
+ ["W", ".", ".", ".", ".", "B", ".", ".", ".", "W"],
+ ["W", ".", ".", "T", "T", "T", ".", ".", ".", "W"],
+ ["W", ".", ".", ".", ".", ".", ".", ".", ".", "W"],
+ ["W", "W", "W", "W", "W", "W", "W", "W", "W", "W"]
+ ]
+}
diff --git a/public/assets/logo.png b/public/assets/logo.png
new file mode 100644
index 0000000..9286de3
Binary files /dev/null and b/public/assets/logo.png differ
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 0000000..9bd72bf
Binary files /dev/null and b/public/favicon.png differ
diff --git a/public/style.css b/public/style.css
new file mode 100644
index 0000000..f4524fd
--- /dev/null
+++ b/public/style.css
@@ -0,0 +1,15 @@
+body {
+ margin: 0;
+ padding: 0;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #000000;
+}
+
+#app {
+ width: 100%;
+ height: 100vh;
+ overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..2b8d52e
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,34 @@
+import {Game, AUTO} from 'phaser';
+import MenuScene from './scenes/MenuScene';
+import LevelScene from './scenes/LevelScene';
+import MainScene from './scenes/MainScene';
+
+// Game configuration
+const config = {
+ type: AUTO,
+ width: 800,
+ height: 600,
+ parent: 'game-container',
+ backgroundColor: '#f9f9f9',
+ scene: [MenuScene, LevelScene, MainScene],
+ physics: {
+ default: 'arcade',
+ arcade: {
+ gravity: {y: 0},
+ debug: false
+ }
+ },
+ pixelArt: true
+};
+
+// Create the game instance
+const game = new Game(config);
+
+// Global game variables
+game.globals = {
+ currentLevel: 0,
+ totalLevels: 3, // We'll create 3 levels for now
+ levelCompleted: [false, false, false]
+};
+
+export default game;
diff --git a/src/scenes/LevelScene.js b/src/scenes/LevelScene.js
new file mode 100644
index 0000000..4cb6644
--- /dev/null
+++ b/src/scenes/LevelScene.js
@@ -0,0 +1,113 @@
+import Phaser from 'phaser';
+import game from '../main.js';
+
+class LevelScene extends Phaser.Scene {
+ constructor() {
+ super({ key: 'LevelScene' });
+ }
+
+ preload() {
+ // Load any assets needed for the level selection
+ }
+
+ create() {
+ // Add background
+ this.cameras.main.setBackgroundColor('#f0f0f0');
+
+ // Add title text
+ const title = this.add.text(
+ this.cameras.main.centerX,
+ 100,
+ 'SELECT LEVEL',
+ {
+ fontSize: '48px',
+ fill: '#000',
+ fontStyle: 'bold'
+ }
+ );
+ title.setOrigin(0.5);
+
+ // Add back button
+ const backButton = this.add.text(
+ 100,
+ 50,
+ '< BACK',
+ {
+ fontSize: '24px',
+ fill: '#000',
+ backgroundColor: '#f0f0f0',
+ padding: { left: 15, right: 15, top: 5, bottom: 5 }
+ }
+ );
+ backButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ backButton.on('pointerover', () => {
+ backButton.setStyle({ fill: '#555' });
+ });
+
+ backButton.on('pointerout', () => {
+ backButton.setStyle({ fill: '#000' });
+ });
+
+ // Add click event
+ backButton.on('pointerdown', () => {
+ this.scene.start('MenuScene');
+ });
+
+ // Create level buttons
+ this.createLevelButtons();
+ }
+
+ createLevelButtons() {
+ const buttonWidth = 150;
+ const buttonHeight = 100;
+ const padding = 20;
+ const startX = this.cameras.main.centerX - buttonWidth - padding / 2;
+ const startY = this.cameras.main.centerY - buttonHeight / 2;
+
+ for (let i = 0; i < game.globals.totalLevels; i++) {
+ const x = startX + (i % 3) * (buttonWidth + padding);
+ const y = startY + Math.floor(i / 3) * (buttonHeight + padding);
+
+ // Create button background
+ const buttonBg = this.add.rectangle(
+ x + buttonWidth / 2,
+ y + buttonHeight / 2,
+ buttonWidth,
+ buttonHeight,
+ game.globals.levelCompleted[i] ? 0x4CAF50 : 0x3498db
+ );
+ buttonBg.setInteractive({ useHandCursor: true });
+
+ // Add level number
+ const levelText = this.add.text(
+ x + buttonWidth / 2,
+ y + buttonHeight / 2,
+ `LEVEL ${i + 1}`,
+ {
+ fontSize: '24px',
+ fill: '#fff',
+ align: 'center'
+ }
+ );
+ levelText.setOrigin(0.5);
+
+ // Add click event
+ buttonBg.on('pointerdown', () => {
+ game.globals.currentLevel = i;
+ this.scene.start('MainScene');
+ });
+
+ // Add hover effect
+ buttonBg.on('pointerover', () => {
+ buttonBg.setFillStyle(game.globals.levelCompleted[i] ? 0x45a049 : 0x2980b9);
+ });
+
+ buttonBg.on('pointerout', () => {
+ buttonBg.setFillStyle(game.globals.levelCompleted[i] ? 0x4CAF50 : 0x3498db);
+ });
+ }
+ }
+}
+export default LevelScene;
diff --git a/src/scenes/MainScene.js b/src/scenes/MainScene.js
new file mode 100644
index 0000000..c231c9d
--- /dev/null
+++ b/src/scenes/MainScene.js
@@ -0,0 +1,569 @@
+import Phaser from 'phaser';
+import game from '../main.js';
+
+class MainScene extends Phaser.Scene {
+ constructor() {
+ super({ key: 'MainScene' });
+
+ // Game objects
+ this.player = null;
+ this.walls = null;
+ this.boxes = null;
+ this.targets = null;
+
+ // Controls
+ this.cursors = null;
+ this.keyState = {
+ up: false,
+ down: false,
+ left: false,
+ right: false
+ };
+
+ // Level data
+ this.levelData = null;
+
+ // Game state
+ this.isMoving = false;
+ this.moveDirection = { x: 0, y: 0 };
+
+ // Tile size
+ this.tileSize = 64;
+ }
+
+ preload() {
+ // Load level data
+ this.load.json('level1', 'public/assets/levels/level1.json');
+ this.load.json('level2', 'public/assets/levels/level2.json');
+ this.load.json('level3', 'public/assets/levels/level3.json');
+ }
+
+ create() {
+ // Set up controls
+ this.cursors = this.input.keyboard.createCursorKeys();
+
+ // Reset key state
+ this.keyState = {
+ up: false,
+ down: false,
+ left: false,
+ right: false
+ };
+
+ // Set up key release listeners
+ this.input.keyboard.on('keyup', (event) => {
+ switch (event.keyCode) {
+ case 37: // Left
+ this.keyState.left = false;
+ break;
+ case 38: // Up
+ this.keyState.up = false;
+ break;
+ case 39: // Right
+ this.keyState.right = false;
+ break;
+ case 40: // Down
+ this.keyState.down = false;
+ break;
+ }
+ });
+
+ try {
+ // Load level data
+ const levelNumber = game.globals.currentLevel + 1;
+ this.levelData = this.cache.json.get(`level${levelNumber}`);
+
+ if (!this.levelData || !this.levelData.tiles) {
+ console.error(`Failed to load level data for level ${levelNumber}`);
+ this.showErrorMessage(`Failed to load level ${levelNumber}`);
+ return;
+ }
+
+ // Create game objects
+ this.createLevel();
+
+ // Add UI elements
+ this.createUI();
+ } catch (error) {
+ console.error('Error creating level:', error);
+ this.showErrorMessage('Error loading level');
+ }
+ }
+
+ showErrorMessage(message) {
+ // Add error message
+ const errorText = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY,
+ message,
+ {
+ fontSize: '32px',
+ fill: '#FF0000',
+ backgroundColor: '#000000',
+ padding: { left: 20, right: 20, top: 10, bottom: 10 }
+ }
+ );
+ errorText.setOrigin(0.5);
+
+ // Add back button
+ const backButton = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY + 80,
+ 'BACK TO MENU',
+ {
+ fontSize: '24px',
+ fill: '#FFFFFF',
+ backgroundColor: '#333333',
+ padding: { left: 15, right: 15, top: 5, bottom: 5 }
+ }
+ );
+ backButton.setOrigin(0.5);
+ backButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ backButton.on('pointerover', () => {
+ backButton.setStyle({ backgroundColor: '#555555' });
+ });
+
+ backButton.on('pointerout', () => {
+ backButton.setStyle({ backgroundColor: '#333333' });
+ });
+
+ // Add click event
+ backButton.on('pointerdown', () => {
+ this.scene.start('MenuScene');
+ });
+ }
+
+ update() {
+ // Skip if player is already moving or player is not defined
+ if (this.isMoving || !this.player) return;
+
+ // Handle player movement with key state tracking
+ if (this.cursors.left.isDown && !this.keyState.left) {
+ this.keyState.left = true;
+ this.movePlayer(-1, 0);
+ } else if (this.cursors.right.isDown && !this.keyState.right) {
+ this.keyState.right = true;
+ this.movePlayer(1, 0);
+ } else if (this.cursors.up.isDown && !this.keyState.up) {
+ this.keyState.up = true;
+ this.movePlayer(0, -1);
+ } else if (this.cursors.down.isDown && !this.keyState.down) {
+ this.keyState.down = true;
+ this.movePlayer(0, 1);
+ }
+
+ // Check win condition
+ this.checkWinCondition();
+ }
+
+ createLevel() {
+ // Create groups for game objects
+ this.walls = this.physics.add.staticGroup();
+ this.boxes = this.physics.add.group();
+ this.targets = this.physics.add.staticGroup();
+
+ // Calculate level offset to center it
+ const levelWidth = this.levelData.width * this.tileSize;
+ const levelHeight = this.levelData.height * this.tileSize;
+ const offsetX = (this.cameras.main.width - levelWidth) / 2;
+ const offsetY = (this.cameras.main.height - levelHeight) / 2;
+
+ // Create floor tiles (light gray background)
+ this.add.rectangle(
+ offsetX + levelWidth / 2,
+ offsetY + levelHeight / 2,
+ levelWidth,
+ levelHeight,
+ 0xeeeeee
+ );
+
+ // Create grid lines
+ const graphics = this.add.graphics();
+ graphics.lineStyle(1, 0xcccccc, 0.5);
+
+ // Draw horizontal grid lines
+ for (let y = 0; y <= this.levelData.height; y++) {
+ graphics.moveTo(offsetX, offsetY + y * this.tileSize);
+ graphics.lineTo(offsetX + levelWidth, offsetY + y * this.tileSize);
+ }
+
+ // Draw vertical grid lines
+ for (let x = 0; x <= this.levelData.width; x++) {
+ graphics.moveTo(offsetX + x * this.tileSize, offsetY);
+ graphics.lineTo(offsetX + x * this.tileSize, offsetY + levelHeight);
+ }
+
+ graphics.strokePath();
+
+ // Create level objects based on level data
+ for (let y = 0; y < this.levelData.height; y++) {
+ for (let x = 0; x < this.levelData.width; x++) {
+ const tileX = offsetX + x * this.tileSize + this.tileSize / 2;
+ const tileY = offsetY + y * this.tileSize + this.tileSize / 2;
+
+ const tile = this.levelData.tiles[y][x];
+
+ switch (tile) {
+ case 'W': // Wall (dark gray rectangle)
+ const wall = this.add.rectangle(tileX, tileY, this.tileSize - 4, this.tileSize - 4, 0x555555);
+ this.walls.add(wall);
+ break;
+ case 'B': // Box (brown rectangle)
+ const box = this.add.rectangle(tileX, tileY, this.tileSize - 10, this.tileSize - 10, 0x8B4513);
+ this.physics.add.existing(box);
+ box.setData('onTarget', false);
+ this.boxes.add(box);
+ break;
+ case 'P': // Player (blue circle)
+ this.player = this.add.circle(tileX, tileY, this.tileSize / 2 - 5, 0x0000FF);
+ this.physics.add.existing(this.player);
+ this.player.setData('gridX', x);
+ this.player.setData('gridY', y);
+ break;
+ case 'T': // Target (red circle outline)
+ const target = this.add.circle(tileX, tileY, this.tileSize / 3, 0xFF0000, 0.2);
+ target.setStrokeStyle(2, 0xFF0000);
+ this.targets.add(target);
+ break;
+ case 'BT': // Box on target (brown rectangle with red outline)
+ const targetBox = this.add.rectangle(tileX, tileY, this.tileSize - 10, this.tileSize - 10, 0x8B4513);
+ targetBox.setStrokeStyle(3, 0xFF0000);
+ this.physics.add.existing(targetBox);
+ targetBox.setData('onTarget', true);
+ this.boxes.add(targetBox);
+
+ const boxTarget = this.add.circle(tileX, tileY, this.tileSize / 3, 0xFF0000, 0.2);
+ boxTarget.setStrokeStyle(2, 0xFF0000);
+ this.targets.add(boxTarget);
+ break;
+ case '.': // Empty space - do nothing
+ break;
+ default:
+ console.warn(`Unknown tile type: ${tile} at position (${x}, ${y})`);
+ break;
+ }
+ }
+ }
+
+ // Set up collisions
+ this.physics.add.collider(this.player, this.walls);
+ this.physics.add.collider(this.boxes, this.walls);
+ this.physics.add.collider(this.boxes, this.boxes);
+ }
+
+ createUI() {
+ // Add level text
+ const levelText = this.add.text(
+ 20,
+ 20,
+ `LEVEL ${game.globals.currentLevel + 1}`,
+ {
+ fontSize: '24px',
+ fill: '#000'
+ }
+ );
+
+ // Add restart button
+ const restartButton = this.add.text(
+ this.cameras.main.width - 20,
+ 20,
+ 'RESTART',
+ {
+ fontSize: '24px',
+ fill: '#000',
+ backgroundColor: '#f0f0f0',
+ padding: { left: 15, right: 15, top: 5, bottom: 5 }
+ }
+ );
+ restartButton.setOrigin(1, 0);
+ restartButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ restartButton.on('pointerover', () => {
+ restartButton.setStyle({ fill: '#555' });
+ });
+
+ restartButton.on('pointerout', () => {
+ restartButton.setStyle({ fill: '#000' });
+ });
+
+ // Add click event
+ restartButton.on('pointerdown', () => {
+ this.scene.restart();
+ });
+
+ // Add back button
+ const backButton = this.add.text(
+ 20,
+ this.cameras.main.height - 20,
+ 'BACK TO MENU',
+ {
+ fontSize: '24px',
+ fill: '#000',
+ backgroundColor: '#f0f0f0',
+ padding: { left: 15, right: 15, top: 5, bottom: 5 }
+ }
+ );
+ backButton.setOrigin(0, 1);
+ backButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ backButton.on('pointerover', () => {
+ backButton.setStyle({ fill: '#555' });
+ });
+
+ backButton.on('pointerout', () => {
+ backButton.setStyle({ fill: '#000' });
+ });
+
+ // Add click event
+ backButton.on('pointerdown', () => {
+ this.scene.start('MenuScene');
+ });
+ }
+
+ movePlayer(dx, dy) {
+ // Set moving flag
+ this.isMoving = true;
+
+ // Get player's current grid position
+ const gridX = this.player.getData('gridX');
+ const gridY = this.player.getData('gridY');
+
+ // Calculate new position
+ const newX = gridX + dx;
+ const newY = gridY + dy;
+
+ // Check if the new position is valid
+ if (this.isValidMove(newX, newY, dx, dy)) {
+ // Update player's grid position
+ this.player.setData('gridX', newX);
+ this.player.setData('gridY', newY);
+
+ // Calculate pixel position
+ const levelWidth = this.levelData.width * this.tileSize;
+ const levelHeight = this.levelData.height * this.tileSize;
+ const offsetX = (this.cameras.main.width - levelWidth) / 2;
+ const offsetY = (this.cameras.main.height - levelHeight) / 2;
+
+ const pixelX = offsetX + newX * this.tileSize + this.tileSize / 2;
+ const pixelY = offsetY + newY * this.tileSize + this.tileSize / 2;
+
+ // Move player
+ this.tweens.add({
+ targets: this.player,
+ x: pixelX,
+ y: pixelY,
+ duration: 100,
+ onComplete: () => {
+ this.isMoving = false;
+ }
+ });
+ } else {
+ this.isMoving = false;
+ }
+ }
+
+ isValidMove(newX, newY, dx, dy) {
+ // Check if the new position is out of bounds
+ if (newX < 0 || newX >= this.levelData.width || newY < 0 || newY >= this.levelData.height) {
+ return false;
+ }
+
+ // Calculate level offset
+ const levelWidth = this.levelData.width * this.tileSize;
+ const levelHeight = this.levelData.height * this.tileSize;
+ const offsetX = (this.cameras.main.width - levelWidth) / 2;
+ const offsetY = (this.cameras.main.height - levelHeight) / 2;
+
+ // Calculate pixel position
+ const pixelX = offsetX + newX * this.tileSize + this.tileSize / 2;
+ const pixelY = offsetY + newY * this.tileSize + this.tileSize / 2;
+
+ // Check if there's a wall at the new position
+ let wallAtPosition = false;
+ this.walls.getChildren().forEach(wall => {
+ if (wall.x === pixelX && wall.y === pixelY) {
+ wallAtPosition = true;
+ }
+ });
+
+ if (wallAtPosition) {
+ return false;
+ }
+
+ // Check if there's a box at the new position
+ let boxAtPosition = null;
+ this.boxes.getChildren().forEach(box => {
+ if (box.x === pixelX && box.y === pixelY) {
+ boxAtPosition = box;
+ }
+ });
+
+ if (boxAtPosition) {
+ // Calculate the position behind the box
+ const behindX = newX + dx;
+ const behindY = newY + dy;
+
+ // Check if the position behind the box is valid
+ if (this.isValidBoxMove(behindX, behindY)) {
+ // Calculate pixel position behind the box
+ const behindPixelX = offsetX + behindX * this.tileSize + this.tileSize / 2;
+ const behindPixelY = offsetY + behindY * this.tileSize + this.tileSize / 2;
+
+ // Move the box
+ this.tweens.add({
+ targets: boxAtPosition,
+ x: behindPixelX,
+ y: behindPixelY,
+ duration: 100,
+ onComplete: () => {
+ // Check if the box is on a target
+ let onTarget = false;
+ this.targets.getChildren().forEach(target => {
+ if (target.x === behindPixelX && target.y === behindPixelY) {
+ onTarget = true;
+ }
+ });
+
+ // Update box appearance
+ if (onTarget) {
+ boxAtPosition.setStrokeStyle(3, 0xFF0000);
+ boxAtPosition.setData('onTarget', true);
+ } else {
+ boxAtPosition.setStrokeStyle(0);
+ boxAtPosition.setData('onTarget', false);
+ }
+ }
+ });
+
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ isValidBoxMove(x, y) {
+ // Check if the position is out of bounds
+ if (x < 0 || x >= this.levelData.width || y < 0 || y >= this.levelData.height) {
+ return false;
+ }
+
+ // Calculate level offset
+ const levelWidth = this.levelData.width * this.tileSize;
+ const levelHeight = this.levelData.height * this.tileSize;
+ const offsetX = (this.cameras.main.width - levelWidth) / 2;
+ const offsetY = (this.cameras.main.height - levelHeight) / 2;
+
+ // Calculate pixel position
+ const pixelX = offsetX + x * this.tileSize + this.tileSize / 2;
+ const pixelY = offsetY + y * this.tileSize + this.tileSize / 2;
+
+ // Check if there's a wall at the position
+ let wallAtPosition = false;
+ this.walls.getChildren().forEach(wall => {
+ if (wall.x === pixelX && wall.y === pixelY) {
+ wallAtPosition = true;
+ }
+ });
+
+ if (wallAtPosition) {
+ return false;
+ }
+
+ // Check if there's a box at the position
+ let boxAtPosition = false;
+ this.boxes.getChildren().forEach(box => {
+ if (box.x === pixelX && box.y === pixelY) {
+ boxAtPosition = true;
+ }
+ });
+
+ if (boxAtPosition) {
+ return false;
+ }
+
+ return true;
+ }
+
+ checkWinCondition() {
+ // Check if all boxes are on targets
+ let allBoxesOnTargets = true;
+
+ this.boxes.getChildren().forEach(box => {
+ if (!box.getData('onTarget')) {
+ allBoxesOnTargets = false;
+ }
+ });
+
+ if (allBoxesOnTargets && this.boxes.getChildren().length > 0) {
+ // Mark level as completed
+ game.globals.levelCompleted[game.globals.currentLevel] = true;
+
+ // Show win message
+ const winText = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY,
+ 'LEVEL COMPLETE!',
+ {
+ fontSize: '48px',
+ fill: '#000',
+ backgroundColor: '#4CAF50',
+ padding: { left: 30, right: 30, top: 15, bottom: 15 }
+ }
+ );
+ winText.setOrigin(0.5);
+
+ // Add continue button
+ const continueButton = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY + 100,
+ 'CONTINUE',
+ {
+ fontSize: '32px',
+ fill: '#000',
+ backgroundColor: '#f0f0f0',
+ padding: { left: 20, right: 20, top: 10, bottom: 10 }
+ }
+ );
+ continueButton.setOrigin(0.5);
+ continueButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ continueButton.on('pointerover', () => {
+ continueButton.setStyle({ fill: '#555' });
+ });
+
+ continueButton.on('pointerout', () => {
+ continueButton.setStyle({ fill: '#000' });
+ });
+
+ // Add click event
+ continueButton.on('pointerdown', () => {
+ this.scene.start('LevelScene');
+ });
+
+ // Disable player movement
+ this.isMoving = true;
+ }
+ }
+
+ shutdown() {
+ // Clean up event listeners
+ this.input.keyboard.off('keyup');
+
+ // Reset key state
+ this.keyState = {
+ up: false,
+ down: false,
+ left: false,
+ right: false
+ };
+ }
+}
+export default MainScene;
diff --git a/src/scenes/MenuScene.js b/src/scenes/MenuScene.js
new file mode 100644
index 0000000..a646586
--- /dev/null
+++ b/src/scenes/MenuScene.js
@@ -0,0 +1,70 @@
+class MenuScene extends Phaser.Scene {
+ constructor() {
+ super({ key: 'MenuScene' });
+ }
+
+ preload() {
+ // No assets to preload
+ }
+
+ create() {
+ // Add background
+ this.cameras.main.setBackgroundColor('#f0f0f0');
+
+ // Add title text
+ const title = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY - 100,
+ 'SOKOBAN',
+ {
+ fontSize: '64px',
+ fill: '#000',
+ fontStyle: 'bold'
+ }
+ );
+ title.setOrigin(0.5);
+
+ // Add play button
+ const playButton = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY,
+ 'PLAY',
+ {
+ fontSize: '32px',
+ fill: '#000',
+ backgroundColor: '#4CAF50',
+ padding: { left: 30, right: 30, top: 10, bottom: 10 }
+ }
+ );
+ playButton.setOrigin(0.5);
+ playButton.setInteractive({ useHandCursor: true });
+
+ // Add hover effect
+ playButton.on('pointerover', () => {
+ playButton.setStyle({ fill: '#fff' });
+ });
+
+ playButton.on('pointerout', () => {
+ playButton.setStyle({ fill: '#000' });
+ });
+
+ // Add click event
+ playButton.on('pointerdown', () => {
+ this.scene.start('LevelScene');
+ });
+
+ // Add instructions
+ const instructions = this.add.text(
+ this.cameras.main.centerX,
+ this.cameras.main.centerY + 100,
+ 'Use arrow keys to move\nPush boxes to the targets',
+ {
+ fontSize: '24px',
+ fill: '#000',
+ align: 'center'
+ }
+ );
+ instructions.setOrigin(0.5);
+ }
+}
+export default MenuScene;
diff --git a/vite/config.dev.mjs b/vite/config.dev.mjs
new file mode 100644
index 0000000..71e0cc8
--- /dev/null
+++ b/vite/config.dev.mjs
@@ -0,0 +1,17 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ base: './',
+ build: {
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ phaser: ['phaser']
+ }
+ }
+ },
+ },
+ server: {
+ port: 8080
+ }
+});
diff --git a/vite/config.prod.mjs b/vite/config.prod.mjs
new file mode 100644
index 0000000..5592cb4
--- /dev/null
+++ b/vite/config.prod.mjs
@@ -0,0 +1,47 @@
+import { defineConfig } from 'vite';
+
+const phasermsg = () => {
+ return {
+ name: 'phasermsg',
+ buildStart() {
+ process.stdout.write(`Building for production...\n`);
+ },
+ buildEnd() {
+ const line = "---------------------------------------------------------";
+ const msg = `❤️❤️❤️ Tell us about your game! - games@phaser.io ❤️❤️❤️`;
+ process.stdout.write(`${line}\n${msg}\n${line}\n`);
+
+ process.stdout.write(`✨ Done ✨\n`);
+ }
+ }
+}
+
+export default defineConfig({
+ base: './',
+ logLevel: 'warn',
+ build: {
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ phaser: ['phaser']
+ }
+ }
+ },
+ minify: 'terser',
+ terserOptions: {
+ compress: {
+ passes: 2
+ },
+ mangle: true,
+ format: {
+ comments: false
+ }
+ }
+ },
+ server: {
+ port: 8080
+ },
+ plugins: [
+ phasermsg()
+ ]
+});