Bound the command card to the screen so its buttons stay reachable - #157
Merged
Merged
Conversation
The right-hand cluster is bottom-anchored with no bound of its own, so a card taller than the screen sent its excess off the TOP. Measured on an 844x390 landscape phone with a town centre selected: a 531px card in a 390px root, its first train button at y -74..-30. The Q train button, both research buttons and the title were above the viewport, nothing scrolled, and a player on that device could not train a villager or research anything from a town centre at all. The cluster now takes a measured max-height — from its own bottom up to whichever is lower, the top bar or the objectives panel's head — and the card scrolls inside it, top-anchored so the title and train row are what you see first. The bound is converted into the scaled stage's units, since the cluster lives inside the stage while the edges are measured on the unscaled root. It reads the objectives HEAD and never the panel's full height: the panel's list is already measured against this cluster, so the list would close a layout loop. The queue's full 140px reserve exists so chips appearing never shove the bottom-anchored card's train buttons under the player's thumb. A capped card scrolls, so its box cannot move and the reserve protects nothing — it drops to one row there, judged against the card as it would be with the reserve restored so the two states cannot flip-flop. Five fixes from review of the first cut, all confirmed in a browser: rebuildCard writes '0px' rather than clearing minHeight, so the "does this building queue?" test is a flag now instead of a style read that never matched — a villager was getting a phantom reserve; the same broken test was inflating every capped card by 96px and defeating the hysteresis; the card's scroll position is preserved across a rebuild, which the card key triggers on every train tap and every hp tick under attack; the scrollbar is hidden, because a classic one takes 15px out of a 246px box holding a 236px grid of 44px buttons and clipped the fifth column; and the bound is never applied from inside the cluster's own ResizeObserver. Verified at 844x390, 1280x800 and 390x844, and at 75%/125% HUD scale: nothing off-screen, every command button reachable, the desktop card unchanged and still holding its full reserve, no ResizeObserver errors. Closes #151 Signed-off-by: Claude <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed?
The right-hand cluster is bottom-anchored with nothing bounding its height, so a card taller than the screen sent its excess off the top. Measured on an 844×390 landscape phone with a Town Center selected:
The Q train button, both research buttons and the title were off-screen, nothing scrolled, and a player on that device could not train a villager or research anything from a Town Center at all.
The cluster now takes a measured
max-height— from its own bottom up to whichever is lower, the top bar or the objectives panel's head — and the card scrolls inside it, top-anchored so the title and train row are what you see first. The bound is converted into the scaled stage's units, since the cluster lives inside the stage while every edge is measured on the unscaled root.The queue's 140px reserve (26% of that card, empty) exists so chips appearing never shove the bottom-anchored card's train buttons under the player's thumb. A capped card scrolls, so its box cannot move and the reserve protects nothing — it drops to one row there.
Related issue
Closes #151
Why this approach?
Same contract as the two HUD fixes before it (#143, #144): each overlay publishes its real edges and the others size themselves from measurement. A breakpoint cannot answer this one either — the card's height depends on the selected building, the bar wraps, and the HUD scale setting moves both edges.
The bound reads the objectives head and never the panel's full height. The panel's list is already measured against this cluster, so feeding the list back in would close a layout loop; the head's height depends only on the objective text, which nothing here influences.
Dropping the reserve is judged against the card as it would be with the reserve restored. Measuring the shortened card would let a card that only just overflows un-cap itself, restore the reserve, overflow again, and flip every frame.
Alternatives considered: shrinking the 44px cells (the touch floor is not negotiable), and paginating the card (a redesign, not a fit). Scrolling keeps every control exactly where it is.
No simulation code is touched; this is all DOM HUD in
packages/game.Verification
npm run typechecknpm test— 1391 passed, 11 skippednpm run build(vianpm run check, bundle budget included)Driven in a browser on
wallace-1with a Town Center selected:offScreenPx: 0andeveryButtonReachable: truein all five; desktop is byte-for-byte the layout it had before.A review of the first cut found five defects, each then confirmed fixed in the browser:
rebuildCardwritesminHeight = '0px'rather than clearing it, so the "does this building queue?" test never matched — a villager got a phantom reserve, and every capped card was judged 96px taller than it was, defeating the hysteresis. It is a flag now (villagerReserve: 0px, still0pxacross a viewport flip).gridClipped: false, 5 columns).ResizeObserver, which is what produces "ResizeObserver loop completed with undelivered notifications". Its inputs each notify separately now (resizeObserverErrors: 0).Provenance and AI assistance
Claude Code (Anthropic) wrote the implementation, tests and this description, driven and reviewed by the repository owner. No generated assets.
Contributor checklist
CONTRIBUTING.mdand followed the deterministic simulation rulesgit commit -s)Generated by Claude Code