Skip to content

feat(19): immersive UI shell + contextual dialogue overlay#7

Merged
moyunzero merged 8 commits into
mainfrom
feat/moyunzero/phase-19-immersive-ui-shell
Jun 15, 2026
Merged

feat(19): immersive UI shell + contextual dialogue overlay#7
moyunzero merged 8 commits into
mainfrom
feat/moyunzero/phase-19-immersive-ui-shell

Conversation

@moyunzero

@moyunzero moyunzero commented Jun 13, 2026

Copy link
Copy Markdown
Owner

Summary

  • Ship Phase 19 immersive shell: ImmersiveShell, wood-frame DialogueBar, ShellDrawer, CornerMenu, and NpcAvatarStrip replacing the old tab bar layout.
  • Add contextual dialogue overlay (DialogueOverlay) with engaged-mode composer, Esc to dismiss, and lighter parchment styling (GAP-19-UI-01 polish).
  • Fix NPC click picking on desktop by using event pointer + camera world coords; add chat bubble bob animation and verify:phase19 layout gate.

Test plan

  • pnpm --filter @aetherlife/web test (89/89)
  • pnpm verify:phase19
  • pnpm agent:verify (pre-push hook)
  • Manual UAT: click NPC → dialogue overlay (not move); hover bubble; drawer/history; debug panels only with ?debug=1
  • Before merge: pnpm agent:verify --e2e golden flows (GF-01–03 if touching speak/move)

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Introduced the Immersive Shell layout with overlay-based UI (corner menu, shell drawer, and dialogue overlay).
    • Added a dialogue bar/overlay experience with an “end dialogue” action.
    • Implemented an interactive nearby NPC avatar strip with improved keyboard support.
    • Added viewport-based NPC visibility and click/hover NPC interactions (with thinking/hover-aware chat bubbles).
    • Enhanced the collective panel with an embeddable mode.
  • Style

    • Updated Phase 19 shell/chat styling and dialogue UI tokens (including reduced-motion behavior).
  • Tests

    • Added unit tests for viewport/NPC selection helpers and immersive shell drawer accessibility.
    • Added a Phase 19 Playwright smoke test (verify:phase19).

moyunzero and others added 7 commits June 13, 2026 10:26
- Introduce full-viewport ImmersiveShell with world/bottomHud/overlays slots
- Add --shell-* and --status-* tokens per UI-SPEC V3
- Deprecate .chat-page 720px column constraints

Co-authored-by: Cursor <cursoragent@cursor.com>
- Refactor ChatPage to use ImmersiveShell slots (world/bottomHud/overlays)
- Add phaser-stage-fill testid and flex-fill CSS chain
- Remove 1:1 aspect-ratio and 576px viewport max-width constraints

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add tickViewportVisibleNpcIds with pure rect overlap helpers and vitest
- Hit-test NPC sprites on pointerup before grid move; publish registry key
- Bridge viewportVisibleNpcIds and onNpcSpriteClick through PhaserGame

Co-authored-by: Cursor <cursoragent@cursor.com>
- Viewport-filtered horizontal avatar chips in bottom HUD with Tomodachi styling
- Wire selectNpc from map clicks and strip; remove NpcTabBar from active UI

Co-authored-by: Cursor <cursoragent@cursor.com>
- Move composer and speak status into bottom DialogueBar without changing useNpcChat
- Add overlay drawer for history, collective browse, and memory tabs
- Replace thick chat-header with corner menu; world column is canvas-only

Co-authored-by: Cursor <cursoragent@cursor.com>
Register Playwright smoke for immersive-shell testids and frozen UX
regression via verify:phase13; keep npc-avatar-strip testid when viewport is empty.

Co-authored-by: Cursor <cursoragent@cursor.com>
Wire Engaged DialogueOverlay (Esc/end, drawer, nearby fallback), fix desktop
pointer pick for map NPC clicks, and refine chat bubble plus parchment shell
styling. Gate debug overlays behind ?debug=1 so normal play matches UAT 9/9.

Co-authored-by: Cursor <cursoragent@cursor.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 56d744c5-2b56-4ca6-978f-6bfa3a859a53

📥 Commits

Reviewing files that changed from the base of the PR and between ce345c3 and 0c2e4a8.

📒 Files selected for processing (8)
  • apps/web/src/ChatPage.tsx
  • apps/web/src/components/DialogueOverlay.tsx
  • apps/web/src/components/NpcAvatarStrip.tsx
  • apps/web/src/components/ShellDrawer.test.ts
  • apps/web/src/components/ShellDrawer.tsx
  • apps/web/src/index.css
  • apps/web/src/lib/stripNpcsForViewport.test.ts
  • apps/web/src/lib/stripNpcsForViewport.ts

📝 Walkthrough

Walkthrough

This PR implements Phase 19's immersive dialogue shell UI. It refactors ChatPage to use a new ImmersiveShell wrapper, adds overlay UI components (CornerMenu, DialogueBar, DialogueOverlay, ShellDrawer, NpcAvatarStrip), introduces viewport-based NPC visibility tracking and pointer hit-testing, integrates NPC selection into game input, animates chat bubbles on hover/thinking, and updates styling and E2E verification.

Changes

Phase 19 Immersive Shell Implementation

Layer / File(s) Summary
ImmersiveShell layout wrapper
apps/web/src/ImmersiveShell.tsx
New top-level wrapper component that defines overlays and world regions for the immersive layout structure.
Overlay UI components
apps/web/src/components/CornerMenu.tsx, DialogueBar.tsx, DialogueOverlay.tsx, NpcAvatarStrip.tsx, ShellDrawer.tsx, ShellDrawer.test.ts, CollectiveBrowsePanel.tsx
CornerMenu renders connection status, players, nearby NPCs, and dialogue controls. DialogueBar handles message composition with drawer access. DialogueOverlay frames engagement with NPC portrait/name. NpcAvatarStrip provides clickable NPC selection tabs with keyboard navigation. ShellDrawer hosts tabbed history, collective, and memory views with accessible tab wiring. CollectiveBrowsePanel adds embedded mode for drawer reuse.
NPC visibility and hit-testing utilities
apps/web/src/game/roomSceneViewport.ts, roomSceneViewport.test.ts
New module exports viewport-based NPC tracking via camera AABB overlap, pointer hit-testing to select top-most NPC by depth, grid-cell fallback, and constant for viewport tick frequency. Includes comprehensive test coverage.
Game input NPC selection
apps/web/src/game/roomSceneInput.ts
Extends input handling for pinch-zoom, NPC hover updates on pointermove, and NPC selection on pointerup with fallback to grid lookup. Stores hover state in registry and integrates bubble refresh on hover changes.
Chat bubble animations and visibility
apps/web/src/game/entitySprites.ts, roomSceneSync.ts
Positions chat bubbles using exported constants and adds bobbing tween animation gated by reduced-motion. Centralizes bubble visibility management via refreshNpcChatBubbles when thinking or hovered. Batches refresh after NPC syncs.
PhaserGame callbacks and registry
apps/web/src/components/PhaserGame.tsx
Adds optional onNpcSpriteClick and onViewportVisibleNpcIdsChange callbacks, wires them into Phaser registry, switches scale mode from FIT to RESIZE, and forwards viewport NPC visibility to client via React effect.
RoomScene viewport ticking and input
apps/web/src/game/RoomScene.ts
Integrates per-frame viewport NPC visibility computation with throttling, wires optional NPC click callback into input context, and publishes visible NPC ids to registry for client forwarding.
Viewport-based NPC filtering utility
apps/web/src/lib/stripNpcsForViewport.ts, stripNpcsForViewport.test.ts
New utility that filters NPC chips based on viewport-visible ids when Phaser is active, or returns the full list when unavailable. Includes test coverage for grid fallback and viewport filtering paths.
ChatPage refactoring with immersive shell
apps/web/src/ChatPage.tsx
Refactors to use ImmersiveShell with overlays and world content. Adds dialogueEngaged state, explicit engagement/disengagement lifecycle, viewport-filtered nearby NPCs, drawer state management, and URL-driven debug flags. Delegates composer to DialogueOverlay and removes old in-page panels.
CSS styling and E2E verification
apps/web/src/index.css, package.json, scripts/verify-phase19.mjs
Adds Phase 19 design tokens and comprehensive styling for immersive-shell layout, overlays, corner menu, drawer, NPC avatar strip, and updated viewport/stage sizing with reduced-motion safeguards. Adds verify:phase19 npm script with Playwright E2E test validating shell layout, dialogue engagement, drawer interactions, and boot-time metrics.

Sequence Diagram(s)

sequenceDiagram
  participant ChatPage
  participant ImmersiveShell
  participant CornerMenu
  participant Phaser as PhaserGame
  participant RoomScene as RoomScene.update
  participant Input as roomSceneInput
  participant Viewport as roomSceneViewport
  participant NPC as entitySprites
  ChatPage->>ImmersiveShell: render world + overlays
  RoomScene->>Viewport: tickViewportVisibleNpcIds
  Viewport-->>RoomScene: visibleNpcIds[]
  RoomScene->>Phaser: registry.set(viewportVisibleNpcIds)
  Phaser-->>ChatPage: onViewportVisibleNpcIdsChange
  User->>Input: pointermove on NPC
  Input->>Viewport: pickNpcAtWorldPoint
  Viewport-->>Input: hoveredNpcId
  Input->>NPC: refreshNpcChatBubbles(hovering)
  NPC-->>User: show + animate bubble
  User->>CornerMenu: click NPC tab
  CornerMenu->>ChatPage: onSelectNpc(npcId)
  ChatPage->>ChatPage: engageNpc(npcId)
  ChatPage-->>User: DialogueOverlay engaged
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • moyunzero/AetherLife#1: Modifies the Phaser NPC sprite/chat-bubble rendering flow including PhaserGame.tsx, RoomScene.ts, and entitySprites.ts around NPC bubble/thinking visuals and scene wiring.
  • moyunzero/AetherLife#6: Earlier modularization of RoomScene; this PR builds directly on it by further updating RoomScene.ts and roomSceneInput.ts for NPC interaction (sprite click/hover and viewport-visible ticking).

Poem

