@forgeax/engine-input 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +312 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/__tests__/browser-backend-dual-instance.test.d.ts +2 -0
  5. package/dist/__tests__/browser-backend-dual-instance.test.d.ts.map +1 -0
  6. package/dist/__tests__/browser-backend-focus-loss.test.d.ts +2 -0
  7. package/dist/__tests__/browser-backend-focus-loss.test.d.ts.map +1 -0
  8. package/dist/__tests__/browser-backend-lock-error.test.d.ts +2 -0
  9. package/dist/__tests__/browser-backend-lock-error.test.d.ts.map +1 -0
  10. package/dist/__tests__/browser-backend-lock-gate.test.d.ts +2 -0
  11. package/dist/__tests__/browser-backend-lock-gate.test.d.ts.map +1 -0
  12. package/dist/__tests__/browser-backend-lock-release.test.d.ts +2 -0
  13. package/dist/__tests__/browser-backend-lock-release.test.d.ts.map +1 -0
  14. package/dist/__tests__/browser-backend-lock-state.test.d.ts +2 -0
  15. package/dist/__tests__/browser-backend-lock-state.test.d.ts.map +1 -0
  16. package/dist/__tests__/canvas-input-boundary.test.d.ts +2 -0
  17. package/dist/__tests__/canvas-input-boundary.test.d.ts.map +1 -0
  18. package/dist/__tests__/canvas-input-owner.test-d.d.ts +2 -0
  19. package/dist/__tests__/canvas-input-owner.test-d.d.ts.map +1 -0
  20. package/dist/__tests__/composite-backend.test.d.ts +2 -0
  21. package/dist/__tests__/composite-backend.test.d.ts.map +1 -0
  22. package/dist/__tests__/controller-platform-owner.test-d.d.ts +2 -0
  23. package/dist/__tests__/controller-platform-owner.test-d.d.ts.map +1 -0
  24. package/dist/__tests__/input-snapshot.test-d.d.ts +2 -0
  25. package/dist/__tests__/input-snapshot.test-d.d.ts.map +1 -0
  26. package/dist/__tests__/input-snapshot.test.d.ts +2 -0
  27. package/dist/__tests__/input-snapshot.test.d.ts.map +1 -0
  28. package/dist/__tests__/swipe-direction-owner.test-d.d.ts +2 -0
  29. package/dist/__tests__/swipe-direction-owner.test-d.d.ts.map +1 -0
  30. package/dist/__tests__/ui-input-matrix.test.d.ts +2 -0
  31. package/dist/__tests__/ui-input-matrix.test.d.ts.map +1 -0
  32. package/dist/__tests__/ui-ownership-edge.test.d.ts +2 -0
  33. package/dist/__tests__/ui-ownership-edge.test.d.ts.map +1 -0
  34. package/dist/__tests__/ui-ownership.test.d.ts +2 -0
  35. package/dist/__tests__/ui-ownership.test.d.ts.map +1 -0
  36. package/dist/__tests__/ui-reset-idempotence.test.d.ts +2 -0
  37. package/dist/__tests__/ui-reset-idempotence.test.d.ts.map +1 -0
  38. package/dist/__tests__/ui-reset.test.d.ts +2 -0
  39. package/dist/__tests__/ui-reset.test.d.ts.map +1 -0
  40. package/dist/action-state.d.ts +146 -0
  41. package/dist/action-state.d.ts.map +1 -0
  42. package/dist/browser-backend.d.ts +121 -0
  43. package/dist/browser-backend.d.ts.map +1 -0
  44. package/dist/canvas-input-boundary.d.ts +13 -0
  45. package/dist/canvas-input-boundary.d.ts.map +1 -0
  46. package/dist/composite-backend.d.ts +34 -0
  47. package/dist/composite-backend.d.ts.map +1 -0
  48. package/dist/controller-db-data.d.ts +5 -0
  49. package/dist/controller-db-data.d.ts.map +1 -0
  50. package/dist/controller-db-data.mjs +12 -0
  51. package/dist/controller-db-data.mjs.map +1 -0
  52. package/dist/controller-db.d.ts +70 -0
  53. package/dist/controller-db.d.ts.map +1 -0
  54. package/dist/controller-db.mjs +119 -0
  55. package/dist/controller-db.mjs.map +1 -0
  56. package/dist/frame-start-scan-system.d.ts +37 -0
  57. package/dist/frame-start-scan-system.d.ts.map +1 -0
  58. package/dist/gamepad-frame.d.ts +42 -0
  59. package/dist/gamepad-frame.d.ts.map +1 -0
  60. package/dist/gesture-recognizer.d.ts +145 -0
  61. package/dist/gesture-recognizer.d.ts.map +1 -0
  62. package/dist/index.d.ts +13 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.mjs +1502 -0
  65. package/dist/index.mjs.map +1 -0
  66. package/dist/input-snapshot.d.ts +420 -0
  67. package/dist/input-snapshot.d.ts.map +1 -0
  68. package/dist/plugin-service.d.ts +11 -0
  69. package/dist/plugin-service.d.ts.map +1 -0
  70. package/dist/ui-ownership.d.ts +17 -0
  71. package/dist/ui-ownership.d.ts.map +1 -0
  72. package/dist/virtual-joystick.d.ts +39 -0
  73. package/dist/virtual-joystick.d.ts.map +1 -0
  74. package/package.json +72 -0
  75. package/src/__tests__/browser-backend-dual-instance.test.ts +379 -0
  76. package/src/__tests__/browser-backend-focus-loss.test.ts +239 -0
  77. package/src/__tests__/browser-backend-lock-error.test.ts +425 -0
  78. package/src/__tests__/browser-backend-lock-gate.test.ts +283 -0
  79. package/src/__tests__/browser-backend-lock-release.test.ts +641 -0
  80. package/src/__tests__/browser-backend-lock-state.test.ts +604 -0
  81. package/src/__tests__/canvas-input-boundary.test.ts +65 -0
  82. package/src/__tests__/canvas-input-owner.test-d.ts +39 -0
  83. package/src/__tests__/composite-backend.test.ts +299 -0
  84. package/src/__tests__/controller-platform-owner.test-d.ts +46 -0
  85. package/src/__tests__/input-snapshot.test-d.ts +78 -0
  86. package/src/__tests__/input-snapshot.test.ts +96 -0
  87. package/src/__tests__/swipe-direction-owner.test-d.ts +45 -0
  88. package/src/__tests__/ui-input-matrix.test.ts +31 -0
  89. package/src/__tests__/ui-ownership-edge.test.ts +33 -0
  90. package/src/__tests__/ui-ownership.test.ts +35 -0
  91. package/src/__tests__/ui-reset-idempotence.test.ts +17 -0
  92. package/src/__tests__/ui-reset.test.ts +25 -0
  93. package/src/action-state.ts +380 -0
  94. package/src/browser-backend.ts +884 -0
  95. package/src/canvas-input-boundary.ts +81 -0
  96. package/src/composite-backend.ts +189 -0
  97. package/src/controller-db-data.ts +25 -0
  98. package/src/controller-db.ts +218 -0
  99. package/src/frame-start-scan-system.ts +93 -0
  100. package/src/gamepad-frame.ts +259 -0
  101. package/src/gesture-recognizer.ts +495 -0
  102. package/src/index.ts +101 -0
  103. package/src/input-snapshot.ts +732 -0
  104. package/src/plugin-service.ts +31 -0
  105. package/src/ui-ownership.ts +61 -0
  106. package/src/virtual-joystick.ts +103 -0
  107. package/vendor/gamecontrollerdb.txt +2114 -0
