Skip to content

Commit 50bff19

Browse files
committed
Ship the mobile pause visibility and compact overlay fix as v1.1.11
This follow-up release fixes the mobile pause button lifecycle and makes the pause overlay more usable on ultra-short landscape phone screens without changing the underlying pause/save flow. Constraint: Must preserve the existing pause-state controller and save-slot interactions while reducing visual crowding on iPhone-class landscape viewports Constraint: Must keep the mobile pause affordance available after rotate cycles without reintroducing accidental fire-touch input coupling Rejected: Rebuild the mobile pause overlay into a separate phone-specific screen | too much scope for a visibility/layout follow-up patch Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep future mobile pause/HUD work validated against ultra-short landscape phone layouts and first-render touch-control visibility Tested: bun test; bun run levels:validate; bun run lint; bun run build; bun run knip; bun run bundle:check Not-tested: fresh device screenshot after final release packaging
1 parent c585beb commit 50bff19

9 files changed

Lines changed: 79 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
## [1.1.11] - 2026-04-27
6+
7+
### Fixed
8+
- Fixed the mobile pause button so it renders immediately on first mobile load instead of only appearing after a rotate/reflow cycle.
9+
- Fixed mobile pause-button visibility across portrait/landscape reorientation so the touch pause affordance remains available after rotating back into gameplay.
10+
11+
### Changed
12+
- Tightened the ultra-short mobile pause overlay by reducing the oversized `PAUSED` title and dropping subtitle/hint bands on constrained landscape phone screens, giving the checkpoint grid and footer controls more breathing room.
13+
14+
### Quality
15+
- Added regression coverage for ultra-short phone pause layout behavior.
16+
- Verified with `bun test`, `bun run levels:validate`, `bun run lint`, `bun run build`, `bun run knip`, and `bun run bundle:check`.
17+
518
## [1.1.10] - 2026-04-27
619

720
### Changed

docs/releases/1.1.11.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Release 1.1.11 — Mobile pause visibility and compact overlay polish
2+
3+
## Highlights
4+
5+
- Fixes the mobile pause button so it appears immediately and stays available after rotate cycles.
6+
- Makes the pause overlay less cramped on ultra-short landscape phone screens such as the iPhone 13 mini.
7+
8+
## What changed
9+
10+
- Mobile pause button lifecycle:
11+
- `src/systems/MobileControls.ts`
12+
- The touch pause control now draws on first render, remains visible as a mobile affordance across blocked/unblocked states, and no longer depends on a relayout cycle to appear.
13+
14+
- Compact mobile pause overlay:
15+
- `src/scenes/gameScene/PauseOverlay.ts`
16+
- `src/scenes/gameScene/pauseOverlay/{types,view}.ts`
17+
- On ultra-short landscape phone viewports, the pause title scales down and the extra subtitle/hint copy is removed so checkpoint rows and footer actions have more usable space.
18+
19+
- Validation coverage:
20+
- `tests/responsiveLayout.test.ts`
21+
- Added coverage that locks the ultra-short phone pause overlay into the less-cramped layout rules.
22+
23+
## Validation
24+
25+
- `bun test`
26+
- `bun run levels:validate`
27+
- `bun run lint`
28+
- `bun run build`
29+
- `bun run knip`
30+
- `bun run bundle:check`

docs/releases/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
Latest first.
44

5+
- [`1.1.11`](./1.1.11.md) — fixes mobile pause-button first-render/rotate visibility and relaxes the ultra-short phone pause layout
56
- [`1.1.10`](./1.1.10.md) — lowers the mobile pause button beneath the HUD for cleaner touch spacing
67
- [`1.1.9`](./1.1.9.md) — mobile menu title-band fix plus top-right touch pause control and fire-touch filtering cleanup
78
- [`1.1.8`](./1.1.8.md) — pause controls, persistent checkpoints, shared neon UI controls, and music-volume parity polish

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "space-explorer",
3-
"version": "1.1.10",
3+
"version": "1.1.11",
44
"author": "Douwe de Vries",
55
"license": "MIT",
66
"private": true,

