Keep the scenario message banner off the objectives panel - #150
Merged
Conversation
The banner is centred at min(560px,92%) and the objectives panel is right-anchored at min(300px,60vw), and both hang from the top bar — so their vertical ranges always meet and whether they collide is decided horizontally. Solving w/2 + 280 > w - 306 puts the overlap at every viewport up to ~1172px wide, but the only clearance was a media query at the 720px narrow breakpoint. From there up to a windowed desktop the banner painted over the objective head, and the current goal and its progress read as ghost text under it. The panel now publishes its own footprint the way the HUD publishes the top bar's and the command cluster's edges: the first clear y below everything it occupies, and its left edge. The banner places itself from those measurements. Two ways out, tried in order: sideways into the strip left of the panel, which is 524px on an 844px landscape phone and needs no vertical movement at all on a screen where every row below the bar is already spoken for; failing that, down below the panel, bounded by the command cluster so dodging one HUD does not simply land this one — z-index 28 and pointer-events:auto — on the command card and eat its taps. The published bottom is the panel's real bottom, the list's when it is open, so clearing the head no longer just moves the banner onto the list. The two shared CSS variables and the px parser move to layout.ts, where the other cross-overlay edges already live; objectives.ts loses its private copy of the parser. Verified in a browser, message showing, at 844x390, 390x844 and 1280x800, with and without a selection card up: no overlap with the panel or the cluster in any of the six, the banner stays on screen, and the desktop layout is unchanged. Closes #144 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 scenario dialogue banner painted over the objectives panel's head, leaving the current goal and its progress as ghost text under it. The only clearance was a media query at the 720px narrow breakpoint — but that is not where the collision ends. The banner is centred at
min(560px, 92%)and the panel is right-anchored atmin(300px, 60vw), and both hang from the top bar, so their vertical ranges always meet and the overlap is decided horizontally:Every viewport from 721px to ~1171px collided with no clearance applied — landscape phones, small tablets, and a windowed desktop browser. Above ~1172px the banner genuinely cannot reach the panel, which is why it looks fine maximised.
The panel now publishes its own footprint the way the HUD already publishes the top bar's and the command cluster's edges:
--bf-objectives-message-top(the first clear y below everything it occupies) and--bf-objectives-left. The banner places itself from those measurements, with two ways out tried in order:pointer-events: auto, so landing on the command card would swallow its taps for the message's lifetime.If neither fits, it stays under the bar — overlapping the panel it came from is the lesser evil there, since the panel yields its own taps when the column is that full.
The published bottom is the panel's real bottom (the list's when it is open), so clearing the head no longer just moves the banner onto the list instead.
Related issue
Closes #144
Why this approach?
A breakpoint cannot answer this question. Whether two boxes overlap depends on both widths and both anchors, and the panel's own height varies with the objective text and whether its list is open — so the collision is computed from measured edges, the same contract
--bf-top-bar-bottom(#104) and--bf-right-cluster-top(#143) already use. The two shared variables and the px parser move tolayout.ts, where those edges live;objectives.tsloses its private copy of the parser.Sideways-first is deliberate. Dropping the banner is the more obvious fix and is what the old narrow path did, but on a landscape phone it costs vertical space that does not exist, and it moves the text away from where the player is already looking. The horizontal strip is free real estate in exactly the band where the collision happens.
No simulation code is touched; this is all DOM HUD in
packages/game.Verification
npm run typechecknpm test— 1385 passed, 11 skippednpm run build(vianpm run check, bundle budget included)Driven in a real browser on
wallace-1with a message showing, at 844×390, 390×844 and 1280×800, each with and without a selection card up — six states, rects measured directly:overlapsPanelandoverlapsClusterare false in all six, the banner stays inside the root, anddocument.elementFromPointat the objective head returns the head rather than the banner.A review of the first cut caught two things, both fixed here: the drop was unbounded, so on a landscape phone it landed on the command card (the same bug moved); and
position()readoffsetWidthevery frame a message was up, forcing a synchronous reflow — the published edges already cover every case that changes the banner's width.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