feat: 驾驶舱控制台交互完善(Cockpit Console Refinements) #15

Closed
opened 2026-09-02 11:09:23 +08:00 by petrezhu · 0 comments
Owner

驾驶舱控制台交互完善(Cockpit Console Refinements)

基于 3584dc9(三区壳)+ f589b98(控制台 tab 化)的第二轮打磨。
通过 grill-me 三轮设计树对齐(Q1-Q10),12 项决策全部落锁。

Problem Statement

驾驶舱 UI 已落地三区壳+右舷控制台三页签(日报/飞船/勘探),但存在三个交互断裂点:

  1. 舷窗→控制台联动断裂:点击已勘探星球仍弹 slide-right 浮层,绕过控制台——「看星球→查矿点」动线被劈成两半。
  2. 重复入口:顶栏倒计时 chip 弹 top-drawer 日报,与控制台已铺开的日报重复。
  3. 控制台宽度固定:460px 对矿点列表偏窄,用户无法按需调整;面板避让规则硬编码,与控制台实际宽度脱节。

此外,船员对话缺少「始终在船上」的陪伴感(需要主动打开浮层),星图被拖乱后无复位手段。

Solution

  1. 星球点击→控制台切勘探页签并同步定位该星域(Shift 保留浮层大视图)。
  2. 倒计时点击→控制台切日报页签(窄屏回退弹抽屉)。
  3. 控制台左边框加拖拽手柄,用户自由调宽(300-700px),宽度写入 --console-width CSS 变量 + localStorage。
  4. 船员常驻前台小窗:屏幕左下角,默认折叠为一行按钮,点击展开/折叠,z-index 最高。
  5. HUD 右下角加复位按钮(重跑 fit + panBy)。

User Stories

  1. As a player, when I click a planet on the star map, the right console automatically switches to the Exploration tab showing that planet's ore list, so I can immediately drill into the knowledge I'm looking at.
  2. As a player, when I shift-click a planet, the full floating panel opens instead, so I can use the wider view when I need it.
  3. As a player, when I click the jump countdown chip in the top bar, the console switches back to the Briefing tab, so I don't see two copies of the daily report.
  4. As a player on narrow screens (≤1100px), clicking the countdown chip still opens the top-drawer briefing, because the console is collapsed and there's no room for it.
  5. As a player, I can drag the console's left border to resize it freely between 300px and 700px, so I can make the ore list wider when scanning sector details.
  6. As a player, while dragging the console width, a DSEG7-style tooltip shows the current width (e.g. "W: 520"), and it disappears when I release the mouse.
  7. As a player, my preferred console width is remembered across sessions (localStorage), so I don't have to re-drag every time.
  8. As a player, when I drag the console wider, all floating panels (ship, mining, test, etc.) automatically adjust their right-edge avoidance to not overlap the console.
  9. As a player, I see a small crew button "[🧑‍🚀 船员]" in the bottom-left corner of the screen, always visible, so I know my crew is "on the bridge" even when I'm not chatting.
  10. As a player, clicking the crew button expands a small floating window (320×420) with the full NPC chat interface, so I can quickly ask a question without leaving my current view.
  11. As a player, clicking the crew button again (or pressing ESC) collapses the crew window, so it doesn't obstruct my work.
  12. As a player, the crew mini-window appears above all other panels (highest z-index), so it's never hidden behind the console or floating panels.
  13. As a player, the crew mini-window shares conversation history with the full NPC panel, so switching between quick-chat and immersive chat doesn't lose context.
  14. As a player, I see a small reset button in the HUD corner of the star map viewport, so I can return to the "commander's default view" after dragging/zooming the map.
  15. As a player, clicking the reset button smoothly re-centers the star map (fit + panBy), so I can quickly orient myself.
  16. As a player, the console CSS uses a single --console-width variable that drives all layout rules (panel avoidance, HUD frame inset, console width), so the system stays consistent when I drag.
  17. As a player, when I first visit (no localStorage), the console defaults to 460px, so the initial experience is identical to the current cockpit.

