seawolf2357 commited on
Commit
4b19933
Β·
1 Parent(s): 924b98d

Minimap mobile scaling, countdown pop-in, reduced-motion a11y

Browse files

- style.css: scale #minimap to 0.62x on max-width:640px so it no longer
overlaps the right-cluster touch buttons; add countdownPop keyframe
and prefers-reduced-motion support.
- js/game.js: add setCountdown() helper that restarts the pop keyframe
on each digit change so 3->2->1->GO! punches into view.

Files changed (2) hide show
  1. js/game.js +18 -13
  2. style.css +45 -2
js/game.js CHANGED
@@ -486,6 +486,19 @@ countdownEl.style.cssText = `
486
  `;
487
  document.body.appendChild(countdownEl);
488
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  // ══ RESULTS OVERLAY ══
490
  const resultsEl = document.createElement('div');
491
  resultsEl.id = 'results-overlay';
@@ -1021,23 +1034,15 @@ function update() {
1021
  if (raceState === 'countdown') {
1022
  const countdownElapsed = elapsed - countdownStartTime;
1023
 
1024
- // Show 3, 2, 1, GO
1025
  if (countdownElapsed < 1) {
1026
- countdownEl.textContent = '3';
1027
- countdownEl.style.color = '#ff3333';
1028
- countdownEl.style.opacity = '1';
1029
  } else if (countdownElapsed < 2) {
1030
- countdownEl.textContent = '2';
1031
- countdownEl.style.color = '#ffaa00';
1032
- countdownEl.style.opacity = '1';
1033
  } else if (countdownElapsed < 3) {
1034
- countdownEl.textContent = '1';
1035
- countdownEl.style.color = '#00ff66';
1036
- countdownEl.style.opacity = '1';
1037
  } else if (countdownElapsed < 3.8) {
1038
- countdownEl.textContent = 'GO!';
1039
- countdownEl.style.color = '#ffffff';
1040
- countdownEl.style.opacity = '1';
1041
  } else {
1042
  countdownEl.style.opacity = '0';
1043
  }
 
486
  `;
487
  document.body.appendChild(countdownEl);
488
 
489
+ let _lastCountdownText = '';
490
+ function setCountdown(text, color) {
491
+ countdownEl.style.opacity = '1';
492
+ countdownEl.style.color = color;
493
+ if (_lastCountdownText === text) return; // same digit β€” don't retrigger
494
+ _lastCountdownText = text;
495
+ countdownEl.textContent = text;
496
+ // Restart the pop keyframe by toggling the animation property.
497
+ countdownEl.style.animation = 'none';
498
+ void countdownEl.offsetWidth; // force reflow
499
+ countdownEl.style.animation = 'countdownPop 0.55s cubic-bezier(0.2, 1.2, 0.4, 1) forwards';
500
+ }
501
+
502
  // ══ RESULTS OVERLAY ══
503
  const resultsEl = document.createElement('div');
504
  resultsEl.id = 'results-overlay';
 
1034
  if (raceState === 'countdown') {
1035
  const countdownElapsed = elapsed - countdownStartTime;
1036
 
1037
+ // Show 3, 2, 1, GO (each digit pops in via countdownPop keyframe)
1038
  if (countdownElapsed < 1) {
1039
+ setCountdown('3', '#ff3333');
 
 
1040
  } else if (countdownElapsed < 2) {
1041
+ setCountdown('2', '#ffaa00');
 
 
1042
  } else if (countdownElapsed < 3) {
1043
+ setCountdown('1', '#00ff66');
 
 
1044
  } else if (countdownElapsed < 3.8) {
1045
+ setCountdown('GO!', '#ffffff');
 
 
1046
  } else {
1047
  countdownEl.style.opacity = '0';
1048
  }
style.css CHANGED
@@ -87,8 +87,11 @@ body::after {
87
  }
88
  }
89
 
90
- /* Scale the bottom-left HUD gauge down on phones so it no longer
91
- overlaps the on-screen steering buttons. */
 
 
 
92
  @media (max-width: 640px) {
93
  #hud-canvas {
94
  transform: scale(0.68);
@@ -98,6 +101,11 @@ body::after {
98
  transform: scale(0.85);
99
  transform-origin: top left;
100
  }
 
 
 
 
 
101
  }
102
 
103
  /* ═══════════════════════════════════════════════════════
@@ -178,3 +186,38 @@ body::after {
178
  85% { opacity: 1; }
179
  100% { opacity: 0; }
180
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
  }
89
 
90
+ /* Scale the HUD gauge, top overlay, and minimap down on phones so
91
+ they no longer overlap the on-screen steering / pedal / nitro
92
+ touch buttons. The minimap is bottom-right at 180Γ—180 and the
93
+ right-cluster touch buttons live right: 24-212px Γ— bottom: 100-252px,
94
+ so without this rule they collide directly. */
95
  @media (max-width: 640px) {
96
  #hud-canvas {
97
  transform: scale(0.68);
 
101
  transform: scale(0.85);
102
  transform-origin: top left;
103
  }
104
+ #minimap {
105
+ transform: scale(0.62);
106
+ transform-origin: bottom right;
107
+ opacity: 0.7;
108
+ }
109
  }
110
 
111
  /* ═══════════════════════════════════════════════════════
 
186
  85% { opacity: 1; }
187
  100% { opacity: 0; }
188
  }
189
+
190
+ /* ═══════════════════════════════════════════════════════
191
+ * Countdown pop-in β€” applied via inline animation from
192
+ * js/game.js each time the countdown digit changes so the
193
+ * "3 β†’ 2 β†’ 1 β†’ GO!" beats actually punch into view instead
194
+ * of just color-swapping. The transform is compounded with
195
+ * the existing `translate(-50%, -50%)` set on countdownEl.
196
+ * ═══════════════════════════════════════════════════════ */
197
+ @keyframes countdownPop {
198
+ 0% { transform: translate(-50%, -50%) scale(0.35); opacity: 0; filter: blur(6px); }
199
+ 35% { transform: translate(-50%, -50%) scale(1.18); opacity: 1; filter: blur(0); }
200
+ 55% { transform: translate(-50%, -50%) scale(0.96); opacity: 1; }
201
+ 100% { transform: translate(-50%, -50%) scale(1.00); opacity: 1; }
202
+ }
203
+
204
+ /* ═══════════════════════════════════════════════════════
205
+ * Accessibility: honor the user's "reduce motion" OS pref.
206
+ * We keep state transitions (fades) but strip the bouncy
207
+ * keyframes and vignette pulse so motion-sensitive players
208
+ * still get a usable, polished HUD.
209
+ * ═══════════════════════════════════════════════════════ */
210
+ @media (prefers-reduced-motion: reduce) {
211
+ *,
212
+ *::before,
213
+ *::after {
214
+ animation-duration: 0.001ms !important;
215
+ animation-iteration-count: 1 !important;
216
+ transition-duration: 0.08s !important;
217
+ }
218
+ #loading-veil .lv-dots span {
219
+ animation: none !important;
220
+ opacity: 0.7 !important;
221
+ transform: none !important;
222
+ }
223
+ }