← Brand Vantage · Web Developer
Hand Voice Bench

Touch scroll sensor
Pointer events

Appendix — input

Scrolling by holding still

Press and hold the upper half of the pad and the page scrolls up; hold the lower half and it goes down. How far from the centre you press sets the speed, so a touch near the middle creeps and one near the edge travels — the same throttle law the hand sensor uses, driven by a finger instead of a palm. A quick tap jumps one screen. Switch to Drag to throw the page around with fling inertia instead, or take over the whole screen as one giant pad. Works with touch, pen and mouse alike, because they are all just pointers.

01

One event model, three input devices

Pointer events unify mouse, pen and touch behind one interface, so nothing here branches on device type. A mouse is simply a pointer that reports pressure 0.5 and never has a second contact. Writing to touch events alone would have excluded every desktop visitor for no benefit.

02

The browser wants this gesture

By default a drag on a touchscreen belongs to the browser's own scrolling, and it takes it without asking — pointermove stops arriving partway through and the element goes dead. touch-action: none is what declines that, and it is the one line this page cannot work without.

03

Capture, or lose the finger at the edge

Slide off the pad mid-gesture and events stop unless the pointer was captured. setPointerCapture redirects everything to the original element until release, which is what lets a hold near the edge keep working when your finger drifts outside.

04

Pressure is real, and mostly absent

Pens report genuine pressure, most touchscreens report a constant, and mice always say 0.5 while a button is down. It is shown here because it is interesting, not because anything depends on it — building a control that needs pressure excludes almost every device.

05

A tap is a hold that changed its mind

There is no tap event worth having. A tap is defined here as a contact released within 180 ms having moved less than 10 px — both conditions matter, since a fast flick satisfies the first and should never be mistaken for a tap.

06

Fling is just velocity you kept

Drag mode samples the last few moves before release and keeps that velocity, then decays it. Sampling the final event alone gives a number that is mostly noise; averaging over roughly the last 100 ms is what makes a throw feel like it went where you aimed it.

End — tap the upper half to go back
▲ Up
▼ Down

Press & hold

Pointer—
Contacts0
Pressure—
Position—
Zone—
Hold—
Velocity—
Progress0%
Gesture—
Checking input capabilities… maxTouchPoints — hover:none — pointer:coarse — last pointer —

Gesture

Hold above or below centre — distance sets the speed

How it works — the signal chain

Five stages between a finger and a scrollbar

Touch is the shortest of the three chains on this site — no model to load, no service to call, no latency worth measuring. Which means every problem it has is a problem of ownership: who gets the gesture, and who keeps it.

Stage 01

Claim

touch-action: none tells the browser not to interpret drags on this element as scrolling. Declared in CSS rather than by calling preventDefault, so the compositor knows before the gesture starts instead of after.

out → events keep arriving
Stage 02

Capture

setPointerCapture on pointerdown binds the pointer to the pad until release, so a finger sliding past the edge keeps reporting instead of silently vanishing.

out → pointer id
Stage 03

Normalise

Client coordinates become a 0–1 position within the pad, clamped. Everything downstream works in that space, which is why the pad, the fullscreen veil and any future surface can share one control law.

out → y · 0–1
Stage 04

Classify

Dead band, then direction, then a response curve — the same throttle used by the hand sensor. On release, duration and travel decide whether it was a tap, a hold, or a fling worth keeping velocity from.

out → velocity · px/s
Stage 05

Integrate

Velocity eases toward its target and accumulates into scrollTop, stopping itself at either end. Identical to the other two sensors, because by this point the input device has been abstracted away entirely.

out → scrollTop · px

The one line that matters

Why the gesture stops halfway through

Write this without touch-action: none and it will work perfectly with a mouse, work in the desktop device emulator, and fail on a real phone in a way that looks like a dropped event. You press, you drag, and a few frames in pointermove simply stops. Nothing errors.

What happened is that the browser decided the gesture was a scroll. Touch gestures are handled on the compositor thread so that scrolling stays smooth while JavaScript is busy, which means the decision to claim a gesture is made before your handler runs and cannot be undone from inside it. Calling preventDefault on the first pointermove is already too late, and on a passive listener it does nothing at all — touch listeners default to passive precisely so that scrolling cannot be blocked by slow JavaScript.

touch-action is the declaration that resolves this. It is CSS, so the compositor knows the element's intentions before a finger lands. none claims every direction; pan-x would keep horizontal scrolling and claim only the vertical, which is what a carousel wants.

Two gestures

Holding and throwing solve different problems

GestureHow it behavesWhere it wins
ZonesDefault Press and hold; position from centre sets a steady speed, held as long as you stay down. Long documents and one-handed use. Your thumb never moves, nothing accelerates away from you, and releasing always means stop. This is what a reading control should do.
Drag The page follows your finger directly, then keeps going when you throw it. Short, precise moves — nudging a paragraph into view. Familiar because it is what every native list does, but crossing a long document means repeated strokes.

The pattern across all three sensors on this site is the same: position for holding, motion for throwing. The hand sensor's Hold and Wave modes are these two ideas driven by a palm; voice reaches the same place with a latched direction, since a word cannot express a distance at all.

Nothing is captured and nothing leaves the page. Unlike the hand and voice sensors, this one needs no permission, no model and no network — pointer events are simply delivered. The pad claims gestures only within its own bounds; the rest of the page scrolls normally, and Esc stops motion and releases the fullscreen surface.

Idle