Appearance
Input API
Pointer lock for first-person or mouse-based games.
Overview
Pointer lock (also called "mouse capture") hides the cursor and provides unlimited mouse movement. Essential for first-person games, mouse-look controls, or any game needing raw mouse input.
Methods
requestPointerLock()
Request pointer lock. Usually called after a user interaction (click).
javascript
await gemshell.input.requestPointerLock();Returns: Promise<void>
User Interaction Required
Browsers require a user gesture (click) before pointer lock can be activated. Call this in response to a click event.
exitPointerLock()
Release pointer lock and show the cursor.
javascript
await gemshell.input.exitPointerLock();Returns: Promise<void>
isPointerLocked()
Check if pointer lock is currently active.
javascript
const locked = await gemshell.input.isPointerLocked();Returns: Promise<boolean>
Examples
First-Person Controls
javascript
// Start game on click
document.addEventListener('click', async () => {
if (!await gemshell.input.isPointerLocked()) {
await gemshell.input.requestPointerLock();
}
});
// Handle mouse movement
document.addEventListener('mousemove', (e) => {
if (isPointerLocked) {
// Use movementX/Y for camera rotation
camera.rotation.y -= e.movementX * sensitivity;
camera.rotation.x -= e.movementY * sensitivity;
camera.rotation.x = Math.max(-Math.PI/2, Math.min(Math.PI/2, camera.rotation.x));
}
});
// ESC releases pointer lock (browser default)
document.addEventListener('keydown', async (e) => {
if (e.key === 'Escape') {
await gemshell.input.exitPointerLock();
showPauseMenu();
}
});Click to Play
javascript
let gameStarted = false;
async function startGame() {
if (!gameStarted) {
await gemshell.input.requestPointerLock();
gameStarted = true;
hideStartScreen();
gameLoop();
}
}
document.getElementById('startButton').addEventListener('click', startGame);Pause Menu Integration
javascript
async function togglePause() {
isPaused = !isPaused;
if (isPaused) {
await gemshell.input.exitPointerLock();
showPauseMenu();
} else {
hidePauseMenu();
await gemshell.input.requestPointerLock();
}
}
// Check lock state changes
document.addEventListener('pointerlockchange', async () => {
const locked = await gemshell.input.isPointerLocked();
if (!locked && !isPaused) {
// User pressed ESC or clicked outside - pause game
isPaused = true;
showPauseMenu();
}
});Mouse Look Toggle
javascript
let mouseLook = false;
async function toggleMouseLook() {
mouseLook = !mouseLook;
if (mouseLook) {
await gemshell.input.requestPointerLock();
} else {
await gemshell.input.exitPointerLock();
}
}
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
toggleMouseLook();
}
});RTS Camera
javascript
// Right-click drag for camera rotation
let isDragging = false;
document.addEventListener('mousedown', async (e) => {
if (e.button === 2) { // Right click
isDragging = true;
await gemshell.input.requestPointerLock();
}
});
document.addEventListener('mouseup', async (e) => {
if (e.button === 2) {
isDragging = false;
await gemshell.input.exitPointerLock();
}
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
camera.rotation.y -= e.movementX * 0.003;
camera.pitch -= e.movementY * 0.003;
}
});Notes
- Pointer lock is automatically released when the user presses Escape (browser behavior)
- The cursor is hidden while locked
- Use
movementXandmovementYfrom mouse events for relative movement - Some browsers show a notification when pointer lock is requested
