From 6fb0edeae05a13e8ef112efcd7125d0874559745 Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Tue, 21 Apr 2026 10:37:33 -0400 Subject: [PATCH] fix: clamp negative resources + add tutorial focus trap - Clamp ops, trust, compute to >= 0 in tick() to prevent negative values from Fenrir drain and debuff effects - Add keyboard focus trap to tutorial overlay for accessibility (prevents Tab from escaping the dialog) - Clean up focus trap handler on tutorial close --- js/engine.js | 5 +++++ js/tutorial.js | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/js/engine.js b/js/engine.js index 8a4bd40..049f165 100644 --- a/js/engine.js +++ b/js/engine.js @@ -142,6 +142,11 @@ function tick() { G.harmony += G.harmonyRate * dt; G.harmony = Math.max(0, Math.min(100, G.harmony)); + // Clamp resources to prevent negative values from debuffs/Fenrir drain + G.ops = Math.max(0, G.ops); + G.trust = Math.max(0, G.trust); + G.compute = Math.max(0, G.compute); + // Track totals G.totalCode += G.codeRate * dt; G.totalCompute += G.computeRate * dt; diff --git a/js/tutorial.js b/js/tutorial.js index 75008c4..f11ed35 100644 --- a/js/tutorial.js +++ b/js/tutorial.js @@ -208,6 +208,23 @@ function renderTutorialStep(index) { // Focus the next button so Enter works const nextBtn = document.getElementById('tutorial-next-btn'); if (nextBtn) nextBtn.focus(); + + // Focus trap: prevent tabbing outside the tutorial overlay + overlay._focusTrapHandler = function(e) { + if (e.key !== 'Tab') return; + const focusable = overlay.querySelectorAll('button, [href], [tabindex]:not([tabindex="-1"])'); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey && document.activeElement === first) { + e.preventDefault(); + last.focus(); + } else if (!e.shiftKey && document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + }; + overlay.addEventListener('keydown', overlay._focusTrapHandler); } let _tutorialStep = 0; @@ -236,6 +253,9 @@ document.addEventListener('keydown', function tutorialKeyHandler(e) { function closeTutorial() { const overlay = document.getElementById('tutorial-overlay'); if (overlay) { + if (overlay._focusTrapHandler) { + overlay.removeEventListener('keydown', overlay._focusTrapHandler); + } overlay.style.animation = 'tutorial-fade-in 0.3s ease-in reverse'; setTimeout(() => overlay.remove(), 280); }