Implementation Decisions

ID1: CSS Variable Architecture (--console-width)

  • :root { --console-width: 460px } in cockpit.css
  • Drag handler: document.documentElement.style.setProperty('--console-width', newW + 'px')
  • All hardcoded 460px / 486px references in cockpit.css and base.css replaced with calc(var(--console-width) + 12px) or var(--console-width)
  • HUD frame inset: 10px calc(var(--console-width) + 24px) 10px 10px
  • localStorage key: ark.console.width; on load, restore before first paint (sync script or CSS var in <head>)

ID2: Planet→Console Routing (t02 → boot.js)

  • t02 tap handler (explore node click): after setLocation(node.id()), call ARK.showConsoleTab("explore") instead of ARK.show("sector-detail")
  • ARK.t05.ctx.sectorId is set synchronously (fire-and-forget fetch for location POST)
  • Shift-click: ARK.show("sector-detail") (original behavior, wide floating panel)
  • t02 must detect typeof ARK.showConsoleTab === "function" before routing (graceful degradation if boot.js not loaded)

ID3: Countdown→Console Routing (t10 → boot.js)

  • t10 countdown chip click handler: wide screen + console mounted → ARK.showConsoleTab("briefing"); narrow screen → ARK.show("briefing") (top-drawer)
  • window.matchMedia("(max-width: 1100px)") as the switching condition

ID4: Drag Handle

  • Element: 3 horizontal dots (···), 28px tall, positioned at console left border
  • cursor: col-resize; mousedown/mousemove/mouseup listener (touch not needed: ≤1100px console is drawer, no drag handle)
  • Width clamp: Math.max(300, Math.min(700, startX + deltaX))
  • Tooltip: absolute-positioned span showing "W: " + width, appears during drag, hidden on mouseup
  • localStorage write on mouseup (debounced)

ID5: Crew Mini-Window (t04 extension)

  • New element: .ark-crew-mini in bottom-left corner (fixed position, above footer)
  • Default: collapsed = single button [🧑‍🚀 船员] (120px × 36px)
  • Expanded: 320×420 floating window, reuses t04's NPC sidebar + chat area rendering (shared histories dict)
  • z-index: 300 (above console z-3, above center-modal z-200)
  • ESC handler: if crew mini-window is expanded, collapse it (priority below closing floating panels)
  • Transition: one-shot CSS (width/height/opacity), no looping animation

ID6: Star Map Reset Button

  • New element: .ark-hud-reset in HUD frame bottom-right corner
  • Label: small circle with "⟲" or "◉" icon, 24×24px
  • On click: cy.fit(undefined, 60); cy.panBy({ x: -230, y: 0 }) (same as initial load positioning)
  • Must access ARK.t02.cy (exposed in t02 build function)

ID7: Mouse-based Drag Events Only

  • No touch event support needed: at ≤1100px the console is drawer mode (no drag handle visible)
  • No pointer capture needed: simple document-level mousemove/mouseup during drag

Testing Decisions

Test Seams

  1. boot.js ARK.showConsoleTab(key) — Highest seam. All tab switching flows through this API. Tests verify: correct tab activates, content renders, no floating panel opens (except Shift-path).
  2. t02 tap handler — Verify setLocation + showConsoleTab("explore") called; Shift-click → ARK.show("sector-detail").
  3. t10 countdown chip — Verify wide screen → showConsoleTab("briefing"); narrow → ARK.show("briefing").
  4. CSS variable — Verify --console-width is set on drag; all panel avoidance rules use it (CSS regression: check computed right values).
  5. t04 crew mini-window — Verify fold/unfold state transitions; z-index above console; ESC collapses.
  6. HUD reset button — Verify cy.fit + cy.panBy called.

