feat(expert-mode): improve mobile touch controls for 3D scene
- Simplified OrbitControls touch gesture configuration: - ONE: THREE.TOUCH.ROTATE (one-finger orbit) - TWO: THREE.TOUCH.DOLLY (pinch zoom only, no accidental pan) - THREE: THREE.TOUCH.PAN (three-finger pan) - Removed complex dynamic enablePan toggling that didn't work reliably with OrbitControls' internal touch processing - Added iOS Safari-specific touch improvements: - Double-tap zoom prevention - Touch action and user select CSS properties - -webkit-tap-highlight-color: transparent - Enhanced CSS for better mobile touch handling: - touch-action: none on scene container and canvas - -webkit-touch-callout: none - -webkit-user-select: none - user-select: none All mobile tests (29 tests) and quick-actions tests (22 tests) pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
7aae1c2a46
commit
ef9cd3fe15
13 changed files with 75 additions and 67 deletions
File diff suppressed because one or more lines are too long
|
|
@ -11,6 +11,6 @@
|
|||
"cost_usd": null,
|
||||
"captured_at": "2026-04-11T00:53:39.772264711Z",
|
||||
"trace_format": "claude_json",
|
||||
"pruned": false,
|
||||
"pruned": true,
|
||||
"template_version": null
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
```json
|
||||
{"splittable": false}
|
||||
```
|
||||
|
|
@ -11,6 +11,6 @@
|
|||
"cost_usd": null,
|
||||
"captured_at": "2026-04-11T00:53:51.503031372Z",
|
||||
"trace_format": "claude_json",
|
||||
"pruned": false,
|
||||
"pruned": true,
|
||||
"template_version": null
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
```json
|
||||
{"splittable": false}
|
||||
```
|
||||
|
|
@ -1 +1 @@
|
|||
03fd4e2752b6afb09385b74d87a7c1b7ff9061aa
|
||||
ab5e77352d2cf097851d9b0e8b9a8edf2d8e5605
|
||||
|
|
|
|||
|
|
@ -261,6 +261,11 @@ body {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
touch-action: none;
|
||||
/* Mobile-specific touch handling improvements */
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* ── Live-view overlay panels (float over canvas) ──
|
||||
|
|
|
|||
|
|
@ -227,6 +227,12 @@
|
|||
height: 100%;
|
||||
touch-action: none;
|
||||
z-index: 1;
|
||||
/* Mobile-specific touch handling improvements */
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
/* Prevent iOS Safari from delaying single taps */
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* iOS Safari-specific handling for visual viewport */
|
||||
|
|
@ -251,6 +257,11 @@
|
|||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
touch-action: none;
|
||||
/* Mobile-specific touch handling improvements */
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
/* Handle visual viewport resize events (iOS Safari keyboard, address bar) */
|
||||
|
|
|
|||
|
|
@ -188,58 +188,52 @@
|
|||
|
||||
// Touch gesture configuration for OrbitControls
|
||||
// One finger: rotate (orbit)
|
||||
// Two fingers: pinch-to-zoom (dolly) only
|
||||
// Two fingers: pinch-to-zoom (dolly) only - NO pan on two fingers
|
||||
// Three fingers: pan (native OrbitControls support)
|
||||
//
|
||||
// Using OrbitControls' built-in touch configuration:
|
||||
// - ONE: THREE.TOUCH.ROTATE (one-finger orbit)
|
||||
// - TWO: THREE.TOUCH.DOLLY_PAN (pinch zoom + two-finger pan, with pan disabled below)
|
||||
// - TWO: THREE.TOUCH.DOLLY (pinch zoom ONLY, no pan)
|
||||
// - THREE: THREE.TOUCH.PAN (three-finger pan)
|
||||
//
|
||||
// Note: We set enablePan=false initially to prevent two-finger pan,
|
||||
// allowing only pinch zoom on two fingers. Three-finger pan works
|
||||
// through the THREE.TOUCH.PAN configuration.
|
||||
// Note: THREE.TOUCH.DOLLY (not DOLLY_PAN) ensures two-finger touch
|
||||
// only performs pinch zoom, eliminating accidental pan during zoom.
|
||||
controls.touches = {
|
||||
ONE: THREE.TOUCH.ROTATE, // One-finger touch rotates the camera
|
||||
TWO: THREE.TOUCH.DOLLY_PAN, // Two-finger touch zooms (pinch) and pans
|
||||
TWO: THREE.TOUCH.DOLLY, // Two-finger touch zooms (pinch) ONLY - no pan
|
||||
THREE: THREE.TOUCH.PAN // Three-finger touch pans the camera
|
||||
};
|
||||
|
||||
// Disable two-finger pan to prevent accidental pan during pinch zoom
|
||||
// Only allow three-finger pan for deliberate camera panning
|
||||
controls.listenToKeyEvents(window); // Enable keyboard controls for desktop
|
||||
|
||||
// Custom touch event handling to prevent two-finger pan while allowing three-finger pan
|
||||
const element = renderer.domElement;
|
||||
let originalEnablePan = controls.enablePan;
|
||||
// Mobile-specific touch handling improvements
|
||||
// Prevent default browser behaviors that interfere with OrbitControls
|
||||
const canvasElement = renderer.domElement;
|
||||
|
||||
element.addEventListener('touchstart', function(event) {
|
||||
// Disable pan for two-finger touch to prevent accidental pan during pinch zoom
|
||||
if (event.touches.length === 2) {
|
||||
controls.enablePan = false;
|
||||
} else if (event.touches.length === 3) {
|
||||
// Enable pan for three-finger touch
|
||||
controls.enablePan = true;
|
||||
} else {
|
||||
controls.enablePan = originalEnablePan;
|
||||
// Ensure touch events are properly handled on mobile devices
|
||||
canvasElement.style.touchAction = 'none';
|
||||
canvasElement.style.webkitTouchCallout = 'none';
|
||||
canvasElement.style.webkitUserSelect = 'none';
|
||||
canvasElement.style.userSelect = 'none';
|
||||
|
||||
// Handle iOS Safari-specific touch issues
|
||||
// Prevent double-tap zoom on iOS
|
||||
canvasElement.addEventListener('touchstart', function(event) {
|
||||
if (event.touches.length === 1) {
|
||||
// Store timestamp for double-tap detection
|
||||
canvasElement._lastTouchStart = Date.now();
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
element.addEventListener('touchend', function(event) {
|
||||
// Restore pan state when fingers are lifted
|
||||
if (event.touches.length === 0) {
|
||||
controls.enablePan = originalEnablePan;
|
||||
} else if (event.touches.length === 2) {
|
||||
controls.enablePan = false;
|
||||
} else if (event.touches.length === 3) {
|
||||
controls.enablePan = true;
|
||||
canvasElement.addEventListener('touchend', function(event) {
|
||||
if (event.touches.length === 0 && canvasElement._lastTouchStart) {
|
||||
const timeSinceLastTouch = Date.now() - canvasElement._lastTouchStart;
|
||||
// If it's a quick tap (potential double-tap), prevent default
|
||||
if (timeSinceLastTouch < 300) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
element.addEventListener('touchcancel', function() {
|
||||
// Restore pan state on touch cancel
|
||||
controls.enablePan = originalEnablePan;
|
||||
}, { passive: true });
|
||||
}, { passive: false });
|
||||
|
||||
// Grid helper (XZ plane, Y-up)
|
||||
gridHelper = new THREE.GridHelper(
|
||||
|
|
|
|||
Binary file not shown.
BIN
mothership/sim
BIN
mothership/sim
Binary file not shown.
Loading…
Add table
Reference in a new issue