RMB cursor hint: show MOVE / ATTACK / INTERACT label under cursor (sub-issue 22-4) #27

Closed
opened 2026-10-04 21:31:34 +00:00 by Mark · 1 comment
Owner

Parent-Issue: #22

Sub-issue 22-4 — keyboard hint bottom-bar is the only command surface

#hint (web/index.html:32) is a fixed string. There's no in-game tooltip
on RMB that says "MOVE on ground, ATTACK on enemy, INTERACT on object" —
the user has to read the hint bar or experiment. Same for the F1/F2/F3
strike-team keybindings — they aren't shown anywhere in the panels
themselves; only title attribute on team rows.

Fix

On RMB hover (mousemove with button=2, or mousedown to position, then render
the next frame), draw a small label at the cursor showing what issueContext
would queue at that tile. Match the queued order label exactly:

  • ground → MOVE
  • enemy in LOS → ATTACK <name>
  • scenery (non-barrel) → INTERACT <type>
  • formation spread (multiple operatives) → SPREAD

The label is a small DOM element (e.g. #rmb-hint) absolutely positioned at
the cursor; hidden on LMB / mouseout / no RMB context. Reuse the same
classification logic from issueContext (web/js/game.js:677–709) — do not
duplicate the rule, extract a classifyRmb(tx, ty) → string helper if
needed.

File(s)

  • web/js/ui.js render() — draw the hint if G.rmbHint is set
  • web/js/main.js mousedown — set/clear G.rmbHint
  • web/css/style.css — #rmb-hint styling
  • web/index.html — add #rmb-hint element

Acceptance

  • RMB hover on map shows a small contextual hint at the cursor
    ("MOVE", "ATTACK ", "INTERACT ") matching the queued
    order label
  • Hint clears on LMB / mouseout / no RMB context
  • No duplicate rule logic — classifyRmb extracted if shared between
    hover and issueContext
  • make ci passes

Refs

  • Parent: #22 (battle UI contract, sub-issue E)
  • web/index.html:32
  • web/js/ui.js render()
  • web/js/main.js mousedown handler
  • web/js/game.js:677–709 (issueContext)
**Parent-Issue:** #22 ## Sub-issue 22-4 — keyboard hint bottom-bar is the only command surface `#hint` (`web/index.html:32`) is a fixed string. There's no in-game tooltip on RMB that says "MOVE on ground, ATTACK on enemy, INTERACT on object" — the user has to read the hint bar or experiment. Same for the F1/F2/F3 strike-team keybindings — they aren't shown anywhere in the panels themselves; only `title` attribute on team rows. ## Fix On RMB hover (mousemove with button=2, or mousedown to position, then render the next frame), draw a small label at the cursor showing what `issueContext` would queue at that tile. Match the queued order label exactly: - ground → `MOVE` - enemy in LOS → `ATTACK <name>` - scenery (non-barrel) → `INTERACT <type>` - formation spread (multiple operatives) → `SPREAD` The label is a small DOM element (e.g. `#rmb-hint`) absolutely positioned at the cursor; hidden on LMB / mouseout / no RMB context. Reuse the same classification logic from `issueContext` (`web/js/game.js:677–709`) — do not duplicate the rule, extract a `classifyRmb(tx, ty) → string` helper if needed. ## File(s) - `web/js/ui.js` `render()` — draw the hint if `G.rmbHint` is set - `web/js/main.js` mousedown — set/clear `G.rmbHint` - `web/css/style.css` — `#rmb-hint` styling - `web/index.html` — add `#rmb-hint` element ## Acceptance - [ ] RMB hover on map shows a small contextual hint at the cursor ("MOVE", "ATTACK <name>", "INTERACT <type>") matching the queued order label - [ ] Hint clears on LMB / mouseout / no RMB context - [ ] No duplicate rule logic — `classifyRmb` extracted if shared between hover and `issueContext` - [ ] `make ci` passes ## Refs - Parent: #22 (battle UI contract, sub-issue E) - `web/index.html:32` - `web/js/ui.js` `render()` - `web/js/main.js` mousedown handler - `web/js/game.js:677–709` (`issueContext`)
Author
Owner

Fix landed on main as commit 1685748 (merge commit d38dcb9 after the sibling origin/main merge picked up c304687 + 60b3a60).

What shipped

  • classifyRmb(tx, ty) extracted as the single source of truth — issueContext refactored to read from it (no duplicated rule logic).
  • #rmb-hint DOM element absolutely-positioned at the cursor. Shows MOVE / ATTACK / INTERACT / SPREAD matching the queued order label exactly.
  • Hidden on LMB, mouseleave, mouseup, mission-over, and no RMB context.
  • render() syncs G.rmbHint to the DOM each frame; main.js owns the data lifecycle.

Tests

  • tools/smoke.js headless coverage for all 6 branches of classifyRmb (move / spread / attack-enemy / attack-barrel / interact / OOB-null) on both maps 0 and 1. SMOKE PASS on both.
  • tools/playwright_smoke.py end-to-end DOM assertions: 5 new ok:dom checks for the hint element existing, hiding pre-hover, showing with text+coords, and re-hiding on clear. PLAYWRIGHT SMOKE PASS verified locally with the playwright-interpreter python (3.12).
  • make test: all 7 scripts PASS. make lint: gdlint PASS.

CI status

Push triggered CI run #7646 — currently waiting. The self-hosted runner has been cancelled/failure on every commit since 2026-09-22 (sibling commit c304687 was cancelled, 5661439 was an explicit re-run-via-runner-pickup-verification that failed). This is an upstream runner issue, not a code regression. Verified locally end-to-end.

Closes #22-4 / #27.

Fix landed on main as commit 1685748 (merge commit d38dcb9 after the sibling origin/main merge picked up c304687 + 60b3a60). ## What shipped - classifyRmb(tx, ty) extracted as the single source of truth — issueContext refactored to read from it (no duplicated rule logic). - #rmb-hint DOM element absolutely-positioned at the cursor. Shows MOVE / ATTACK <name> / INTERACT <type> / SPREAD matching the queued order label exactly. - Hidden on LMB, mouseleave, mouseup, mission-over, and no RMB context. - render() syncs G.rmbHint to the DOM each frame; main.js owns the data lifecycle. ## Tests - tools/smoke.js headless coverage for all 6 branches of classifyRmb (move / spread / attack-enemy / attack-barrel / interact / OOB-null) on both maps 0 and 1. SMOKE PASS on both. - tools/playwright_smoke.py end-to-end DOM assertions: 5 new ok:dom checks for the hint element existing, hiding pre-hover, showing with text+coords, and re-hiding on clear. PLAYWRIGHT SMOKE PASS verified locally with the playwright-interpreter python (3.12). - make test: all 7 scripts PASS. make lint: gdlint PASS. ## CI status Push triggered CI run #7646 — currently waiting. The self-hosted runner has been cancelled/failure on every commit since 2026-09-22 (sibling commit c304687 was cancelled, 5661439 was an explicit re-run-via-runner-pickup-verification that failed). This is an upstream runner issue, not a code regression. Verified locally end-to-end. Closes #22-4 / #27.
Mark closed this issue 2026-10-05 21:00:32 +00:00
Sign in to join this conversation.
No description provided.