Skip to content

Let a short window fold the HUD's scale and timeline away - #1023

Merged
zkWizard merged 4 commits into
mainfrom
codex/uiux-hudfold-20260818-0157
Aug 18, 2026
Merged

Let a short window fold the HUD's scale and timeline away#1023
zkWizard merged 4 commits into
mainfrom
codex/uiux-hudfold-20260818-0157

Conversation

@zkWizard

@zkWizard zkWizard commented Aug 18, 2026

Copy link
Copy Markdown
Owner

The decision three backlog items were waiting on

docs/BACKLOG.md carries three open UI/UX items — the HUD covering the aim
below ~610px, a landscape phone reaching none of the nine overlays, and a phone
dropping the layer caption — and all three end at the same sentence: "a
collapsible or compact panel below a size threshold. Three items now wait on
that one call."
#980 spent the panel's spacing buying the aim back and said in
its own comment that the spacing was then spent; what is left can only come out
of content.

This makes that call in the one way that does not require guessing on the
reader's behalf: the panel keeps every row it has ever had, and gains a way to
fold the two tall ones out of the view.
Nothing folds on its own.

Visible: on a window 720px tall or shorter, a chevron appears in the HUD
panel's top-right corner. Pressing it folds the colour scale and the timeline
away — the panel drops from 294px to 75px at 1280x620 — leaving the layer
selector and the provenance line. Pressing it again restores them. Above 720px
tall the control is not rendered at all.

What the fold keeps, and why that is the design

The layer selector still names what is on the globe, and the provenance line
still carries the product ID and the month (MODIS_Terra_L3_NDVI_Monthly · Jul 2026). No citation and no date is lost to a gesture meant to buy screen
space.
What goes is the colour ramp and the timeline — which are the height,
and which the reader has just said they are not reading. This is deliberately
unlike the phone-caption item the backlog files separately: there the app drops
a compositing caveat silently at a width the reader never chose, here nothing
goes without the gesture that asks for it. No scientific wording was moved or
reworded by this PR.

Verified

  • Height-neutral, measured rather than asserted. The button is out of flow
    and the corner it reserves is horizontal. Re-measuring the expanded panel with
    my two rules neutralised at runtime gives the identical number — 294 vs 294
    at 1280x720 and 266 vs 266 at 1280x665. This is what stops the affordance
    from pushing the panel back over the aim it exists to uncover, and it is a
    test, not a note.
  • The landscape win, stated as the defect. At 844x390 the spec first asserts
    the centre of the view is not the globe — the panel is three quarters of the
    display — then folds the panel and polls until it is. That premise passed on
    origin/main during the red-check, so the defect is real and not an artefact
    of the spec.
  • Cannot strand a row. Both the button and the collapsed state are declared
    inside the same @media (max-height: 720px) block, so a window growing past
    the threshold restores every row on its own. Without this a reader could fold
    the panel at 600px tall, maximise, and be left with rows hidden and no visible
    control to bring them back. The last test drives exactly that sequence.
  • The control meets the 44px touch target on the device it exists for. Its
    first draft was 28px everywhere, which is under the app's own coarse-pointer
    standard on exactly the case this PR headlines — a phone in landscape. It now
    takes 44px under (max-height: 720px) and (pointer: coarse), and the corner
    reserved for it grows with it so the bigger box cannot land on the layer
    selector. This could not be added to a11y.spec.ts's TOUCH_TARGETS list:
    that suite runs at 390x844, a height where this button is deliberately not
    rendered, and it counts "not rendered" as a failure — so the guarantee is
    pinned in the new spec at a size where it does render. No existing spec is
    both short and coarse, so the block is reachable only by the new assertion.
  • Red-checked: with index.html, src/style.css and src/main.ts reverted
    to origin/main, 3 of the 4 new tests fail for the right reason (the control
    does not exist). The fourth passes by design — it asserts the control is
    absent at roomy heights, so it is a guard rather than a red-check candidate.
  • Full local chromium e2e run for the layout change (the HUD trap); unit suite
    4755 passed / 315 files; tsc and prettier clean.
  • Bundle: entry chunk 51.7 kB gzip ok (from 51.1) — one button, two inline
    chevrons and a toggle. Every other chunk ok.

Not closed by this PR

The affordance shipped alone; none of the three items is checked off, and
docs/BACKLOG.md records what each still needs now that the mechanism exists —
the landscape item in particular is unblocked rather than fixed, since the
nine overlays stay unreachable until the bottom-bar layout is re-measured
against a folded panel.

Draft #959 also touches index.html and src/style.css; it is a parked
maintainer decision and was not modified here.

🤖 Generated with Claude Code

zkWizard and others added 4 commits August 17, 2026 20:07
The panel's spacing was spent by #980, which said so in its own comment: below
about 610px the crosshair lands back on the HUD, and a phone held in landscape
is 360-430px tall, where the panel is three quarters of the display. Three
items in docs/BACKLOG.md converge on the same call - the rest of the height can
only come out of content, and which content is the reader's decision rather
than a threshold to guess at.

So the panel keeps every row it has ever had and gains a way to fold the two
tall ones out of the view. What the fold keeps is the point: the layer selector
still names what is on the globe and the provenance line still carries the
product ID and the month, so no citation and no date is lost to a gesture meant
to buy screen space - unlike the phone caption the backlog files separately,
nothing goes without the gesture that asks for it.

The button is out of flow and the corner it reserves is horizontal, so an
expanded panel measures exactly what it did before (294px and 266px, unchanged
at both heights measured). Button and collapsed state are declared inside the
one media query, so a window growing past the threshold restores every row on
its own rather than stranding a reader with rows hidden and no control to undo
it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A phone held in landscape is the case this control was added for, and it is
also a coarse pointer, where the rest of the chrome takes 44px. The button was
28px there. It cannot be added to a11y.spec.ts's TOUCH_TARGETS list, which runs
at 390x844 - a height where this button is deliberately not rendered and where
that suite counts "not rendered" as a failure - so the guarantee is pinned in
hud-collapse.spec.ts at a size where it does render.

The corner reserved for the button grows with it, since a 44px box would
otherwise land on the layer selector, which is the one control the fold always
keeps. Scoped to short AND coarse together: no existing spec is both, and on a
mouse the 28px box is already comfortable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… ring

The full local e2e run caught two defects in the first draft, both real.

The button was in the panel's top-RIGHT corner, which is the strip the overlay
bar reaches into at narrow desktop widths - 66px of overlap at 560px wide - and
toolbar-height-continuity.spec.ts exists precisely to say that strip stays
empty. It moves to the left corner, which is clear of both the bar and the
steppers in the bottom right.

It also fell back to the browser's default focus ring, which a11y.spec.ts
enumerates every keyboard stop to forbid. It now joins the focus-ring parity
block and takes the same 2px accent outline as every other control.

The new spec's own last test flaked: it reloaded the page mid-test to undo an
injected stylesheet. Height neutrality moves to the end of the test instead, so
nothing has to be undone and the second boot is gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant