Replace fixed mobile joystick with Stampede-style drag control#102
Conversation
Portrait-cover scenes now use horizontal analog drag with an ephemeral indicator at the touch anchor, tap-to-interact, and no on-screen buttons. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Code Review
This pull request replaces the previous mobile touch controls (on-screen joystick, jump, and interact buttons) with a new 'Portrait-Cover Touch Control' system. Players can now drag anywhere on the game area for horizontal analog movement (with an ephemeral drag indicator) and tap to interact, while jump remains desktop-only. Feedback focuses on optimizing performance by caching container coordinates on pointerdown to avoid calling getBoundingClientRect() on every pointermove event, as well as improving pointer handling to prevent multi-touch hijacking and accidental tap interactions during vertical drags.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ba980e428
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Extract reduceControlMatDragIndicator for portrait-cover and control-mat hooks, flatten touch handler return, unexport internal constants, and remove orphaned useTouchGestures. Co-authored-by: Cursor <cursoragent@cursor.com>
Cache drag anchor on pointer down, ignore secondary touches, and treat vertical travel as drag so release does not accidentally tap interact. Co-authored-by: Cursor <cursoragent@cursor.com>
Satisfies react-refresh/only-export-components by colocating reduceControlMatDragIndicator in controlMatDragIndicatorState.ts. Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Portrait-Cover Touch Controlglossary term inCONTEXT.md.Test plan
npm test -- --run src/game/shell/portraitCoverTouchInput.test.ts src/game/shell/InteractiveApp.test.tsxMade with Cursor