Test Prior Art

  • tests/test_fusion_f4.py: boot API aggregation test (existing seam)
  • tests/test_t02_starmap.py: star map API + Cytoscape rendering tests
  • tests/test_player_flow.py: full e2e player flow (Playwright, 1440×900 viewport)
  • Ad-hoc verification scripts: /tmp/hermes-verify-ark-cockpit.py, /tmp/hermes-verify-ark-tabs.py (pattern: static structure checks + Playwright behavior assertions)

External Behavior Focus

  • Tab switching: verify DOM state (active tab class, content presence) — not internal event flow
  • Drag: verify --console-width CSS variable value changes — not mousemove handler internals
  • Crew mini-window: verify visible/hidden state + z-index ordering — not React-like state management
  • Reset: verify ARK.t02.cy.pan() result — not click handler wiring

Out of Scope

  • Keyboard shortcuts (1/2/3 tab switching, F for fuel collect) — deferred per user decision Q6
  • Touch/pointer drag support — not needed: ≤1100px is drawer mode
  • Control panel width persistence across browser profiles (same localStorage)
  • Crew mini-window voice integration (crew_voice is API-level, unaffected)
  • Star map viewport zoom-to-fit-on-planet-click (separate UX decision)

Further Notes

  • Implementation order: ID1 (CSS variable) → ID4 (drag handle) → ID2+ID3 (routing) → ID6 (reset) → ID5 (crew mini-window). ID1 is the foundation; ID4 depends on it; ID2/ID3 are independent but benefit from ID1 being in place.
  • Regression risk: t02 tap handler change (ID2) affects the main e2e flow (test_player_flow.py step_04); must verify existing ore list rendering still works.
  • localStorage migration: first-time visitors get 460px; existing visitors who already have ark.console.width from prior sessions get their saved value. No migration script needed.
  • Crew mini-window vs ARK.show("npc"): both coexist. Mini-window is quick-chat (320×420), ARK.show("npc") is immersive (full floating panel). They share the same histories dict via t04's IIFE closure.
