How many pointers this input is currently tracking (2026-08-06, A-9).
A pointer is tracked from its first event until it ends (pointerup or
pointercancel), so on a healthy surface this is the number of fingers,
pens, and mice that have touched it and not yet let go — never a running
total. Public so that the leak this closed stays testable from outside the
class: a regression is trackedPointerCount climbing with the number of
completed gestures rather than with the number of live ones.
Removes the surface listeners and forgets every pointer's state. Idempotent (§83: teardown paths must not have to test first).
Captures held at dispose are dropped; listeners registered on nodes by the application are not touched, since this object never added them.
Ends a capture. Releasing a pointer that holds none is a no-op.
Routes every further event from pointerId to node until the pointer is
released (§72: "pointer capture must be supported across mixed 2D/3D
objects").
While captured, moves and ups target node whatever the ray touches —
that is the entire point: a slider whose thumb the pointer has already left
keeps receiving the drag. Two consequences follow and are intended:
The capture is released implicitly by the next pointerup from that
pointer (as in the DOM), and explicitly by
PointerInput.releasePointerCapture. Hover resynchronizes on the
first move after the release — the release itself fires no enter or leave,
because a pointer that has not moved has not crossed anything.
Converts a client-pixel position to normalized device coordinates through
the surface's current rectangle, writing [ndcX, ndcY] into out.
ndcX = 2·(clientX − left)/width − 1 and ndcY = 1 − 2·(clientY − top)/height:
the vertical term is subtracted because client Y grows downwards and NDC Y
grows upwards (§7a). A degenerate rectangle (zero width or height,
which is what a hidden canvas reports) would divide by zero, so it yields
(0, 0) — the centre — rather than infinities; such a surface cannot be
pointed at meaningfully anyway.
Public because a caller with its own event source (XR, a gamepad cursor) needs the same conversion, and because it is the one piece of this class worth testing in isolation.
The camera pointer positions are resolved through. Assignable: swapping the camera (a split view, a cut to another angle) takes effect on the next event, and nothing is cached from it.