# Controls A program using `Forge` can use any camera control scheme they want that is compatible with Three.js and will typically manipulate a `THREE.Camera` object's transform. `Forge` ships with simple, intuitive controls for navigating 3D space that use the keyboard + mouse, game pad, or mobile multi-touch. To add these controls, you can add: ```typescript const controls = new ForgeControls({ canvas: HTMLCanvasElement; }); renderer.setAnimationLoop((time) => { renderer.render(scene, camera);) controls.update(camera); }); ``` `ForgeControls` instantiates two classes `FpsMovement` and `PointerControls` that it updates internally. You can also instantiate and use these two classes separately: ## `class FpsMovement` `FpsMovement` implements controls that will be familiar to anyone who plays First Person Shooters using keyboard + mouse or a gamepad. Creating a `FpsMovement` instance provides many parameters: ```typescript const fpsMovement = new FpsMovement({ moveSpeed?: number; rollSpeed?: number; stickThreshold?: number; rotateSpeed?: number; keycodeMoveMapping?: { [key: string]: THREE.Vector3 }; keycodeRotateMapping?: { [key: string]: THREE.Vector3 }; gamepadMapping?: { [button: number]: "shift" | "ctrl" | "rollLeft" | "rollRight"; }; capsMultiplier?: number; shiftMultiplier?: number; ctrlMultiplier?: number; xr?: THREE.WebXRManager; }); ``` When gamepads are connected, `FpsMovement` will always use gamepad index 0 for twin-stick movement and rotation. If `xr` is passed in, the WebXR controllers can be used as a split gamepad to control movement and rotation. (tested on Quest 3) ### Optional parameters | Parameter | Default | Description | |-----------|---------|-------------| | `moveSpeed` | `1.0` | Base movement speed | | `rollSpeed` | `2.0` | Speed of roll rotation | | `stickThreshold` | `0.1` | Deadzone for gamepad analog sticks | | `rotateSpeed` | `2.0` | Speed of rotation when using gamepad or keys | | `keycodeMoveMapping` | `{...WASD_KEYCODE_MOVE, ...ARROW_KEYCODE_MOVE}` | Maps keyboard keys to movement directions | | `keycodeRotateMapping` | `{...QE_KEYCODE_ROTATE, ...ARROW_KEYCODE_ROTATE}` | Maps keyboard keys to rotation directions | | `gamepadMapping` | `{4: "rollLeft", 5: "rollRight", 6: "ctrl", 7: "shift"}` | Maps gamepad buttons to actions | | `capsMultiplier` | `10.0` | Speed multiplier when Caps Lock is active | | `shiftMultiplier` | `5.0` | Speed multiplier when Shift is held | | `ctrlMultiplier` | `0.2` | Speed multiplier when Ctrl is held | | `xr` | `undefined` | Optional WebXR manager for XR controller stick support ### `update(deltaTime, control)` Call this method in your render loop with `control` set to the object to control (`THREE.Camera` or a `THREE.Object3D` that contains it), with `deltaTime` in seconds since the last update. The update method handles: - Processing keyboard input for movement and rotation - Processing gamepad input for movement and rotation - Applying speed multipliers based on modifier keys and gamepad buttons - Applying movement and rotation to the controlled object ## `class PointerControls` `PointerControls` implements pointer/mouse/touch controls on the canvas, for both desktop and mobile web applications. Creating a new control: ```typescript const pointerControls = new PointerControls({ canvas: HTMLCanvasElement; rotateSpeed?: number; slideSpeed?: number; scrollSpeed?: number; reverseRotate?: boolean; reverseSlide?: boolean; reverseSwipe?: boolean; reverseScroll?: boolean; moveInertia?: number; rotateInertia?: number; doublePress?: ({ position, intervalMs, }: { position: THREE.Vector2; intervalMs: number }) => void; }) ``` ### Require parameters | Parameter | Description | |-----------|-------------| | `canvas` | The HTML canvas element to attach pointer events to | ### Optional parameters | Parameter | Default | Description | |-----------|---------|-------------| | `rotateSpeed` | `0.002` | Speed of rotation when dragging | | `slideSpeed` | `0.006` | Speed of sliding when dragging with right button or two fingers | | `scrollSpeed` | `0.0015` | Speed of movement when using mouse wheel | | `reverseRotate` | `false` | Reverse the direction of rotation | | `reverseSlide` | `false` | Reverse the direction of sliding | | `reverseSwipe` | `false` | Reverse the direction of swipe gestures | | `reverseScroll` | `false` | Reverse the direction of scroll wheel movement | | `moveInertia` | `0.15` | Inertia factor for movement | | `rotateInertia` | `0.15` | Inertia factor for rotation | | `doublePress` | `undefined` | Callback function for double-press/double-tap events | ### `update(deltaTime, control)` Call this method in your render loop with `control` set to the object to control (`THREE.Camera` or a `THREE.Object3D` that contains it), with `deltaTime` in seconds since the last update. The update method handles: - Processing pointer/mouse/touch movements for rotation - Handling dual-press touch gestures for camera movement - Applying scroll wheel input - Calculating and applying inertia for smooth motion - Updating the camera position and orientation ## Adding a simple GUI to configure controls Add `lil-gui` to your package (`npm add lil-gui`) to provide a simple configurable GUI. ```typescript import GUI from "lil-gui"; const gui = new GUI({ title: "Settings + Controls" }).close(); const controlOptions = { reversePointerFps: false, reversePointerPan: false, }; gui .add(controlOptions, "reversePointerFps") .name("Reverse Pointer FPS") .onChange((value: boolean) => { pointerControls.reverseRotate = value; pointerControls.reverseScroll = value; }); gui .add(controlOptions, "reversePointerPan") .name("Reverse Pointer Pan") .onChange((value: boolean) => { pointerControls.reverseSlide = value; pointerControls.reverseSwipe = value; }); ```