From 2990344b4ab46e1ad793bb178a9313d23e78ecb6 Mon Sep 17 00:00:00 2001 From: Ayinkx Date: Sat, 24 Oct 2026 09:43:55 +0100 Subject: [PATCH 1/4] fix: respect reduced motion for impact hit-stop --- web/game.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/web/game.js b/web/game.js index b7cd5d5..65103db 100644 --- a/web/game.js +++ b/web/game.js @@ -185,6 +185,9 @@ function comboMilestoneText(combo) { function shouldRenderScreenFlash(settings = {}) { return settings.reducedMotion !== true; } +function shouldApplyHitStop(settings = {}) { + return settings.reducedMotion !== true; +} function segDist(px, py, x1, y1, x2, y2) { const dx = x2 - x1, dy = y2 - y1; const len2 = dx * dx + dy * dy; @@ -2158,7 +2161,12 @@ class Game { this.time += dt; this.ads.update(dt); this.flash = Math.max(0, this.flash - dt); if (this.paused) return; - if (this.hitStop > 0) { this.hitStop = Math.max(0, this.hitStop - dt); return; } + if (this.hitStop > 0 && shouldApplyHitStop(this.save.settings)) { + this.hitStop = Math.max(0, this.hitStop - dt); + return; + } + // Reduced Motion skips the brief simulation freeze used for impact emphasis. + this.hitStop = 0; this.shake = Math.max(0, this.shake - dt); this.parts = this.parts.filter(p => { p.x += p.vx * dt; p.y += p.vy * dt; p.vx *= .96; p.vy *= .96; return (p.life -= dt) > 0; }); this.floats = this.floats.filter(f => { f.y -= 50 * dt; return (f.life -= dt) > 0; }); @@ -3466,5 +3474,5 @@ if (typeof module !== "undefined" && module.exports) module.exports = { Game, MockAdProvider, AdMobProvider, createAdProvider, Save, Sfx, Social, Leaderboard, CAMPAIGN_SECTORS, STORY_ENTRIES, EXPLORATION_OBJECTIVES, freshCampaign, sanitizeCampaign, DemoIapProvider, DisabledIapProvider, CdvIapProvider, createIapProvider, GEM_PACKS, CONTINUE_BASE_COST, SHIPS, CONTRACTS, MISSION_POOL, BIOMES, METEOR_TYPES, SHOP_ITEMS, - dateKey, weekKey, mulberry32, difficultyProfile, flareWarningText, bossWarningText, comboMilestoneText, shouldRenderScreenFlash, W, H }; + dateKey, weekKey, mulberry32, difficultyProfile, flareWarningText, bossWarningText, comboMilestoneText, shouldRenderScreenFlash, shouldApplyHitStop, W, H }; else window.addEventListener("load", boot); From b1c9cb0cba8a2ad00ebf2f74ba6a3573b87c33fb Mon Sep 17 00:00:00 2001 From: Ayinkx Date: Sat, 24 Oct 2026 09:44:02 +0100 Subject: [PATCH 2/4] fix: respect reduced motion for impact hit-stop --- web/test/game.test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/test/game.test.js b/web/test/game.test.js index 4aa1f23..f6c345d 100644 --- a/web/test/game.test.js +++ b/web/test/game.test.js @@ -4,7 +4,7 @@ const test = require("node:test"); const assert = require("node:assert/strict"); const { Game, MockAdProvider, AdMobProvider, Save, Social, Leaderboard, MISSION_POOL, CONTRACTS, BIOMES, SHOP_ITEMS, GEM_PACKS, DemoIapProvider, dateKey, weekKey, CAMPAIGN_SECTORS, STORY_ENTRIES, EXPLORATION_OBJECTIVES, freshCampaign, - sanitizeCampaign, difficultyProfile, flareWarningText, comboMilestoneText, shouldRenderScreenFlash } = require("../game.js"); + sanitizeCampaign, difficultyProfile, flareWarningText, comboMilestoneText, shouldRenderScreenFlash, shouldApplyHitStop } = require("../game.js"); function localStore() { const store = {}; @@ -680,6 +680,12 @@ test("reduced motion disables full-screen flash overlays without changing defaul assert.equal(shouldRenderScreenFlash(), true); }); +test("reduced motion skips hit-stop pauses while normal settings retain them", () => { + assert.equal(shouldApplyHitStop({ reducedMotion: true }), false); + assert.equal(shouldApplyHitStop({ reducedMotion: false }), true); + assert.equal(shouldApplyHitStop(), true); +}); + test("combo milestone copy names the streak tiers clearly and rejects invalid values", () => { assert.equal(comboMilestoneText(2), "x2 WARM STREAK"); assert.equal(comboMilestoneText(4), "x4 HOT STREAK"); From a54a4bdcde963155147f63db2de00f06664fd108 Mon Sep 17 00:00:00 2001 From: Ayinkx Date: Sat, 24 Oct 2026 09:44:07 +0100 Subject: [PATCH 3/4] fix: respect reduced motion for impact hit-stop --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 961a11e..77399ba 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ still runs offline with a personal local board. crystals), volatile (chain explosion) and splitter (splits on approach). - Crystal shop: trails, ship skins and titles. Cosmetic-only; no ranked advantage. -- Settings: colour-blind flare cues, reduced motion (including no full-screen flash overlays), low-FX mode, music and SFX. +- Settings: colour-blind flare cues, reduced motion (no screen shake, full-screen flash overlays, or impact hit-stop pauses), low-FX mode, music and SFX. - Share result cards (PNG) and challenge links, plus PWA install prompt and manifest shortcuts. - Local analytics counters plus server event logging for the run/board/install From fbafd5c6986927adac21789e46cdb24562d5dab0 Mon Sep 17 00:00:00 2001 From: Ayinkx Date: Sat, 24 Oct 2026 09:44:09 +0100 Subject: [PATCH 4/4] fix: respect reduced motion for impact hit-stop --- web/sw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/sw.js b/web/sw.js index 8ac9df9..83fc774 100644 --- a/web/sw.js +++ b/web/sw.js @@ -1,7 +1,7 @@ // Service worker: caches the game so it works offline once installed. // Bump CACHE whenever the game files change. Navigation is network-first so a // deployed update is picked up as soon as the player is online. -const CACHE = "orbit-runner-v16"; +const CACHE = "orbit-runner-v17"; const FILES = ["./", "./index.html", "./config.js", "./game.js", "./manifest.json", "./icon-192.png", "./icon-512.png"]; self.addEventListener("install", e => {