Stripped Down Version of PointerLockControls Module

In the process of converting my Flight Simulation Demo to modules, I needed to create a version of PointerLockControls that did not automatically rotate the camera. Instead, I merely wanted it to return the XY differences so that I could decide what to do with them. (I use them to fly the plane and, if the shift key is pressed, to rotate the camera.)

Here is the code for the stripped down version (r136):

import {
} from '../../../build/three.module.js';

const _changeEvent = { type: 'change' };
const _lockEvent = { type: 'lock' };
const _unlockEvent = { type: 'unlock' };

const _PI_2 = Math.PI / 2;

class PointerLockControls extends EventDispatcher {

	constructor( camera, domElement ) {


		if ( domElement === undefined ) {

			console.warn( 'THREE.PointerLockControls: The second parameter "domElement" is now mandatory.' );
			domElement = document.body;


		this.domElement = domElement;
		this.isLocked = false;

		const scope = this;

		function onMouseMove( event ) {

			if ( scope.isLocked === false ) return;

			const movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
			const movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
			MosXDf = movementX;
			MosYDf = movementY;


		function onPointerlockChange() {

			if ( scope.domElement.ownerDocument.pointerLockElement === scope.domElement ) {

				scope.dispatchEvent( _lockEvent );

				scope.isLocked = true;

			} else {

				scope.dispatchEvent( _unlockEvent );

				scope.isLocked = false;



		function onPointerlockError() {

			console.error( 'THREE.PointerLockControls: Unable to use Pointer Lock API' );


		this.connect = function () {

			scope.domElement.ownerDocument.addEventListener( 'mousemove', onMouseMove );
			scope.domElement.ownerDocument.addEventListener( 'pointerlockchange', onPointerlockChange );
			scope.domElement.ownerDocument.addEventListener( 'pointerlockerror', onPointerlockError );


		this.disconnect = function () {

			scope.domElement.ownerDocument.removeEventListener( 'mousemove', onMouseMove );
			scope.domElement.ownerDocument.removeEventListener( 'pointerlockchange', onPointerlockChange );
			scope.domElement.ownerDocument.removeEventListener( 'pointerlockerror', onPointerlockError );


		this.dispose = function () {



		this.lock = function () {



		this.unlock = function () {






export { PointerLockControls };

In the operating program, I had to define MosXDf and MosYDf prior to importing the PointerLockControls module. I used essentially all of the setup from the example (misc_controls_pointerlock.html) verbatim, except that I did not include:

scene.add( controls.getObject() );

Let me know if this all looks okay or if I have overlooked something critical.

You can see the revised module in action here.

NOTE: The reason I needed to use PointerLockControl is that the normal MouseMove routine is designed to operate within the limits of a screen. So, when using the normal routine, it was easy to get jammed up against a side of a screen, such that the controls would no longer work in that direction. In contrast, the PointerLockControls only detect changes in Mouse position

I was in this same predicament a few days ago myself and I decided to utilize yomotsu/camera-controls as an alternative to editing the native stuff. You’re already done, so this is probably fine and I wouldn’t worry too much but this is more to offer an alternative option for you or others down the road.

In my case, I noticed the PointerLockControls module was causing some weird behavior where the camera would ‘jump’ or ‘skip’ sometimes. I could essentially make the side effect occur less often, but not entirely prevent it from happening.

I also feel like the three.js camera controllers leave a lot to be desired and this library is really really nice to have in a pinch, especially for game-like projects where controls are of higher importance.

Thanks. It’s always good to have alternatives. However, the link you gave does not work.

I have never had any problems with the three.js camera controllers - or my slightly modified versions of them. To the contrary, one would expect that the official three.js versions would work seamlessly with three.js programs.

If you are just after xy offset between events, you do not need PointerLockControls not even Pointer Lock API.
You also don’t need the outdated vendor prefixes.

Element.onmousemove = function get_xy(event) { return [ event.movementX , event.movementY ] } 

My wireless keyboard fires 60 times/sec, wired keyboard should do 125 and gamers much higher.

Thanks, I will give that a try.
I agree that 60 reads per second minimum should be plenty.
Is there a way to make the pointer disappear as it does with PointerLockControls? = ‘none’; // to hide the mouse = ‘none’ // to hide from JavaScript

To mask an overlaid element form event action pointer-events does wonders.

To get RayTracer working correctly in all scenarios event.offsetX event.offsetY.

See it in action

1 Like

Thanks! I hadn’t found anything helpful online.
This definitely shows that it can be done and and done well.

my mistake, GitHub - yomotsu/camera-controls: A camera control for three.js, similar to THREE.OrbitControls yet supports smooth transitions and more features.

1 Like

Very impressive!