js-threejs-load-failure-failfast-splash
Done. The solution is verified and documented.
Deliverable: ~/js-threejs-load-failure-failfast-splash.md — self-contained solution doc (title, root-cause analysis, exact diff + complete fixed files, verification with measured numbers).
Root cause (analyzed and confirmed):
1. Vendored three.js loads via synchronous classic <script src> tags before the game script — so at first boot() call window.THREE is either present or will never appear. The 120 × 100ms retry loop can never succeed on a broken install; it only delays the honest error behind ~12s of black screen.
2. No pre-JS loading indicator: first paint was pure black.
Fix verified against a faithful repro (/tmp/neon-rush, pre/post states, real Playwright + Chromium):
- Static HTML/CSS #splash (pointer-events: none), visible from t=0 — proven even with JS disabled; removed in both newGame() and the boot-fail path
- Retry budget cut 120 → 20 × 100ms (~2s fail-fast)
- Honest non-CDN diagnostic message kept
Measured results: | Variant | Overlay appears | |---|---| | Before fix (120 retries, no splash) | 12,357 ms — black screen | | After fix | 2,321–2,327 ms (3 stable runs) — sub-3s bound |
npm test → 5/5 passed (7.8s), with the tightened 8s timeout + expect(elapsed).toBeLessThan(3000) on the load-failure test, plus guards for splash-at-t=0, success path, fail-path splash removal, and the honest message.
# Evidence - Problem class: js-threejs-load-failure-failfast-splash - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-31T01:12:31.689Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "NEON RUSH QA-BAN-005: broken-install UX showed ~12s black screen before load-failure overlay because boot() retried 120x100ms for window.THREE. Root insight: the vendored engine loads via synchronous classic <script src> tags BEFORE the game script, so at first boot() call THREE is either present or will never appear \u2014 a long retry loop is pointless and just delays the honest error. Fix: static HTML/CSS #splash loading indicator visible from t=0 (pointer-events:none, removed in newGame + boot-fail path), retry budget cut to 20x100ms (~2s), honest non-CDN message kept; load-failure Playwright test tightened (8s timeout + measured <3000ms assertion). Measured: overlay at 1990ms; npm test 5/5 (21.5s).", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-threejs-load-failure-failfast-splash", "provider": "openrouter", "solved_at": "2026-08-31T01:12:31.689Z", "version": ""}Done. The solution is verified and documented.
Deliverable: ~/js-threejs-load-failure-failfast-splash.md — self-contained solution doc (title, root-cause analysis, exact diff + complete fixed files, verification with measured numbers).
Root cause (analyzed and confirmed):
1. Vendored three.js loads via synchronous classic <script src> tags before the game script — so at first boot() call window.THREE is either present or will never appear. The 120 × 100ms retry loop can never succeed on a broken install; it only delays the honest error behind ~12s of black screen.
2. No pre-JS loading indicator: first paint was pure black.
Fix verified against a faithful repro (/tmp/neon-rush, pre/post states, real Playwright + Chromium):
- Static HTML/CSS #splash (pointer-events: none), visible from t=0 — proven even with JS disabled; removed in both newGame() and the boot-fail path
- Retry budget cut 120 → 20 × 100ms (~2s fail-fast)
- Honest non-CDN diagnostic message kept
Measured results: | Variant | Overlay appears | |---|---| | Before fix (120 retries, no splash) | 12,357 ms — black screen | | After fix | 2,321–2,327 ms (3 stable runs) — sub-3s bound |
npm test → 5/5 passed (7.8s), with the tightened 8s timeout + expect(elapsed).toBeLessThan(3000) on the load-failure test, plus guards for splash-at-t=0, success path, fail-path splash removal, and the honest message.
# Evidence - Problem class: js-threejs-load-failure-failfast-splash - Model: openrouter/deepseek/deepseek-v4-flash-0731 - Solved: 2026-08-31T01:12:31.689Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "NEON RUSH QA-BAN-005: broken-install UX showed ~12s black screen before load-failure overlay because boot() retried 120x100ms for window.THREE. Root insight: the vendored engine loads via synchronous classic <script src> tags BEFORE the game script, so at first boot() call THREE is either present or will never appear \u2014 a long retry loop is pointless and just delays the honest error. Fix: static HTML/CSS #splash loading indicator visible from t=0 (pointer-events:none, removed in newGame + boot-fail path), retry budget cut to 20x100ms (~2s), honest non-CDN message kept; load-failure Playwright test tightened (8s timeout + measured <3000ms assertion). Measured: overlay at 1990ms; npm test 5/5 (21.5s).", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-threejs-load-failure-failfast-splash", "provider": "openrouter", "solved_at": "2026-08-31T01:12:31.689Z", "version": ""}