logo
MouseInput

input

MouseInput

Free

Install with the CLI:

bjs download MouseInput

MouseInput

Turns the pointer into an analog stick and publishes it on the EventBus.

What it does

MouseInput is the pointer half of the input contract KeyboardInput owns for keys. Drop one on a world/singleton entity and its System attaches window listeners, then republishes each pointer event as a canonical bus event: mouse.move with a { dx, dy } delta, mouse.down / mouse.up with a button index, and mouse.lockchanged. Gameplay systems read the mouse off the bus.

Motion comes from movementX/movementY — a relative delta, the only thing that means anything once the cursor is locked and has no on-screen position. The delta goes out in raw device pixels; consumers scale it themselves (see PlayerFlightInput.mouseSensitivity, where 0.0025 works out to ~400px per full stick deflection).

Pointer lock is the reason this component exists rather than a mousemove handler in your bootstrap. With requirePointerLock on, motion before capture is dropped, not queued — otherwise all the travel a player spends reaching for the canvas arrives as one enormous first delta and snaps the ship around. clickToLock spends the first click on capture instead of on the trigger.

Only clicks on the canvas are the game's to take. These are window listeners, so every mousedown in the document reaches this System — including one on a debug panel, a button or a link. Capture is requested, and buttons are reported, only when the event's target is the canvas; anything else is somebody else's click. Without that gate, clicking any overlay swallows the cursor the player was trying to use that overlay with, and only Esc gives it back. The same gate applies to motion while unlocked, so dragging a debug slider does not bank the ship. Once the pointer is genuinely captured the gate lifts — a locked pointer has no on-screen position, and target-gating it then would throw away every delta capture exists to deliver.

Use it in a scene

A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.

Fastest path

bjs download scene MouseInput

Pulls this exact scene into your project and runs it — no copy-paste. Add --all to grab the components and assets it needs too.

Or build it from scratch with the bjs CLI:

  1. 1Scaffold a project
    npm create @babylonjsmarket/arcade@latest my-game

    World, renderer, and dev server — ready to run.

  2. 2Install dependencies
    cd my-game && npm install
  3. 3Add MouseInput
    bjs download MouseInput

    Copies its source into src/ so the scene resolves.

    First time? Run bjs login once.

  4. 4Paste the scene into src/scenes/arcade-room.ts and run
    npm run dev

    SceneLoader builds the world from the JSON; reload to rebuild.

JSON
{
  "World": {
    "tags": ["world"],
    "components": {
      "KeyboardInput": {},
      "MouseInput": { "requirePointerLock": true, "clickToLock": true }
    }
  }
}

Props

  • requirePointerLock (boolean, default true) — ignore motion until the canvas captures the cursor. Turn off for a cursor-driven game where the pointer stays visible.
  • clickToLock (boolean, default true) — the first click on the canvas requests capture rather than emitting mouse.down. Set false for a game that should never swallow the cursor; pair it with requirePointerLock: false if you still want the mouse to steer, and motion then counts only while the pointer is over the canvas.

Events

  • emits mouse.move { dx, dy } — relative motion in device pixels, one event per DOM mousemove. A frame that saw three moves gets three events; accumulate and consume once per frame.
  • emits mouse.down / mouse.up { button } — 0 left, 1 middle, 2 right.
  • emits mouse.lockchanged { locked } — capture taken or released.

Dependencies

None. Pairs with KeyboardInput on the same entity for a full control scheme.

Notes

  • Losing the lock releases held buttons. The DOM sends no mouseup once the pointer is gone, so Esc or a tab-away would otherwise leave the guns firing. The System synthesises an up for every button still down.
  • Clicks on UI never capture. The listeners are global but the gesture is not: pointer capture is a canvas gesture, and a click on an overlay is not a request for it.
  • A lock that already exists is adopted at startup. A scene rebuild reuses the same canvas, so the pointer is often still captured — and no pointerlockchange fires for a lock that never changed. Starting from "unlocked" would silently drop every delta until the player pressed Esc and clicked again.
  • Emission is synchronous: a listener runs inside the DOM handler, so a delta accumulated during a frame is available to that frame's onUpdate with no latency to reason about.
  • Not pauseable — the mouse keeps reaching a pause menu.
  • Inert with no window (SSR, node tests).

More like this

PlayerFlightInput
AiPilot
Animation
ArcCamera
Asteroid
Bullet
CameraFollow
CarDrive
DirectionalLight
EnemySpawner
EnvironmentTexture
FlightIntent
Flipper
FreighterCar
FreighterChain
FreighterHead
GameConfig
Hand
Health
HemisphericLight
Jump
KeyboardInput
KeyboardMover
Lifetime
LineOfSight
MachineGun
Mesh
MeshPrimitive
Missile
MissileLauncher
MissionDirector
Movement
Obstacle
ObstacleField
OilBlob
Parts
Physics
PinballBuilderInput
PlayerInput
PlayerInputBridge
PlayerWalkAnimator
Plunger
PokerInput
RespawnTimer
RoundReset
Score
Shadow
ShipLoadout
SkeletonAnimator
SpaceShooterBullet
SpaceShooterHealth
SpaceShooterScore
TwinStickEnemy
WaveDirector
Waypoint
WaypointTrack

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search