Skip to content

Commit 030dee9

Browse files
launcher: show exactly one route (hosted vs folder-picker); add standalone deploy
- Launcher probes for the game-data COPY on the server (HEAD ja2-gamedata.data + .js). Present → show ONLY "Play now" (loads from server, no upload), hide the folder-picker + remembered-install bar. Absent → show ONLY the folder picker. - Dead-simple deploy for a prebuilt bundle: deploy/standalone/{Dockerfile, docker-compose.yml} — `docker compose up` serves it with COOP/COEP + gzip. Verified: launcher at /, isolation headers + wasm gzip all correct. - SELF_HOSTING quick-start now shows both `python3 server.py` and `docker compose up`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 14e02e5 commit 030dee9

4 files changed

Lines changed: 42 additions & 12 deletions

File tree

SELF_HOSTING.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ prebuilt engine and everything below. No compiler needed.
66

77
## Quick start (local)
88

9+
Grab a [release](https://github.com/Virtastic/ja2-web/releases), unzip, and pick one:
10+
911
```bash
1012
unzip ja2-web-*.zip -d ja2-web && cd ja2-web
11-
python3 server.py # http://localhost:8795 (override with PORT=…)
13+
14+
# A) no dependencies but Python:
15+
python3 server.py # http://localhost:8795 (override with PORT=…)
16+
17+
# B) Docker (bundled Dockerfile + compose):
18+
docker compose up # http://localhost:8080
1219
```
1320

1421
Open the URL in **desktop Chrome/Chromium**. The launcher (`launcher.html`) lets

deploy/standalone/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Dead-simple standalone image: serve a PREBUILT ja2-web bundle (no compiler needed).
2+
# Used by the release bundle's `docker compose up`. For building the engine from source,
3+
# see the repo-root Dockerfile instead.
4+
FROM nginx:1.27-alpine
5+
# COOP/COEP/CORP (SharedArrayBuffer), gzip_static, wasm mime, launcher at /.
6+
COPY nginx.conf /etc/nginx/conf.d/default.conf
7+
# The prebuilt front-end + engine (index.html, launcher.html, ja2.{js,wasm,data}(+.gz), …).
8+
COPY . /usr/share/nginx/html/
9+
EXPOSE 80
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Dead-simple deploy of a prebuilt ja2-web bundle: docker compose up → http://localhost:8080
2+
services:
3+
ja2-web:
4+
build: .
5+
ports:
6+
- "8080:80"
7+
restart: unless-stopped

play/launcher.html

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,9 @@
6969

7070
/* --- Choice cards, styled as stamped ammo-crate plaques --- */
7171
.cards{display:grid; grid-template-columns:minmax(0,460px); justify-content:center; gap:22px}
72-
/* When the server hosts the game data, a second "Play now" card is revealed → two columns. */
73-
.cards.two{grid-template-columns:repeat(2,minmax(0,440px))}
74-
@media (max-width:720px){ .cards.two{grid-template-columns:minmax(0,460px)} }
75-
#card-hosted[hidden]{display:none}
72+
/* Exactly one card shows: hosted "Play now" if the server has the data, else the folder picker.
73+
.card sets display:flex, which would override the plain [hidden] attribute, so force it here. */
74+
.card[hidden]{display:none}
7675
.card{
7776
position:relative; padding:32px 30px 28px;
7877
background:linear-gradient(160deg,var(--panel-2),var(--panel));
@@ -205,7 +204,7 @@
205204
<div class="wrap">
206205
<p class="eyebrow reveal d1">Jagged Alliance 2 · in your browser</p>
207206
<h1 class="reveal d1">Jagged Alliance <span class="two">2</span></h1>
208-
<p class="deck reveal d2">Assemble your squad and liberate Arulco, running entirely on your
207+
<p class="deck reveal d2" id="deck">Assemble your squad and liberate Arulco, running entirely on your
209208
machine, nothing uploaded. Point the engine at your own copy of the game to play.</p>
210209
<div class="rule reveal d2"><span class="diamond"></span></div>
211210

@@ -424,20 +423,28 @@ <h4>If something's off</h4>
424423
note('Needs a Chromium browser (Chrome/Edge/Brave) on desktop.','muted');
425424
}
426425

427-
// --- Hosted-data card: reveal only if the operator serves the data package here.
428-
// index.html (no query) already loads ja2-gamedata.js from the server, so "Play now"
429-
// just points there. Absent on the public upload-only deploy → card stays hidden. ---
426+
// --- Hosted-data card: reveal only if the server actually hosts the game-data COPY.
427+
// index.html (no query) loads ja2-gamedata.js, which in turn fetches the big
428+
// ja2-gamedata.data blob — so we probe the .data (the real payload) AND the .js loader.
429+
// Both must be present or the boot fails. Absent (public upload-only deploy) → stay hidden. ---
430430
(async function(){
431431
try {
432-
const r = await fetch('ja2-gamedata.js', { method:'HEAD' });
433-
if (!r.ok) return;
432+
const [d, j] = await Promise.all([
433+
fetch('ja2-gamedata.data', { method:'HEAD' }),
434+
fetch('ja2-gamedata.js', { method:'HEAD' }),
435+
]);
436+
if (!d.ok || !j.ok) return; // no hosted data → folder-picker card stays (the default)
434437
} catch(e){ return; }
438+
// Hosted data is present: this is the ONLY route. Show "Play now", hide the folder-picker path.
435439
const play = () => { location.href = 'index.html'; };
436440
const card = $('card-hosted');
437441
card.hidden = false;
438-
document.querySelector('.cards').classList.add('two');
439442
card.addEventListener('click', play);
440443
card.addEventListener('keydown', (e)=>{ if(e.key==='Enter'||e.key===' '){ e.preventDefault(); play(); } });
444+
const local = $('card-local'); if (local) local.hidden = true;
445+
const cont = $('continue'); if (cont) cont.classList.remove('show');
446+
const deck = $('deck'); if (deck) deck.textContent =
447+
'Assemble your squad and liberate Arulco, running right here in your browser — no install, no upload.';
441448
})();
442449

443450
// --- Return-visit fast path ---

0 commit comments

Comments
 (0)