diff --git a/assets/images/originals/ss-01-int-04.png b/assets/images/originals/ss-01-int-04.png new file mode 100644 index 0000000..969e8c5 Binary files /dev/null and b/assets/images/originals/ss-01-int-04.png differ diff --git a/dev/video-reopen.html b/dev/video-reopen.html new file mode 100644 index 0000000..f9db505 --- /dev/null +++ b/dev/video-reopen.html @@ -0,0 +1,17 @@ + + + + + + Orbit — video reopen regression (dev) + + + + +
+ + + diff --git a/dev/video-reopen.mjs b/dev/video-reopen.mjs new file mode 100644 index 0000000..dd28c4f --- /dev/null +++ b/dev/video-reopen.mjs @@ -0,0 +1,106 @@ +/** + * Dev-only: the EXACT player-reported flow against the real Research + * window — open the console, close it, open it again: the feed must be + * PLAYING every time it opens (it used to stay paused on reopen, because + * Phaser 4's video play() is a no-op after pause(); the window now + * resumes via video.resume()). + * + * node dev/server.mjs 8123 + * node dev/shot-firefox.mjs \ + * "http://127.0.0.1:8123/dev/video-reopen.html" \ + * "window.__VIDEO_REOPEN ? '1' : null" VIDEO_REOPEN.png 45000 + */ +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 errors = []; +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))); +window.addEventListener('unhandledrejection', (e) => errors.push(`rejection: ${e.reason}`)); + +const report = document.createElement('pre'); +report.id = 'report'; +report.style.cssText = + 'position:fixed;left:10px;top:10px;z-index:9999;margin:0;padding:10px 14px;font:13px/1.55 monospace;color:#eaf6ff;background:rgba(6,20,16,0.94);border:1px solid #1b3a5a;white-space:pre-wrap;max-width:60%;'; +document.body.appendChild(report); +const setReport = (lines) => { report.textContent = (Array.isArray(lines) ? lines : [lines]).join('\n'); }; +setReport('booting…'); + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +const done = (lines) => { + setReport(lines); + window.__VIDEO_REOPEN = { ready: true, lines, errors }; +}; + +const gameConfig = createGameConfig(); +gameConfig.scene = [GameScene]; // main.js does the same +const game = new Phaser.Game(gameConfig); +window.game = game; + +async function waitScene() { + for (let i = 0; i < 150; i++) { + const s = game.scene.getScene('GameScene'); + if (s && s.ship && s.researchWindow) return s; + await sleep(100); + } + throw new Error('GameScene never booted'); +} + +const results = []; +const line = (ok, tag, detail) => results.push(`${ok ? 'PASS' : 'FAIL'} ${tag} — ${detail}`); +const vstate = (w) => { + const el = w.video && w.video.video; + return el ? `state=${w.openState} video:${el.paused ? 'paused' : 'playing'} t=${(el.currentTime || 0).toFixed(2)}s` : 'NO SIGNAL'; +}; + +try { + const s = await waitScene(); + const w = s.researchWindow; + await sleep(800); // boot reveal settles + + // ── open #1 (deck RESEARCH button) ───────────────────────────────── + s.deckAction('research'); + await sleep(1500); + const el = w.video.video; + line(w.isOpen && el && !el.paused, 'open #1', vstate(w)); + + // ── close (the ✕ / deck toggle) ──────────────────────────────────── + w.close(); + await sleep(700); + line(!w.isOpen && el.paused, 'close', vstate(w)); + + // ── open #2 — the reported bug: the feed must play again ─────────── + s.deckAction('research'); + await sleep(1500); + const t2 = el.currentTime; + line(w.isOpen && !el.paused, 'open #2 (reopen — was stuck paused before the fix)', vstate(w)); + await sleep(900); + line(el.currentTime > t2, 'open #2 time advancing', `t=${t2.toFixed(2)}s → ${el.currentTime.toFixed(2)}s`); + + // ── close → open #3: repeated toggles keep working ───────────────── + w.close(); + await sleep(700); + line(el.paused, 'close #2', vstate(w)); + s.deckAction('research'); + await sleep(1500); + line(w.isOpen && !el.paused, 'open #3', vstate(w)); + + const allPass = results.every((r) => r.startsWith('PASS')); + const lines = [ + allPass ? 'VIDEO REOPEN (RESEARCH WINDOW) — ALL PASS' : 'VIDEO REOPEN (RESEARCH WINDOW) — FAILURES', + '─'.repeat(64), + ...results, + errors.length ? `errors:\n${errors.slice(0, 5).join('\n')}` : 'no console errors', + ]; + done(lines); +} catch (err) { + errors.push(`FATAL: ${err.message}`); + done(['VIDEO REOPEN — ERROR', String(err.message), ...errors.slice(0, 5)]); +} diff --git a/dev/video-replay.html b/dev/video-replay.html new file mode 100644 index 0000000..64b84cb --- /dev/null +++ b/dev/video-replay.html @@ -0,0 +1,20 @@ + + + + + + Orbit — video replay regression (dev) + + + + +
+ + + + + diff --git a/dev/video-replay.mjs b/dev/video-replay.mjs new file mode 100644 index 0000000..9b8448f --- /dev/null +++ b/dev/video-replay.mjs @@ -0,0 +1,167 @@ +/** + * Dev-only regression test: feed-window video play/pause/replay. + * + * Symptom under test (Build/Research/Map/Quests windows): open the + * window, close it, open it again — the feed stays PAUSED. + * + * Root cause lives in the vendored Phaser 4 Video object: play() only + * issues the native