@@ -0,0 +1,420 @@
1
+ import type { ActionConfig, ActionState, GetVectorOptions } from './action-state';
2
+ import type { GestureEvent, GestureState } from './gesture-recognizer';
3
+ export type PointerType = 'mouse' | 'pen' | 'touch';
4
+ /** Standard-layout gamepad button index (0-16 per W3C Gamepad spec). */
5
+ export type GamepadButtonIndex = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16;
6
+ /** Standard-layout gamepad axis index (0-3 per W3C Gamepad spec). */
7
+ export type GamepadAxisIndex = 0 | 1 | 2 | 3;
8
+ /** W3C MouseEvent.button index (0=primary, 1=auxiliary, 2=secondary). */
9
+ export type MouseButtonIndex = 0 | 1 | 2;
10
+ /** Per-slot gamepad frame data produced by `sample()`. */
11
+ export interface GamepadSlotSample {
12
+ readonly index: number;
13
+ /**
14
+ * True when the browser reports a standard mapping OR the SDL controller
15
+ * DB has normalized a non-standard layout at the acquisition layer (M3
16
+ * D-1 redefinition). The Feat1 meaning ("browser-reported standard
17
+ * mapping only") is widened here: a non-standard pad whose GUID matches
18
+ * gamecontrollerdb.txt is re-projected onto the standard layout and
19
+ * reported as standardMapping=true, so bindings and direct reads see a
20
+ * uniform standard button/axis space. A non-standard pad with no DB match
21
+ * (or before the DB has loaded) keeps standardMapping=false + empty
22
+ * readpoints (graceful degradation).
23
+ */
24
+ readonly standardMapping: boolean;
25
+ readonly pressed: ReadonlySet<number>;
26
+ readonly justPressed: ReadonlySet<number>;
27
+ readonly justReleased: ReadonlySet<number>;
28
+ readonly buttonValues: ReadonlyMap<number, number>;
29
+ readonly axes: readonly [number, number, number, number];
30
+ }
31
+ /** Per-pointer live state (active contacts tracked by pointerId).
32
+ *
33
+ * D-5 / E-10: `pointerType` is a 3-literal union. `'mouse'` is the default
34
+ * placeholder for inactive pointers — when `active=false`, `pointerType` is
35
+ * always `'mouse'`. The semantic "no pointer" is carried by the `active`
36
+ * field, never by a sentinel string value.
37
+ */
38
+ export interface PointerSample {
39
+ readonly pointerId: number;
40
+ readonly x: number;
41
+ readonly y: number;
42
+ readonly pressure: number;
43
+ readonly pointerType: PointerType;
44
+ readonly active: boolean;
45
+ readonly delta: {
46
+ readonly x: number;
47
+ readonly y: number;
48
+ };
49
+ }
50
+ /** Per-frame phase event (down/move/up/cancel queue, one-frame lifecycle). */
51
+ export interface PointerPhaseEvent {
52
+ readonly pointerId: number;
53
+ readonly phase: 'down' | 'move' | 'up' | 'cancel';
54
+ readonly x: number;
55
+ readonly y: number;
56
+ readonly pressure: number;
57
+ readonly pointerType: PointerType;
58
+ }
59
+ /** Per-frame virtual axis output (named joystick derived from pointer input). */
60
+ export interface VirtualAxisSample {
61
+ readonly name: string;
62
+ readonly x: number;
63
+ readonly y: number;
64
+ }
65
+ /**
66
+ * Configuration for an on-screen virtual joystick (M3). Consumed by
67
+ * attachBrowserInputBackend and passed through to deriveVirtualAxes.
68
+ *
69
+ * Fixed mode: origin is config.anchor (or region center if anchor omitted).
70
+ * Floating mode: origin is the first pointerdown position within the region.
71
+ */
72
+ export interface VirtualJoystickConfig {
73
+ readonly name: string;
74
+ readonly mode: 'fixed' | 'floating';
75
+ /** Canvas-pixel region where touches are eligible to bind this joystick. */
76
+ readonly region: {
77
+ readonly x: number;
78
+ readonly y: number;
79
+ readonly width: number;
80
+ readonly height: number;
81
+ };
82
+ /** Fixed-mode origin anchor. Defaults to region center when omitted. */
83
+ readonly anchor?: {
84
+ readonly x: number;
85
+ readonly y: number;
86
+ } | undefined;
87
+ /** Max drag radius in canvas pixels. Vector is clamped then normalized to radius. */
88
+ readonly radius: number;
89
+ /** Normalized deadzone (0..1). |vec| < deadzone → zero vector output. */
90
+ readonly deadzone: number;
91
+ }
92
+ /** Capability snapshot (frozen at backend attach time). */
93
+ export interface Capabilities {
94
+ readonly gamepad: boolean;
95
+ readonly pointer: boolean;
96
+ }
97
+ /**
98
+ * Frozen value-shape view exposed to user systems via the `InputSnapshot`
99
+ * Resource. The methods are pure reads; calling them does not mutate any
100
+ * accumulator (charter P3 -- no observable side effects from the accessor
101
+ * surface). A fresh `InputSnapshot` instance is constructed by the
102
+ * frame-start scan system once per `world.update()` and replaces the
103
+ * previous Resource value.
104
+ */
105
+ export interface InputSnapshot {
106
+ /** Keyboard view (held state plus frame edges). */
107
+ readonly keyboard: {
108
+ /**
109
+ * `true` while `key` is currently held. `key` matches the value the
110
+ * backend records (KeyboardEvent.key for the browser backend). When
111
+ * the key is not in the held set, returns `false` -- never throws
112
+ * (charter P3: empty signal is the signal).
113
+ */
114
+ down(key: string): boolean;
115
+ /** `true` for the first frame in which `key` becomes held. */
116
+ justPressed(key: string): boolean;
117
+ /**
118
+ * `true` for one frame after the key was released (the up-edge). The
119
+ * edge collapses on the following `world.update()`. `key` not in the
120
+ * up-edge set returns `false`.
121
+ */
122
+ up(key: string): boolean;
123
+ /** Code-key equivalent of `down`, using KeyboardEvent.code identity. */
124
+ downCode(code: string): boolean;
125
+ /** Code-key equivalent of `justPressed`. */
126
+ justPressedCode(code: string): boolean;
127
+ /** Code-key equivalent of `up`. */
128
+ upCode(code: string): boolean;
129
+ };
130
+ /** Mouse view (charter F2 minimal surface: position + movementDelta + button + wheelDelta). */
131
+ readonly mouse: {
132
+ /**
133
+ * Latest canvas-pixel cursor position. This is available during hover;
134
+ * it does not require a button press or pointer capture. The position is
135
+ * frozen with the rest of the frame-start snapshot.
136
+ */
137
+ readonly position: {
138
+ readonly x: number;
139
+ readonly y: number;
140
+ } | undefined;
141
+ /**
142
+ * PointerLock-style accumulated movement since the previous frame.
143
+ * Value is frozen at frame-start; reading it does not clear the
144
+ * accumulator. The next `world.update()` produces a fresh delta
145
+ * (zero if no movement events arrived).
146
+ */
147
+ readonly movementDelta: {
148
+ readonly x: number;
149
+ readonly y: number;
150
+ };
151
+ /**
152
+ * Merged pointer-lock state: true when either W3C pointer-lock
153
+ * (pointerLockElement === this backend's canvas) OR the lockProvider
154
+ * path has engaged. Consumers read this to decide whether to consume
155
+ * movementDelta for look/camera rotation. Required field, alongside
156
+ * movementDelta -- both facts sit at the same attribute path for
157
+ * single-point indexing (charter F1).
158
+ */
159
+ readonly pointerLocked: boolean;
160
+ /**
161
+ * `true` while the W3C MouseEvent.button slot `i` is held. `i` is
162
+ * narrowed to the literal `0 | 1 | 2` so out-of-range indices are
163
+ * rejected at compile time (charter P3 explicit failure: TS literal
164
+ * narrowing replaces a runtime bounds-clamp).
165
+ *
166
+ * - 0 -- primary button (left)
167
+ * - 1 -- auxiliary button (middle)
168
+ * - 2 -- secondary button (right)
169
+ */
170
+ button(i: MouseButtonIndex): boolean;
171
+ /** `true` for the first frame in which button `i` becomes held. */
172
+ justPressed(i: MouseButtonIndex): boolean;
173
+ /** `true` for the frame in which button `i` is released. */
174
+ justReleased(i: MouseButtonIndex): boolean;
175
+ /**
176
+ * Discrete wheel notches accumulated since the previous frame.
177
+ * Plan-strategy D-5 sign-discrete: each `WheelEvent` contributes
178
+ * `Math.sign(event.deltaY)` to the per-frame accumulator regardless
179
+ * of `deltaMode` (PIXEL / LINE / PAGE all collapse). Sign convention
180
+ * follows W3C `WheelEvent.deltaY`: positive = scroll down / away
181
+ * from user, negative = scroll up / toward user.
182
+ *
183
+ * Value is frozen at frame-start; reading it does not clear the
184
+ * accumulator. The next `world.update()` produces a fresh delta
185
+ * (zero when no wheel events arrived).
186
+ *
187
+ * Trade-off (plan-strategy R-7): trackpad high-resolution wheel
188
+ * events collapse to one notch per event, losing sub-notch fidelity.
189
+ * AI users who need analog magnitude must opt in via a future
190
+ * unitful surface (OOS-7 ScrollSnapshot is the deferred shape).
191
+ */
192
+ readonly wheelDelta: number;
193
+ };
194
+ /**
195
+ * Per-slot gamepad reader. Returns a reader object for the gamepad at
196
+ * slot `i` regardless of connection state: disconnected or out-of-range
197
+ * slots report `connected=false`, all button/axis readpoints return
198
+ * `false`/`0` (charter P3 empty signal). The slot index is intentionally
199
+ * not narrowed — platform slot counts vary, and bounds handling is a
200
+ * runtime concern.
201
+ */
202
+ gamepad(i: number): {
203
+ readonly connected: boolean;
204
+ readonly standardMapping: boolean;
205
+ button(b: GamepadButtonIndex): boolean;
206
+ buttonValue(b: GamepadButtonIndex): number;
207
+ justPressed(b: GamepadButtonIndex): boolean;
208
+ justReleased(b: GamepadButtonIndex): boolean;
209
+ axis(a: GamepadAxisIndex): number;
210
+ };
211
+ /**
212
+ * Frozen capabilities snapshot, determined once at backend attach time.
213
+ * Consumers use this to decide whether gamepad/pointer readpoints will
214
+ * ever carry live data, without probing per-frame.
215
+ */
216
+ readonly capabilities: Capabilities;
217
+ /**
218
+ * Per-pointerId reader. Returns `{ active: true/false, x, y, pressure,
219
+ * pointerType, delta }` for the given pointerId. Unknown pointerIds
220
+ * return `{ active: false, ... }` without throwing.
221
+ */
222
+ pointer(id: number): PointerSample & {
223
+ readonly delta: {
224
+ readonly x: number;
225
+ readonly y: number;
226
+ };
227
+ };
228
+ /**
229
+ * Named virtual axis reader (joystick-derived). Returns `{ x, y }` for
230
+ * the given joystick config name. Unknown names return the zero-vector
231
+ * `{ x: 0, y: 0 }` without throwing.
232
+ */
233
+ virtualAxis(name: string): {
234
+ readonly x: number;
235
+ readonly y: number;
236
+ };
237
+ /**
238
+ * Per-frame phase event queue (down/move/up/cancel). One-frame
239
+ * lifecycle; drained by `sample()` at frame end. Empty array when no
240
+ * pointer events occurred this frame.
241
+ */
242
+ readonly pointerEvents: readonly PointerPhaseEvent[];
243
+ /**
244
+ * Continuous gesture values (pinch scale + rotation angle) for the
245
+ * active dual-finger gesture. Returns the identity empty signal
246
+ * (`pinchScale=1`, `rotationAngle=0`) when no gesture is active (AC-12);
247
+ * an active gesture retains its value on idle frames (fingers held still
248
+ * are not a gesture end). AC-11: reading the same frame's snapshot twice
249
+ * returns the identical object.
250
+ */
251
+ readonly gesture: GestureState;
252
+ /**
253
+ * Per-frame gesture lifecycle + instantaneous event queue (begin / end /
254
+ * cancel / swipe / long-press / double-tap). One-frame lifecycle, same
255
+ * pattern as `pointerEvents` (charter P4). Empty array when no gesture
256
+ * activity occurred this frame. Closed discriminant union (AC-13): a
257
+ * consumer exhaustively switches on `kind` without a default branch.
258
+ */
259
+ readonly gestureEvents: readonly GestureEvent[];
260
+ /**
261
+ * Action mapping readpoint. Returns a frozen reader for the named action.
262
+ * When `name` is registered in the InputMap, `isPressed()` / `justPressed()`
263
+ * / `justReleased()` / `strength` reflect the derived state. Unregistered
264
+ * action names return empty signal (false / 0 / false / false / 0) without
265
+ * throwing (charter P3: empty signal is the signal). AC-11: calling
266
+ * action() multiple times in the same frame returns identical values.
267
+ */
268
+ action(name: string): {
269
+ readonly isPressed: () => boolean;
270
+ readonly justPressed: () => boolean;
271
+ readonly justReleased: () => boolean;
272
+ readonly strength: number;
273
+ };
274
+ /**
275
+ * Compose a 1D axis value from two opposing actions.
276
+ *
277
+ * Returns `strength(pos) - strength(neg)`, range [-1, 1].
278
+ * Both registered: combines normally. One unregistered: contributes 0
279
+ * (E-3). Same action for both ends: always 0 (E-12).
280
+ *
281
+ * @param neg - Action name for the negative direction (e.g. 'moveLeft').
282
+ * @param pos - Action name for the positive direction (e.g. 'moveRight').
283
+ */
284
+ getAxis(neg: string, pos: string): number;
285
+ /**
286
+ * Compose a 2D vector from four directional actions with a single radial
287
+ * deadzone (Godot input.cpp three-branch formula). Uses `raw` (not
288
+ * `strength`) to avoid per-axis deadzone stacking into a square deadzone
289
+ * (AC-06).
290
+ *
291
+ * @param negX - Action name for negative X (e.g. 'moveLeft').
292
+ * @param posX - Action name for positive X (e.g. 'moveRight').
293
+ * @param negY - Action name for negative Y (e.g. 'moveUp').
294
+ * @param posY - Action name for positive Y (e.g. 'moveDown').
295
+ * @param opts - Optional override (deadzone).
296
+ */
297
+ getVector(negX: string, posX: string, negY: string, posY: string, opts?: GetVectorOptions): {
298
+ readonly x: number;
299
+ readonly y: number;
300
+ };
301
+ }
302
+ /**
303
+ * Backend protocol consumed by the frame-start scan system. The browser
304
+ * implementation (`browser-backend.ts`) is the production producer;
305
+ * tests inject fakes that emit synthetic samples.
306
+ */
307
+ export interface InputBackend {
308
+ /**
309
+ * Produce one frame's worth of input data and reset the per-frame
310
+ * accumulators (movement delta + up-edge set). Held-key state and
311
+ * held-button state survive across calls.
312
+ *
313
+ * Contract notes:
314
+ * - `downKeys` is the held-key set as of the call (held across frames)
315
+ * - `upKeys` is the up-edge set since the previous sample (cleared
316
+ * after the call so the edge appears in exactly one frame)
317
+ * - `buttons` is the held-button slot tuple `[b0, b1, b2]`
318
+ * - `movementX` / `movementY` are the accumulated PointerLock delta
319
+ * since the previous sample (cleared after the call)
320
+ * - `focused` mirrors `document.hasFocus()` so the scan system can
321
+ * suppress spurious up-edges across alt-tab transitions
322
+ */
323
+ sample(): InputBackendSample;
324
+ /**
325
+ * Command-set game gate for pointer-lock. When set to `false`, the
326
+ * backend will not request pointer-lock on click AND will immediately
327
+ * release any currently active lock (W3C path: `exitPointerLock`;
328
+ * provider path: `exitLock()`). When `true` (default), pointer-lock
329
+ * can be requested through the normal gate logic.
330
+ *
331
+ * Optional -- backends without pointer-lock support omit this method.
332
+ */
333
+ setPointerLockAllowed?(allowed: boolean): void;
334
+ /**
335
+ * Atomically discard acquired state without detaching listeners. A host calls
336
+ * this when it revokes a control lease so held keys/buttons, contacts, frame
337
+ * edges, deltas and pointer lock cannot bleed into a later consumer. Optional
338
+ * keeps synthetic backends source-compatible.
339
+ */
340
+ clear?(): void;
341
+ /** Detach DOM listeners; called when the engine shuts down. */
342
+ detach(): void;
343
+ }
344
+ /** Snapshot value returned by `InputBackend.sample()` (POD). */
345
+ export interface InputBackendSample {
346
+ readonly downKeys: ReadonlySet<string>;
347
+ readonly upKeys: ReadonlySet<string>;
348
+ /** Physical code identity (KeyboardEvent.code), when the producer has it. */
349
+ readonly downCodes?: ReadonlySet<string>;
350
+ /** One-frame physical code release edges, when the producer has them. */
351
+ readonly upCodes?: ReadonlySet<string>;
352
+ readonly buttons: readonly [boolean, boolean, boolean];
353
+ readonly movementX: number;
354
+ readonly movementY: number;
355
+ /** Latest canvas-pixel mouse position; absent for non-pointer backends. */
356
+ readonly mouseX?: number;
357
+ readonly mouseY?: number;
358
+ /**
359
+ * Sign-discrete wheel notch accumulator since the previous sample
360
+ * (plan-strategy D-5). Browser backend writes `Math.sign(deltaY)` per
361
+ * `WheelEvent`; sample() drains the value and resets the producer
362
+ * accumulator (mirrors movementX/Y semantics).
363
+ */
364
+ readonly wheelDelta: number;
365
+ /** True for the first sample after blur/hidden state reset. */
366
+ readonly focusReset?: boolean;
367
+ readonly focused: boolean;
368
+ /** M1+ gamepad per-slot frame data (optional — absent when backend lacks gamepad support). */
369
+ readonly gamepads?: readonly GamepadSlotSample[];
370
+ /** M1+ frozen capability snapshot (optional — absent for pre-M1 backends). */
371
+ readonly capabilities?: Capabilities;
372
+ /** M2+ active pointer contacts (optional — absent for keyboard-only backends). */
373
+ readonly pointers?: readonly PointerSample[];
374
+ /** M2+ per-frame phase event queue (optional — absent when no pointer events occurred). */
375
+ readonly pointerEvents?: readonly PointerPhaseEvent[];
376
+ /** M3+ virtual joystick axis outputs (optional — absent when no virtual joysticks configured). */
377
+ readonly virtualAxes?: readonly VirtualAxisSample[];
378
+ /** M5+ continuous gesture values (optional — absent when no gesture is active). */
379
+ readonly gestures?: GestureState;
380
+ /** M5+ per-frame gesture event queue (optional — absent when no gesture activity occurred). */
381
+ readonly gestureEvents?: readonly GestureEvent[];
382
+ /**
383
+ * Merged pointer-lock state: true when either W3C pointer-lock is active
384
+ * (pointerLockElement === this backend's canvas) OR the lockProvider path
385
+ * has engaged (requestLock() was called and not yet released). Required
386
+ * field -- always present, defaults to false when no lock is active.
387
+ */
388
+ readonly pointerLocked: boolean;
389
+ }
390
+ /** Build the neutral backend sample used before or outside an active consumer. */
391
+ export declare function createEmptyInputBackendSample(): InputBackendSample;
392
+ /**
393
+ * Build an `InputSnapshot` from a backend sample.
394
+ *
395
+ * @param sample - One frame's raw input backend sample (POD).
396
+ * @param actionStates - Optional per-frame derived action states from
397
+ * deriveActionStates(). When provided, snap.action(name) returns mapped
398
+ * values; when absent or empty, all action readpoints return empty signal
399
+ * (charter P3: false/0, never throws). AC-11: actionStates is frozen into
400
+ * the snapshot so same-frame re-reads return identical values.
401
+ */
402
+ export declare function snapshotFromSample(sample: InputBackendSample, actionStates?: readonly ActionState[], inputMap?: readonly ActionConfig[], previousSnapshot?: InputSnapshot): InputSnapshot;
403
+ /**
404
+ * @internal Read previously derived action states from a snapshot for edge diff.
405
+ * Used by the frame-start scan system (D-6: prev snapshot = edge baseline).
406
+ */
407
+ export declare function readActionStatesForEdgeDiff(snap: InputSnapshot): readonly ActionState[] | undefined;
408
+ /**
409
+ * Construct an empty snapshot for the pre-start window
410
+ * (`engine.run()` has not yet attached a backend). Returns the full
411
+ * multi-device shape as `snapshotFromSample`, with every accessor
412
+ * returning `false` / `0` / zero-vector. AI users can put this into the
413
+ * Resource store to satisfy `world.getResource('InputSnapshot')` calls
414
+ * in fixtures or unit tests (charter P3: empty signal is the signal).
415
+ * The underlying 7-field POD sample contract is unchanged (D-9).
416
+ */
417
+ export declare function createInputSnapshot(): InputSnapshot;
418
+ /** Stable Resource key for `world.insertResource` / `world.getResource`. */
419
+ export declare const INPUT_SNAPSHOT_RESOURCE_KEY = "InputSnapshot";
420
+ //# sourceMappingURL=input-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-snapshot.d.ts","sourceRoot":"","sources":["../src/input-snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Plugin } from '@forgeax/engine-plugin';
2
+ import type { InputBackend } from './input-snapshot';
3
+ declare module '@forgeax/engine-plugin' {
4
+ interface EngineContextServices {
5
+ input?: InputBackend;
6
+ }
7
+ }
8
+ export declare function inputBackendPlugin(backend: InputBackend): Plugin;
9
+ /** Provide an App-acquired input backend and release its Host listeners with the Fiber. */
10
+ export declare function ownedInputBackendPlugin(backend: InputBackend, dispose: () => void): Plugin;
11
+ //# sourceMappingURL=plugin-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-service.d.ts","sourceRoot":"","sources":["../src/plugin-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAU,qBAAqB;QAC7B,KAAK,CAAC,EAAE,YAAY,CAAC;KACtB;CACF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAQhE;AAED,2FAA2F;AAC3F,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,CAS1F"}
@@ -0,0 +1,17 @@
1
+ /** Event-path ownership and lifecycle reset primitives for browser hosts. */
2
+ export interface UiOwnershipResult {
3
+ readonly owned: boolean;
4
+ readonly source: 'composed-path' | 'target-fallback' | 'unknown';
5
+ }
6
+ export interface UiInputResetBoundaryOptions {
7
+ readonly clear: () => void;
8
+ readonly signal?: AbortSignal;
9
+ }
10
+ export interface UiInputResetBoundary {
11
+ readonly reset: () => void;
12
+ readonly dispose: () => void;
13
+ }
14
+ export declare function resolveUiOwnership(event: Event, host: Node): UiOwnershipResult;
15
+ export declare function isUiOwnedEvent(event: Event, host: Node): boolean;
16
+ export declare function createUiInputResetBoundary(options: UiInputResetBoundaryOptions): UiInputResetBoundary;
17
+ //# sourceMappingURL=ui-ownership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-ownership.d.ts","sourceRoot":"","sources":["../src/ui-ownership.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAE7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB,GAAG,SAAS,CAAC;CAClE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAOD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,iBAAiB,CAe9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAEhE;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,oBAAoB,CAetB"}
@@ -0,0 +1,39 @@
1
+ import type { VirtualAxisSample, VirtualJoystickConfig } from './input-snapshot';
2
+ /**
3
+ * Per-joystick binding state. The backend closure owns a
4
+ * Map<string, BindState> keyed by joystick config name.
5
+ */
6
+ export interface BindState {
7
+ /** bound pointerId, or undefined if unbound */
8
+ pointerId?: number | undefined;
9
+ /** origin in canvas pixels (anchor for fixed, first-touch for floating) */
10
+ originX: number;
11
+ originY: number;
12
+ }
13
+ /**
14
+ * Derive one frame of virtual axis outputs from live pointer state and
15
+ * per-joystick binding state.
16
+ *
17
+ * Pure function: no DOM access. The backend closure is the SSOT for
18
+ * per-joystick state; binding + origin selection happens in
19
+ * browser-backend.ts onPointerDown. This function only reads bindState
20
+ * and computes per-frame vectors.
21
+ *
22
+ * Unbound joysticks always produce the zero vector.
23
+ *
24
+ * @param configs - configured virtual joysticks
25
+ * @param pointerMap - live pointer positions keyed by pointerId
26
+ * @param bindState - per-joystick binding state (read-only)
27
+ * @returns one VirtualAxisSample per configured joystick
28
+ */
29
+ export declare function deriveVirtualAxes(configs: readonly VirtualJoystickConfig[], pointerMap: Map<number, {
30
+ readonly x: number;
31
+ readonly y: number;
32
+ }>, bindState: Map<string, BindState>): VirtualAxisSample[];
33
+ /**
34
+ * Unbind a joystick when its bound pointer goes up or is cancelled.
35
+ * Sets pointerId to undefined; the next deriveVirtualAxes call will
36
+ * produce a zero vector for the unbound joystick.
37
+ */
38
+ export declare function handleVirtualJoystickUnbind(bindState: Map<string, BindState>, pointerId: number): void;
39
+ //# sourceMappingURL=virtual-joystick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtual-joystick.d.ts","sourceRoot":"","sources":["../src/virtual-joystick.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EACnE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GAChC,iBAAiB,EAAE,CAyBrB;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EACjC,SAAS,EAAE,MAAM,GAChB,IAAI,CAMN"}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@forgeax/engine-input",
3
+ "version": "0.1.2",
4
+ "private": false,
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "sideEffects": false,
8
+ "description": "Frame-start scanned, frozen InputSnapshot Resource (logical keyboard key and physical code held/press/release edges + mouse.position/movementDelta + mouse.button(0|1|2)) + browser PointerLock backend for forgeax-engine.",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.mjs"
13
+ },
14
+ "./controller-db": {
15
+ "types": "./dist/controller-db.d.ts",
16
+ "import": "./dist/controller-db.mjs"
17
+ },
18
+ "./controller-db-data": {
19
+ "types": "./dist/controller-db-data.d.ts",
20
+ "import": "./dist/controller-db-data.mjs"
21
+ },
22
+ "./package.json": "./package.json"
23
+ },
24
+ "main": "./dist/index.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "files": [
27
+ "dist",
28
+ "src",
29
+ "vendor",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
33
+ "dependencies": {
34
+ "@forgeax/engine-ecs": "0.1.2",
35
+ "@forgeax/engine-plugin": "0.1.2"
36
+ },
37
+ "forgeax": {
38
+ "metrics": {
39
+ "bundle-size": {
40
+ "enabled": true,
41
+ "path": "dist/index.mjs",
42
+ "compression": "gzip",
43
+ "baseline": {
44
+ "source": "b2ea70919",
45
+ "threshold": 13280
46
+ },
47
+ "reason": "dist/index.mjs = 12069 B gzip after the normalized input snapshot and action/gesture readpoints. Threshold 13280 B = approximately 10% headroom over measured gzip. Prior baseline 10899 B gzip @ b2ea70919 (threshold 11990). Includes: action-state.ts (deriveActionStates + getAxis/getVector), gesture-recognizer.ts (5 state machines), gamepad-frame.ts (DB remap), browser-backend.ts (recognizer wiring + lazy-load), composite-backend.ts (per-key-yield merge decorator), input-snapshot.ts (keyboard/mouse/action/gesture readpoints + PointerType narrowing), index.ts (barrel). The SDL controller DB sub-export (dist/controller-db.mjs, ~1.5 KB gzip) and data sub-export (dist/controller-db-data.mjs, ~45 KB gzip / 545 KB raw) are opt-in lazy dynamic-imports and are NOT in the main-entry path (path=dist/index.mjs)."
48
+ },
49
+ "fps": {
50
+ "enabled": false,
51
+ "reason": "library package, no runtime canvas; fps is reported by hello-* / learn-render apps that consume engine.input.snapshot()"
52
+ },
53
+ "bench": {
54
+ "enabled": false,
55
+ "reason": "frame-start scan path is O(events-since-last-tick); not a perf-critical surface for the MVP"
56
+ },
57
+ "gate": {
58
+ "enabled": false,
59
+ "reason": "no package-level binary gate; AC-07 surface coverage runs as part of pnpm test:unit + tsc -b"
60
+ },
61
+ "spike-report": {
62
+ "enabled": false,
63
+ "reason": "not a spike package; this is a production MVP per plan-strategy D-5 (input internalisation minimal surface)"
64
+ }
65
+ }
66
+ },
67
+ "scripts": {
68
+ "build": "tsup",
69
+ "test": "vitest run",
70
+ "typecheck": "tsc -b"
71
+ }
72
+ }