Skip to content

fix(hub): touch, phones and keyboard — tap to inspect, readable belt views, a drawer and tabs that work - #30

Merged
mikim merged 1 commit into
mainfrom
claude/mobile-a11y
Sep 22, 2026
Merged

mikim merged 1 commit into
mainfrom
claude/mobile-a11y

Conversation

@mikim

@mikim mikim commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Stacked on #29 (← #28 ← #27 ← #26) — merge in order. This PR's diff is only its own commit.

Touch: a tap could never show a tooltip

Phaser runs over → up → out for a single tap. The tooltip, the only place the map states a body's health, appeared and vanished in the same gesture, and pointerup had already called window.open. So a phone user could not find out why Algora is not green, and every exploratory tap left the monitor.

  • First tap selects: the body enlarges and its tooltip is pinned beside it. A second tap opens it. A tap on another body moves the selection; a tap on empty space, or opening the panel, clears it. The touch copy reads "tap again to open …".
  • The tooltip is placed from the body's projected screen point. Touch events have no clientX, so it used to land at NaN. It keeps above the finger and inside the viewport.
  • The selection logic is a Phaser-free state machine (src/ui/map-selection.ts) with tests.
  • Mouse behaviour is unchanged, except that a still cursor now tracks the orbit: a body drifting out from under it clears its tooltip.

Phones: belt views drew their text at 3–5 CSS px

The belt zones fit an 800-px-wide world into ~375 px, then filter NEAREST. Following the review's corrected fix, only text that exists nowhere else gets a DOM overlay: debate topics and context, idea titles and scores, Algora signal titles, Bridge trust and outcomes. Below 768 px it appears in a card for the active belt tab (src/ui/belt-card.ts) with its own LIVE/OFFLINE badge. The card has fixed CSS sizes, scrolls, stays clear of the tab bar, and marks the Korean text with lang="ko". The canvas is unchanged.

Labels

  • Labels, and their DOWN/DEGRADED tags, are clamped to the viewport. "Mossland Signal" was cut off at 360–390 px.
  • Ring names (ECOSYSTEM, OFFICIAL …) now sit in a gap between their ring's bodies and turn with them. They used to sit on top of body labels.
  • Labels step clear of the tab bar, legend and footer. At 1024 px, "Recipe" used to sit under the tab bar.
  • DOM overlap counts, sampled over 15 s: ring name over a body label 22–49 → 0 at every width; label under the tab bar 15 → 0; label over the legend 15–29 → 0.
  • The sidebar's Streaming row no longer runs into Algora (Sense) | ….

Keyboard and screen readers

  • Closed drawer (≤767 px): it is visibility: hidden. Its 28 off-screen links used to be in the tab order, with focus vanishing for 28 presses, and in the accessibility tree.
  • Open drawer: opening moves focus in, and the page behind is inert. Escape or a backdrop tap closes it and returns focus to ☰. Rows are 44 px tall with 13 px text on phones; they used to be 16 px and 10 px.
  • Zone tabs follow the WAI-ARIA tabs pattern: roving tabindex, ←/→/Home/End, aria-controls, and #stage as a labelled tabpanel (src/ui/zone-tabs.ts).
  • Decorative overlay labels and the canvas are aria-hidden. An sr-only note points to the Ecosystem list as the keyboard and screen-reader route to every body, and its links now carry each body's status.
  • Contrast: text below WCAG AA is raised, keeping each hue. Inactive tabs go from 3.89 to 6.55, the HUD hint from 2.81 to 5.31, legend headings from 3.11 to 5.66, and the eco group titles from 3.61 to 5.49. Text below 10 px (11 px on phones) is raised.
  • Reduced motion now also stops belt travel and blinking. Every part follows changes to the OS setting while the tab is open (src/ui/motion.ts). The reduced-motion override for the drawer came before the mobile rules in the stylesheet, so the drawer still slid; that is fixed too.
  • The self star said "click to recentre" on a view that is already centred there. The wording now says what it does.

What is verified, and what is not

  • ✅ typecheck, 228 tests, build
  • ✅ Headless Chrome at 375×812, 414×896 and 820×1180 with real Input.dispatchTouchEvent taps on every kind of body (service, streaming, link, file, self). The first tap never opens a window (watched with Target.targetCreated); the second tap does.
  • ✅ Keyboard-only walkthroughs at 1440×900 and 375×812, and an accessibility-tree dump (Accessibility.getFullAXTree) before and after
  • ✅ Reduced motion, both emulated and toggled while the page is open
  • ⚠️ Not tested on a physical phone or with a real screen reader (VoiceOver/TalkBack); worth a quick check after deploy
  • Known leftovers:
    • on 360–375 px phones, some body labels still overlap each other (e.g. "Governance Monitor" and "CoinMarketCap")
    • when no gap is free, ring names and the core label hide instead of overlapping
    • portrait tablets (768–1100 px) get no belt card; that would be a separate feature

🤖 Generated with Claude Code

…views, a drawer and tabs that work

Touch: one tap ran over, up and out in a single gesture, so a phone user
could never see a tooltip — the only place the map states a body's health —
and every tap left the monitor for another site. Now the first tap selects
and pins the tooltip beside the body, a second tap opens it, a tap elsewhere
clears it. The tooltip is placed from the body's projected point (touch has
no clientX, so it used to land at NaN). Selection logic is Phaser-free and
tested. Mouse behaviour is unchanged; a still cursor now follows the orbit.

Phones: the belt views fit a 800 px world into ~375 px, so their text drew at
3-5 CSS px. The text that exists nowhere else (debates, ideas and scores,
signal titles, Bridge trust and outcomes) now also renders in a DOM card for
the active belt tab below 768 px, with its own LIVE/OFFLINE state. Labels are
clamped to the viewport; ring names sit in gaps between bodies instead of on
their labels; labels step clear of the tab bar, legend and footer.

Drawer and tabs: the closed drawer is visibility:hidden (28 off-screen links
no longer sit in the tab order), opening moves focus in, Escape and the
backdrop close it and return focus to the menu button, the page behind is
inert while it is open, and rows are 44 px on phones. The zone tabs follow the
WAI-ARIA tabs pattern (roving tabindex, arrow/Home/End, aria-controls, a
labelled tabpanel); decorative overlay labels are aria-hidden, and a note
points keyboard and screen-reader users to the Ecosystem list, whose links
now carry each body's status.

Reduced motion now also stops belt travel and blinking, and every part
follows changes to the preference while the tab is open. Text below WCAG AA
contrast or below 10 px (11 px on phones) is raised, keeping each hue. The
self star no longer claims to recentre a view that is already centred.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mikim
mikim changed the base branch from claude/health-honesty to main September 22, 2026 03:24
@mikim
mikim merged commit 1a4b72a into main Sep 22, 2026
1 check passed
@mikim
mikim deleted the claude/mobile-a11y branch September 22, 2026 03:25
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