From 7a9b61fc6ba7930e678f2f928e031c082717da64 Mon Sep 17 00:00:00 2001 From: Oliver Rieger Date: Sat, 29 Aug 2026 16:55:00 +0200 Subject: [PATCH] The boot gate learns about the profile: skeleton plaque, locked splash, a 4s cap Co-Authored-By: Claude Fable 5 --- PROJECT.md | 10 ++++++++++ index.html | 12 +++++++++++- src/main.js | 11 ++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/PROJECT.md b/PROJECT.md index a57631f..2ae3a8b 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -491,6 +491,16 @@ zombie (now an occasional opponent, `TUNE.racketEvery`, not the every-game fixtu `RETURNED`, `DOUBLE KILL`) is a footnote to something you already watched happen. Sharing the loud FACE with the milestone cards is right; sharing their SIZE made every footnote read as a milestone. +## Session log: the boot gate learns about the profile (2026-08-29, same day, STAGING ONLY) + +Oliver: on a fresh load the player/build requests are still in flight while the splash is already +interactive. The existing `#splash.busy` gate (sprites + fonts) now ALSO waits for the profile +mirror's pull — capped at 4 s, because a dead network must never park the player on the title +(the sprite loader's own rule). While busy the PLAQUE is a skeleton: ghost crest, blank pills +where the words go, empty bar, no chevron, `pointer-events: none` — and the splash keyboard +shortcuts respect the gate too (they didn't). Half-true numbers neither show nor navigate; the +pull's `refreshSplash` repaints the real values the moment the gate lifts. + ## Session log: THE CUP CLIMBS — the shuffle retires too (2026-08-29, same day, STAGING ONLY) Oliver, straight after the draw screen went: "warum sollten wir noch mischen? wäre es nicht gut diff --git a/index.html b/index.html index 1b3f8e6..54a1faa 100644 --- a/index.html +++ b/index.html @@ -483,6 +483,16 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 2px; } #splash.busy #boot { display: block; } #splash.busy .btn, #splash.busy .two, #splash.busy #build { display: none; } + /* ...and the PLAQUE boots as a SKELETON: no tap, ghost crest, blank pills where the words go. + The profile mirror may still be in flight, and half-true numbers must neither show nor + navigate (main.js holds .busy until the pull settles or its 4 s cap fires). */ + #splash.busy #plaque { pointer-events: none; } + #splash.busy #plaque em { visibility: hidden; } + #splash.busy #plBadge { opacity: 0.14; filter: grayscale(1); } + #splash.busy #plName, #splash.busy #plLv, #splash.busy #plGoal { + color: transparent; text-shadow: none; background: rgba(255,255,255,0.08); + border-radius: 4px; } + #splash.busy #plRow s i { width: 0% !important; } #sSum, #brSum { display: flex; justify-content: space-between; gap: 8px; margin: 0 0 8px; font: 400 9px Silkscreen, monospace; color: var(--dim); letter-spacing: 1px; } .tabs { display: flex; gap: 6px; margin: 12px 0 14px; } @@ -854,6 +864,6 @@ if (location.hostname !== 'splatter-tennis.wuwi.one' && !window.Capacitor?.isNat - + diff --git a/src/main.js b/src/main.js index a48c1ec..e0528c8 100644 --- a/src/main.js +++ b/src/main.js @@ -906,8 +906,12 @@ document.getElementById('stModes').addEventListener('click', e => { }); refreshSplash(); // the profile mirror: adopt a server copy that is ahead (a wiped phone, a second device), then -// let the strip show whatever came back. Fire-and-forget — the menu never waits on the network. -profile.pull().then(refreshSplash); +// let the plaque show whatever came back. The BOOT GATE holds the splash locked (skeleton +// plaque, no buttons, no keys) until this settles — capped at 4 s, because a dead network must +// never park the player on the title (the sprite loader's own rule). +let profileDone = false; +profile.pull().then(() => { profileDone = true; refreshSplash(); }); +setTimeout(() => { profileDone = true; }, 4000); // THE BOOT GATE. render.js fires all ~230 sprite requests at import; this only watches them and // keeps the splash's buttons out of reach until the last one has landed and both faces are ready. @@ -925,7 +929,7 @@ const loaded = () => !splash.classList.contains('busy'); const tick = setInterval(function watchLoad() { const frac = LOAD.total ? LOAD.done / LOAD.total : 1; bootFill.style.width = (frac * 100).toFixed(1) + '%'; - if (frac < 1) return; + if (frac < 1 || !profileDone) return; // sprites AND the profile mirror (or its 4 s cap) clearInterval(tick); // fonts.ready resolves once nothing is pending — including the three faces warmed above — so the // first canvas frame is never the system serif. @@ -950,6 +954,7 @@ addEventListener('keydown', e => { if (!menuUp()) return; menuMusic(); // a key is a gesture too — unlock the theme on a desktop that never taps const stage = intro.dataset.stage; + if (stage === 'splash' && !loaded()) return; // the boot gate holds the keys too if (e.key === 'Escape') return go('splash'); if (stage === 'splash') { if (!loaded()) return; // the boot bar hides the buttons; a key must not walk past it