diff --git a/assets/scripts/games/two-rivers/gate.js b/assets/scripts/games/two-rivers/gate.js
new file mode 100644
index 0000000..a5e584a
--- /dev/null
+++ b/assets/scripts/games/two-rivers/gate.js
@@ -0,0 +1,35 @@
+(function () {
+ "use strict";
+
+ var root = document.querySelector("[data-two-rivers]");
+ if (!root) return;
+
+ var button = root.querySelector("[data-tr-age-confirm]");
+ var ageScreen = root.querySelector("[data-tr-age]");
+ var loading = root.querySelector("[data-tr-loading]");
+ var loadingCopy = root.querySelector("[data-tr-loading-copy]");
+ var AGE_KEY = "zxh_two_rivers_age_gate_v1";
+
+ if (!button || !ageScreen || !loading) return;
+
+ button.addEventListener("click", function () {
+ root.dataset.ageConfirmed = "true";
+ try {
+ localStorage.setItem(AGE_KEY, "true");
+ } catch (_error) {
+ // The module bootstrap can still use the in-page marker when storage is unavailable.
+ }
+
+ ageScreen.hidden = true;
+ loading.hidden = false;
+ if (loadingCopy) loadingCopy.textContent = "Opening the festival…";
+
+ window.setTimeout(function () {
+ if (!loading.hidden && !root.querySelector("[data-tr-menu]:not([hidden])")) {
+ loading.innerHTML = "
The festival files did not finish loading.Refresh once to fetch the latest game files. If the problem continues, the deployment is incomplete.
Return to the playroom ";
+ var retry = loading.querySelector("[data-tr-gate-retry]");
+ if (retry) retry.addEventListener("click", function () { location.reload(); });
+ }
+ }, 12000);
+ }, {once: true});
+}());
diff --git a/assets/scripts/games/two-rivers/main.js b/assets/scripts/games/two-rivers/main.js
index 962d5b5..c3c0ff2 100644
--- a/assets/scripts/games/two-rivers/main.js
+++ b/assets/scripts/games/two-rivers/main.js
@@ -168,7 +168,7 @@ async function start() {
function showGateOrMenu() {
const age = root.querySelector("[data-tr-age]");
- if (saves.ageConfirmed()) {
+ if (saves.ageConfirmed() || root.dataset.ageConfirmed === "true") {
age.hidden = true;
showMenu();
} else {
@@ -225,6 +225,7 @@ async function start() {
root.querySelector("[data-tr-age-confirm]").addEventListener("click", () => {
saves.confirmAge();
root.querySelector("[data-tr-age]").hidden = true;
+ loadingEl.hidden = true;
audio.unlock();
showMenu();
});
diff --git a/play/two-rivers.org b/play/two-rivers.org
index c4a8f4b..f7696ac 100644
--- a/play/two-rivers.org
+++ b/play/two-rivers.org
@@ -93,10 +93,11 @@
-
+
+
-
+
#+END_EXPORT
diff --git a/tests/two-rivers/game.test.mjs b/tests/two-rivers/game.test.mjs
index 8e512e6..220b80e 100644
--- a/tests/two-rivers/game.test.mjs
+++ b/tests/two-rivers/game.test.mjs
@@ -133,10 +133,12 @@ test("page uses local pinned libraries and production source is clean", () => {
assert.match(page, /phaser-3\.90\.0\.min\.js/);
assert.match(page, /gsap-3\.13\.0\.min\.js/);
assert.match(page, /howler-2\.2\.4\.min\.js/);
+ assert.match(page, /games\/two-rivers\/gate\.js\?v=1\.0\.1/);
assert.doesNotMatch(page, /https?:\/\//);
const source = [
page,
read("assets/scripts/games/two-rivers/main.js"),
+ read("assets/scripts/games/two-rivers/gate.js"),
read("assets/scripts/games/two-rivers/core/state.mjs"),
read("assets/scripts/games/two-rivers/ui/interface.mjs"),
read("assets/scripts/games/two-rivers/scenes/game-scenes.mjs")