Controller+BETADownload

controls reference

Read controls by position, independent of the letters painted on the player's controller. Import from @controller-plus/sdk/controls, the package root, or /sdk/src/controls.mjs on your controller origin.

Input and constants

ControlState is { axes: number[4], buttons: number[16], motion?: { gyro?: number[3], accel?: number[3], orientation?: number[4] }, custom?: Record<string, number> }. Axes are −1…1; buttons are 0…1. Right/down are positive. custom is a local helper field, not part of normal wire input. Motion vectors are bounded to −100…100 and quaternion components to −1…1 by the JSON protocol; units must match your sensor adapter.

Index BUTTONS[index] Classic label Standard label
0 face.south B A
1 face.east A B
2 face.west Y X
3 face.north X Y
4 shoulder.left L L
5 shoulder.right R R
6 trigger.left L2 L2
7 trigger.right R2 R2
8 menu.select SELECT SELECT
9 menu.start START START
10 stick.left.press Left stick press Left stick press
11 stick.right.press Right stick press Right stick press
12 dpad.up Up Up
13 dpad.down Down Down
14 dpad.left Left Left
15 dpad.right Right Right

BUTTONS and AXES are frozen arrays. AXES is ['stick.left.x', 'stick.left.y', 'stick.right.x', 'stick.right.y']. CLASSIC_LABELS and STANDARD_LABELS are frozen maps of the four face positions to the letters above. They do not contain the other labels in the table.

Functions

Full signature Parameters, defaults and return
NEUTRAL(): ControlState New zero-filled arrays on every call; no motion.
clamp(value, low = -1, high = 1): number Clamp a number inclusively. Does not validate finite numbers; NaN remains NaN.
deadzone(value, threshold = 0.12): number Return zero inside the threshold; rescale the remaining range to full travel. Supply a finite threshold below 1. Does not clamp or validate.
controlValue(input, id): number Find a positional button/axis, then input.custom[id]; missing values return zero. Requires an input object.
movement(input): [number, number] Add left stick and D-pad, clamping each axis to −1…1. Does not normalize diagonal length.
fromGamepad(gamepad, threshold = 0.12): ControlState Read four axes and sixteen .buttons[i].value values from a browser Gamepad-like object; clamp and apply the axis deadzone. Missing entries become zero.
quantize(input): ControlState Round supplied axes/buttons to three decimals and clone optional motion. Does not validate length, range or finite values; does not copy custom.

These are pure helpers with no events or network traffic. They do not throw custom errors; invalid argument shapes can cause ordinary JavaScript errors. Use protocol validation at a trust boundary.

Read input

import { NEUTRAL, BUTTONS, AXES, CLASSIC_LABELS, STANDARD_LABELS,
  movement, controlValue, clamp, deadzone, fromGamepad, quantize
} from '@controller-plus/sdk/controls';

const input = NEUTRAL();
input.buttons[15] = 1;
input.buttons[0] = 1;
console.log(movement(input));                 // [1, 0]
console.log(controlValue(input, 'face.south')); // 1
console.log(BUTTONS[0], AXES[0], CLASSIC_LABELS, STANDARD_LABELS);
console.log(clamp(2), deadzone(0.05));          // 1, 0
const pad = fromGamepad({ axes: [0.5], buttons: [{ value: 1 }] });
console.log(quantize(pad));

Keep input per playerId and sample it in the simulation loop. See Read and map input for edge-triggered actions, disconnects, physical controllers and motion.