diff --git a/Dockerfile b/Dockerfile index 8249428..e328e2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,8 @@ # stage COPYs the marker so BuildKit cannot skip this stage as unused. FROM node:22-alpine AS test WORKDIR /app -COPY *.js /app/ +COPY test.js /app/ +COPY src /app/src RUN node test.js && touch /tests-passed FROM python:3.12-alpine @@ -14,7 +15,8 @@ FROM python:3.12-alpine # ponytail: switch to hashed filenames if traffic ever matters. WORKDIR /app COPY --from=test /tests-passed /tmp/tests-passed -COPY index.html manifest.webmanifest *.js server.py /app/ +COPY index.html manifest.webmanifest server.py /app/ +COPY src /app/src COPY assets /app/assets # THE SCORES LIVE HERE AND THIS MUST BE A PERSISTENT VOLUME. Without one the json sits in the # container's writable layer and every deploy silently resets the leaderboard to empty — which diff --git a/PROJECT.md b/PROJECT.md index e863dd5..2ad5fe2 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -29,7 +29,8 @@ the primary target. the Dockerfile. Oliver tests on his phone at splatter-tennis.wuwi.one ~30s after a push. **Bump `main.js?v=N` in index.html every time** or phones keep the old build. The Dockerfile must also COPY any new top-level file (it currently ships `index.html`, - `manifest.webmanifest`, `*.js`, `server.py`, `assets/`). + `manifest.webmanifest`, `server.py`, `src/`, `assets/` — `test.js` only feeds the test stage and + is deliberately not in the served image). - **The image is `python:3.12-alpine` running `server.py`, no longer `nginx:alpine`.** The world board needs one process that can WRITE, and nginx is not one; everything the nginx conf did here (no-cache so a deploy lands on a plain reload, and `application/manifest+json`, without which @@ -51,7 +52,7 @@ the primary target. - **Oliver edits files himself** (tuning values, sometimes sprites). ALWAYS Read current file state before editing; never assume your last version is what is on disk. -## Module map (all in repo root) +## Module map (game code in `src/`; `index.html`, `server.py` and `test.js` at the root) `config.js` TUNE (live T panel) + structural constants + `UI` palette · `state.js` the `G` object + P/O/ball/score + `setupPoint`/`sendBoy` · `gameplay.js` ballistics/swings/serve/rules/AI/`update()` + transition + `splatPoint` + ball-boy routines · `beats.js` **the beat machinery: every mode @@ -827,8 +828,8 @@ Clear the intro first: `document.getElementById('intro')?.remove()`. own geometry could possibly reach. To check WHERE something lands, recompute the projection directly (`T.proj(...)`) and compare numbers; keep pixel-diffing for "did anything at all change". - **The module-refresh list MUST include the VERSIONED entry point.** `index.html` loads - `main.js?v=N`, and `fetch('main.js', {cache:'reload'})` does not bust that URL — so main.js alone - stays stale through a reload while every other module is fresh. Read the src off the page: + `src/main.js?v=N`, and `fetch('src/main.js', {cache:'reload'})` does not bust that URL — so main.js + alone stays stale through a reload while every other module is fresh. Read the src off the page: `document.querySelector('script[type=module]').getAttribute('src')` and fetch that too. Symptom: a change in main.js appears to do nothing at all, repeatably. - **You MUST set `T.TUNE.autoAssist = 1.15` first** — the Browser pane reports `pointer: fine`, so diff --git a/index.html b/index.html index 6536780..ec8dabb 100644 --- a/index.html +++ b/index.html @@ -398,6 +398,6 @@ - + diff --git a/audio.js b/src/audio.js similarity index 100% rename from audio.js rename to src/audio.js diff --git a/beats.js b/src/beats.js similarity index 100% rename from beats.js rename to src/beats.js diff --git a/config.js b/src/config.js similarity index 100% rename from config.js rename to src/config.js diff --git a/dom.js b/src/dom.js similarity index 100% rename from dom.js rename to src/dom.js diff --git a/gameplay.js b/src/gameplay.js similarity index 100% rename from gameplay.js rename to src/gameplay.js diff --git a/input.js b/src/input.js similarity index 100% rename from input.js rename to src/input.js diff --git a/main.js b/src/main.js similarity index 99% rename from main.js rename to src/main.js index b3215a1..991e043 100644 --- a/main.js +++ b/src/main.js @@ -278,7 +278,7 @@ intro.addEventListener('pointerdown', () => menuMusic()); // which build am I looking at? Push = deploy and the browser cannot see git, so the served file's // own timestamp IS the version marker — it changes on every deploy, with nothing to remember to bump. // Match it against `git log -1 --format=%cd` when a phone looks suspiciously out of date. -fetch('main.js', { method: 'HEAD' }) +fetch('src/main.js', { method: 'HEAD' }) // page-relative: index.html sits at the root, the code in src/ .then(r => { const t = r.headers.get('last-modified'); if (!t) return; document.getElementById('build').textContent = 'BUILD ' + new Date(t).toLocaleString('en-GB').replace(',', ''); }) .catch(() => {}); // no header, no line — never a broken start screen diff --git a/panel.js b/src/panel.js similarity index 100% rename from panel.js rename to src/panel.js diff --git a/render.js b/src/render.js similarity index 100% rename from render.js rename to src/render.js diff --git a/state.js b/src/state.js similarity index 100% rename from state.js rename to src/state.js diff --git a/stats.js b/src/stats.js similarity index 100% rename from stats.js rename to src/stats.js diff --git a/zombies.js b/src/zombies.js similarity index 100% rename from zombies.js rename to src/zombies.js diff --git a/test.js b/test.js index 315017b..68ae189 100644 --- a/test.js +++ b/test.js @@ -60,11 +60,11 @@ globalThis.ResizeObserver = class { observe() {} disconnect() {} }; globalThis.getComputedStyle = () => ({ paddingTop: '0' }); // ---- game modules (real code) ---------------------------------------------- -const { G, P, score, ball, setupPoint } = await import('./state.js'); -const { update, forceZombies, splatPoint, restartRun } = await import('./gameplay.js'); -const { startDuel, resolveInterlude, startBossFight, endBossFight } = await import('./beats.js'); -const { zombies, spawnZombie } = await import('./zombies.js'); -const { TUNE } = await import('./config.js'); +const { G, P, score, ball, setupPoint } = await import('./src/state.js'); +const { update, forceZombies, splatPoint, restartRun } = await import('./src/gameplay.js'); +const { startDuel, resolveInterlude, startBossFight, endBossFight } = await import('./src/beats.js'); +const { zombies, spawnZombie } = await import('./src/zombies.js'); +const { TUNE } = await import('./src/config.js'); const DT = 1 / 60; function freshSplatter() {