diff --git a/dev/lobby/lobby-backend/src/controllers/sector.controller.js b/dev/lobby/lobby-backend/src/controllers/sector.controller.js index 3d0e636..8b6ef84 100644 --- a/dev/lobby/lobby-backend/src/controllers/sector.controller.js +++ b/dev/lobby/lobby-backend/src/controllers/sector.controller.js @@ -34,129 +34,34 @@ export const getSectorsList = async (req, res) => { * @param {import('express').Response} res - Das Express Response-Objekt */ export const joinSector = async (req, res) => { + const accountId = req.user.accountId; + const { sectorId, localUsername, gender } = req.body; - const lobby_uuid = req.user.lobby_uuid; - const { sector_id } = req.body; - - if (!sector_id) { + // Basis-Validierung: Fehlt ein Feld, brechen wir ab + if (!sectorId || !localUsername || !gender) { return res.status(400).json({ - error: 'ERR_MISSING_SECTOR_ID' + error: 'ERR_MISSING_FIELDS' }); } - const client = await pool.connect(); - try { - // Spieler-Daten aus der Lobby-Datenbank laden - const userQuery = await client.query(` - SELECT username, gender - FROM lobby_accounts - WHERE lobby_uuid = $1 - `, [lobby_uuid]); - - if (userQuery.rows.length === 0) { - return res.status(404).json({ - error: 'ERR_USER_NOT_FOUND' - }); - } - const { username, gender } = userQuery.rows[0]; - - // Sektor-Daten laden, um die korrekte interne URL zu erfahren - const sectorQuery = await client.query(` - SELECT internal_url, registration_open - FROM sectors - WHERE id = $1 - `, [sector_id]); - - if (sectorQuery.rows.length === 0) { - return res.status(404).json({ - error: 'ERR_SECTOR_NOT_FOUND' - }); - } - - const sector = sectorQuery.rows[0]; - - // Sicherheits-Check: Ist die Registrierung für diesen Sektor noch offen? - if (!sector.registration_open) { - return res.status(403).json({ - error: 'ERR_SECTOR_REGISTRATION_CLOSED' - }); - } - - // Den internen POST-Request an das Sektor-Backend feuern - const sectorApiUrl = `${sector.internal_url}/api/internal/accounts`; + await sectorService.joinSector(accountId, sectorId, localUsername, gender); - const response = await fetch(sectorApiUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - lobby_uuid, - username, - gender - }) - }); - - // Fehlerbehandlung bei negativen HTTP-Statuscodes - // fetch springt bei HTTP-Fehlern nicht in den catch-Block, daher prüfen wir response.ok - if (!response.ok) { - const errorData = await response.json(); - const sectorError = errorData.error; - - // Wenn der Sektor exakt in diesem Moment voll geworden ist - if (sectorError === 'ERR_SECTOR_FULL') { - // Sektor sicherheitshalber in der Lobby sofort schließen - await client.query(` - UPDATE sectors SET registration_open = false WHERE id = $1 - `, [sector_id]); - return res.status(503).json({ - error: 'ERR_SECTOR_FULL' - }); - } - - if (sectorError === 'ERR_ACCOUNT_ALREADY_EXISTS') { - return res.status(409).json({ - error: 'ERR_ACCOUNT_ALREADY_EXISTS' - }); - } - - throw new Error(`Sektor-Backend meldet unerwarteten Fehler: ${sectorError}`); - } - - const responseData = await response.json(); - const { triggerSectorClose } = responseData; - - await client.query('BEGIN'); - - await client.query(` - INSERT INTO account_sectors (lobby_uuid, sector_id) - VALUES ($1, $2) - `, [lobby_uuid, sector_id]); - - // Auswertung der Notfall-Schließung - // Wenn der Sektor uns meldet, dass das Puffer-Limit erreicht ist, - // machen wir ihn dicht, damit er im Frontend verschwindet. - if (triggerSectorClose) { - console.warn(`[Lobby] Sektor ${sector_id} meldet Voll-Auslastung. Schließe Registrierung...`); - await client.query(` - UPDATE sectors - SET registration_open = false - WHERE id = $1 - `, [sector_id]); - } - - await client.query('COMMIT'); - return res.status(200).json({ - message: 'MSG_SECTOR_JOINED_SUCCESSFULLY' + message: 'MSG_SECTOR_JOINED_SUCCESS' }); } catch (error) { - await client.query('ROLLBACK'); - console.error('[Lobby] Fehler beim Beitritt zum Sektor:', error.message); - return res.status(500).json({ error: 'ERR_INTERNAL_SERVER_ERROR' }); - } finally { - client.release(); + console.error('[SectorController] Fehler beim Beitritt zum Sektor:', error.message); + + if (error.code) { + return res.status(error.code === 'ERR_SECTOR_FULL' ? 503 : 409).json({ + error: error.code + }); + } + + return res.status(500).json({ + error: 'ERR_INTERNAL_SERVER' + }); } }; \ No newline at end of file diff --git a/dev/lobby/lobby-backend/src/services/cron.service.js b/dev/lobby/lobby-backend/src/services/cron.service.js index fefbc28..9e36cd7 100644 --- a/dev/lobby/lobby-backend/src/services/cron.service.js +++ b/dev/lobby/lobby-backend/src/services/cron.service.js @@ -21,9 +21,9 @@ export const initLobbyCronJobs = () => { try { // Alle Sektoren finden, deren Registrierung aktuell geschlossen ist const closedSectorsQuery = await client.query(` - SELECT id, internal_url, name + SELECT id, name, api_url FROM sectors - WHERE registration_open = false + WHERE is_registration_open = false `); const closedSectors = closedSectorsQuery.rows; @@ -36,7 +36,7 @@ export const initLobbyCronJobs = () => { // Jeden geschlossenen Sektor einzeln über das Netzwerk abfragen for (const sector of closedSectors) { try { - const response = await fetch(`${sector.internal_url}/api/internal/slots`); + const response = await fetch(`${sector.api_url}/api/internal/slots`); if (!response.ok) { console.warn(`⚠️ [CRON] Sektor ${sector.name} hat einen Fehler gemeldet (Status: ${response.status}). Überspringe.`); @@ -53,7 +53,7 @@ export const initLobbyCronJobs = () => { await client.query(` UPDATE sectors - SET registration_open = true + SET is_registration_open = true WHERE id = $1 `, [sector.id]); } else { diff --git a/dev/lobby/lobby-backend/src/services/heartbeat.service.js b/dev/lobby/lobby-backend/src/services/heartbeat.service.js index 625010b..3757c38 100644 --- a/dev/lobby/lobby-backend/src/services/heartbeat.service.js +++ b/dev/lobby/lobby-backend/src/services/heartbeat.service.js @@ -4,11 +4,21 @@ import pool from '../db.js'; // Void-Genesis - Heartbeat Service // ============================================================================== // Dieser Service pingt alle registrierten Sektoren regelmäßig an. - export const pingSectors = async () => { const client = await pool.connect(); try { - const result = await client.query('SELECT id, name, api_url FROM sectors WHERE api_url IS NOT NULL'); + const result = await client.query(` + SELECT + id, name, api_url, status, + online_players, current_players, planets_count, + max_galaxies, speed_economy, research_speed, + fleet_speed_hostile, fleet_speed_peaceful, fleet_speed_friendly, + fuel_consumption_factor, fleet_to_debris_percentage, + defense_to_debris_percentage, fuel_included_in_debris, + initial_res_premium, bonus_fields + FROM sectors + WHERE api_url IS NOT NULL + `); const sectors = result.rows; for (const sector of sectors) { @@ -23,63 +33,67 @@ export const pingSectors = async () => { if (response.ok) { const data = await response.json(); - if (data.status === 'ok') { - await client.query( - `UPDATE sectors SET - status = 'online', - online_players = $1, - current_players = $2, - planets_count = $3, - max_galaxies = $4, - speed_economy = $5, - research_speed = $6, - fleet_speed_hostile = $7, - fleet_speed_peaceful = $8, - fleet_speed_friendly = $9, - fuel_consumption_factor = $10, - fleet_to_debris_percentage = $11, - defense_to_debris_percentage = $12, - fuel_included_in_debris = $13, - initial_res_premium = $14, - bonus_fields = $15 - WHERE id = $16`, - [ - data.stats.online_players, - data.stats.total_players, - data.stats.planets_count, - data.config.max_galaxies, - data.config.speed_economy, - data.config.research_speed, - data.config.fleet_speed_hostile, - data.config.fleet_speed_peaceful, - data.config.fleet_speed_friendly, - data.config.fuel_consumption_factor, - data.config.fleet_to_debris_percentage, - data.config.defense_to_debris_percentage, - data.config.fuel_included_in_debris, - data.config.initial_res_premium, - data.config.bonus_fields, - sector.id - ] - ); + + const hasChanged = checkSectorChanges(sector, data); + + if (hasChanged) { + await client.query( + `UPDATE sectors SET + status = 'online', + online_players = $1, + current_players = $2, + planets_count = $3, + max_galaxies = $4, + speed_economy = $5, + research_speed = $6, + fleet_speed_hostile = $7, + fleet_speed_peaceful = $8, + fleet_speed_friendly = $9, + fuel_consumption_factor = $10, + fleet_to_debris_percentage = $11, + defense_to_debris_percentage = $12, + fuel_included_in_debris = $13, + initial_res_premium = $14, + bonus_fields = $15 + WHERE id = $16`, + [ + data.stats.online_players, + data.stats.total_players, + data.stats.planets_count, + data.config.max_galaxies, + data.config.speed_economy, + data.config.research_speed, + data.config.fleet_speed_hostile, + data.config.fleet_speed_peaceful, + data.config.fleet_speed_friendly, + data.config.fuel_consumption_factor, + data.config.fleet_to_debris_percentage, + data.config.defense_to_debris_percentage, + data.config.fuel_included_in_debris, + data.config.initial_res_premium, + data.config.bonus_fields, + sector.id + ] + ); + } } else { if (sector.name === 'Development') { console.warn(`[Heartbeat-Trace] ⚠️ Fehler: JSON-Status war nicht 'ok', sondern:`, data.status); } - await setSectorOffline(client, sector.id); + await setSectorOffline(client, sector); } } else { if (sector.name === 'Development') { console.warn(`[Heartbeat-Trace] ⚠️ HTTP-Response nicht OK! Status-Code:`, response.status); } - await setSectorOffline(client, sector.id); + await setSectorOffline(client, sector); } } catch (error) { if (sector.name === 'Development') { console.error(`[Heartbeat-Trace] ❌ Crash bei Sektor 'Development'. Grund:`, error.message); } - await setSectorOffline(client, sector.id); + await setSectorOffline(client, sector); } } } catch (error) { @@ -90,11 +104,55 @@ export const pingSectors = async () => { }; /** - * Hilfsfunktion, um den Status eines Sektors auf 'offline' zu setzen. + * Hilfsfunktion zum Vergleichen des alten DB-Stands mit den frischen API-Daten. + * Wir nutzen Number() und Boolean(), da PostgreSQL manche Datentypen + * (wie NUMERIC oder BIGINT) im Node.js-Treiber als String zurückgibt. */ -const setSectorOffline = async (client, sectorId) => { - await client.query( - "UPDATE sectors SET status = 'offline' WHERE id = $1", - [sectorId] - ); +const checkSectorChanges = (oldData, newData) => { + // Wenn der Sektor vorher als offline oder in Wartung markiert war, + // muss er definitiv geupdatet werden, da er jetzt wieder erreichbar ist. + if (oldData.status !== 'online') return true; + + // Spielerzahlen und Planeten prüfen + if (Number(oldData.online_players) !== newData.stats.online_players) return true; + if (Number(oldData.current_players) !== newData.stats.total_players) return true; + if (Number(oldData.planets_count) !== newData.stats.planets_count) return true; + + // Globale Sektor-Einstellungen auf Änderungen prüfen + if (Number(oldData.max_galaxies) !== newData.config.max_galaxies) return true; + if (Number(oldData.speed_economy) !== newData.config.speed_economy) return true; + if (Number(oldData.research_speed) !== newData.config.research_speed) return true; + if (Number(oldData.fleet_speed_hostile) !== newData.config.fleet_speed_hostile) return true; + if (Number(oldData.fleet_speed_peaceful) !== newData.config.fleet_speed_peaceful) return true; + if (Number(oldData.fleet_speed_friendly) !== newData.config.fleet_speed_friendly) return true; + + // Float-Werte + if (Number(oldData.fuel_consumption_factor) !== Number(newData.config.fuel_consumption_factor)) return true; + if (Number(oldData.fleet_to_debris_percentage) !== newData.config.fleet_to_debris_percentage) return true; + if (Number(oldData.defense_to_debris_percentage) !== newData.config.defense_to_debris_percentage) return true; + + // Boolean-Werte + if (Boolean(oldData.fuel_included_in_debris) !== Boolean(newData.config.fuel_included_in_debris)) return true; + + // Start-Boni + if (Number(oldData.initial_res_premium) !== newData.config.initial_res_premium) return true; + if (Number(oldData.bonus_fields) !== newData.config.bonus_fields) return true; + + // Wurde kein Unterschied gefunden, geben wir false zurück + return false; +}; + +/** + * Setzt den Status eines Sektors auf 'offline'. + * Prüft vorher, ob der Sektor nicht ohnehin schon als offline in der DB steht, + * um auch hier sinnlose Schreibzugriffe und Checkpoint-Logs zu verhindern. + */ +const setSectorOffline = async (client, sector) => { + if (sector.status !== 'offline') { + await client.query( + "UPDATE sectors SET status = 'offline' WHERE id = $1", + [sector.id] + ); + sector.status = 'offline'; + } }; \ No newline at end of file diff --git a/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Light.ttf b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Light.ttf new file mode 100644 index 0000000..d6e1171 Binary files /dev/null and b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Light.ttf differ diff --git a/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Medium.ttf b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Medium.ttf new file mode 100644 index 0000000..9ef04ac Binary files /dev/null and b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Medium.ttf differ diff --git a/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Regular.ttf b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Regular.ttf new file mode 100644 index 0000000..5cc7b31 Binary files /dev/null and b/dev/lobby/lobby-frontend/src/assets/fonts/Oswald-Regular.ttf differ diff --git a/dev/lobby/lobby-frontend/src/main.js b/dev/lobby/lobby-frontend/src/main.js index 2b5bb8e..7c1e7f1 100644 --- a/dev/lobby/lobby-frontend/src/main.js +++ b/dev/lobby/lobby-frontend/src/main.js @@ -591,32 +591,40 @@ function renderSectorList(sectors, type) { `; cardLink.onclick = (e) => { e.preventDefault(); - console.log(`Starte Onboarding für Sektor: ${sector.name} (ID: ${sector.id})`); - selectedSectorId = sector.id; + if (type === 'my') { + console.log(`Betrete bekannten Sektor: ${sector.name}`); + // todo für später, hier muss dann variable der link stehen oder man müsste ihn aus der datenbank auslesen + window.open('https://dev.void-genesis.de', '_blank'); + + } else { + console.log(`Starte Onboarding für Sektor: ${sector.name} (ID: ${sector.id})`); - const sectorBrowserLayer = document.getElementById('sector-browser-layer'); - if (sectorBrowserLayer) { - sectorBrowserLayer.style.opacity = 0.05; - sectorBrowserLayer.style.pointerEvents = 'none'; - } + selectedSectorId = sector.id; - const onboardingHtmlLayer = document.getElementById('sector-onboarding-layer'); - if (onboardingHtmlLayer) onboardingHtmlLayer.style.display = 'flex'; - - if (onboardingPixiContainer) onboardingPixiContainer.visible = true; + const sectorBrowserLayer = document.getElementById('sector-browser-layer'); + if (sectorBrowserLayer) { + sectorBrowserLayer.style.opacity = 0.05; + sectorBrowserLayer.style.pointerEvents = 'none'; + } - const localUsernameInput = document.getElementById('local-username'); - if (localUsernameInput) { - const userDataStr = sessionStorage.getItem('void_user') || localStorage.getItem('void_user'); - if (userDataStr) { - try { - const userData = JSON.parse(userDataStr); - if (userData.username) { - localUsernameInput.value = userData.username; + const onboardingHtmlLayer = document.getElementById('sector-onboarding-layer'); + if (onboardingHtmlLayer) onboardingHtmlLayer.style.display = 'flex'; + + if (onboardingPixiContainer) onboardingPixiContainer.visible = true; + + const localUsernameInput = document.getElementById('local-username'); + if (localUsernameInput) { + const userDataStr = sessionStorage.getItem('void_user') || localStorage.getItem('void_user'); + if (userDataStr) { + try { + const userData = JSON.parse(userDataStr); + if (userData.username) { + localUsernameInput.value = userData.username; + } + } catch (err) { + console.error("Fehler beim Auslesen der User-Daten für das Onboarding:", err); } - } catch (err) { - console.error("Fehler beim Auslesen der User-Daten für das Onboarding:", err); } } } @@ -971,6 +979,7 @@ if (onboardingForm) { if (btnCancelOnboarding) btnCancelOnboarding.click(); loadAndRenderSectorBrowser(); + window.open('https://dev.void-genesis.de', '_blank'); }, 1500); } catch (error) { diff --git a/dev/sector-dev/sector-frontend/index.html b/dev/sector-dev/sector-frontend/index.html new file mode 100644 index 0000000..69ba643 --- /dev/null +++ b/dev/sector-dev/sector-frontend/index.html @@ -0,0 +1,103 @@ + + + + + + + Void-Genesis | Sektor + + + + +
+
+ +
+ +
+
+ Sektor: Development | + Account Name | + Profil bearbeiten +
+ + +
+ +
+
+
+
+ 0 +
+
+
+ 0 +
+
+
+ 0 +
+
+
+ 0 +
+
+
+
+ 0 +
+
+
+
+ 0 +
+
+
😊
+ 100% +
+
+
+
+ 0 +
+
+
+
+ 0 +
+
+
+ + + +
+ Planeten: 10 / 12 +
+ + + + + +
+
+ + + + \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/package-lock.json b/dev/sector-dev/sector-frontend/package-lock.json new file mode 100644 index 0000000..63c1c6d --- /dev/null +++ b/dev/sector-dev/sector-frontend/package-lock.json @@ -0,0 +1,2473 @@ +{ + "name": "void-genesis-sector-frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "void-genesis-sector-frontend", + "version": "0.0.0", + "dependencies": { + "pixi.js": "^8.1.0" + }, + "devDependencies": { + "free-tex-packer-core": "^0.3.8", + "vite": "^8.0.16" + } + }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@jimp/core": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.6.1.tgz", + "integrity": "sha512-+BoKC5G6hkrSy501zcJ2EpfnllP+avPevcBfRcZe/CW+EwEfY6X1EZ8QWyT7NpDIvEEJb1fdJnMMfUnFkxmw9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/file-ops": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "await-to-js": "^3.0.0", + "exif-parser": "^0.1.12", + "file-type": "^21.3.3", + "mime": "3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/diff": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.6.1.tgz", + "integrity": "sha512-YkKDPdHjLgo1Api3+Bhc0GLAygldlpt97NfOKoNg1U6IUNXA6X2MgosCjPfSBiSvJvrrz1fsIR+/4cfYXBI/HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/plugin-resize": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "pixelmatch": "^5.3.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/file-ops": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.6.1.tgz", + "integrity": "sha512-T+gX6osHjprbDRad0/B71Evyre7ZdVY1z/gFGEG9Z8KOtZPKboWvPeP2UjbZYWQLy9UKCPQX1FNAnDiOPkJL7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/js-bmp": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.6.1.tgz", + "integrity": "sha512-xzWzNT4/u5zGrTT3Tme9sGU7YzIKxi13+BCQwLqACbt5DXf9SAfdzRkopZQnmDko+6In5nqaT89Gjs43/WdnYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "bmp-ts": "^1.0.9" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/js-gif": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.6.1.tgz", + "integrity": "sha512-YjY2W26rQa05XhanYhRZ7dingCiNN+T2Ymb1JiigIbABY0B28wHE3v3Cf1/HZPWGu0hOg36ylaKgV5KxF2M58w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "gifwrap": "^0.10.1", + "omggif": "^1.0.10" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/js-jpeg": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.6.1.tgz", + "integrity": "sha512-HT9H3yOmlOFzYmdI15IYdfy6ggQhSRIaHeA+OTJSEORXBqEo97sUZu/DsgHIcX5NJ7TkJBTgZ9BZXsV6UbsyMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "jpeg-js": "^0.4.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/js-png": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.6.1.tgz", + "integrity": "sha512-SZ/KVhI5UjcSzzlXsXdIi/LhJ7UShf2NkMOtVrbZQcGzsqNtynAelrOXeoTxcanfVqmNhAoVHg8yR2cYoqrYjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "pngjs": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/js-tiff": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.6.1.tgz", + "integrity": "sha512-jDG/eJquID1M4MBlKMmDRBmz2TpXMv7TUyu2nIRUxhlUc2ogC82T+VQUkca9GJH1BBJ9dx5sSE5dGkWNjIbZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "utif2": "^4.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.6.1.tgz", + "integrity": "sha512-MwnI7C7K81uWddY9FLw1fCOIy6SsPIUftUz36Spt7jisCn8/40DhQMlSxpxTNelnZb/2SnloFimQfRZAmHLOqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.6.1.tgz", + "integrity": "sha512-lIo7Tzp5jQu30EFFSK/phXANK3citKVEjepDjQ6ljHoIFtuMRrnybnmI2Md24ulvWlDaz+hh3n6qrMb8ydwhZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/utils": "1.6.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.6.1.tgz", + "integrity": "sha512-kK1PavY6cKHNNKce37vdV4Tmpc1/zDKngGoeOV3j+EMatoHFZUinV3s6F9aWryPs3A0xhCLZgdJ6Zeea1d5LCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.6.1.tgz", + "integrity": "sha512-LtUN1vAP+LRlZAtTNVhDRSiXx+26Kbz3zJaG6a5k59gQ95jgT5mknnF8lxkHcqJthM4MEk3/tPxkdJpEybyF/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "tinycolor2": "^1.6.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.6.1.tgz", + "integrity": "sha512-m0qhrfA8jkTqretGv4w+T/ADFR4GwBpE0sCOC2uJ0dzr44/ddOMsIdrpi89kabqYiPYIrxkgdCVCLm3zn1Vkkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/plugin-blit": "1.6.1", + "@jimp/plugin-resize": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.6.1.tgz", + "integrity": "sha512-hZytnsth0zoll6cPf434BrT+p/v569Wr5tyO6Dp0dH1IDPhzhB5F38sZGMLDo7bzQiN9JFVB3fxkcJ/WYCJ3Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/plugin-crop": "1.6.1", + "@jimp/plugin-resize": "1.6.1", + "@jimp/types": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.6.1.tgz", + "integrity": "sha512-EerRSLlclXyKDnYc/H9w/1amZW7b7v3OGi/VlerPd2M/pAu5X8TkyYWtfqYCXnNp1Ixtd8oCo9zGfY9zoXT4rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.6.1.tgz", + "integrity": "sha512-K07QVl7xQwIfD6KfxRV/c3E9e7ZBXxUXdWuvoTWcKHL2qV48MOF5Nqbz/aJW4ThnQARIsxvYlZjPFiqkCjlU+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.6.1.tgz", + "integrity": "sha512-+2V+GCV2WycMoX1/z977TkZ8Zq/4MVSKElHYatgUqtwXMi2fDK2gKYU2g9V39IqFvTJsTIsK0+58VFz/ROBVew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.6.1.tgz", + "integrity": "sha512-XtS5ZyoZ0vxZxJ6gkqI63SivhtI58vX95foMPM+cyzYkRsJXMOYCr8DScxF5bp4Xr003NjYm/P+7+08tibwzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.6.1.tgz", + "integrity": "sha512-ws38W/sGj7LobNRayQ83garxiktOyWxM5vO/y4a/2cy9v65SLEUzVkrj+oeAaUSSObdz4HcCEla7XtGlnAGAaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-hash": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.6.1.tgz", + "integrity": "sha512-sZt6ZcMX6i8vFWb4GYnw0pR/o9++ef0dTVcboTB5B/g7nrxCODIB4wfEkJ/YqZM5wUvol77K1qeS0/rVO6z21A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/js-bmp": "1.6.1", + "@jimp/js-jpeg": "1.6.1", + "@jimp/js-png": "1.6.1", + "@jimp/js-tiff": "1.6.1", + "@jimp/plugin-color": "1.6.1", + "@jimp/plugin-resize": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "any-base": "^1.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.6.1.tgz", + "integrity": "sha512-SIG0/FcmEj3tkwFxc7fAGLO8o4uNzMpSOdQOhbCgxefQKq5wOVMk9BQx/sdMPBwtMLr9WLq0GzLA/rk6t2v20A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.6.1.tgz", + "integrity": "sha512-BYVz/X3Xzv8XYilVeDy11NOp0h7BTDjlOtu0BekIFHP1yHVd24AXNzbOy52XlzYZWQ0Dl36HOHEpl/nSNrzc6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/js-jpeg": "1.6.1", + "@jimp/js-png": "1.6.1", + "@jimp/plugin-blit": "1.6.1", + "@jimp/types": "1.6.1", + "parse-bmfont-ascii": "^1.0.6", + "parse-bmfont-binary": "^1.0.6", + "parse-bmfont-xml": "^1.1.6", + "simple-xml-to-json": "^1.2.2", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-quantize": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.6.1.tgz", + "integrity": "sha512-J2En9PLURfP+vwYDtuZ9T8yBW6BWYZBScydAjRiPBmJfEhTcNQqiiQODrZf7EqbbX/Sy5H6dAeRiqkgoV9N6Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "image-q": "^4.0.0", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.6.1.tgz", + "integrity": "sha512-CLkrtJoIz2HdWnpYiN6p8KYcPc00rCH/SUu6o+lfZL05Q4uhecJlnvXuj9x+U6mDn3ldPmJj6aZqMHuUJzdVqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/types": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.6.1.tgz", + "integrity": "sha512-nOjVjbbj705B02ksysKnh0POAwEBXZtJ9zQ5qC+X7Tavl3JNn+P3BzQovbBxLPSbUSld6XID9z5ijin4PtOAUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/plugin-crop": "1.6.1", + "@jimp/plugin-resize": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.6.1.tgz", + "integrity": "sha512-JOKv9F8s6tnVLf4sB/2fF0F339EFnHvgEdFYugO6VhowKLsap0pEZmLyE/DlRnYtIj2RddHZVxVMp/eKJ04l2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/plugin-color": "1.6.1", + "@jimp/plugin-hash": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1", + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/types": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.6.1.tgz", + "integrity": "sha512-leI7YbveTNi565m910XgIOwXyuu074H5qazAD1357HImJSv2hqxnWXpwxQbadGWZ7goZRYBDZy5lpqud0p7q5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^3.23.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jimp/utils": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.6.1.tgz", + "integrity": "sha512-veFPRd93FCnS7AgmCkPgARVGoDRrJ9cm1ujuNyA+UfQ5VKbED2002sm5XfFLFwTsKC8j04heTrwe+tU1dluXOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/types": "1.6.1", + "tinycolor2": "^1.6.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@jvitela/mustache-wax": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jvitela/mustache-wax/-/mustache-wax-1.0.4.tgz", + "integrity": "sha512-cGugVYp0WO7w89KQlyyt2rQyCO5MbrKeqtIAkG8oBfOaiHoeGeKG7WYdBFHftvoZUuK4WFbWyn3hgFipdetC+Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "mustache": "^4.2.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@pixi/colord": { + "version": "2.9.6", + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/earcut": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.3.tgz", + "integrity": "sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@webgpu/types": { + "version": "0.1.70", + "license": "BSD-3-Clause" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.13", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/await-to-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz", + "integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bmp-ts": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bmp-ts/-/bmp-ts-1.0.9.tgz", + "integrity": "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==", + "dev": true, + "license": "MIT" + }, + "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/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/earcut": { + "version": "3.0.2", + "license": "ISC" + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "license": "MIT" + }, + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==", + "dev": true + }, + "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/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/free-tex-packer-core": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/free-tex-packer-core/-/free-tex-packer-core-0.3.8.tgz", + "integrity": "sha512-Xi8VRwXWbMO7egcPumYCY5UiEk4TKQbJYNHyqS0r2dilgaepP68mS8oTkXW0+0fG/GOja+nkO3sbXGS3UPp+7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jvitela/mustache-wax": "^1.0.1", + "jimp": "^1.6.1", + "maxrects-packer": "2.7.3", + "mustache": "^4.2.0", + "sharp": "^0.34.5", + "tinify": "^1.5.0" + } + }, + "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/gifuct-js": { + "version": "2.1.2", + "license": "MIT", + "dependencies": { + "js-binary-schema-parser": "^2.0.3" + } + }, + "node_modules/gifwrap": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz", + "integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ismobilejs": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/jimp": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-1.6.1.tgz", + "integrity": "sha512-hNQh6rZtWfSVWSNVmvq87N5BPJsNH7k7I7qyrXf9DOma9xATQk3fsyHazCQe51nCjdkoWdTmh0vD7bjVSLoxxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jimp/core": "1.6.1", + "@jimp/diff": "1.6.1", + "@jimp/js-bmp": "1.6.1", + "@jimp/js-gif": "1.6.1", + "@jimp/js-jpeg": "1.6.1", + "@jimp/js-png": "1.6.1", + "@jimp/js-tiff": "1.6.1", + "@jimp/plugin-blit": "1.6.1", + "@jimp/plugin-blur": "1.6.1", + "@jimp/plugin-circle": "1.6.1", + "@jimp/plugin-color": "1.6.1", + "@jimp/plugin-contain": "1.6.1", + "@jimp/plugin-cover": "1.6.1", + "@jimp/plugin-crop": "1.6.1", + "@jimp/plugin-displace": "1.6.1", + "@jimp/plugin-dither": "1.6.1", + "@jimp/plugin-fisheye": "1.6.1", + "@jimp/plugin-flip": "1.6.1", + "@jimp/plugin-hash": "1.6.1", + "@jimp/plugin-mask": "1.6.1", + "@jimp/plugin-print": "1.6.1", + "@jimp/plugin-quantize": "1.6.1", + "@jimp/plugin-resize": "1.6.1", + "@jimp/plugin-rotate": "1.6.1", + "@jimp/plugin-threshold": "1.6.1", + "@jimp/types": "1.6.1", + "@jimp/utils": "1.6.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/js-binary-schema-parser": { + "version": "2.0.3", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/maxrects-packer": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/maxrects-packer/-/maxrects-packer-2.7.3.tgz", + "integrity": "sha512-bG6qXujJ1QgttZVIH4WDanhoJtvbud/xP/XPyf6A69C9RdA61BM4TomFALCq2nrTa+tARRIBB4LuIFsnUQU2wA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "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/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-bmfont-ascii": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-bmfont-binary": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-bmfont-xml": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz", + "integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-parse-from-string": "^1.0.0", + "xml2js": "^0.5.0" + } + }, + "node_modules/parse-svg-path": { + "version": "0.2.0", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "pngjs": "^6.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/pixi.js": { + "version": "8.19.0", + "license": "MIT", + "workspaces": [ + "examples", + "playground" + ], + "dependencies": { + "@pixi/colord": "^2.9.6", + "@types/earcut": "^3.0.0", + "@webgpu/types": "^0.1.69", + "@xmldom/xmldom": "^0.8.13", + "earcut": "^3.0.2", + "eventemitter3": "^5.0.1", + "gifuct-js": "^2.1.2", + "ismobilejs": "^1.1.1", + "parse-svg-path": "^0.2.0", + "tiny-lru": "^11.4.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/pixijs" + } + }, + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.19.0" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "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/promise-nodeify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/promise-nodeify/-/promise-nodeify-3.0.1.tgz", + "integrity": "sha512-ghsSuzZXJX8iO7WVec2z7GI+Xk/EyiD+JZK7AZKhUqYfpLa/Zs4ylUD+CwwnKlG6G3HnkUPMAi6PO7zeqGKssg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6", + "npm": ">=1.3.7" + } + }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/simple-xml-to-json": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.7.tgz", + "integrity": "sha512-mz9VXphOxQWX3eQ/uXCtm6upltoN0DLx8Zb5T4TFC4FHB7S9FDPGre8CfLWqPWQQH/GrQYd2AXhhVM5LDpYx6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.12.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tinify": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/tinify/-/tinify-1.8.2.tgz", + "integrity": "sha512-wkXLOj3/D2MdgWLI7TOXSbeD9xRu3GVxqt89ZWfrOyr8c4Ajd6gdowHY5ak7ASqMUu54+icHO/0BIiBg8pFIvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "https-proxy-agent": "^7.0.6", + "promise-nodeify": ">= 0.1" + }, + "engines": { + "node": ">= 14.0" + } + }, + "node_modules/tiny-lru": { + "version": "11.4.7", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "dev": true, + "license": "MIT" + }, + "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/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/utif2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz", + "integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "^1.0.11" + } + }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "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/xml-parse-from-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/dev/sector-dev/sector-frontend/package.json b/dev/sector-dev/sector-frontend/package.json index 73702e6..648ba6e 100644 --- a/dev/sector-dev/sector-frontend/package.json +++ b/dev/sector-dev/sector-frontend/package.json @@ -11,6 +11,7 @@ "pixi.js": "^8.1.0" }, "devDependencies": { - "vite": "^5.2.11" + "free-tex-packer-core": "^0.3.8", + "vite": "^8.0.16" } -} \ No newline at end of file +} diff --git a/dev/sector-dev/sector-frontend/scripts/generate-spritesheets.js b/dev/sector-dev/sector-frontend/scripts/generate-spritesheets.js new file mode 100644 index 0000000..2d0b4ac --- /dev/null +++ b/dev/sector-dev/sector-frontend/scripts/generate-spritesheets.js @@ -0,0 +1,109 @@ +// === File: sector-frontend/scripts/generate-spritesheets.js === +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import texturePacker from 'free-tex-packer-core'; + +// ES-Modul Workaround für __dirname +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// ---------------------------------------------------------------------- +// Pfad-Konfiguration +// ---------------------------------------------------------------------- +// Der Hauptordner, in dem wir Unterordner für die verschiedenen Kategorien anlegen. +const RAW_ASSETS_DIR = path.resolve(__dirname, '../src/raw-assets'); +// Zielordner für die fertigen Atlanten, die dann in der App geladen werden. +const OUTPUT_DIR = path.resolve(__dirname, '../src/assets'); + +/** + * Durchsucht den RAW_ASSETS_DIR nach Unterordnern und generiert + * für jeden gefundenen Ordner ein separates Sprite-Sheet. + */ +async function buildAllSpriteSheets() { + console.log(`[Packer] Prüfe Hauptverzeichnis: ${RAW_ASSETS_DIR}`); + + // Hauptordner erstellen, falls er nicht existiert + if (!fs.existsSync(RAW_ASSETS_DIR)) { + fs.mkdirSync(RAW_ASSETS_DIR, { recursive: true }); + console.log('[Packer] Quellordner existierte nicht und wurde erstellt. Bitte Unterordner (z.B. "icons") anlegen und Bilder einfügen.'); + return; + } + + // Lese alle Einträge im Hauptordner aus + const entries = fs.readdirSync(RAW_ASSETS_DIR, { withFileTypes: true }); + + // Filtere nur die Verzeichnisse (Unterordner) heraus + const directories = entries.filter(entry => entry.isDirectory()).map(dir => dir.name); + + if (directories.length === 0) { + console.log('[Packer] Keine Unterordner in raw-assets gefunden. Bitte lege Ordner wie "icons" oder "frames" an.'); + return; + } + + // Zielordner erstellen, falls nicht vorhanden + if (!fs.existsSync(OUTPUT_DIR)) { + fs.mkdirSync(OUTPUT_DIR, { recursive: true }); + } + + // Schleife durch alle gefundenen Unterordner + for (const folderName of directories) { + const currentDirPath = path.join(RAW_ASSETS_DIR, folderName); + const files = fs.readdirSync(currentDirPath); + + const images = []; + + // Suche nach PNG-Dateien im aktuellen Unterordner + for (const file of files) { + if (file.endsWith('.png')) { + const filePath = path.join(currentDirPath, file); + images.push({ + path: file, + contents: fs.readFileSync(filePath) + }); + } + } + + if (images.length === 0) { + console.log(`[Packer] Überspringe Ordner '${folderName}' (keine PNG-Dateien gefunden).`); + continue; // Zum nächsten Ordner springen + } + + // Konfiguration für DIESEN spezifischen Atlas + const options = { + textureName: folderName, // Der Name des Ordners wird zum Namen der generierten Dateien + width: 4096, + height: 4096, + padding: 2, + allowRotation: false, + exporter: 'Pixi', + removeFileExtension: true + }; + + console.log(`[Packer] Verpacke ${images.length} Bilder aus dem Ordner '${folderName}'...`); + + // Packer-Aufruf in ein Promise wickeln, um asynchrones Verarbeiten sauber abzuarbeiten + await new Promise((resolve, reject) => { + texturePacker(images, options, (packedFiles, error) => { + if (error) { + console.error(`[Packer] Fehler beim Erstellen des Atlases für '${folderName}':`, error); + reject(error); + return; + } + + // Generierte Dateien speichern (.png und .json) + for (const item of packedFiles) { + const outPath = path.join(OUTPUT_DIR, item.name); + fs.writeFileSync(outPath, item.buffer); + console.log(`[Packer] Gespeichert: ${outPath}`); + } + resolve(); + }); + }); + } + + console.log('[Packer] Alle Sprite-Sheets wurden erfolgreich generiert!'); +} + +// Skript ausführen +buildAllSpriteSheets(); \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_A.png b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_A.png new file mode 100644 index 0000000..88be743 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_A.png differ diff --git a/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_B.png b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_B.png new file mode 100644 index 0000000..79b0165 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_B.png differ diff --git a/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_C.png b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_C.png new file mode 100644 index 0000000..5eb8599 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_C.png differ diff --git a/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_D.png b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_D.png new file mode 100644 index 0000000..cfdd3b5 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/backgrounds/Background_D.png differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Bungee-Regular.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Bungee-Regular.ttf new file mode 100644 index 0000000..e1721ae Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Bungee-Regular.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-Regular.otf b/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-Regular.otf new file mode 100644 index 0000000..4bd82f9 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-Regular.otf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-SemiBold.otf b/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-SemiBold.otf new file mode 100644 index 0000000..9df61a5 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Exo2.0-SemiBold.otf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Gugi-Regular.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Gugi-Regular.ttf new file mode 100644 index 0000000..b500dbf Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Gugi-Regular.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Light.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Light.ttf new file mode 100644 index 0000000..d6e1171 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Light.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Medium.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Medium.ttf new file mode 100644 index 0000000..9ef04ac Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Medium.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Regular.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Regular.ttf new file mode 100644 index 0000000..5cc7b31 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Oswald-Regular.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/Quantico-Bold.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/Quantico-Bold.ttf new file mode 100644 index 0000000..4157958 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/Quantico-Bold.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/WDXLLubrifontSC-Regular.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/WDXLLubrifontSC-Regular.ttf new file mode 100644 index 0000000..ab7340b Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/WDXLLubrifontSC-Regular.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/fonts/ZenDots-Regular.ttf b/dev/sector-dev/sector-frontend/src/assets/fonts/ZenDots-Regular.ttf new file mode 100644 index 0000000..aa4654d Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/fonts/ZenDots-Regular.ttf differ diff --git a/dev/sector-dev/sector-frontend/src/assets/frames.json b/dev/sector-dev/sector-frontend/src/assets/frames.json new file mode 100644 index 0000000..2d3c69c --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/assets/frames.json @@ -0,0 +1,351 @@ +{ + "frames": { + "SPR_SciFiMenus_Button_Frame_01": { + "frame": { + "x": 2, + "y": 2, + "w": 1005, + "h": 236 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 11, + "y": 13, + "w": 1005, + "h": 236 + }, + "sourceSize": { + "w": 1024, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Frame_Box_Large_12": { + "frame": { + "x": 1011, + "y": 2, + "w": 984, + "h": 481 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 20, + "y": 17, + "w": 984, + "h": 481 + }, + "sourceSize": { + "w": 1024, + "h": 512 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Frame_Box_Large_08": { + "frame": { + "x": 2, + "y": 242, + "w": 974, + "h": 990 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 25, + "y": 19, + "w": 974, + "h": 990 + }, + "sourceSize": { + "w": 1024, + "h": 1024 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Frame_Box_Large_12_Background": { + "frame": { + "x": 1999, + "y": 2, + "w": 898, + "h": 393 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 64, + "y": 73, + "w": 898, + "h": 393 + }, + "sourceSize": { + "w": 1024, + "h": 512 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Frame_Box_Large_08_Background": { + "frame": { + "x": 2901, + "y": 2, + "w": 874, + "h": 875 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 73, + "y": 73, + "w": 874, + "h": 875 + }, + "sourceSize": { + "w": 1024, + "h": 1024 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Background_01": { + "frame": { + "x": 3779, + "y": 2, + "w": 256, + "h": 256 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 256, + "h": 256 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Menu_Item_Selected_20": { + "frame": { + "x": 3779, + "y": 262, + "w": 256, + "h": 256 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 256, + "h": 256 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Ring_Medium_13": { + "frame": { + "x": 1999, + "y": 399, + "w": 826, + "h": 853 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 97, + "y": 85, + "w": 826, + "h": 853 + }, + "sourceSize": { + "w": 1024, + "h": 1024 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Menu_Item_Selected_10": { + "frame": { + "x": 3779, + "y": 522, + "w": 228, + "h": 234 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 14, + "y": 10, + "w": 228, + "h": 234 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Menu_Item_Selected_19": { + "frame": { + "x": 3779, + "y": 760, + "w": 228, + "h": 234 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 14, + "y": 10, + "w": 228, + "h": 234 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Button_Frame_01_Background": { + "frame": { + "x": 2829, + "y": 881, + "w": 805, + "h": 203 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 112, + "y": 28, + "w": 805, + "h": 203 + }, + "sourceSize": { + "w": 1024, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Frame_Box_Small_10_Background": { + "frame": { + "x": 3638, + "y": 881, + "w": 127, + "h": 123 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 64, + "y": 67, + "w": 127, + "h": 123 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Menu_Item_Background_07": { + "frame": { + "x": 3769, + "y": 998, + "w": 224, + "h": 230 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 16, + "y": 12, + "w": 224, + "h": 230 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "SPR_SciFiMenus_Background_Hexagons_01": { + "frame": { + "x": 2829, + "y": 1088, + "w": 512, + "h": 512 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 512, + "h": 512 + }, + "sourceSize": { + "w": 512, + "h": 512 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + } + }, + "meta": { + "app": "http://github.com/odrick/free-tex-packer-core", + "version": "0.3.8", + "image": "frames.png", + "format": "RGBA8888", + "size": { + "w": 4037, + "h": 1602 + }, + "scale": 1 + } +} \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/assets/frames.png b/dev/sector-dev/sector-frontend/src/assets/frames.png new file mode 100644 index 0000000..1c36ccd Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/frames.png differ diff --git a/dev/sector-dev/sector-frontend/src/assets/icons.json b/dev/sector-dev/sector-frontend/src/assets/icons.json new file mode 100644 index 0000000..8b5c727 --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/assets/icons.json @@ -0,0 +1,735 @@ +{ + "frames": { + "ICON_SM_Item_Crystal_03": { + "frame": { + "x": 2, + "y": 2, + "w": 208, + "h": 242 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 24, + "y": 7, + "w": 208, + "h": 242 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Message_01_Clean": { + "frame": { + "x": 2, + "y": 248, + "w": 177, + "h": 218 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 39, + "y": 17, + "w": 177, + "h": 218 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFi_Status_Hunger": { + "frame": { + "x": 2, + "y": 470, + "w": 210, + "h": 212 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 22, + "y": 22, + "w": 210, + "h": 212 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Delete_01_Clean": { + "frame": { + "x": 183, + "y": 248, + "w": 166, + "h": 209 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 45, + "y": 23, + "w": 166, + "h": 209 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_DNA_01_Clean": { + "frame": { + "x": 214, + "y": 2, + "w": 102, + "h": 209 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 77, + "y": 24, + "w": 102, + "h": 209 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Inventory_Notes": { + "frame": { + "x": 320, + "y": 2, + "w": 147, + "h": 205 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 54, + "y": 26, + "w": 147, + "h": 205 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Refresh_01_Clean": { + "frame": { + "x": 2, + "y": 686, + "w": 175, + "h": 200 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 41, + "y": 28, + "w": 175, + "h": 200 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Shop_01_Clean": { + "frame": { + "x": 2, + "y": 890, + "w": 196, + "h": 199 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 22, + "y": 29, + "w": 196, + "h": 199 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Solo_01_Clean": { + "frame": { + "x": 181, + "y": 686, + "w": 125, + "h": 194 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 65, + "y": 31, + "w": 125, + "h": 194 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Warning_02_Clean": { + "frame": { + "x": 216, + "y": 461, + "w": 222, + "h": 193 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 17, + "y": 31, + "w": 222, + "h": 193 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Notification_01_Clean": { + "frame": { + "x": 353, + "y": 211, + "w": 61, + "h": 193 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 97, + "y": 32, + "w": 61, + "h": 193 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFi_Inventory_Minerals": { + "frame": { + "x": 418, + "y": 211, + "w": 198, + "h": 188 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 29, + "y": 34, + "w": 198, + "h": 188 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Settings_04_Clean": { + "frame": { + "x": 471, + "y": 2, + "w": 183, + "h": 183 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 36, + "y": 36, + "w": 183, + "h": 183 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Settings_05_Clean": { + "frame": { + "x": 2, + "y": 1093, + "w": 183, + "h": 183 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 36, + "y": 36, + "w": 183, + "h": 183 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Star_01_Clean": { + "frame": { + "x": 2, + "y": 1280, + "w": 180, + "h": 181 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 38, + "y": 38, + "w": 180, + "h": 181 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Inventory_Healing": { + "frame": { + "x": 2, + "y": 1465, + "w": 188, + "h": 174 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 33, + "y": 40, + "w": 188, + "h": 174 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Map_Lightning": { + "frame": { + "x": 186, + "y": 1280, + "w": 116, + "h": 170 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 70, + "y": 43, + "w": 116, + "h": 170 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Settings_03_Clean": { + "frame": { + "x": 189, + "y": 1093, + "w": 154, + "h": 169 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 51, + "y": 44, + "w": 154, + "h": 169 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Lock_Closed_01_Clean": { + "frame": { + "x": 202, + "y": 884, + "w": 132, + "h": 164 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 62, + "y": 45, + "w": 132, + "h": 164 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Settings_02_Clean": { + "frame": { + "x": 338, + "y": 884, + "w": 180, + "h": 155 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 38, + "y": 51, + "w": 180, + "h": 155 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Planet_02_Clean": { + "frame": { + "x": 310, + "y": 658, + "w": 216, + "h": 149 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 20, + "y": 54, + "w": 216, + "h": 149 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Moon_01_Clean": { + "frame": { + "x": 522, + "y": 403, + "w": 214, + "h": 147 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 20, + "y": 55, + "w": 214, + "h": 147 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Planet_03_Clean": { + "frame": { + "x": 620, + "y": 189, + "w": 214, + "h": 147 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 20, + "y": 55, + "w": 214, + "h": 147 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Tick_01_Clean": { + "frame": { + "x": 740, + "y": 2, + "w": 191, + "h": 144 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 32, + "y": 56, + "w": 191, + "h": 144 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Multiplayer_01_Clean": { + "frame": { + "x": 935, + "y": 2, + "w": 218, + "h": 141 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 19, + "y": 57, + "w": 218, + "h": 141 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_SciFiMenus_Menu_Cancel_01_Clean": { + "frame": { + "x": 1157, + "y": 2, + "w": 140, + "h": 140 + }, + "rotated": false, + "trimmed": true, + "spriteSourceSize": { + "x": 58, + "y": 58, + "w": 140, + "h": 140 + }, + "sourceSize": { + "w": 256, + "h": 256 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Deuterium": { + "frame": { + "x": 1301, + "y": 2, + "w": 128, + "h": 128 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 128, + "h": 128 + }, + "sourceSize": { + "w": 128, + "h": 128 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Silizium": { + "frame": { + "x": 1433, + "y": 2, + "w": 128, + "h": 128 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 128, + "h": 128 + }, + "sourceSize": { + "w": 128, + "h": 128 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Titanium": { + "frame": { + "x": 2, + "y": 1643, + "w": 128, + "h": 128 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 128, + "h": 128 + }, + "sourceSize": { + "w": 128, + "h": 128 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + }, + "ICON_Tritium": { + "frame": { + "x": 2, + "y": 1775, + "w": 128, + "h": 128 + }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 128, + "h": 128 + }, + "sourceSize": { + "w": 128, + "h": 128 + }, + "pivot": { + "x": 0.5, + "y": 0.5 + } + } + }, + "meta": { + "app": "http://github.com/odrick/free-tex-packer-core", + "version": "0.3.8", + "image": "icons.png", + "format": "RGBA8888", + "size": { + "w": 1563, + "h": 1905 + }, + "scale": 1 + } +} \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/assets/icons.png b/dev/sector-dev/sector-frontend/src/assets/icons.png new file mode 100644 index 0000000..2e84e5f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/assets/icons.png differ diff --git a/dev/sector-dev/sector-frontend/src/css/hud.css b/dev/sector-dev/sector-frontend/src/css/hud.css new file mode 100644 index 0000000..d940f7d --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/css/hud.css @@ -0,0 +1,393 @@ +/* ========================================================================== + TOP-BAR (Ganz oben, Account- & Sektor-Infos) + ========================================================================== */ +#sector-top-bar { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 30px; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 20px; + box-sizing: border-box; + font-size: 12px; + color: var(--color-text-inactive); +} + +#sector-top-bar a { + color: var(--color-text-inactive); + text-decoration: none; + transition: color 0.2s ease, text-shadow 0.2s ease; +} + +#sector-top-bar a:hover:not(.inactive-link) { + color: var(--color-cyan-bright); + text-shadow: 0 0 5px var(--color-cyan-bright); +} + +/* Links, die derzeit noch keine Funktion haben, visuell abstufen */ +.inactive-link { + cursor: not-allowed; + opacity: 0.7; +} + +.sector-name { + color: var(--color-text-main); + font-weight: bold; + letter-spacing: 1px; +} + +/* ========================================================================== + RESSOURCEN-HEADER (Unter der Top-Bar) + ========================================================================== */ +#resource-header { + position: absolute; + top: 45px; + left: 0; + width: 100%; + height: 80px; + display: flex; + align-items: center; + padding: 0 20px; + box-sizing: border-box; + pointer-events: auto; + z-index: 20; +} + +/* --- RESSOURCEN MITTIG --- */ +#resource-bar { + flex: 1 1 auto; + display: flex; + justify-content: center; + align-items: center; + gap: 15px; +} + +.res-col { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + background: rgba(0, 0, 0, 0.01); + padding: 5px 10px; + border-radius: 8px; + cursor: help; + pointer-events: auto; + transition: background-color 0.2s ease; +} + +/* Der Rahmen für das Icon */ +.res-box { + background: transparent; + border: 1px solid var(--color-res-border); + border-radius: 6px; + width: 45px; + height: 45px; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + pointer-events: none; + transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease; +} + +/* Hover-Effekt anpassen */ +.res-col:hover .res-box { + border-color: var(--color-cyan-bright); + box-shadow: 0 0 10px rgba(0, 240, 255, 0.4); + background-color: rgba(0, 240, 255, 0.15); +} + +.res-val { + font-size: 13px; + color: var(--color-text-main); + font-weight: bold; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.8); +} + +.res-icon { + font-size: 24px; + color: var(--color-cyan-bright); + line-height: 1; +} + +.res-col.premium .res-box { + border-color: rgba(255, 0, 255, 0.4); +} +.res-col.premium .res-icon { + color: #ff00ff; +} +.res-col.premium:hover .res-box { + border-color: #ff00ff; + box-shadow: 0 0 10px rgba(255, 0, 255, 0.5); + background-color: rgba(255, 0, 255, 0.15); +} + +.res-divider { + /*width: 1px;*/ + height: 60px; + background: var(--color-cyan-dark); + opacity: 0.3; + margin: 0 5px; +} + +/* ========================================================================== + SIDE-MENU (Linke Navigation) + ========================================================================== */ +#side-menu-container { + position: absolute; + top: 160px; + left: 20px; + width: 210px; + bottom: 60px; + overflow-y: scroll; + overflow-x: hidden; + display: flex; + flex-direction: column; + gap: 15px; + pointer-events: auto; + z-index: 20; + padding-right: 15px; + box-sizing: border-box; + scrollbar-gutter: stable; +} + +/* Der einzelne, klickbare Wrapper für einen Menüpunkt */ +.menu-item { + position: relative; + width: 200px; + height: 30px; + flex-shrink: 0; + display: flex; + align-items: center; + padding-left: 70px; + cursor: pointer; + box-sizing: border-box; + background: transparent; +} + +/* Der Text innerhalb des Menüpunkts */ +.menu-text { + color: var(--color-text-main); + font-size: 14px; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + transition: color 0.2s ease, text-shadow 0.2s ease; +} + +/* Schöner Hover-Effekt: Text leuchtet in unserem Cyan auf */ +.menu-item:hover .menu-text { + color: var(--color-text-main); + text-shadow: none; +} + +/* ========================================================================== + PLANETEN-LIMIT (Zähler über der rechten Sidebar) + ========================================================================== */ +#planet-limit-container { + position: absolute; + top: 100px; + right: 20px; + width: 215px; + height: 45px; + display: flex; + align-items: center; + justify-content: center; + z-index: 20; + /* Da es ein reines Info-Element ist, deaktivieren wir die Klicks */ + pointer-events: none; +} + +.planet-limit-text { + color: var(--color-text-main); + font-size: 13px; + font-weight: bold; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + /* Ein kleiner Abstand zwischen Buchstaben (Letter-Spacing) lässt + Sci-Fi UIs oft etwas hochwertiger wirken */ + letter-spacing: 0.5px; +} + +#val_planet_count { + color: var(--color-cyan-bright); /* Aktuelle Planetenanzahl hervorheben */ +} + +#val_planet_max { + color: var(--color-text-inactive); /* Das Limit etwas abdunkeln */ +} + +/* ========================================================================== + RIGHT-SIDEBAR (Rechte Planeten-Navigation) + ========================================================================== */ +#right-sidebar-container { + position: absolute; + top: 160px; + right: 20px; + width: 215px; + + bottom: 60px; + overflow-y: scroll; + overflow-x: hidden; + display: flex; + flex-direction: column; + gap: 25px; + pointer-events: auto; + z-index: 20; + padding-left: 5px; + padding-right: 30px; + + box-sizing: border-box; + scrollbar-gutter: stable; +} + +/* ========================================================================== + PLANETEN-EINTRÄGE (70/30 HTML-Struktur) + ========================================================================== */ +.planet-item { + position: relative; + width: 200px; + height: 90px; + flex-shrink: 0; + /* Wir nutzen jetzt eine Reihe (Row), um die Bereiche nebeneinander zu legen */ + display: flex; + flex-direction: row; + align-items: stretch; /* Beide Bereiche füllen die volle Höhe von 90px aus */ + justify-content: flex-start; + box-sizing: border-box; + background: transparent; +} + +/* Der 70% Hauptbereich für den Planeten */ +.planet-click-area { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 6px; + box-sizing: border-box; + cursor: pointer; +} + +/* Der 30% Nebenbereich für den Mond */ +.moon-click-area { + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + /* Standardmäßig kein Pointer, da die Box leer sein könnte */ + cursor: default; +} + +/* Trennlinie und Klick-Cursor NUR anzeigen, wenn auch wirklich ein Mond da ist */ +.moon-click-area.has-moon { + cursor: pointer; + border-left: 1px solid rgba(0, 240, 255, 0.1); +} + +/* HTML-Anker für PixiJS */ +.planet-icon-anchor { + width: 30px; + height: 30px; +} + +.moon-icon-anchor { + width: 16px; + height: 16px; + z-index: 25; + border-radius: 50%; + transition: transform 0.2s ease; +} + +/* Hover-Effekte skalieren das Icon, wenn der Spieler im 30%-Feld ist */ +.moon-click-area:hover .moon-icon-anchor { + transform: scale(1.25); +} + +.planet-text-wrapper { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; +} + +.planet-name { + color: var(--color-text-main); + font-size: 14px; + font-weight: bold; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + transition: color 0.2s ease, text-shadow 0.2s ease; +} + +.planet-coords { + color: var(--color-text-inactive); + font-size: 11px; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.8); + transition: color 0.2s ease; +} + +/* ========================================================================== + SCROLLBAR-STYLING FÜR WEBKIT (Chrome, Safari, Edge) + ========================================================================== */ +/* Definiert die Breite der Scrollbar für beide Menüs */ +#side-menu-container::-webkit-scrollbar, +#right-sidebar-container::-webkit-scrollbar { + width: 6px; +} + +/* Die sichtbare "Spur" (Track), auf der der Scrollbalken läuft */ +#side-menu-container::-webkit-scrollbar-track, +#right-sidebar-container::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.2); + border-radius: 4px; +} + +/* Der sichtbare, greifbare Teil des Scrollbalkens (Thumb) */ +#side-menu-container::-webkit-scrollbar-thumb, +#right-sidebar-container::-webkit-scrollbar-thumb { + background: var(--color-cyan-dark); + border-radius: 4px; +} + +/* Hover-Effekt: Der Anfasser leuchtet im helleren Cyan auf */ +#side-menu-container::-webkit-scrollbar-thumb:hover, +#right-sidebar-container::-webkit-scrollbar-thumb:hover { + background: var(--color-cyan-bright); +} + +/* ========================================================================== + FOOTER + ========================================================================== */ +#game-footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 40px; + background: var(--color-panel-bg); + border-top: 1px solid var(--color-cyan-dark); + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 40px; + box-sizing: border-box; + color: var(--color-text-inactive); + font-size: 12px; +} + +.footer-left { flex: 1; text-align: left; } +.footer-center { flex: 1; text-align: center; } +.footer-right { flex: 1; text-align: right; } + +#game-footer a { + color: var(--color-text-inactive); + text-decoration: none; + transition: color 0.2s ease, text-shadow 0.2s ease; +} + +#game-footer a:hover { + color: var(--color-cyan-bright); + text-shadow: 0 0 5px var(--color-cyan-bright); +} + diff --git a/dev/sector-dev/sector-frontend/src/css/layout.css b/dev/sector-dev/sector-frontend/src/css/layout.css new file mode 100644 index 0000000..a13169f --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/css/layout.css @@ -0,0 +1,65 @@ +/* + * Beinhaltet das absolute Grundgerüst der Sektor-Seite. + * Reset-Regeln und die Positionierung der Haupt-Container (Z-Index Ebenen). + * Dies stellt sicher, dass das UI immer über dem PixiJS-Canvas liegt. + */ + +body, html { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: var(--color-bg-page); + font-family: var(--font-ui); + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; + position: fixed; + overscroll-behavior: none; +} + +#game-wrapper { + position: relative; + width: 100%; + height: 100%; +} + +/* Der Container für den PixiJS-Hintergrund und die Spielwelt */ +#pixi-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 0; +} + +/* Die UI-Ebene liegt über dem Pixi-Canvas */ +#ui-layer { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10; + pointer-events: none; +} + +/* * Alle interaktiven HUD-Elemente müssen pointer-events wieder aktivieren, + * sonst können wir keine Links klicken oder Hover-Effekte auslösen. + */ +#sector-top-bar, +#resource-header, +#game-footer { + pointer-events: auto; +} + +/* Verhindert den unsichtbaren Scroll-Abstand (Baseline-Gap) bei Canvas-Elementen */ +#pixi-container canvas { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/css/variables.css b/dev/sector-dev/sector-frontend/src/css/variables.css new file mode 100644 index 0000000..5e698d2 --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/css/variables.css @@ -0,0 +1,34 @@ +/* + * Globale Variablen für das Sektor-Frontend. + * Wir nutzen eine temporäre Standard-Schriftart für das UI und die bekannte Logo-Font. + */ + +@font-face { + font-family: 'UI Font'; + src: url('../assets/fonts/Oswald-Regular.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'Logo Font'; + src: url('../assets/fonts/Quantico-Bold.ttf') format('truetype'); + font-weight: normal; + font-style: normal; +} + +:root { + --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + --font-ui: 'UI Font', sans-serif; + --font-logo: 'Logo Font', sans-serif; + --color-bg-page: #000000; + --color-panel-bg: rgba(11, 25, 44, 0.85); + --color-text-main: #ffffff; + --color-text-inactive: rgba(255, 255, 255, 0.5); + --color-cyan-bright: #00f0ff; + --color-cyan-dark: #00a0aa; + --color-green-bright: #00ff00; + --color-error: #ff4444; + --color-res-border: rgba(0, 240, 255, 0.3); + --color-res-bg: rgba(0, 0, 0, 0.6); +} \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/main.js b/dev/sector-dev/sector-frontend/src/main.js new file mode 100644 index 0000000..2239010 --- /dev/null +++ b/dev/sector-dev/sector-frontend/src/main.js @@ -0,0 +1,1066 @@ +import { Application, Assets, Sprite, Container, Text, Graphics, NineSliceSprite } from 'pixi.js'; +let iconSheet = null; +let frameSheet = null; +let background = null; +let logoContainer = null; +let pixiIcons = {}; +let pixiMenuItems = {}; +let pixiMenuContainer = null; +let pixiMenuMask = null; +let pixiPlanetItems = {}; +let pixiPlanetIcons = {}; +let pixiMoonIcons = {}; +let pixiPlanetContainer = null; +let pixiPlanetMask = null; +let pixiPlanetLimitContainer = null; + +// ============================================================================ +// FORMATIERUNGS-LOGIK +// ============================================================================ + +/** + * Formatiert Ressourcen-Werte nach unseren Vorgaben: + * - Unter 10.000.000: Normale Darstellung mit Tausendertrennzeichen + * - Ab 10.000.000: Abgekürzte Darstellung (z.B. 10,5 Mio) + * - Ab 1.000.000.000: Abgekürzte Darstellung (z.B. 1,2 Mrd) + * * @param {number} value - Der rohe Zahlenwert aus der Datenbank/Engine + * @returns {string} - Der fertig formatierte String für das HTML-HUD + */ +export function formatResourceNumber(value) { + if (value === undefined || value === null || isNaN(value)) { + return '0'; + } + + if (value < 10000000) { + return value.toLocaleString('de-DE'); + } else if (value >= 1000000000) { + const formatted = (value / 1000000000).toFixed(1); + return `${formatted.replace('.', ',')} Mrd`; + } else { + const formatted = (value / 1000000).toFixed(1); + return `${formatted.replace('.', ',')} Mio`; + } +} + + +/** + * Formatiert Zahlen exakt (ohne Abkürzungen wie "Mio"), + * aber mit deutschen Tausendertrennzeichen für die Tooltips. + */ +export function formatExactNumber(value) { + if (value === undefined || value === null || isNaN(value)) return '0'; + return value.toLocaleString('de-DE'); +} + +// ============================================================================ +// MENÜ-KONFIGURATION +// ============================================================================ + +/** + * Das datengetriebene Array für unsere linke Navigationsleiste. + * Wir haben die Liste optimiert: Kernfunktionen nutzen Tabs, + * während oft genutzte Features (Galaxie, Netzwerk) als Schnellzugriff bleiben. + * * Eigenschaften: + * - id: Eindeutige HTML-ID für die PixiJS-Synchronisation + * - label: Der angezeigte Text im UI + * - unlocked: Steuert die Sichtbarkeit im Menü + * - actionId: Der Identifier für den Klick-Event-Listener + */ +const menuConfig = [ + { + id: 'menu_btn_dashboard', + label: 'Dashboard', + unlocked: true, + actionId: 'view_dashboard' + }, + { + id: 'menu_btn_communication', + label: 'Kommunikation', + // Beinhaltet später Tabs: Nachrichten, Chat + unlocked: true, + actionId: 'view_communication' + }, + { + id: 'menu_btn_infrastructure', + label: 'Infrastruktur', + // Beinhaltet später Tabs: Verwaltung, Produktion, Zivile Gebäude, Anlagen + unlocked: true, + actionId: 'view_infrastructure' + }, + { + id: 'menu_btn_military', + label: 'Militär', + // Beinhaltet NUR Bau-Aspekte: Schiffswerft (Flotte bauen), Verteidigung (Anlagen bauen) + unlocked: true, + actionId: 'view_military' + }, + { + id: 'menu_btn_research', + label: 'Forschung', + // Beinhaltet später Tabs: Lokale Forschung, Globale Forschung + unlocked: true, + actionId: 'view_research' + }, + { + id: 'menu_btn_dispatch', + label: 'Flotte versenden', + // Beinhaltet den aktiven Flottenversand: Transporte, Angriffe, Stationierungen + // und Einsätze wie die "Lokale Erkundung" + unlocked: true, + actionId: 'view_dispatch' + }, + { + id: 'menu_btn_galaxy', + label: 'Galaxie', + // Direkter Absprung auf die Sternenkarte + unlocked: true, + actionId: 'view_galaxy' + }, + { + id: 'menu_btn_alliance', + label: 'Allianz', + // Direkter Zugriff auf die Allianz-Verwaltung + unlocked: true, + actionId: 'view_alliance' + }, + { + id: 'menu_btn_friends', + label: 'Freunde', + unlocked: true, + actionId: 'view_friends' + }, + { + id: 'menu_btn_highscore', + label: 'Highscore', + unlocked: true, + actionId: 'view_highscore' + }, + { + id: 'menu_btn_search', + label: 'Suche', + unlocked: true, + actionId: 'view_search' + }, + { + id: 'menu_btn_void_gate', + label: 'Void Gate', + // Zugang zu PvE und Händler-Tauschbörse. + // Kann z.B. false sein, bis eine bestimmte Forschung abgeschlossen ist. + unlocked: true, + actionId: 'view_void_gate' + }, + { + id: 'menu_btn_shop', + label: 'Shop', + unlocked: true, + actionId: 'view_shop' + } +]; + +// ============================================================================ +// PLANETEN-KONFIGURATION (Dummy-Daten) +// ============================================================================ + +/** + * Das aktualisierte datengetriebene Array für unsere Planetenleiste. + * Neu: Die "Running Gag" Sektornamen sowie Flags für Monde und Icon-Farben. + * + * Eigenschaften: + * - id: Eindeutige HTML-ID für die PixiJS-Synchronisation + * - name: Der Anzeigename der Welt (Alpha, Beta, etc.) + * - coords: Die Koordinaten + * - isActive: Boolean; markiert den aktuell ausgewählten Planeten + * - hasMoon: Boolean; steuert, ob das kleine Mond-Icon gerendert werden soll + * - planetColor: Hex-Wert; damit färben wir später das Planet-Icon (tint) dynamisch ein + */ +const planetConfig = [ + { + id: 'planet_btn_alpha', + name: 'Alpha', + coords: '1:15:6', + isActive: true, + hasMoon: true, + planetColor: 0x40a0b0 // Dezentere Cyan-Variante + }, + { + id: 'planet_btn_beta', + name: 'Beta', + coords: '1:15:8', + isActive: false, + hasMoon: false, + planetColor: 0xc08040 // Dezentere Orange/Amber-Variante + }, + { + id: 'planet_btn_gamma', + name: 'Gamma', + coords: '1:16:7', + isActive: false, + hasMoon: true, + planetColor: 0x40a050 // Dezentere Salbei-Grün-Variante + }, + { + id: 'planet_btn_delta', + name: 'Delta', + coords: '1:16:8', + isActive: false, + hasMoon: false, + planetColor: 0xa050a0 // Dezentere Violett-Variante + }, + { + id: 'planet_btn_epsilon', + name: 'Epsilon', + coords: '1:16:9', + isActive: false, + hasMoon: false, + planetColor: 0xc08040 // Dezentere Orange/Amber-Variante + }, + { + id: 'planet_btn_zeta', + name: 'Zeta', + coords: '1:17:10', + isActive: false, + hasMoon: true, + planetColor: 0x40a050 // Dezentere Salbei-Grün-Variante + }, + { + id: 'planet_btn_eta', + name: 'Eta', + coords: '1:17:12', + isActive: false, + hasMoon: false, + planetColor: 0xa050a0 // Dezentere Violett-Variante + }, + { + id: 'planet_btn_theta', + name: 'Theta', + coords: '1:20:4', + isActive: false, + hasMoon: false, + planetColor: 0xc08040 // Dezentere Orange/Amber-Variante + }, + { + id: 'planet_btn_iota', + name: 'Iota', + coords: '1:20:10', + isActive: false, + hasMoon: true, + planetColor: 0x40a050 // Dezentere Salbei-Grün-Variante + }, + { + id: 'planet_btn_kappa', + name: 'Kappa', + coords: '1:22:8', + isActive: false, + hasMoon: false, + planetColor: 0xa050a0 // Dezentere Violett-Variante + } +]; + +/** + * Liest das menuConfig-Array aus und baut die HTML-Struktur für die linke Navigation. + * Nur Einträge, die 'unlocked: true' haben, werden gerendert. + * * Jeder Menüpunkt bekommt: + * 1. Die exakte ID aus der Config (damit PixiJS später weiß, wohin die Grafik muss). + * 2. Ein data-Attribut für die auszuführende Aktion beim Klick. + * 3. Ein Span-Element für den formatierten Text. + */ +function renderSideMenu() { + const container = document.getElementById('side-menu-container'); + + if (!container) return; + container.innerHTML = ''; + + menuConfig.forEach(item => { + if (item.unlocked) { + + const menuItem = document.createElement('div'); + menuItem.className = 'menu-item'; + menuItem.id = item.id; + menuItem.dataset.action = item.actionId; + + const textSpan = document.createElement('span'); + textSpan.className = 'menu-text'; + textSpan.textContent = item.label; + + menuItem.appendChild(textSpan); + + // Klick-Logik + menuItem.addEventListener('click', () => { + console.log(`[Menü] Klick auf: ${item.label} (Action: ${item.actionId})`); + }); + + // NEU: Hover-In Logik (Hintergrund leuchtet auf) + menuItem.addEventListener('mouseenter', () => { + if (pixiMenuItems[item.id] && pixiMenuItems[item.id].bgSprite) { + // Wir wechseln zu einem helleren Cyan und machen ihn etwas deckender + pixiMenuItems[item.id].bgSprite.tint = 0x00f0ff; + pixiMenuItems[item.id].bgSprite.alpha = 0.9; + } + }); + + // NEU: Hover-Out Logik (Hintergrund zurück auf Standard) + menuItem.addEventListener('mouseleave', () => { + if (pixiMenuItems[item.id] && pixiMenuItems[item.id].bgSprite) { + // Zurück zum dunkleren Cyan und weniger Deckkraft + pixiMenuItems[item.id].bgSprite.tint = 0x00a0aa; + pixiMenuItems[item.id].bgSprite.alpha = 0.6; + } + }); + + container.appendChild(menuItem); + } + }); +} + +// ============================================================================ +// RECHTES MENÜ (PLANETEN-LISTE) RENDER-LOGIK +// ============================================================================ + +/** + * Baut die HTML-Struktur auf. Neues Layout: Strikter 70/30 Split für ALLE Einträge. + * Linke Seite (70%): Planeten-Icon, Name, Koordinaten. + * Rechte Seite (30%): Mond-Icon (falls vorhanden) oder leerer Platzhalter. + * Dadurch bleiben alle Planeten vertikal perfekt in einer Linie. + */ +function renderPlanetMenu() { + const container = document.getElementById('right-sidebar-container'); + if (!container) return; + + container.innerHTML = ''; + + planetConfig.forEach(planet => { + // Haupt-Wrapper (Flex-Row) + const planetItem = document.createElement('div'); + planetItem.className = 'planet-item'; + planetItem.id = planet.id; + + // --- LINKE SEITE: PLANETEN-BEREICH (IMMER 70%) --- + const planetArea = document.createElement('div'); + planetArea.className = 'planet-click-area'; + planetArea.id = `planet_area_${planet.id}`; + + // ZWINGEND: Immer 70% Breite, damit die Zentrierung für alle Welten identisch ist + planetArea.style.width = '70%'; + + // HTML-Anker für PixiJS Planeten-Icon + const planetAnchor = document.createElement('div'); + planetAnchor.className = 'planet-icon-anchor'; + planetAnchor.id = `planet_anchor_${planet.id}`; + + // Textelemente + const textWrapper = document.createElement('div'); + textWrapper.className = 'planet-text-wrapper'; + + const nameSpan = document.createElement('span'); + nameSpan.className = 'planet-name'; + nameSpan.textContent = planet.name; + + const coordsSpan = document.createElement('span'); + coordsSpan.className = 'planet-coords'; + coordsSpan.textContent = `[${planet.coords}]`; + + textWrapper.appendChild(nameSpan); + textWrapper.appendChild(coordsSpan); + + planetArea.appendChild(planetAnchor); + planetArea.appendChild(textWrapper); + + // Klick-Event für den Planeten + planetArea.addEventListener('click', () => { + console.log(`[Planeten-Bereich] Klick auf Planet: ${planet.name}`); + }); + + planetItem.appendChild(planetArea); + + // --- RECHTE SEITE: MOND-BEREICH (IMMER 30%) --- + const moonArea = document.createElement('div'); + moonArea.className = 'moon-click-area'; + moonArea.id = `moon_area_${planet.id}`; + + // ZWINGEND: Immer 30% Breite als fester Platzhalter + moonArea.style.width = '30%'; + + // Nur wenn ein Mond existiert, fügen wir den Inhalt und die Klick-Logik hinzu + if (planet.hasMoon) { + // Eine CSS-Klasse hinzufügen, damit wir z.B. den Rahmen nur hier anzeigen + moonArea.classList.add('has-moon'); + + // HTML-Anker für das PixiJS Mond-Icon + const moonAnchor = document.createElement('div'); + moonAnchor.className = 'moon-icon-anchor'; + moonAnchor.id = `moon_anchor_${planet.id}`; + + moonArea.appendChild(moonAnchor); + + // Klick-Event für den Mond + moonArea.addEventListener('click', (e) => { + e.stopPropagation(); + console.log(`[Mond-Bereich] Klick auf Mond von: ${planet.name}`); + }); + } + + planetItem.appendChild(moonArea); + + // --- GEMEINSAME HOVER-LOGIK (Für den PixiJS-Rahmen) --- + // Wir legen das Hover-Event jetzt auf das gesamte Item (100%), + // damit der PixiJS-Hintergrund für die ganze Zeile aufleuchtet. + planetItem.addEventListener('mouseenter', () => { + if (pixiPlanetItems[planet.id]) { + pixiPlanetItems[planet.id].alpha = 0.6; + } + }); + + planetItem.addEventListener('mouseleave', () => { + if (pixiPlanetItems[planet.id]) { + pixiPlanetItems[planet.id].alpha = planet.isActive ? 0.45 : 0; + } + }); + + container.appendChild(planetItem); + }); +} + +// ============================================================================ +// HUD-UPDATE-LOGIK +// ============================================================================ + +/** + * Sucht die passenden HTML-Elemente anhand ihrer IDs und schreibt + * die formatierten Werte aus einem Daten-Objekt hinein. + * * @param {Object} data - Das Objekt mit den aktuellen Sektor-Daten + */ +export function updateResourceUI(data) { + // Aktualisiert Wert, Tooltip und prüft auf Lager-Überlauf + const updateMainRes = (idKey, name, val, cap) => { + const valEl = document.getElementById(`val_${idKey}`); + const wrapperEl = document.getElementById(`wrapper_${idKey}`); + + // Gekürzte Zahl im UI anzeigen (z.B. 14,5 Mio) + if (valEl) valEl.textContent = formatResourceNumber(val); + + // Tooltip mit exakten Zahlen generieren + // Fallback auf 0, falls noch keine Kapazität vom Backend geliefert wurde + const safeCap = cap || 0; + const tooltipText = `${name}\nMenge: ${formatExactNumber(val)}\nLagerkapazität: ${formatExactNumber(safeCap)}`; + if (wrapperEl) wrapperEl.setAttribute('title', tooltipText); + + // Farbe prüfen: Rot, wenn Menge die Kapazität übersteigt + if (valEl) { + if (val >= safeCap) { + valEl.style.color = 'var(--color-error)'; + } else { + valEl.style.color = 'var(--color-text-main)'; + } + } + }; + + // Aufruf der Hilfsfunktion für die 4 Hauptressourcen + updateMainRes('res_primary', 'Titanium', data.res_primary, data.cap_primary); + updateMainRes('res_secondary', 'Silizium', data.res_secondary, data.cap_secondary); + updateMainRes('res_fuel_base', 'Deuterium', data.res_fuel_base, data.cap_fuel_base); + updateMainRes('res_fuel_adv', 'Tritium', data.res_fuel_adv, data.cap_fuel_adv); + + // --- Energie --- + const energyEl = document.getElementById('val_energy'); + if (energyEl) { + energyEl.textContent = formatResourceNumber(data.energy); + // Rot färben, wenn wir im Minus sind + if (data.energy < 0) { + energyEl.style.color = 'var(--color-error)'; + } else { + energyEl.style.color = 'var(--color-text-main)'; + } + } + + // --- Bevölkerung & Zufriedenheit (Aggregiert) --- + // Gesamtsumme berechnen + const popTotal = (data.pop_idle || 0) + (data.pop_work || 0) + (data.pop_injured || 0); + document.getElementById('val_pop_total').textContent = formatResourceNumber(popTotal); + + // Tooltip-String aufbauen + const popTooltip = `Bevölkerung Details:\nIdle: ${formatResourceNumber(data.pop_idle)}\nArbeitend: ${formatResourceNumber(data.pop_work)}\nVerletzt: ${formatResourceNumber(data.pop_injured)}`; + document.getElementById('wrapper_pop').setAttribute('title', popTooltip); + + // Zufriedenheit verarbeiten + const happiness = data.pop_happiness !== undefined ? data.pop_happiness : 100; + document.getElementById('val_pop_happiness').textContent = `${happiness}%`; + + // Dynamische Emote-Logik basierend auf deinen Vorgaben + let happyIcon = '😊'; // Standard-Wert + if (happiness <= 20) { + happyIcon = '😠'; // Sauer + } else if (happiness <= 40) { + happyIcon = '😢'; // Weinend + } else if (happiness <= 60) { + happyIcon = '😐'; // Neutral + } else if (happiness <= 80) { + happyIcon = '🙂'; // Leicht lächelnd + } else if (happiness <= 100) { + happyIcon = '😊'; // Glücklich + } else { + happyIcon = '😍'; // Herzen in den Augen (> 100) + } + document.getElementById('icon_happiness').textContent = happyIcon; + + // --- Nahrung (Aggregiert) --- + // Gesamtsumme berechnen + const foodTotal = (data.res_food_base || 0) + (data.res_food_adv || 0); + document.getElementById('val_res_food_total').textContent = formatResourceNumber(foodTotal); + + // Tooltip-String aufbauen + const foodTooltip = `Nahrung Details:\nGrundnahrung: ${formatResourceNumber(data.res_food_base)}\nVerarbeitet: ${formatResourceNumber(data.res_food_adv)}`; + document.getElementById('wrapper_food').setAttribute('title', foodTooltip); + + // --- Premium-Währung (Void Kristalle) --- + // Wir zeigen die Gesamtsumme im UI an + document.getElementById('val_res_premium').textContent = formatResourceNumber(data.res_premium); + + // Tooltip-String für die Aufschlüsselung (Global vs Lokal) aufbauen + const premiumTooltip = `Void Kristalle:\nGlobal: ${formatResourceNumber(data.res_premium_global)}\nLokal: ${formatResourceNumber(data.res_premium_local)}`; + document.getElementById('wrapper_premium').setAttribute('title', premiumTooltip); +} + +// ============================================================================ +// PIXI-ENGINE & RESIZE LOGIK +// ============================================================================ + +/** + * Übernimmt die Skalierungslogik für PixiJS. + * Wird jedes Mal aufgerufen, wenn der Spieler das Browserfenster vergrößert/verkleinert. + * @param {Application} app - Die laufende PixiJS Instanz + */ +function setupResize(app) { + function resize() { + const screenWidth = window.innerWidth; + const screenHeight = window.innerHeight; + + // --- Hintergrund responsiv anpassen (Cover-Effekt) --- + if (background && background.texture) { + const scaleX = screenWidth / background.texture.width; + const scaleY = screenHeight / background.texture.height; + + const scale = Math.max(scaleX, scaleY); + background.scale.set(scale); + + background.x = (screenWidth - background.width) / 2; + background.y = (screenHeight - background.height) / 2; + } + + // --- Logo positionieren --- + if (logoContainer) { + logoContainer.position.set(150, 90); + } + + // --- Menü-Maske dynamisch anpassen --- + if (pixiMenuMask) { + pixiMenuMask.clear(); + + // Die Koordinaten entsprechen exakt unserem CSS (#side-menu-container) + const maskX = 20; + const maskY = 160; + const maskWidth = 220; + + // Die Höhe berechnet sich aus: Fensterhöhe MINUS Top-Abstand (160) MINUS Bottom-Abstand (60) + const maskHeight = screenHeight - 160 - 60; + + pixiMenuMask.rect(maskX, maskY, maskWidth, maskHeight); + pixiMenuMask.fill(0xffffff); + } + + // --- Rechte Menü-Maske dynamisch anpassen --- + if (pixiPlanetMask) { + pixiPlanetMask.clear(); + + // Die Parameter orientieren sich an unserem CSS für #right-sidebar-container + const maskWidth = 235; + // X-Koordinate: Fensterbreite minus Containerbreite minus den rechten Abstand (right: 20px) + const maskX = screenWidth - maskWidth - 20; + const maskY = 160; // Entspricht top: 160px + + // Die Höhe berechnet sich aus: Fensterhöhe MINUS Top-Abstand (160) MINUS Bottom-Abstand (60) + const maskHeight = screenHeight - 160 - 60; + + // Maske zeichnen + pixiPlanetMask.rect(maskX, maskY, maskWidth, maskHeight); + pixiPlanetMask.fill(0xffffff); + } + } + + app.renderer.on('resize', resize); + resize(); +} + +// ============================================================================ +// INITIALISIERUNG +// ============================================================================ + +/** + * Startet die PixiJS-Engine, lädt die Assets und baut die Basis-Szene auf. + */ +async function initSector() { + const app = new Application(); + + await app.init({ + resizeTo: window, + backgroundAlpha: 0, + antialias: true, + resolution: window.devicePixelRatio || 1, + autoDensity: true + }); + + document.getElementById('pixi-container').appendChild(app.canvas); + + // --- Asset Loading --- + try { + console.log("[PixiJS] Lade Assets und Schriftarten..."); + await document.fonts.load('16px "Logo Font"'); + await document.fonts.load('16px "UI Font"'); + + // Wir laden nun auch explizit den Hintergrund für den Sektor + const assetsToLoad = { + bg: 'src/assets/backgrounds/Background_D.png', + icons: 'src/assets/icons.json', + frames: 'src/assets/frames.json' + }; + + const bgTexture = await Assets.load(assetsToLoad.bg); + iconSheet = await Assets.load(assetsToLoad.icons); + frameSheet = await Assets.load(assetsToLoad.frames); + + // --- Hintergrund rendern --- + background = new Sprite(bgTexture); + app.stage.addChild(background); + + // --- Logo rendern --- + logoContainer = new Container(); + + const ringTexture = frameSheet.textures['SPR_SciFiMenus_Ring_Medium_13']; + if (ringTexture) { + const logoRing = new Sprite(ringTexture); + logoRing.anchor.set(0.5); + logoRing.tint = 0x00f0ff; + logoRing.scale.set(0.12); + logoRing.alpha = 0.8; + logoContainer.addChild(logoRing); + } + + const logoText = new Text({ + text: 'Void-Genesis', + style: { + fontFamily: 'Logo Font', + fontSize: 33, + fill: 0x00f0ff, + letterSpacing: 6, + } + }); + logoText.anchor.set(0.5); + logoContainer.addChild(logoText); + + app.stage.addChild(logoContainer); + + // --- Ressourcen-Icons generieren --- + // Zuordnung: HTML-ID der Box -> Textur-Name im Sprite-Sheet + const iconMapping = { + 'box_primary': 'ICON_Titanium', + 'box_secondary': 'ICON_Silizium', + 'box_fuel_base': 'ICON_Deuterium', + 'box_fuel_adv': 'ICON_Tritium', + 'box_energy': 'ICON_Map_Lightning', + 'box_pop_total': 'ICON_SciFiMenus_Menu_Multiplayer_01_Clean', + 'box_food_total': 'ICON_SciFi_Status_Hunger', + 'box_premium': 'ICON_SM_Item_Crystal_03' + }; + + if (iconSheet) { + for (const boxId in iconMapping) { + const texName = iconMapping[boxId]; + if (iconSheet.textures[texName]) { + + const boxContainer = new Container(); + const bgGraphic = new Graphics(); + bgGraphic.roundRect(-22.5, -22.5, 45, 45, 6); + bgGraphic.fill({ color: 0x000000, alpha: 0.6 }); + boxContainer.addChild(bgGraphic); + const sprite = new Sprite(iconSheet.textures[texName]); + sprite.anchor.set(0.5); + + if (boxId == 'box_primary' || boxId == 'box_secondary' || boxId == 'box_fuel_base' || boxId == 'box_fuel_adv') { + sprite.scale.set(0.50); + const mask = new Graphics(); + mask.roundRect(-22.5, -22.5, 45, 45, 6); + mask.fill(0xffffff); + sprite.mask = mask; + boxContainer.addChild(mask); + } + else if (boxId == 'box_pop_total' || boxId == 'box_food_total') { + sprite.scale.set(0.15); + } + else if (boxId === 'box_energy') { + sprite.scale.set(0.15); + sprite.tint = 0xffff00; + } + else if (boxId === 'box_premium') { + sprite.scale.set(0.15); + sprite.tint = 0xff00ff; + } + else { + sprite.scale.set(0.12); // Fallback + } + + boxContainer.addChild(sprite); + + app.stage.addChild(boxContainer); + + pixiIcons[boxId] = boxContainer; + } else { + console.warn(`[PixiJS] Icon-Textur nicht gefunden: ${texName}`); + } + } + } + + // --- Absolute HTML/PixiJS Synchronisation (Ticker) --- + // Der Ticker läuft mit bis zu 60 FPS. Er garantiert, dass die PixiJS-Icons + // immer exakt den HTML-Rahmen folgen, egal ob Schriften nachladen + // oder Flexbox-Abstände sich dynamisch ändern. + app.ticker.add(() => { + for (const boxId in pixiIcons) { + const container = pixiIcons[boxId]; + const htmlBox = document.getElementById(boxId); + + if (htmlBox && container) { + const rect = htmlBox.getBoundingClientRect(); + container.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + + for (const menuId in pixiMenuItems) { + const container = pixiMenuItems[menuId]; + const htmlBox = document.getElementById(menuId); + + if (htmlBox && container) { + const rect = htmlBox.getBoundingClientRect(); + container.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + + // Synchronisation der Planeten-Box-Hintergründe + for (const planetId in pixiPlanetItems) { + const container = pixiPlanetItems[planetId]; + const htmlBox = document.getElementById(planetId); + + if (htmlBox && container) { + const rect = htmlBox.getBoundingClientRect(); + container.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + + // Synchronisation der Planeten-Icons auf ihren spezifischen Anker + for (const planetId in pixiPlanetIcons) { + const container = pixiPlanetIcons[planetId]; + const htmlAnchor = document.getElementById(`planet_anchor_${planetId}`); + + if (htmlAnchor && container) { + const rect = htmlAnchor.getBoundingClientRect(); + container.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + + // Synchronisation der Monde auf den separat verschobenen Mond-Anker + for (const planetId in pixiMoonIcons) { + const container = pixiMoonIcons[planetId]; + const htmlAnchor = document.getElementById(`moon_anchor_${planetId}`); + + if (htmlAnchor && container) { + const rect = htmlAnchor.getBoundingClientRect(); + container.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + + // Planeten-Limit Container an HTML heften + if (pixiPlanetLimitContainer) { + const limitHtmlBox = document.getElementById('planet-limit-container'); + if (limitHtmlBox) { + const rect = limitHtmlBox.getBoundingClientRect(); + pixiPlanetLimitContainer.position.set( + rect.left + (rect.width / 2), + rect.top + (rect.height / 2) + ); + } + } + }); + + console.log("[PixiJS] Assets erfolgreich geladen und gerendert!"); + } catch (error) { + console.error("[PixiJS] Fehler beim Laden der Assets:", error); + } + + renderSideMenu(); + renderPlanetMenu(); + + // ==================================================================== + // LINKE SEITENMENÜ GRAFIKEN (PIXIJS) + // ==================================================================== + + pixiMenuContainer = new Container(); + app.stage.addChild(pixiMenuContainer); + pixiMenuMask = new Graphics(); + app.stage.addChild(pixiMenuMask); + pixiMenuContainer.mask = pixiMenuMask; + + menuConfig.forEach(item => { + if (item.unlocked && frameSheet) { + const bgTexture = frameSheet.textures['SPR_SciFiMenus_Menu_Item_Background_07']; + const frameTexture = frameSheet.textures['SPR_SciFiMenus_Menu_Item_Selected_10']; + + if (bgTexture && frameTexture) { + const menuContainer = new Container(); + + const bgSprite = new NineSliceSprite({ + texture: bgTexture, + leftWidth: 120, + topHeight: 120, + rightWidth: 120, + bottomHeight: 120 + }); + + bgSprite.width = 150; + bgSprite.height = 30; + bgSprite.x = -50; + bgSprite.y = -15; + bgSprite.tint = 0x00a0aa; + bgSprite.alpha = 0.6; + + const frameSprite = new NineSliceSprite({ + texture: frameTexture, + leftWidth: 100, + topHeight: 120, + rightWidth: 140, + bottomHeight: 120 + }); + + frameSprite.width = 150; + frameSprite.height = 30; + frameSprite.x = -50; + frameSprite.y = -15; + frameSprite.tint = 0x00f0ff; + frameSprite.alpha = 1; + + menuContainer.bgSprite = bgSprite; + + menuContainer.addChild(bgSprite); + menuContainer.addChild(frameSprite); + + pixiMenuContainer.addChild(menuContainer); + pixiMenuItems[item.id] = menuContainer; + } + } + }); + + // ==================================================================== + // PLANETEN-LIMIT GRAFIK (PIXIJS) + // ==================================================================== + if (frameSheet) { + // Die von dir vorgegebenen Texturen laden + const limitBgTexture = frameSheet.textures['SPR_SciFiMenus_Button_Frame_01_Background']; + const limitFrameTexture = frameSheet.textures['SPR_SciFiMenus_Button_Frame_01']; + + if (limitBgTexture && limitFrameTexture) { + pixiPlanetLimitContainer = new Container(); + + // 1. Hintergrund + const limitBgSprite = new NineSliceSprite({ + texture: limitBgTexture, + leftWidth: 500, + topHeight: 100, + rightWidth: 500, + bottomHeight: 100 + }); + limitBgSprite.width = 165; + limitBgSprite.height = 45; + // Exakt um die Hälfte verschieben, da wir den Container auf die HTML-Mitte zentrieren + limitBgSprite.x = -85.5; + limitBgSprite.y = -22.5; + // Leicht abgedunkeltes Cyan für den Hintergrund + limitBgSprite.tint = 0x00a0aa; + limitBgSprite.alpha = 0.5; + + // 2. Rahmen (liegt über dem Hintergrund) + const limitFrameSprite = new NineSliceSprite({ + texture: limitFrameTexture, + leftWidth: 500, + topHeight: 100, + rightWidth: 500, + bottomHeight: 100 + }); + limitFrameSprite.width = 200; + limitFrameSprite.height = 45; + limitFrameSprite.x = -100; + limitFrameSprite.y = -22.5; + limitFrameSprite.alpha = 1.0; + + pixiPlanetLimitContainer.addChild(limitBgSprite); + pixiPlanetLimitContainer.addChild(limitFrameSprite); + + // WICHTIG: Direkt an app.stage hängen, NICHT in den scrollbaren Masken-Container! + app.stage.addChild(pixiPlanetLimitContainer); + } + } + + // ==================================================================== + // RECHTE SEITENMENÜ GRAFIKEN & ICONS (PIXIJS) + // ==================================================================== + + // NEU: Wir erstellen einen Haupt-Container für alle rechten PixiJS-Elemente + pixiPlanetContainer = new Container(); + app.stage.addChild(pixiPlanetContainer); + + // NEU: Wir erstellen die Maske, fügen sie der Stage hinzu und weisen sie dem Container zu + pixiPlanetMask = new Graphics(); + app.stage.addChild(pixiPlanetMask); + pixiPlanetContainer.mask = pixiPlanetMask; + + planetConfig.forEach(planet => { + if (frameSheet && iconSheet) { + + // --- 1. Hintergrund-Rahmen --- + const bgTexture = frameSheet.textures['SPR_SciFiMenus_Frame_Box_Small_10_Background']; + if (bgTexture) { + const bgContainer = new Container(); + + const bgSprite = new NineSliceSprite({ + texture: bgTexture, + leftWidth: 30, + topHeight: 30, + rightWidth: 30, + bottomHeight: 30 + }); + + bgSprite.width = 195; + bgSprite.height = 105; + bgSprite.x = -97.5; + bgSprite.y = -52.5; + bgSprite.tint = 0x00f0ff; + + bgContainer.addChild(bgSprite); + + // ÄNDERUNG: Statt app.stage packen wir es in unseren maskierten Container + pixiPlanetContainer.addChild(bgContainer); + + bgContainer.alpha = planet.isActive ? 0.45 : 0; + pixiPlanetItems[planet.id] = bgContainer; + } + + // --- 2. Haupt-Planet Icon --- + const planetTexture = iconSheet.textures['ICON_SciFiMenus_Menu_Planet_03_Clean']; + if (planetTexture) { + const planetContainer = new Container(); + const planetSprite = new Sprite(planetTexture); + + planetSprite.anchor.set(0.5); + planetSprite.scale.set(0.24); + planetSprite.tint = planet.planetColor; + planetSprite.alpha = 0.8; + + planetContainer.addChild(planetSprite); + + // ÄNDERUNG: In den maskierten Container packen + pixiPlanetContainer.addChild(planetContainer); + + pixiPlanetIcons[planet.id] = planetContainer; + } + + // --- 3. Mond Icon --- + const moonTexture = iconSheet.textures['ICON_SciFiMenus_Menu_Moon_01_Clean']; + if (planet.hasMoon && moonTexture) { + const moonContainer = new Container(); + const moonSprite = new Sprite(moonTexture); + + moonSprite.anchor.set(0.5); + moonSprite.scale.set(0.12); + moonSprite.alpha = 0.75; + + moonContainer.addChild(moonSprite); + + // ÄNDERUNG: In den maskierten Container packen + pixiPlanetContainer.addChild(moonContainer); + + pixiMoonIcons[planet.id] = moonContainer; + } + } + }); + + setupResize(app); + + // ======================================================================== + // LIVE-STATE & GAME-LOOP SIMULATION + // ======================================================================== + + // Wir lagern die Daten in ein reaktives Zustandsobjekt aus. + // Später wird dieses Objekt durch die echte Backend-API befüllt + // (z.B. über WebSockets oder Polling, ähnlich wie in der Lobby). + const sectorState = { + res_primary: 1000, cap_primary: 10000, + res_secondary: 500, cap_secondary: 10000, + res_fuel_base: 0,cap_fuel_base: 10000, + res_fuel_adv: 0, cap_fuel_adv: 10000, + + energy: 0, + + pop_idle: 500, + pop_work: 0, + pop_injured: 500, + pop_happiness: 50, + res_food_base: 10000, + res_food_adv: 0, + res_premium: 150, + res_premium_global: 100, + res_premium_local: 50 + }; + + updateResourceUI(sectorState); + + /** + * Hilfsfunktion für gedeckelte Ressourcen-Produktion. + * Erhöht den aktuellen Wert um 'amount', stoppt aber exakt am 'cap'. + * Ist der Wert bereits über dem Cap (z.B. durch Startwerte oder Boni), + * wird nichts abgezogen, aber die Produktion pausiert. + */ + function addResourceWithCap(currentValue, productionAmount, capacity) { + if (currentValue >= capacity) { + return currentValue; + } + + const newValue = currentValue + productionAmount; + + if (newValue > capacity) { + return capacity; + } + + return newValue; + } + + // --- Der simulierte Game-Loop --- + setInterval(() => { + sectorState.res_primary = addResourceWithCap(sectorState.res_primary, 15, sectorState.cap_primary); + sectorState.res_secondary = addResourceWithCap(sectorState.res_secondary, 5, sectorState.cap_secondary); + sectorState.res_food_base -= 10; + updateResourceUI(sectorState); + }, 1000); +} + +initSector(); \ No newline at end of file diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_01.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_01.png new file mode 100644 index 0000000..89d0139 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_01.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_Hexagons_01.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_Hexagons_01.png new file mode 100644 index 0000000..ab03f8c Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Background_Hexagons_01.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01.png new file mode 100644 index 0000000..9aa8a3f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01_Background.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01_Background.png new file mode 100644 index 0000000..66c877c Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Button_Frame_01_Background.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08.png new file mode 100644 index 0000000..9a031ab Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08_Background.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08_Background.png new file mode 100644 index 0000000..c883a1b Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_08_Background.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12.png new file mode 100644 index 0000000..ce8c5b1 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12_Background.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12_Background.png new file mode 100644 index 0000000..1cf76b0 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Large_12_Background.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Small_10_Background.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Small_10_Background.png new file mode 100644 index 0000000..12f0bcd Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Frame_Box_Small_10_Background.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Background_07.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Background_07.png new file mode 100644 index 0000000..065ba2f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Background_07.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_10.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_10.png new file mode 100644 index 0000000..37d4e66 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_10.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_19.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_19.png new file mode 100644 index 0000000..1b84ba9 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_19.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_20.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_20.png new file mode 100644 index 0000000..016000a Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Menu_Item_Selected_20.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Ring_Medium_13.png b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Ring_Medium_13.png new file mode 100644 index 0000000..87f929a Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/frames/SPR_SciFiMenus_Ring_Medium_13.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Deuterium.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Deuterium.png new file mode 100644 index 0000000..b6a8d19 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Deuterium.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Healing.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Healing.png new file mode 100644 index 0000000..3769171 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Healing.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Notes.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Notes.png new file mode 100644 index 0000000..f8af518 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Inventory_Notes.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Map_Lightning.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Map_Lightning.png new file mode 100644 index 0000000..0d9bd7e Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Map_Lightning.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SM_Item_Crystal_03.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SM_Item_Crystal_03.png new file mode 100644 index 0000000..5f3ef93 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SM_Item_Crystal_03.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Cancel_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Cancel_01_Clean.png new file mode 100644 index 0000000..79a135b Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Cancel_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_DNA_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_DNA_01_Clean.png new file mode 100644 index 0000000..e93b183 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_DNA_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Delete_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Delete_01_Clean.png new file mode 100644 index 0000000..440eeda Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Delete_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Lock_Closed_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Lock_Closed_01_Clean.png new file mode 100644 index 0000000..8d2fabe Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Lock_Closed_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Message_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Message_01_Clean.png new file mode 100644 index 0000000..5a29168 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Message_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Moon_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Moon_01_Clean.png new file mode 100644 index 0000000..d9248a8 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Moon_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Multiplayer_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Multiplayer_01_Clean.png new file mode 100644 index 0000000..e57513b Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Multiplayer_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Notification_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Notification_01_Clean.png new file mode 100644 index 0000000..94d8beb Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Notification_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_02_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_02_Clean.png new file mode 100644 index 0000000..52423a6 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_02_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_03_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_03_Clean.png new file mode 100644 index 0000000..9a56b9f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Planet_03_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Refresh_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Refresh_01_Clean.png new file mode 100644 index 0000000..86ccb9f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Refresh_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_02_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_02_Clean.png new file mode 100644 index 0000000..a294a3e Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_02_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_03_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_03_Clean.png new file mode 100644 index 0000000..5e2f906 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_03_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_04_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_04_Clean.png new file mode 100644 index 0000000..9c02e97 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_04_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_05_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_05_Clean.png new file mode 100644 index 0000000..becb79b Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Settings_05_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Shop_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Shop_01_Clean.png new file mode 100644 index 0000000..e946d12 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Shop_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Solo_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Solo_01_Clean.png new file mode 100644 index 0000000..05899a9 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Solo_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Star_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Star_01_Clean.png new file mode 100644 index 0000000..cbf643e Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Star_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Tick_01_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Tick_01_Clean.png new file mode 100644 index 0000000..d37a03f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Tick_01_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Warning_02_Clean.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Warning_02_Clean.png new file mode 100644 index 0000000..0087b6d Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFiMenus_Menu_Warning_02_Clean.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Inventory_Minerals.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Inventory_Minerals.png new file mode 100644 index 0000000..eed0ff8 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Inventory_Minerals.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Status_Hunger.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Status_Hunger.png new file mode 100644 index 0000000..4f1f7b2 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_SciFi_Status_Hunger.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Silizium.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Silizium.png new file mode 100644 index 0000000..959ffa0 Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Silizium.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Titanium.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Titanium.png new file mode 100644 index 0000000..1c0fb2f Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Titanium.png differ diff --git a/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Tritium.png b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Tritium.png new file mode 100644 index 0000000..9ed13ca Binary files /dev/null and b/dev/sector-dev/sector-frontend/src/raw-assets/icons/ICON_Tritium.png differ diff --git a/dev/sector-dev/sector-frontend/style.css b/dev/sector-dev/sector-frontend/style.css new file mode 100644 index 0000000..88e661c --- /dev/null +++ b/dev/sector-dev/sector-frontend/style.css @@ -0,0 +1,3 @@ +@import url('./src/css/layout.css'); +@import url('./src/css/variables.css'); +@import url('./src/css/hud.css'); diff --git a/dev/sector-dev/sector-frontend/vite.config.js b/dev/sector-dev/sector-frontend/vite.config.js new file mode 100644 index 0000000..f8ef544 --- /dev/null +++ b/dev/sector-dev/sector-frontend/vite.config.js @@ -0,0 +1,31 @@ +import { defineConfig } from 'vite'; + +export default defineConfig({ + server: { + // Erlaubt Vite, Verbindungen über diese spezifische Domain anzunehmen. + // Verhindert Blockaden, wenn wir hinter dem Nginx Proxy Manager arbeiten. + allowedHosts: [ + 'sector.void-genesis.de', + 'dev.void-genesis.de' + ], + // 'host: true' stellt sicher, dass Vite auf allen Netzwerk-Interfaces (0.0.0.0) lauscht. + // Das ist zwingend notwendig, damit wir aus dem Docker-Container heraus zugreifen können. + host: true, + }, + build: { + // ---------------------------------------------------------------------- + // EULA-Konformität: Base64-Zwang für alle Assets + // ---------------------------------------------------------------------- + // Wir setzen das Limit für das Inlining von Assets auf einen extrem hohen Wert. + // Dadurch zwingen wir Vite dazu, sämtliche importierten Grafiken (PixiJS Assets) + // als Base64-Strings direkt in die generierten JS/CSS-Dateien einzubetten. + // So liegen nach dem Build keine rohen Bilddateien mehr auf dem Server. + // ---------------------------------------------------------------------- + assetsInlineLimit: 100000000, + + // Wir deaktivieren das Generieren von Source Maps für den produktiven Build, + // da diese durch die Base64-Strings gigantisch groß werden würden und wir + // unsere Code-Struktur nicht nach außen freigeben wollen. + sourcemap: false, + } +}); \ No newline at end of file