UI needs to adapt when showed on a big PC screen #228

Closed
opened 2026-09-12 11:54:14 +00:00 by metaheavens · 1 comment
Owner
No description provided.
Author
Owner

Done in f1292db.

The measurement. The HUD is authored in canvas units. With stretch canvas_items / aspect expand over a 1920x1080 base, a 720x1280 phone scales by 0.375 and gets 1920x3413 canvas units — while any 16:9-or-wider screen lands on 1920x1080 units however many pixels it really has. The canvas is three times shorter, so a 148-unit button went from 4.3% of the screen's height to 13.7%. That is 3.16x, confirmed twice: once by hand off the scene file, once by the new test failing with the rule disabled.

Worth recording: nothing collided. I checked every element pair on both canvases and the same six pairs overlap on each, all of them same-slot alternatives. An earlier claim of mine that the top and bottom bands overlap by 276 units on a PC was wrong — the bands do cross, but no top/bottom pair shares horizontal space. The fault was only that everything was enormous.

The fix. ui/HudScale.gd captures each HUD control's authored offsets once, then moves it toward the edge it hangs off and scales the node. Scaling the rect alone was tried first and was wrong: half the HUD draws its own contents at fixed sizes — ResourceReadout lays its rows out in code, Labels carry their own font size — so shrunken boxes kept full-size content and the build button slid up underneath the resource list. Scaling the node takes content and children with it.

What that cost. position (parent space) and size (local space) now differ by the scale, and a lot of code here assumed they did not. Five places, four found by tests after my own test was green:

  • ResourceReadout.content_bottom() added a scaled position to an unscaled height, overstating itself by more than a button — so _seat_hud_columns() pushed the whole column down to clear space nothing occupied. A live bug, not a bad measurement.
  • HUD_COLUMN_MARGIN would have been the one gap still phone-sized on a desktop.
  • _layout_context_buttons() wrote its row stride and horizontal pitch unscaled, landing the action row on the building-action row — which is the second of the two regressions test_hud_layout was written for, in a new disguise.
  • test_hud_layout and test_hangar_management compared authored rects.
  • HudScale reapplies on resize, which wiped the two layouts BuildController writes at runtime — so dragging a desktop window left the context row stranded. Both re-run on size_changed now, deferred, because which of two siblings connected first is not a thing to depend on.

Guard strengthened: test_hud_layout ran at a single window shape, which happened to be the desktop canvas. It now runs every check at both — 1080 units where the scale is 0.45, and 3413 where it is 1.0 — so this class cannot hide at whichever shape was not being exercised.

Rejected approaches. Scaling the UI CanvasLayer does not work at all: Control anchors resolve against the viewport rect, so bottom-anchored elements land mid-screen. A single scaled wrapper Control with the HUD reparented under it is the genuinely clean shape and would need no scale-aware arithmetic anywhere — but it changes every node path and would break every get_node in the controllers and tests. Worth doing if this area is ever reworked.

Two judgement calls left open, both one-liners:

  1. MIN_SCALE floors the shrink at 0.45 rather than the proportional 0.316, because a landscape phone gets the same short canvas as a desktop and there the sticks are still thumb targets. That leaves the HUD at 1.42x its phone share on a PC rather than 1.0x. Keying the scale on GameState.pointer_is_touch instead would give mouse users the full shrink and leave touch devices alone.
  2. The resource readout text now renders around 8px at 1080p — legible but small. Raising the floor, or exempting the readout from scaling, are the two ways out.

177/177 at JOBS=3.

Done in f1292db. **The measurement.** The HUD is authored in canvas units. With stretch `canvas_items` / aspect `expand` over a 1920x1080 base, a 720x1280 phone scales by 0.375 and gets **1920x3413** canvas units — while any 16:9-or-wider screen lands on **1920x1080** units however many pixels it really has. The canvas is three times shorter, so a 148-unit button went from 4.3% of the screen's height to 13.7%. That is 3.16x, confirmed twice: once by hand off the scene file, once by the new test failing with the rule disabled. Worth recording: **nothing collided.** I checked every element pair on both canvases and the same six pairs overlap on each, all of them same-slot alternatives. An earlier claim of mine that the top and bottom bands overlap by 276 units on a PC was wrong — the bands do cross, but no top/bottom pair shares horizontal space. The fault was only that everything was enormous. **The fix.** `ui/HudScale.gd` captures each HUD control's authored offsets once, then moves it toward the edge it hangs off and scales the *node*. Scaling the rect alone was tried first and was wrong: half the HUD draws its own contents at fixed sizes — `ResourceReadout` lays its rows out in code, `Label`s carry their own font size — so shrunken boxes kept full-size content and the build button slid up underneath the resource list. Scaling the node takes content and children with it. **What that cost.** `position` (parent space) and `size` (local space) now differ by the scale, and a lot of code here assumed they did not. Five places, four found by tests *after* my own test was green: - `ResourceReadout.content_bottom()` added a scaled position to an unscaled height, overstating itself by more than a button — so `_seat_hud_columns()` pushed the whole column down to clear space nothing occupied. A **live bug**, not a bad measurement. - `HUD_COLUMN_MARGIN` would have been the one gap still phone-sized on a desktop. - `_layout_context_buttons()` wrote its row stride and horizontal pitch unscaled, landing the action row on the building-action row — which is the second of the two regressions `test_hud_layout` was written for, in a new disguise. - `test_hud_layout` and `test_hangar_management` compared authored rects. - `HudScale` reapplies on resize, which wiped the two layouts `BuildController` writes at runtime — so dragging a desktop window left the context row stranded. Both re-run on `size_changed` now, deferred, because which of two siblings connected first is not a thing to depend on. **Guard strengthened:** `test_hud_layout` ran at a single window shape, which happened to be the desktop canvas. It now runs every check at **both** — 1080 units where the scale is 0.45, and 3413 where it is 1.0 — so this class cannot hide at whichever shape was not being exercised. **Rejected approaches.** Scaling the `UI` CanvasLayer does not work at all: Control anchors resolve against the viewport rect, so bottom-anchored elements land mid-screen. A single scaled wrapper Control with the HUD reparented under it is the genuinely clean shape and would need no scale-aware arithmetic anywhere — but it changes every node path and would break every `get_node` in the controllers and tests. Worth doing if this area is ever reworked. **Two judgement calls left open, both one-liners:** 1. `MIN_SCALE` floors the shrink at 0.45 rather than the proportional 0.316, because a landscape phone gets the same short canvas as a desktop and there the sticks are still thumb targets. That leaves the HUD at 1.42x its phone share on a PC rather than 1.0x. Keying the scale on `GameState.pointer_is_touch` instead would give mouse users the full shrink and leave touch devices alone. 2. The resource readout text now renders around 8px at 1080p — legible but small. Raising the floor, or exempting the readout from scaling, are the two ways out. 177/177 at JOBS=3.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
metaheavens/spaceship#228
No description provided.