Controls
A program using Forge
can use any camera control scheme that is compatible with THREE.js and will typically manipulate a THREE.Camera
object's transform. Forge
also 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 create a ForgeControls
instance:
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:
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;
});
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:
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.
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;
});