Skip to content

Repository files navigation

pjfix icon

pjfix

Raw (unaccelerated) pointer-lock mouse input and jump-delta filter for Web 3D games.

Fixes the sudden view / crosshair jumps in browser games that use the Pointer Lock API (Eaglercraft, krunker, three.js FPS demos, and similar) — without touching the game's code.

npm downloads license dependencies Node raw input

▶ Usage  ·  npm  ·  Configuration  ·  How it works


Root cause

Camera spin-outs under pointer lock are caused by three well-known issues:

Cause Description Fix
OS mouse acceleration Locking without options delivers accelerated values, so fast movement over-rotates the camera Inject unadjustedMovement: true
High-polling-rate mice Chromium (Windows) with 500–1000 Hz mice randomly spikes movementX/Y (e.g. 1 → 627) Velocity spike filter
Lock re-acquire / tab resume A single huge delta arrives right after (re)lock and tab focus return Recovery window (120 ms) + stall detection (250 ms)

Usage

A) npx — recommended for most users

pjfix is a zero-install CLI: if you have Node installed, it downloads and runs automatically. Point it at the folder that contains your game HTML files:

npx -y pjfix                        # inject into all *.html in the current directory
cd E:\games && npx -y pjfix         # go to your game folder first, then run it

Each targeted file gets a *.orig backup automatically — nothing is ever lost:

npx -y pjfix                        # patch all *.html in the current dir (backs up as *.orig)
npx -y pjfix a.html b.html         # only these files
npx -y pjfix --root ..              # target the parent directory instead
npx -y pjfix --unpatch              # restore the original files from *.orig
npx -y pjfix --help                 # show all options
npx -y pjfix --version              # print the version

Works when opened via file://. Re-running updates the fix in place; --unpatch restores the originals any time.

  • Requires: Node.js 18+. If you don't have Node, use the userscript (B) or the one-line <script> include (C) instead.

B) Browser extension userscript (Tampermonkey / Violentmonkey)

Paste pointer-jump-fix.user.js as a new script. Narrow the @match lines to limit targets.

C) Direct include

<script src="pointer-jump-fix.js"></script>

Configuration

Define window.__PLFIX__ before the script runs to override defaults (in the userscript put it before the CORE marker).

window.__PLFIX__ = {
  unadjustedMovement: true, // inject { unadjustedMovement: true } into requestPointerLock
  clampEnabled: true,       // absolute-delta safety limiter
  maxDelta: 0,              // 0 = auto (larger screen edge ×2)
  recoverMs: 120,           // recovery window after lock/focus re-acquire (ms)
  stallMs: 250,             // zero the first delta after an inactivity longer than this (ms)
  spikeFloor: 256,          // min delta (px) to be considered a spike
  spikeRatio: 6,            // reject deltas above this multiple of the recent average (flicks pass)
  spikeMaxGapMs: 64,        // max event gap for a spike verdict (ms)
  resetOnRelock: true,      // recovery window on pointerlockchange / pointerlockerror
  resetOnFocus: true,       // recovery window on focus / visibilitychange
  autoRelock: false,        // click to re-lock after Esc
  relockGraceMs: 1500,      // auto-re-lock grace period after Esc (ms)
  debug: false              // log activity to the console
};

Debugging

window.__PLFIX__stats exposes hit counters for every filter:

__PLFIX__stats.clamped()   // events zeroed by the absolute limiter
__PLFIX__stats.spiked()    // events zeroed by the spike filter
__PLFIX__stats.stalled()   // events zeroed by stall recovery
__PLFIX__stats.recovered() // events zeroed inside the recovery window
__PLFIX__stats.rawLocks()  // requestPointerLock calls with injected raw input
__PLFIX__stats.config      // active configuration

Development

npm test                     # core + CLI self-tests (Node only)
node cli.mjs --help          # CLI reference
npm pack --dry-run           # preview the publish contents

Files

File Purpose
pointer-jump-fix.js Core (HTML injection / console)
lib.mjs Shared inject / restore / build logic
cli.mjs CLI (also the npm bin entry)
pointer-jump-fix.user.js Tampermonkey / Violentmonkey userscript (synced from core)
test/ Core and CLI test suites (npm test)

Notes

  • No effect on games or pages that do not use Pointer Lock.
  • To run the userscript on file:// pages, enable "Allow access to file URLs" in the userscript manager settings.
  • A Chrome extension with the same core lives in a separate folder / repository (not part of this package).
  • Use at your own risk if game terms of service prohibit modifications.

About

Stops pointer/camera jumps in Web 3D games - raw (unaccelerated) pointer-lock input + spike/re-acquire filtering for Eaglercraft, krunker, three.js FPS. CLI (npx), userscript and Chrome extension.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages