Phones and tablets

On a phone, fly mode suits exploring: one-finger look and two-finger move (or the joystick) respond directly. A page offering both modes can start phones in fly:

const touchFirst = matchMedia('(pointer: coarse)').matches;
createVantage({ ...options, modes: ['orbit', 'fly'], mode: touchFirst ? 'fly' : 'orbit' });

The demo does this.

Joystick

fly: { joystick: 'left' } (or 'right') draws a move stick in the bottom corner of the viewer in fly mode. Pushing it moves like WASD (with the fly response curve); every other touch on the scene looks around, so one thumb steers while the other looks. With the stick shown, a two-finger drag no longer moves, and a pinch still sets the speed. setJoystick('left' | 'right' | null) changes it at run time, and with settingsKey the choice is remembered with the other fly settings. The stick is an absolutely positioned element added to the viewer element’s parent (made position: relative if it was static), placed clear of the screen’s safe-area insets; fly.joystickSize sets its diameter (120 CSS px), and fly.joystickCurve its response (the power applied to the push: 1 is linear, 2, the default from fly.curve, leaves more room for slow moves near the center). It shows only in fly mode while the controller is enabled. A page that offers it on touch devices only can pass joystick: matchMedia('(pointer: coarse)').matches ? 'left' : null. The demo starts phones with the stick on the left; its panel moves it or turns it off.

Gestures and tuning

Touch works without page code: vantagekit sets touch-action: none on the canvas, so drags do not scroll the page. Pass touches (camera-controls touch actions) to choose other orbit gestures. A touch device has no F key, so a page that offers both modes needs a button that calls setMode(); pass { lock: false } from a tap, since a phone has no Esc to release a pointer lock. In fly mode there is no up or down gesture: look up or down and move. fly.touchSensitivity (degrees per pixel, 0.25) and fly.touchStickPx (drag distance for full speed, 60) tune the gestures. fitBox steps back on a portrait screen so the box still fits across it; set the camera aspect before framing. For battery and frame rate, cap the renderer’s pixel ratio on phones (renderer.setPixelRatio(Math.min(devicePixelRatio, 2))). touchBindings lists the gestures for a help panel.

Orbit pinch zoom follows the fingers: spreading them to twice their distance halves the distance to the orbit point, as on a map. (camera-controls on its own zooms by the change in finger spread in pixels, measured from the fingers’ midpoint, which on a phone came to about half the finger ratio.) pinchFollowsFingers: false keeps camera-controls’ own rate.