/** * Dev-only smoke test: boots the game directly into the GameScene * (skipping the menu), so the flight scene can be screenshotted/checked * without clicking "New Game". * * python3 -m http.server 8080 * firefox --headless --screenshot shot.png \ * --window-size=1280,720 http://localhost:8080/dev/test-game.html * * Dev hooks (URL params, dev only — ignored by the game itself): * ?ship=, teleport the ship to a world position after boot * (screenshots of far-off states — e.g. the off-screen * compass arrows pointing back at the home world). * ?near= fly the ship to (edge-to-edge) from the first * system planet — screenshots the discovery moment * (rim ping + toast) with the world in view. * ?tethers=x,y,level;x,y,level add dev tethers (union-boundary tests) * ?homeLevel= set the home tether's level (bigger/smaller range) * ?seed= use a DETERMINISTIC dev galaxy (same seed ⇒ same * system, planets, asteroid clusters) — reproducible shots * ?report=1 paint console errors (or "SMOKE OK") on the canvas */ import Phaser from '../js/vendor/phaser.js'; import { config } from '../js/config/Config.js'; import { ConfigLoader } from '../js/config/ConfigLoader.js'; import { createGameConfig } from '../js/config/GameConfig.js'; import { GameScene } from '../js/scenes/GameScene.js'; const data = await ConfigLoader.load(); config.init(data); const gameConfig = createGameConfig(); const params = typeof location !== 'undefined' ? new URLSearchParams(location.search) : null; const shipParam = params ? params.get('ship') : null; const nearParam = params ? params.get('near') : null; const tethersParam = params ? params.get('tethers') : null; const homeLevelParam = params ? params.get('homeLevel') : null; const seedParam = params ? params.get('seed') : null; // Deterministic dev galaxy for reproducible screenshots (GameScene. // ensureGalaxy reads this when the registry is empty). if (seedParam && typeof globalThis !== 'undefined') globalThis.__ORBIT_DEV_SEED = seedParam; // Dev: capture console errors + uncaught exceptions for ?report=1. const __errors = []; if (typeof window !== 'undefined') { const origErr = console.error.bind(console); console.error = (...a) => { __errors.push(a.map(String).join(' ')); origErr(...a); }; window.addEventListener('error', (e) => __errors.push(String(e.message))); } gameConfig.scene = [GameScene]; const game = new Phaser.Game(gameConfig); window.game = game; console.info('smoke: game booted into GameScene'); if (shipParam) { const [sx, sy] = shipParam.split(',').map(Number); if (Number.isFinite(sx) && Number.isFinite(sy)) { setTimeout(() => { const s = game.scene.getScene('GameScene'); s.ship.setPosition(sx, sy); s.cameras.main.setScroll(sx - s.scale.width / 2, sy - s.scale.height / 2); console.info(`smoke: ship teleported to (${sx}, ${sy})`); }, 500); } } if (tethersParam || homeLevelParam) { setTimeout(() => { const s = game.scene.getScene('GameScene'); if (homeLevelParam) { const home = s.tetherField.tethers[0]; if (home) s.tetherField.setLevel(home.id, Number(homeLevelParam) || 1); } if (tethersParam) { tethersParam.split(';').forEach((triple, i) => { const [tx, ty, tl] = triple.split(',').map(Number); if (Number.isFinite(tx) && Number.isFinite(ty)) { s.tetherField.add('dev' + i, tx, ty, Number.isFinite(tl) ? tl : 1, 'dev'); } }); } console.info(`smoke: dev tethers ready (homeLevel=${homeLevelParam ?? '—'}, extra=${tethersParam ?? '—'})`); }, 600); } if (params && params.get('report') === '1') { // After boot, paint any captured console errors onto the canvas so a // headless screenshot shows whether the scene is healthy. setTimeout(() => { const s = game.scene.getScene('GameScene'); if (!s) return; const msg = __errors.length === 0 ? 'SMOKE OK — no console errors' : __errors.slice(0, 3).join('\n'); s.add.text(16, 690, msg, { fontFamily: 'monospace', fontSize: '12px', color: __errors.length === 0 ? '#7ce8a4' : '#ff2d6f', align: 'left', }).setOrigin(0, 1).setScrollFactor(0).setDepth(9000); }, 3000); } if (nearParam) { const px = Number(nearParam) || 400; setTimeout(() => { const s = game.scene.getScene('GameScene'); const p = s.systemPlanets[0]; if (!p) return; // Place the ship on the planet→origin axis, `px` (edge-to-edge) off // the rim — inside the discovery distance, with the world in view. const ang = Math.atan2(-p.y, -p.x); const sx = p.x + Math.cos(ang) * (p.radius + px); const sy = p.y + Math.sin(ang) * (p.radius + px); s.ship.setPosition(sx, sy); s.cameras.main.setScroll(sx - s.scale.width / 2, sy - s.scale.height / 2); console.info(`smoke: ship parked ${px}px off ${p.discoveryName}'s rim`); }, 500); }