idle
SourceA snapshot with nothing held, for initializing an input resource before the first capture.
Browser
Touch controls over one element: a floating stick, buttons (some of which aim by dragging: tap to use, drag to aim, release to fire), and an optional swipe area that reports how far a finger moved, for turning or camera control (Genshin Impact style: move on the left, swipe anywhere to look).
The layout is a function of the element's size, so controls stay anchored to corners on any screen. Each finger belongs to the first control it lands on: a button when it lands inside one, otherwise the stick when it lands in the stick's region (the stick then appears under the thumb), otherwise the swipe area when it lands in its region. Fingers that land elsewhere are ignored, and a control keeps its finger until it lifts.
Games read one snapshot per update, like keyboard actions: the stick's vector, and per button held/pressed/released edges that survive taps shorter than a frame, plus the drag aim, which is still reported on the release. A touch the browser cancels (a system gesture, the window losing focus) releases with cancelled: true, so games can skip firing. view() returns the live positions for drawing the controls without consuming edges.
Only touch pointers are tracked by default, so a mouse keeps working through Pointer; pass pointerTypes to also drive the controls with a mouse while developing. The module sets touch-action: none on the element so the browser does not scroll or zoom under the controls.
const touch = Touch.track(canvas, window, ({ width, height }) => ({
stick: { region: { left: 0, top: 0, width: width / 2, height }, radius: 60 },
buttons: {
attack: { center: { x: width - 90, y: height - 90 }, radius: 55, aimRadius: 80 },
dash: { center: { x: width - 200, y: height - 60 }, radius: 36 }
}
}))
// Once per update:
const { stick, buttons } = touch.snapshot()
move(stick.vector)
if (buttons.attack.released && !buttons.attack.cancelled) fire(buttons.attack.aim)
For tests and headless runs, scripted(...) plays a timeline of stick vectors, presses, drags, and releases.
A snapshot with nothing held, for initializing an input resource before the first capture.
trackStarts tracking touches over target with the controls layout returns for the element's current size (it is read again on every new touch, so a resize takes effect at the next touch). blurHost (usually window) cancels held controls when the page loses focus.
scriptedPlays timeline over controls named buttons: before the snapshot at index frame, every entry for that frame is applied. Vectors longer than 1 are clamped. Scripted controls report touched from the first entry on.
A snapshot with nothing held, for initializing an input resource before the first capture.
Starts tracking touches over target with the controls layout returns for the element's current size (it is read again on every new touch, so a resize takes effect at the next touch). blurHost (usually window) cancels held controls when the page loses focus.
Plays timeline over controls named buttons: before the snapshot at index frame, every entry for that frame is applied. Vectors longer than 1 are clamped. Scripted controls report touched from the first entry on.