# 驾驶舱控制台交互完善(Cockpit Console Refinements) > 基于 3584dc9(三区壳)+ f589b98(控制台 tab 化)的第二轮打磨。 > 通过 grill-me 三轮设计树对齐(Q1-Q10),12 项决策全部落锁。 ## Problem Statement 驾驶舱 UI 已落地三区壳+右舷控制台三页签(日报/飞船/勘探),但存在三个交互断裂点: 1. **舷窗→控制台联动断裂**:点击已勘探星球仍弹 slide-right 浮层,绕过控制台——「看星球→查矿点」动线被劈成两半。 2. **重复入口**:顶栏倒计时 chip 弹 top-drawer 日报,与控制台已铺开的日报重复。 3. **控制台宽度固定**:460px 对矿点列表偏窄,用户无法按需调整;面板避让规则硬编码,与控制台实际宽度脱节。 此外,船员对话缺少「始终在船上」的陪伴感(需要主动打开浮层),星图被拖乱后无复位手段。 ## Solution 1. 星球点击→控制台切勘探页签并同步定位该星域(Shift 保留浮层大视图)。 2. 倒计时点击→控制台切日报页签(窄屏回退弹抽屉)。 3. 控制台左边框加拖拽手柄,用户自由调宽(300-700px),宽度写入 `--console-width` CSS 变量 + localStorage。 4. 船员常驻前台小窗:屏幕左下角,默认折叠为一行按钮,点击展开/折叠,z-index 最高。 5. HUD 右下角加复位按钮(重跑 fit + panBy)。 ## User Stories 1. As a player, when I click a planet on the star map, the right console automatically switches to the Exploration tab showing that planet's ore list, so I can immediately drill into the knowledge I'm looking at. 2. As a player, when I shift-click a planet, the full floating panel opens instead, so I can use the wider view when I need it. 3. As a player, when I click the jump countdown chip in the top bar, the console switches back to the Briefing tab, so I don't see two copies of the daily report. 4. As a player on narrow screens (≤1100px), clicking the countdown chip still opens the top-drawer briefing, because the console is collapsed and there's no room for it. 5. As a player, I can drag the console's left border to resize it freely between 300px and 700px, so I can make the ore list wider when scanning sector details. 6. As a player, while dragging the console width, a DSEG7-style tooltip shows the current width (e.g. "W: 520"), and it disappears when I release the mouse. 7. As a player, my preferred console width is remembered across sessions (localStorage), so I don't have to re-drag every time. 8. As a player, when I drag the console wider, all floating panels (ship, mining, test, etc.) automatically adjust their right-edge avoidance to not overlap the console. 9. As a player, I see a small crew button "[🧑‍🚀 船员]" in the bottom-left corner of the screen, always visible, so I know my crew is "on the bridge" even when I'm not chatting. 10. As a player, clicking the crew button expands a small floating window (320×420) with the full NPC chat interface, so I can quickly ask a question without leaving my current view. 11. As a player, clicking the crew button again (or pressing ESC) collapses the crew window, so it doesn't obstruct my work. 12. As a player, the crew mini-window appears above all other panels (highest z-index), so it's never hidden behind the console or floating panels. 13. As a player, the crew mini-window shares conversation history with the full NPC panel, so switching between quick-chat and immersive chat doesn't lose context. 14. As a player, I see a small reset button in the HUD corner of the star map viewport, so I can return to the "commander's default view" after dragging/zooming the map. 15. As a player, clicking the reset button smoothly re-centers the star map (fit + panBy), so I can quickly orient myself. 16. As a player, the console CSS uses a single `--console-width` variable that drives all layout rules (panel avoidance, HUD frame inset, console width), so the system stays consistent when I drag. 17. As a player, when I first visit (no localStorage), the console defaults to 460px, so the initial experience is identical to the current cockpit. ## Implementation Decisions ### ID1: CSS Variable Architecture (`--console-width`) - `:root { --console-width: 460px }` in `cockpit.css` - Drag handler: `document.documentElement.style.setProperty('--console-width', newW + 'px')` - All hardcoded `460px` / `486px` references in `cockpit.css` and `base.css` replaced with `calc(var(--console-width) + 12px)` or `var(--console-width)` - HUD frame `inset`: `10px calc(var(--console-width) + 24px) 10px 10px` - localStorage key: `ark.console.width`; on load, restore before first paint (sync script or CSS var in `<head>`) ### ID2: Planet→Console Routing (t02 → boot.js) - t02 tap handler (`explore` node click): after `setLocation(node.id())`, call `ARK.showConsoleTab("explore")` instead of `ARK.show("sector-detail")` - `ARK.t05.ctx.sectorId` is set synchronously (fire-and-forget fetch for location POST) - Shift-click: `ARK.show("sector-detail")` (original behavior, wide floating panel) - t02 must detect `typeof ARK.showConsoleTab === "function"` before routing (graceful degradation if boot.js not loaded) ### ID3: Countdown→Console Routing (t10 → boot.js) - t10 countdown chip click handler: wide screen + console mounted → `ARK.showConsoleTab("briefing")`; narrow screen → `ARK.show("briefing")` (top-drawer) - `window.matchMedia("(max-width: 1100px)")` as the switching condition ### ID4: Drag Handle - Element: 3 horizontal dots (`···`), 28px tall, positioned at console left border - `cursor: col-resize`; mousedown/mousemove/mouseup listener (touch not needed: ≤1100px console is drawer, no drag handle) - Width clamp: `Math.max(300, Math.min(700, startX + deltaX))` - Tooltip: absolute-positioned span showing `"W: " + width`, appears during drag, hidden on mouseup - localStorage write on mouseup (debounced) ### ID5: Crew Mini-Window (t04 extension) - New element: `.ark-crew-mini` in bottom-left corner (fixed position, above footer) - Default: collapsed = single button `[🧑‍🚀 船员]` (120px × 36px) - Expanded: 320×420 floating window, reuses t04's NPC sidebar + chat area rendering (shared `histories` dict) - z-index: 300 (above console z-3, above center-modal z-200) - ESC handler: if crew mini-window is expanded, collapse it (priority below closing floating panels) - Transition: one-shot CSS (width/height/opacity), no looping animation ### ID6: Star Map Reset Button - New element: `.ark-hud-reset` in HUD frame bottom-right corner - Label: small circle with "⟲" or "◉" icon, 24×24px - On click: `cy.fit(undefined, 60); cy.panBy({ x: -230, y: 0 })` (same as initial load positioning) - Must access `ARK.t02.cy` (exposed in t02 build function) ### ID7: Mouse-based Drag Events Only - No touch event support needed: at ≤1100px the console is drawer mode (no drag handle visible) - No pointer capture needed: simple document-level mousemove/mouseup during drag ## Testing Decisions ### Test Seams 1. **boot.js `ARK.showConsoleTab(key)`** — Highest seam. All tab switching flows through this API. Tests verify: correct tab activates, content renders, no floating panel opens (except Shift-path). 2. **t02 tap handler** — Verify `setLocation` + `showConsoleTab("explore")` called; Shift-click → `ARK.show("sector-detail")`. 3. **t10 countdown chip** — Verify wide screen → `showConsoleTab("briefing")`; narrow → `ARK.show("briefing")`. 4. **CSS variable** — Verify `--console-width` is set on drag; all panel avoidance rules use it (CSS regression: check computed right values). 5. **t04 crew mini-window** — Verify fold/unfold state transitions; z-index above console; ESC collapses. 6. **HUD reset button** — Verify `cy.fit` + `cy.panBy` called. ### Test Prior Art - `tests/test_fusion_f4.py`: boot API aggregation test (existing seam) - `tests/test_t02_starmap.py`: star map API + Cytoscape rendering tests - `tests/test_player_flow.py`: full e2e player flow (Playwright, 1440×900 viewport) - Ad-hoc verification scripts: `/tmp/hermes-verify-ark-cockpit.py`, `/tmp/hermes-verify-ark-tabs.py` (pattern: static structure checks + Playwright behavior assertions) ### External Behavior Focus - Tab switching: verify DOM state (active tab class, content presence) — not internal event flow - Drag: verify `--console-width` CSS variable value changes — not mousemove handler internals - Crew mini-window: verify visible/hidden state + z-index ordering — not React-like state management - Reset: verify `ARK.t02.cy.pan()` result — not click handler wiring ## Out of Scope - Keyboard shortcuts (1/2/3 tab switching, F for fuel collect) — deferred per user decision Q6 - Touch/pointer drag support — not needed: ≤1100px is drawer mode - Control panel width persistence across browser profiles (same localStorage) - Crew mini-window voice integration (crew_voice is API-level, unaffected) - Star map viewport zoom-to-fit-on-planet-click (separate UX decision) ## Further Notes - **Implementation order**: ID1 (CSS variable) → ID4 (drag handle) → ID2+ID3 (routing) → ID6 (reset) → ID5 (crew mini-window). ID1 is the foundation; ID4 depends on it; ID2/ID3 are independent but benefit from ID1 being in place. - **Regression risk**: t02 tap handler change (ID2) affects the main e2e flow (`test_player_flow.py step_04`); must verify existing ore list rendering still works. - **localStorage migration**: first-time visitors get 460px; existing visitors who already have `ark.console.width` from prior sessions get their saved value. No migration script needed. - **Crew mini-window vs ARK.show("npc")**: both coexist. Mini-window is quick-chat (320×420), `ARK.show("npc")` is immersive (full floating panel). They share the same `histories` dict via t04's IIFE closure.
Sign in to join this conversation.
No labels
ready-for-agent
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
petrezhu/ARK#15
No description provided.