memlnaut-nisps/manifold/src/inputs/xy-pad-source.ts
monkey-w1n5t0n 091cfe2716 feat(inputs): modular input layer — adapter interface + XY/MIDI/gamepad sources
Workstream F core. Pull-based InputSource interface (N axes + discrete
actions), three sources (XYPadSource push-based, WebMidiInputSource with
learn-map CCs/notes, GamepadSource single/double stick), and an InputLayer
that composes active sources into one N-dim vector at the head of the
reactive spine. Arity reduction blends >2 axes down to the fixed 2-input
WASM head; the true multi-WASM reshape is a documented TODO (inputs-spec).

useInputLayer is the React binding (enable/config/status/channel layout).
2026-06-28 04:23:13 +02:00

56 lines
1.4 KiB
TypeScript

/**
* XYPadSource — the existing on-screen XY pad / joystick / manifold drag,
* wrapped as a 2-axis InputSource.
*
* Push-based: the pad's `onMove(x, y)` handler calls `pushAxes(x, y)`, which
* latches the values. `sample()` reads them back through the standard pull path
* so the XY pad composes identically with poll-based sources (MIDI/gamepad).
*
* This is always available (it's an on-screen widget), so it starts `ready`.
*/
import { BaseSource } from './base-source';
import type { InputSourceKind } from './types';
export class XYPadSource extends BaseSource {
readonly kind: InputSourceKind = 'xy-pad';
readonly label = 'XY pad';
private x = 0.5;
private y = 0.5;
constructor() {
super({ state: 'ready', message: 'XY pad ready' });
}
axisCount(): number {
return 2;
}
axisLabels(): string[] {
return ['X', 'Y'];
}
/** Latch the latest pad position (∈ [0,1]). Called from the pad's onMove. */
pushAxes(x: number, y: number): void {
this.x = clamp01(x);
this.y = clamp01(y);
}
sample(out: Float32Array, offset: number): number {
out[offset] = this.x;
out[offset + 1] = this.y;
return 2;
}
start(): void {
this.setStatus({ state: 'ready', message: 'XY pad ready' });
}
stop(): void {
this.setStatus({ state: 'idle', message: 'XY pad off' });
}
}
function clamp01(v: number): number {
return v < 0 ? 0 : v > 1 ? 1 : v;
}