src/scenes/gameScene/PauseOverlay.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ export class PauseOverlay {
214214
this.blocker.setSize(layout.width, layout.height);
215215
drawPauseOverlayBackdrop(this.dimmer, this.panel, layout);
216216

217+
this.titleText.setFontSize(layout.titleFontSize);
218+
this.subtitleText.setFontSize(layout.subtitleFontSize);
219+
this.hintText.setFontSize(layout.hintFontSize);
217220
this.titleText.setPosition(layout.centerX, layout.titleY);
218221
this.subtitleText.setPosition(layout.centerX, layout.subtitleY);
219222
this.hintText.setPosition(layout.centerX, layout.hintY);

src/scenes/gameScene/pauseOverlay/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ export interface PauseOverlayLayout {
4343
panelY: number;
4444
panelWidth: number;
4545
panelHeight: number;
46+
titleFontSize: number;
47+
subtitleFontSize: number;
48+
hintFontSize: number;
4649
titleY: number;
4750
subtitleY: number;
4851
subtitleVisible: boolean;

src/scenes/gameScene/pauseOverlay/view.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const PAUSE_OVERLAY_SLIDER_SPACING = 68;
1919

2020
const PAUSE_BREAKPOINT_NARROW_WIDTH = 720;
2121
const PAUSE_BREAKPOINT_SHORT_HEIGHT = 520;
22-
const PAUSE_BREAKPOINT_VERY_SHORT_HEIGHT = 360;
22+
const PAUSE_BREAKPOINT_VERY_SHORT_HEIGHT = 400;
2323
const PAUSE_BREAKPOINT_ULTRA_COMPACT_WIDTH = 340;
2424
const PAUSE_BREAKPOINT_ULTRA_COMPACT_HEIGHT = 380;
2525

@@ -131,9 +131,12 @@ export function getPauseOverlayLayout(scene: Phaser.Scene): PauseOverlayLayout {
131131
? panelWidth - contentInset * 2
132132
: Math.min(310, panelX + panelWidth - contentRight - 42);
133133
const slotBlockHeight = slotRowHeight * 3 + slotRowGap * 2;
134-
const titleY = panelY + (shortViewport ? 38 : 96);
135-
const baseSubtitleY = panelY + (shortViewport ? 72 : 176);
136-
const baseHintY = panelY + (shortViewport ? 96 : 216);
134+
const titleFontSize = veryShortViewport ? 64 : shortViewport ? 72 : 86;
135+
const subtitleFontSize = veryShortViewport ? 14 : 16;
136+
const hintFontSize = veryShortViewport ? 12 : 14;
137+
const titleY = panelY + (veryShortViewport ? 60 : shortViewport ? 38 : 96);
138+
const baseSubtitleY = panelY + (veryShortViewport ? 94 : shortViewport ? 72 : 176);
139+
const baseHintY = panelY + (veryShortViewport ? 118 : shortViewport ? 96 : 216);
137140
let musicHeaderY = panelY + (shortViewport ? 96 : compact ? 148 : 252);
138141
let sliderStartY = panelY + (shortViewport ? 126 : compact ? 176 : 284);
139142
const desiredSlotStartY = stackedLayout
@@ -144,7 +147,7 @@ export function getPauseOverlayLayout(scene: Phaser.Scene): PauseOverlayLayout {
144147
const earliestSlotStartY = panelY + (ultraCompactViewport ? 34 : veryShortViewport ? 36 : shortViewport ? 24 : stackedLayout ? 130 : 150);
145148
const latestSlotStartY = statusY - statusTextHeight / 2 - 8 - slotBlockHeight;
146149

147-
let subtitleVisible = !ultraCompactViewport;
150+
let subtitleVisible = !ultraCompactViewport && !veryShortViewport;
148151
let hintVisible = !ultraCompactViewport && !veryShortViewport;
149152
let subtitleY = baseSubtitleY;
150153
let hintY = baseHintY;
@@ -225,6 +228,9 @@ export function getPauseOverlayLayout(scene: Phaser.Scene): PauseOverlayLayout {
225228
panelY,
226229
panelWidth,
227230
panelHeight,
231+
titleFontSize,
232+
subtitleFontSize,
233+
hintFontSize,
228234
titleY,
229235
subtitleY,
230236
subtitleVisible,
@@ -284,7 +290,7 @@ export function drawPauseOverlayBackdrop(
284290
glow: true,
285291
});
286292

287-
drawNeonDivider(panel, layout.centerX, layout.titleY - 48, Math.min(620, layout.panelWidth - 160));
293+
drawNeonDivider(panel, layout.centerX, Math.max(layout.panelY + 24, layout.titleY - 48), Math.min(620, layout.panelWidth - 160));
288294
if (layout.hintVisible) {
289295
drawNeonDivider(
290296
panel,

src/systems/MobileControls.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ export class MobileControls {
104104

105105
this.refreshVisibility();
106106
this.updateJoystickVisual();
107+
this.updatePauseButtonVisual();
107108

108109
return this;
109110
}
@@ -163,6 +164,7 @@ export class MobileControls {
163164
}
164165

165166
this.refreshVisibility();
167+
this.updatePauseButtonVisual();
166168
}
167169

168170
isEnabled(): boolean {
@@ -260,19 +262,20 @@ export class MobileControls {
260262

261263
private refreshVisibility(): void {
262264
const visible = this.isEnabled();
265+
const pauseVisible = this.enabledForTouchDevice && this.scene !== null;
263266

264267
this.joystickBase?.setVisible(visible);
265268
this.joystickCenter?.setVisible(visible);
266269
this.joystickThumb?.setVisible(visible);
267-
this.pauseButtonBg?.setVisible(visible);
268-
this.pauseButtonIcon?.setVisible(visible);
269-
this.pauseButtonHitArea?.setVisible(visible);
270+
this.pauseButtonBg?.setVisible(pauseVisible);
271+
this.pauseButtonIcon?.setVisible(pauseVisible);
272+
this.pauseButtonHitArea?.setVisible(pauseVisible);
270273

271274
if (this.joystickBase?.input) {
272275
this.joystickBase.input.enabled = visible;
273276
}
274277
if (this.pauseButtonHitArea?.input) {
275-
this.pauseButtonHitArea.input.enabled = visible;
278+
this.pauseButtonHitArea.input.enabled = pauseVisible && !this.blocked;
276279
}
277280
}
278281

tests/responsiveLayout.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,15 @@ describe('responsive save-slot layouts', () => {
324324
expect(layout.slotRows[0]?.width).toBeGreaterThan(400);
325325
});
326326

327+
test('pause overlay drops subtitle and hint bands on ultra-short phone landscape viewports', () => {
328+
const layout = getPauseOverlayLayout(createScene(812, 375) as never);
329+
330+
expect(layout.subtitleVisible).toBe(false);
331+
expect(layout.hintVisible).toBe(false);
332+
expect(layout.titleFontSize).toBeLessThan(86);
333+
assertPauseRequiredControlsDoNotOverlap({ width: 812, height: 375 });
334+
});
335+
327336
test.each([
328337
{ width: 1024, height: 768 },
329338
{ width: 1280, height: 800 },

0 commit comments

Comments
 (0)