Skip to content

InvalidStateError when clicking while in Pointer Lock mode #235

@ringohoffman

Description

@ringohoffman

Description

When using SparkControls in an application that also utilizes the Pointer Lock API, clicking on the canvas while the pointer is locked results in an Uncaught InvalidStateError.

Uncaught InvalidStateError: Failed to execute 'setPointerCapture' on 'Element': InvalidStateError
    at HTMLCanvasElement.<anonymous> (SparkControls.js:...)

This occurs because SparkControls attempts to call setPointerCapture() on the element during the pointerdown event. According to the spec, setPointerCapture throws an NotFoundError if pointerId does not match any active pointer.

Minimum Reproducible Example

Here is a minimal example demonstrating the error. To reproduce:

  1. Click the canvas to enter Pointer Lock.
  2. Click again while locked.
  3. Observe the error in the console.
<!DOCTYPE html>
<html>
<head>
  <title>SparkControls Pointer Lock Bug</title>
  <style>body { margin: 0; }</style>
</head>
<body>
  <script type="module">
    import * as THREE from 'three';
    import { SparkControls, SparkRenderer } from '@sparkjsdev/spark';

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    const controls = new SparkControls({ canvas: renderer.domElement });
    
    // This simulates an app that uses Pointer Lock for its own camera handling
    renderer.domElement.addEventListener('click', () => {
      renderer.domElement.requestPointerLock();
    });

    function animate() {
      requestAnimationFrame(animate);
      renderer.render(scene, camera);
    }
    animate();
  </script>
</body>
</html>

Suggested Fix

In the pointerdown event listener in PointerControls:

      if (document.pointerLockElement) {
        return;
      }

and maybe also

      if (!this.pointerControls.enable) {
        return;
      }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions