Looking with the Mouse

In which you trigger the camera's behaviors using the mouse.

Cameras that show a first-person perspective of a virtual world are often pointed in other directions by the user's mouse movements. If the user moves the mouse left or right, the camera yaws. If the user moves up or down, the camera pitches. Applications with first-person cameras typically hide the mouse cursor because its absolute position isn't important. Only its relative motion matters.

Browsers provide the PointerLock API to control the mouse's behavior. When the pointer is locked, the mouse is not constrained to the browser window or screen, and the cursor is hidden. To keep a JavaScript application from taking over a user's computer, browsers forbid hiding the pointer until the user has engaged with the page in some way, such as clicking on an element. This JavaScript locks the pointer after the user clicks anywhere on the page:

window.addEventListener('pointerdown', () => {

After the cursor is hidden, the user will start moving the mouse and generating traditional pointermove events. However, instead of asking for the mouse's x- and y-coordinates in your move listener, you ask how much the mouse moved on the x- and y-axes.

This move listener uses the horizontal motion to yaw the camera and the vertical motion to pitch the camera:

window.addEventListener('pointermove', event => {
  if (document.pointerLockElement) {
    camera.yaw(-event.movementX * rotationSpeed);
    camera.pitch(-event.movementY * rotationSpeed);

If the pointer is not locked, then the condition is false and the camera will not yaw or pitch as the mouse moves.

Try out the first-person camera in this renderer. Click on the canvas to lock the cursor.

The camera's pitch is clamped to 15 degrees up or down. Hit Escape to regain your mouse cursor.

Pitching up or down changes the forward vector. Advancing the camera pushes it along this new forward vector. By putting these two actions together, you can fly into the sky or descend through the floor. If this is bad, you might want to consider separating the camera's pitch from the direction of movement.