🐰 A shell so immersive, with corners and drawers,
NPCs dance in bubbles across all the floors,
Hit-tests and tweens make the pointers sing true,
Phase 19 blooms bright—let's see what is new! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: introducing an immersive UI shell layout with a contextual dialogue overlay, which aligns with the substantial refactoring across ChatPage, new component additions (ImmersiveShell, DialogueOverlay, CornerMenu, ShellDrawer, NpcAvatarStrip), and layout/styling updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/moyunzero/phase-19-immersive-ui-shell

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/ChatPage.tsx`:
- Around line 230-233: stripNpcs is always derived from viewportVisibleNpcIds so
when PhaserGame isn’t mounted (phaserOk is false) and
onViewportVisibleNpcIdsChange never runs, stripNpcs stays empty and CornerMenu
has no chips; update the useMemo that defines stripNpcs to use
viewportVisibleNpcIds only when phaserOk is true, otherwise fall back to a
nearby NPC set (nearbyNpcIds) if that state exists, and if not available fall
back to showing npcs (i.e., use npcs.filter by nearbyNpcIds when present, else
return npcs); refer to the stripNpcs constant, useMemo, viewportVisibleNpcIds,
phaserOk, onViewportVisibleNpcIdsChange and CornerMenu when making the change.

In `@apps/web/src/components/NpcAvatarStrip.tsx`:
- Around line 55-65: The NPC tabs are only selectable via onPointerDown and
inactive chips use tabIndex={-1}, blocking keyboard users; change the button in
NpcAvatarStrip to use onClick (replace onPointerDown) so activation works with
mouse/touch and keyboard, add an onKeyDown handler that calls onSelect(npc.id)
when Enter or Space is pressed, and implement simple roving-keyboard behavior in
that onKeyDown to handle ArrowLeft/ArrowRight by moving focus to the
previous/next element with role="tab" (or wrapping) so users can navigate tabs
with arrows while preserving aria-selected and tabIndex={isActive ? 0 : -1}.

In `@apps/web/src/components/ShellDrawer.tsx`:
- Around line 69-80: The tab buttons rendered from TABS need proper ARIA wiring:
give each button a stable id (e.g. `tab-${item.id}`) and add aria-controls
pointing to the corresponding panel id (e.g. `panel-${item.id}`), keep
role="tab" and aria-selected as-is; then update the drawer panel elements (the
elements currently labeled by `npc-avatar-*`) to have role="tabpanel",
id=`panel-${id}`, and aria-labelledby=`tab-${id}` and only expose the active
panel (matching the tab state) to screen readers (hide others with aria-hidden
or display:none). Update the CSS class names
`shell-drawer__tab`/`shell-drawer__panel` use and the onTabChange/tab state
logic as needed so IDs match the active item; ensure no changes are left that
reference `npc-avatar-*` as the tab label.

In `@apps/web/src/index.css`:
- Line 186: Remove the unnecessary quotes around the custom font name "Fraunces"
in the font-family declarations (e.g., change font-family: "Fraunces", "Noto
Serif SC", serif; to font-family: Fraunces, "Noto Serif SC", serif;) so the
identifier is unquoted to satisfy Stylelint's font-family-name-quotes rule; make
the same change at each occurrence where Fraunces is currently quoted.
- Around line 835-843: The visually-hidden rule uses the deprecated clip
property; replace the line "clip: rect(0, 0, 0, 0);" with a modern clip-path and
vendor prefix for compatibility (for example, add "clip-path: inset(0 0 0 0);"
and "-webkit-clip-path: inset(0 0 0 0);"), keeping the surrounding properties
(position, width, height, padding, margin, overflow, white-space, border) intact
so the element remains visually hidden but accessible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3e3a19db-a1a0-4a72-93b5-26ba48e009c3

📥 Commits

Reviewing files that changed from the base of the PR and between 94c773a and ce345c3.

⛔ Files ignored due to path filters (1)
  • apps/web/public/assets/sprites/ui-speech.png is excluded by !**/*.png
📒 Files selected for processing (18)
  • apps/web/src/ChatPage.tsx
  • apps/web/src/ImmersiveShell.tsx
  • apps/web/src/components/CollectiveBrowsePanel.tsx
  • apps/web/src/components/CornerMenu.tsx
  • apps/web/src/components/DialogueBar.tsx
  • apps/web/src/components/DialogueOverlay.tsx
  • apps/web/src/components/NpcAvatarStrip.tsx
  • apps/web/src/components/PhaserGame.tsx
  • apps/web/src/components/ShellDrawer.tsx
  • apps/web/src/game/RoomScene.ts
  • apps/web/src/game/entitySprites.ts
  • apps/web/src/game/roomSceneInput.ts
  • apps/web/src/game/roomSceneSync.ts
  • apps/web/src/game/roomSceneViewport.test.ts
  • apps/web/src/game/roomSceneViewport.ts
  • apps/web/src/index.css
  • package.json
  • scripts/verify-phase19.mjs

Comment thread apps/web/src/ChatPage.tsx Outdated
Comment thread apps/web/src/components/NpcAvatarStrip.tsx
Comment thread apps/web/src/components/ShellDrawer.tsx
Comment thread apps/web/src/index.css Outdated
Comment thread apps/web/src/index.css
Restore NPC chips when Phaser is unavailable, add keyboard navigation for
avatar strip and shell drawer tabs, and fix ARIA/CSS review nits.

Co-authored-by: Cursor <cursoragent@cursor.com>
@moyunzero moyunzero merged commit c7f9c05 into main Jun 15, 2026
1 of 2 checks passed
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