three-gamepad-controls 0.25.3 → 0.25.5

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.
package/dist/core.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- //#region src/core.d.ts
2
1
  /**
3
2
  * Smallest valid browser-assigned gamepad index.
4
3
  *
@@ -60,5 +59,4 @@ export type GamepadAxisKey = keyof typeof GAMEPAD_AXIS;
60
59
  /**
61
60
  * Union type of all valid {@link GAMEPAD_AXIS} values.
62
61
  */
63
- export type GamepadAxisValue = (typeof GAMEPAD_AXIS)[keyof typeof GAMEPAD_AXIS];
64
- //#endregion
62
+ export type GamepadAxisValue = (typeof GAMEPAD_AXIS)[keyof typeof GAMEPAD_AXIS];
package/dist/core.js CHANGED
@@ -1,4 +1,4 @@
1
- //#region src/core.ts
1
+ // src/core.ts
2
2
  /**
3
3
  * Smallest valid browser-assigned gamepad index.
4
4
  *
@@ -45,5 +45,4 @@ const GAMEPAD_AXIS = {
45
45
  RightX: 2,
46
46
  RightY: 3
47
47
  };
48
- //#endregion
49
48
  export { GAMEPAD_AXIS, GAMEPAD_BUTTON, MAX_GAMEPAD_INDEX, MIN_GAMEPAD_INDEX };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { ArcballControls } from "three/addons/controls/ArcballControls.js";
4
- //#region src/gamepad-arcball-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadArcballControls}.
7
6
  *
@@ -113,5 +112,4 @@ export declare class GamepadArcballControls extends GamepadControls {
113
112
  * @param gamepad - The gamepad that just disconnected.
114
113
  */
115
114
  protected onGamepadDisconnected(gamepad: Gamepad): void;
116
- }
117
- //#endregion
115
+ }
@@ -2,7 +2,7 @@ import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { Vector2, Vector3 } from "three";
5
- //#region src/gamepad-arcball-controls.ts
5
+ // src/gamepad-arcball-controls.ts
6
6
  const DEFAULT_ARCBALL_OPTIONS = {
7
7
  rotateSpeed: 1,
8
8
  panSpeed: 1,
@@ -342,5 +342,4 @@ var GamepadArcballControls = class extends GamepadControls {
342
342
  }
343
343
  }
344
344
  };
345
- //#endregion
346
345
  export { GamepadArcballControls };
@@ -1,6 +1,5 @@
1
1
  import { GamepadInput, GamepadInputOptions } from "./gamepad-input.js";
2
2
  import { EventDispatcher } from "three";
3
- //#region src/gamepad-controls.d.ts
4
3
  /**
5
4
  * Event map for {@link GamepadControls}.
6
5
  *
@@ -132,5 +131,4 @@ export declare abstract class GamepadControls extends EventDispatcher<GamepadCon
132
131
  * @param gamepad - The gamepad that was active before disconnection.
133
132
  */
134
133
  protected onGamepadDisconnected(gamepad: Gamepad): void;
135
- }
136
- //#endregion
134
+ }
@@ -1,6 +1,6 @@
1
1
  import { GamepadInput } from "./gamepad-input.js";
2
2
  import { EventDispatcher } from "three";
3
- //#region src/gamepad-controls.ts
3
+ // src/gamepad-controls.ts
4
4
  /**
5
5
  * Abstract base class for Three.js gamepad controls.
6
6
  *
@@ -153,5 +153,4 @@ var GamepadControls = class extends EventDispatcher {
153
153
  });
154
154
  }
155
155
  };
156
- //#endregion
157
156
  export { GamepadControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { DragControls } from "three/addons/controls/DragControls.js";
4
- //#region src/gamepad-drag-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadDragControls}.
7
6
  *
@@ -66,5 +65,4 @@ export declare class GamepadDragControls extends GamepadControls {
66
65
  * @param gamepad - The gamepad that just disconnected.
67
66
  */
68
67
  protected onGamepadDisconnected(gamepad: Gamepad): void;
69
- }
70
- //#endregion
68
+ }
@@ -3,7 +3,7 @@ import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./ga
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { getCameraViewSize } from "./three-utils.js";
5
5
  import { Matrix4, Vector2, Vector3 } from "three";
6
- //#region src/gamepad-drag-controls.ts
6
+ // src/gamepad-drag-controls.ts
7
7
  const DEFAULT_DRAG_OPTIONS = {
8
8
  dragSpeed: 1,
9
9
  rotateSpeed: 1,
@@ -286,5 +286,4 @@ var GamepadDragControls = class extends GamepadControls {
286
286
  getCameraViewSize(camera, this.#selectedWorldPosition, this.#viewSize, this.#cameraToSelected);
287
287
  }
288
288
  };
289
- //#endregion
290
289
  export { GamepadDragControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { FirstPersonControls } from "three/addons/controls/FirstPersonControls.js";
4
- //#region src/gamepad-first-person-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadFirstPersonControls}.
7
6
  *
@@ -68,5 +67,4 @@ export declare class GamepadFirstPersonControls extends GamepadControls {
68
67
  * @param deltaTime - Seconds since the last frame.
69
68
  */
70
69
  protected onUpdate(deltaTime: number): void;
71
- }
72
- //#endregion
70
+ }
@@ -2,7 +2,7 @@ import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { MathUtils, Spherical, Vector3 } from "three";
5
- //#region src/gamepad-first-person-controls.ts
5
+ // src/gamepad-first-person-controls.ts
6
6
  const DEFAULT_FIRST_PERSON_OPTIONS = {
7
7
  moveSpeed: 1,
8
8
  lookSpeed: 1,
@@ -157,5 +157,4 @@ var GamepadFirstPersonControls = class extends GamepadControls {
157
157
  };
158
158
  }
159
159
  };
160
- //#endregion
161
160
  export { GamepadFirstPersonControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { FlyControls } from "three/addons/controls/FlyControls.js";
4
- //#region src/gamepad-fly-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadFlyControls}.
7
6
  *
@@ -56,7 +55,9 @@ export type GamepadFlyControlsOptions = GamepadControlsOptions & {
56
55
  * Adds full 6DOF gamepad support to Three.js `FlyControls`.
57
56
  *
58
57
  * Gamepad input is additive with keyboard/mouse input — call both
59
- * `gamepadControls.update(delta)` and `controls.update(delta)` each frame.
58
+ * `gamepadControls.update(delta)` before `controls.update(delta)` each frame.
59
+ * Applied backward translation suppresses only auto-forward for the next native
60
+ * update. Neutral or blocked input leaves native automation and manual input intact.
60
61
  * Bindings and speeds are configurable via {@link GamepadFlyControlsOptions}.
61
62
  */
62
63
  export declare class GamepadFlyControls extends GamepadControls {
@@ -67,11 +68,24 @@ export declare class GamepadFlyControls extends GamepadControls {
67
68
  * Any property not provided falls back to its default value.
68
69
  */
69
70
  constructor(controls: FlyControls, options?: Partial<GamepadFlyControlsOptions>);
71
+ /**
72
+ * Starts a fresh input frame, dropping any unconsumed auto-forward suppression.
73
+ * Recursive updates from pipelines or native change listeners are ignored.
74
+ *
75
+ * @param deltaTime - Seconds since the last frame.
76
+ */
77
+ update(deltaTime: number): void;
78
+ /**
79
+ * Disables input and releases this instance's update adapter. Later application
80
+ * replacements are preserved; the native control remains owned by the caller.
81
+ */
82
+ dispose(): void;
83
+ /** Releases pending suppression before notifying disconnection listeners. */
84
+ protected onGamepadDisconnected(gamepad: Gamepad): void;
70
85
  /**
71
86
  * Maps the current gamepad state to `FlyControls` translation and rotation.
72
87
  *
73
88
  * @param deltaTime - Seconds since the last frame.
74
89
  */
75
90
  protected onUpdate(deltaTime: number): void;
76
- }
77
- //#endregion
91
+ }
@@ -2,7 +2,7 @@ import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { Quaternion } from "three";
5
- //#region src/gamepad-fly-controls.ts
5
+ // src/gamepad-fly-controls.ts
6
6
  const DEFAULT_FLY_OPTIONS = {
7
7
  moveSpeed: 1,
8
8
  rotateSpeed: 1,
@@ -26,12 +26,22 @@ const DEFAULT_FLY_OPTIONS = {
26
26
  * Adds full 6DOF gamepad support to Three.js `FlyControls`.
27
27
  *
28
28
  * Gamepad input is additive with keyboard/mouse input — call both
29
- * `gamepadControls.update(delta)` and `controls.update(delta)` each frame.
29
+ * `gamepadControls.update(delta)` before `controls.update(delta)` each frame.
30
+ * Applied backward translation suppresses only auto-forward for the next native
31
+ * update. Neutral or blocked input leaves native automation and manual input intact.
30
32
  * Bindings and speeds are configurable via {@link GamepadFlyControlsOptions}.
31
33
  */
32
34
  var GamepadFlyControls = class extends GamepadControls {
33
35
  #controls;
34
36
  #options;
37
+ #originalUpdate;
38
+ #originalUpdateDescriptor;
39
+ #nativeUpdate;
40
+ #backwardObject = null;
41
+ #backwardGamepad = null;
42
+ #updating = false;
43
+ #nativeUpdating = false;
44
+ #disposed = false;
35
45
  #tmpQuaternion;
36
46
  /**
37
47
  * @param controls - A Three.js `FlyControls` instance.
@@ -48,6 +58,87 @@ var GamepadFlyControls = class extends GamepadControls {
48
58
  lookStick: resolveGamepadStickBinding(DEFAULT_FLY_OPTIONS.lookStick, options?.lookStick)
49
59
  };
50
60
  this.#tmpQuaternion = new Quaternion();
61
+ this.#originalUpdate = controls.update;
62
+ this.#originalUpdateDescriptor = Object.getOwnPropertyDescriptor(controls, "update");
63
+ this.#nativeUpdate = (deltaTime) => this.#updateNative(deltaTime);
64
+ controls.update = this.#nativeUpdate;
65
+ }
66
+ /**
67
+ * Starts a fresh input frame, dropping any unconsumed auto-forward suppression.
68
+ * Recursive updates from pipelines or native change listeners are ignored.
69
+ *
70
+ * @param deltaTime - Seconds since the last frame.
71
+ */
72
+ update(deltaTime) {
73
+ if (this.#updating || this.#nativeUpdating || this.#disposed) return;
74
+ this.#clearBackwardInput();
75
+ this.#updating = true;
76
+ try {
77
+ super.update(deltaTime);
78
+ } finally {
79
+ this.#updating = false;
80
+ }
81
+ }
82
+ /**
83
+ * Disables input and releases this instance's update adapter. Later application
84
+ * replacements are preserved; the native control remains owned by the caller.
85
+ */
86
+ dispose() {
87
+ if (this.#disposed) return;
88
+ this.#disposed = true;
89
+ this.#clearBackwardInput();
90
+ super.dispose();
91
+ if (this.#controls.update === this.#nativeUpdate) {
92
+ if (this.#originalUpdateDescriptor === void 0) Reflect.deleteProperty(this.#controls, "update");
93
+ else Object.defineProperty(this.#controls, "update", this.#originalUpdateDescriptor);
94
+ }
95
+ }
96
+ /** Releases pending suppression before notifying disconnection listeners. */
97
+ onGamepadDisconnected(gamepad) {
98
+ this.#clearBackwardInput();
99
+ super.onGamepadDisconnected(gamepad);
100
+ }
101
+ /** Clears the destination and snapshot that received backward translation. */
102
+ #clearBackwardInput() {
103
+ this.#backwardObject = null;
104
+ this.#backwardGamepad = null;
105
+ }
106
+ /** Revalidates the frame after a user-supplied stick pipeline returns. */
107
+ #canApplyInput(gamepad, object) {
108
+ return !this.#disposed && this.enabled && this.#controls.enabled && this.gamepadInput.gamepad === gamepad && this.#controls.object === object;
109
+ }
110
+ /**
111
+ * Consumes one applied backward frame before the original native update.
112
+ * Only longitudinal automation is omitted; native movement, rotation, and
113
+ * change publication remain in the original method. Conditional cleanup uses
114
+ * current configuration and manual state, including changes made by listeners.
115
+ */
116
+ #updateNative(deltaTime) {
117
+ if (this.#nativeUpdating) return;
118
+ const controls = this.#controls;
119
+ const gamepad = this.#backwardGamepad;
120
+ const object = this.#backwardObject;
121
+ this.#clearBackwardInput();
122
+ this.#nativeUpdating = true;
123
+ try {
124
+ if (gamepad === null || deltaTime === 0 || !this.#canApplyInput(gamepad, object)) {
125
+ this.#originalUpdate.call(controls, deltaTime);
126
+ return;
127
+ }
128
+ const vector = controls._moveVector;
129
+ const manualZ = controls._moveState.back - (controls._moveState.forward ? 1 : 0);
130
+ vector.z = manualZ;
131
+ try {
132
+ this.#originalUpdate.call(controls, deltaTime);
133
+ } finally {
134
+ if (controls._moveVector === vector && vector.z === manualZ) {
135
+ const { forward, back } = controls._moveState;
136
+ vector.z = back - (forward || controls.autoForward && !back ? 1 : 0);
137
+ }
138
+ }
139
+ } finally {
140
+ this.#nativeUpdating = false;
141
+ }
51
142
  }
52
143
  /**
53
144
  * Maps the current gamepad state to `FlyControls` translation and rotation.
@@ -58,11 +149,22 @@ var GamepadFlyControls = class extends GamepadControls {
58
149
  if (!this.#controls.enabled) return;
59
150
  const { moveSpeed, rotateSpeed, buttonDeadzone, moveStick, lookStick, buttonRollLeft, buttonRollRight, buttonMoveUp, buttonMoveDown } = this.#options;
60
151
  const input = this.gamepadInput;
152
+ const gamepad = input.gamepad;
153
+ const object = this.#controls.object;
61
154
  const move = input.stick(moveStick.xAxis, moveStick.yAxis, moveStick.pipeline);
155
+ if (!this.#canApplyInput(gamepad, object)) return;
62
156
  const look = input.stick(lookStick.xAxis, lookStick.yAxis, lookStick.pipeline);
157
+ if (!this.#canApplyInput(gamepad, object)) return;
63
158
  const moveMult = deltaTime * this.#controls.movementSpeed * moveSpeed;
64
159
  const fwd = move.y;
65
- if (fwd !== 0) this.#controls.object.translateZ(fwd * moveMult);
160
+ if (fwd !== 0) {
161
+ const displacement = fwd * moveMult;
162
+ object.translateZ(displacement);
163
+ if (displacement > 0) {
164
+ this.#backwardObject = object;
165
+ this.#backwardGamepad = gamepad;
166
+ }
167
+ }
66
168
  const strafe = move.x;
67
169
  if (strafe !== 0) this.#controls.object.translateX(strafe * moveMult);
68
170
  const up = input.buttonValue(buttonMoveUp);
@@ -79,5 +181,4 @@ var GamepadFlyControls = class extends GamepadControls {
79
181
  }
80
182
  }
81
183
  };
82
- //#endregion
83
184
  export { GamepadFlyControls };
@@ -1,4 +1,4 @@
1
- //#region src/gamepad-haptics.ts
1
+ // src/gamepad-haptics.ts
2
2
  /**
3
3
  * Returns the primary vibration actuator exposed by a gamepad at runtime.
4
4
  *
@@ -84,5 +84,4 @@ const resetGamepadVibration = async (gamepad) => {
84
84
  throw error;
85
85
  }
86
86
  };
87
- //#endregion
88
87
  export { isGamepadVibrationSupported, playGamepadVibrationEffect, resetGamepadVibration };
@@ -1,5 +1,4 @@
1
1
  import { GamepadStick, GamepadStickPipeline } from "./gamepad-stick-processing.js";
2
- //#region src/gamepad-input.d.ts
3
2
  /**
4
3
  * Native custom event map for {@link GamepadInput}.
5
4
  * Gamepad snapshots are available through `event.detail.gamepad`.
@@ -267,4 +266,4 @@ export declare class GamepadInput extends EventTarget {
267
266
  */
268
267
  resetVibration(): Promise<GamepadHapticsResult | null>;
269
268
  }
270
- //#endregion
269
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { isGamepadVibrationSupported, playGamepadVibrationEffect, resetGamepadVibration } from "./gamepad-haptics.js";
2
2
  import { GamepadManager } from "./gamepad-manager.js";
3
3
  import { DEFAULT_GAMEPAD_STICK_PIPELINE } from "./gamepad-stick-processing.js";
4
- //#region src/gamepad-input.ts
4
+ // src/gamepad-input.ts
5
5
  const DEFAULT_GAMEPAD_INPUT_OPTIONS = {
6
6
  axisDeadzone: .1,
7
7
  stickPipeline: DEFAULT_GAMEPAD_STICK_PIPELINE
@@ -347,5 +347,4 @@ var GamepadInput = class extends EventTarget {
347
347
  return options?.deadzone ?? this.#options.axisDeadzone;
348
348
  }
349
349
  };
350
- //#endregion
351
350
  export { GamepadInput };
@@ -1,5 +1,5 @@
1
1
  import { MAX_GAMEPAD_INDEX } from "./core.js";
2
- //#region src/gamepad-manager.ts
2
+ // src/gamepad-manager.ts
3
3
  const EMPTY_UPDATE_RESULT = {
4
4
  gamepad: null,
5
5
  connected: null,
@@ -164,5 +164,4 @@ var GamepadManager = class {
164
164
  };
165
165
  }
166
166
  };
167
- //#endregion
168
167
  export { GamepadManager };
@@ -1,6 +1,5 @@
1
1
  import { GamepadOrbitControls, GamepadOrbitControlsOptions } from "./gamepad-orbit-controls.js";
2
2
  import { MapControls } from "three/addons/controls/MapControls.js";
3
- //#region src/gamepad-map-controls.d.ts
4
3
  /**
5
4
  * Adds gamepad support to Three.js `MapControls`.
6
5
  *
@@ -18,5 +17,4 @@ export declare class GamepadMapControls extends GamepadOrbitControls {
18
17
  * Any property not provided falls back to its default value.
19
18
  */
20
19
  constructor(controls: MapControls, options?: Partial<GamepadOrbitControlsOptions>);
21
- }
22
- //#endregion
20
+ }
@@ -1,6 +1,6 @@
1
1
  import { GAMEPAD_AXIS } from "./core.js";
2
2
  import { GamepadOrbitControls } from "./gamepad-orbit-controls.js";
3
- //#region src/gamepad-map-controls.ts
3
+ // src/gamepad-map-controls.ts
4
4
  const DEFAULT_MAP_OPTIONS = {
5
5
  panStick: {
6
6
  xAxis: GAMEPAD_AXIS.LeftX,
@@ -42,5 +42,4 @@ var GamepadMapControls = class extends GamepadOrbitControls {
42
42
  });
43
43
  }
44
44
  };
45
- //#endregion
46
45
  export { GamepadMapControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { OrbitControls } from "three/addons/controls/OrbitControls.js";
4
- //#region src/gamepad-orbit-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadOrbitControls}.
7
6
  *
@@ -91,5 +90,4 @@ export declare class GamepadOrbitControls extends GamepadControls {
91
90
  * @param gamepad - The gamepad that just disconnected.
92
91
  */
93
92
  protected onGamepadDisconnected(gamepad: Gamepad): void;
94
- }
95
- //#endregion
93
+ }
@@ -1,7 +1,7 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
- //#region src/gamepad-orbit-controls.ts
4
+ // src/gamepad-orbit-controls.ts
5
5
  const DEFAULT_ORBIT_OPTIONS = {
6
6
  rotateSpeed: 1,
7
7
  panSpeed: 1,
@@ -192,5 +192,4 @@ var GamepadOrbitControls = class extends GamepadControls {
192
192
  }
193
193
  }
194
194
  };
195
- //#endregion
196
195
  export { GamepadOrbitControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
4
- //#region src/gamepad-pointer-lock-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadPointerLockControls}.
7
6
  *
@@ -63,5 +62,4 @@ export declare class GamepadPointerLockControls extends GamepadControls {
63
62
  * @param deltaTime - Seconds since the last frame.
64
63
  */
65
64
  protected onUpdate(deltaTime: number): void;
66
- }
67
- //#endregion
65
+ }
@@ -2,7 +2,7 @@ import { GAMEPAD_AXIS } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { Euler, Quaternion } from "three";
5
- //#region src/gamepad-pointer-lock-controls.ts
5
+ // src/gamepad-pointer-lock-controls.ts
6
6
  const DEFAULT_POINTER_LOCK_OPTIONS = {
7
7
  moveSpeed: 5,
8
8
  lookSpeed: 1,
@@ -95,5 +95,4 @@ var GamepadPointerLockControls = class extends GamepadControls {
95
95
  }
96
96
  }
97
97
  };
98
- //#endregion
99
98
  export { GamepadPointerLockControls };
@@ -1,4 +1,3 @@
1
- //#region src/gamepad-stick-processing.d.ts
2
1
  /**
3
2
  * Geometry used when processing two-dimensional stick values.
4
3
  *
@@ -169,5 +168,4 @@ export declare const DEFAULT_GAMEPAD_STICK_PIPELINE: GamepadStickPipeline;
169
168
  * @param options - Optional binding overrides.
170
169
  * @returns Complete resolved binding.
171
170
  */
172
- export declare const resolveGamepadStickBinding: (defaults: GamepadStickBinding, options?: GamepadStickBindingOptions) => GamepadStickBinding;
173
- //#endregion
171
+ export declare const resolveGamepadStickBinding: (defaults: GamepadStickBinding, options?: GamepadStickBindingOptions) => GamepadStickBinding;
@@ -1,4 +1,4 @@
1
- //#region src/gamepad-stick-processing.ts
1
+ // src/gamepad-stick-processing.ts
2
2
  const DEFAULT_GAMEPAD_STICK_PROCESSING_MODE = "axial";
3
3
  const DEFAULT_GAMEPAD_DEADZONE_THRESHOLD = .1;
4
4
  /**
@@ -195,5 +195,4 @@ const resolveGamepadStickBinding = (defaults, options) => {
195
195
  pipeline: options?.pipeline ?? defaults.pipeline
196
196
  };
197
197
  };
198
- //#endregion
199
198
  export { DEFAULT_GAMEPAD_STICK_PIPELINE, gamepadStickPipeline, resolveGamepadStickBinding };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { TrackballControls } from "three/addons/controls/TrackballControls.js";
4
- //#region src/gamepad-trackball-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadTrackballControls}.
7
6
  *
@@ -91,5 +90,4 @@ export declare class GamepadTrackballControls extends GamepadControls {
91
90
  * @param gamepad - The gamepad that just disconnected.
92
91
  */
93
92
  protected onGamepadDisconnected(gamepad: Gamepad): void;
94
- }
95
- //#endregion
93
+ }
@@ -1,7 +1,7 @@
1
1
  import { GAMEPAD_AXIS, GAMEPAD_BUTTON } from "./core.js";
2
2
  import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./gamepad-stick-processing.js";
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
- //#region src/gamepad-trackball-controls.ts
4
+ // src/gamepad-trackball-controls.ts
5
5
  const DEFAULT_TRACKBALL_OPTIONS = {
6
6
  rotateSpeed: 1,
7
7
  panSpeed: 1,
@@ -174,5 +174,4 @@ var GamepadTrackballControls = class extends GamepadControls {
174
174
  }
175
175
  }
176
176
  };
177
- //#endregion
178
177
  export { GamepadTrackballControls };
@@ -1,7 +1,6 @@
1
1
  import { GamepadStickBindingOptions } from "./gamepad-stick-processing.js";
2
2
  import { GamepadControls, GamepadControlsOptions } from "./gamepad-controls.js";
3
3
  import { TransformControls } from "three/addons/controls/TransformControls.js";
4
- //#region src/gamepad-transform-controls.d.ts
5
4
  /**
6
5
  * Configuration for {@link GamepadTransformControls}.
7
6
  *
@@ -92,6 +91,8 @@ export type GamepadTransformControlsOptions = GamepadControlsOptions & {
92
91
  * Modes and axes are selected explicitly with buttons. Moving the transform
93
92
  * stick starts a native-style transform interaction, and releasing it ends
94
93
  * the interaction while keeping the active axis highlighted.
94
+ * Selection follows the native helper's explicit visibility flags, including
95
+ * combined axes and planes, independently of camera-alignment hiding.
95
96
  */
96
97
  export declare class GamepadTransformControls extends GamepadControls {
97
98
  #private;
@@ -118,5 +119,4 @@ export declare class GamepadTransformControls extends GamepadControls {
118
119
  * @param gamepad - The gamepad that just disconnected.
119
120
  */
120
121
  protected onGamepadDisconnected(gamepad: Gamepad): void;
121
- }
122
- //#endregion
122
+ }
@@ -3,7 +3,7 @@ import { DEFAULT_GAMEPAD_STICK_PIPELINE, resolveGamepadStickBinding } from "./ga
3
3
  import { GamepadControls } from "./gamepad-controls.js";
4
4
  import { getCameraViewSize } from "./three-utils.js";
5
5
  import { Matrix4, Quaternion, Vector2, Vector3 } from "three";
6
- //#region src/gamepad-transform-controls.ts
6
+ // src/gamepad-transform-controls.ts
7
7
  const DEFAULT_TRANSFORM_OPTIONS = {
8
8
  translateSpeed: 1,
9
9
  rotateSpeed: 1,
@@ -66,6 +66,8 @@ const PROJECTED_AXIS_EPSILON = .001;
66
66
  * Modes and axes are selected explicitly with buttons. Moving the transform
67
67
  * stick starts a native-style transform interaction, and releasing it ends
68
68
  * the interaction while keeping the active axis highlighted.
69
+ * Selection follows the native helper's explicit visibility flags, including
70
+ * combined axes and planes, independently of camera-alignment hiding.
69
71
  */
70
72
  var GamepadTransformControls = class extends GamepadControls {
71
73
  #controls;
@@ -321,9 +323,10 @@ var GamepadTransformControls = class extends GamepadControls {
321
323
  * callbacks, interrupting this update if its context or segment was invalidated.
322
324
  *
323
325
  * @param context - Context expected after the operation that invoked callbacks.
326
+ * @param validateAxis - Also validate a newly selected axis before acquisition.
324
327
  * @returns `true` when this update may continue applying gamepad input.
325
328
  */
326
- #afterCallback(context) {
329
+ #afterCallback(context, validateAxis = false) {
327
330
  const segment = this.#segment;
328
331
  if (!this.#matchesContext(context)) {
329
332
  this.#interrupted = true;
@@ -331,6 +334,7 @@ var GamepadTransformControls = class extends GamepadControls {
331
334
  }
332
335
  this.#reconcileSegment();
333
336
  if (segment !== null && this.#segment !== segment) this.#interrupted = true;
337
+ if (validateAxis && context.axis !== null && !this.#isAxisAllowed(context.mode, context.axis)) this.#interrupted = true;
334
338
  return this.#canApplyInput();
335
339
  }
336
340
  /**
@@ -347,7 +351,7 @@ var GamepadTransformControls = class extends GamepadControls {
347
351
  };
348
352
  const controls = this.#controls;
349
353
  controls[key] = value;
350
- this.#afterCallback(context);
354
+ this.#afterCallback(context, key === "axis");
351
355
  }
352
356
  /**
353
357
  * Applies mode, space, and axis button transitions from the current frame.
@@ -404,7 +408,10 @@ var GamepadTransformControls = class extends GamepadControls {
404
408
  * @param axis - Axis requested by the gamepad button mapping.
405
409
  */
406
410
  #selectAxis(axis) {
407
- if (!this.#isAxisAllowed(this.#controls.mode, axis)) return;
411
+ if (!this.#isAxisAllowed(this.#controls.mode, axis)) {
412
+ if (this.#resolveAxis() === null) this.#setActiveAxis(null);
413
+ return;
414
+ }
408
415
  this.#endTransform(false);
409
416
  if (!this.#canApplyInput()) return;
410
417
  this.#setActiveAxis(axis);
@@ -413,8 +420,7 @@ var GamepadTransformControls = class extends GamepadControls {
413
420
  * Selects the next visible composite axis available in the current mode.
414
421
  */
415
422
  #cycleCompositeAxis() {
416
- const validAxes = this.#getVisibleAxes(COMPOSITE_AXES[this.#controls.mode]);
417
- this.#cycleThroughAxes(validAxes, 1);
423
+ this.#cycleThroughAxes(COMPOSITE_AXES[this.#controls.mode], 1);
418
424
  }
419
425
  /**
420
426
  * Cycles through all valid axes for the current mode.
@@ -422,17 +428,18 @@ var GamepadTransformControls = class extends GamepadControls {
422
428
  * @param direction - `1` for next axis, `-1` for previous axis.
423
429
  */
424
430
  #cycleAxis(direction) {
425
- this.#cycleThroughAxes(this.#getValidAxes(this.#controls.mode), direction);
431
+ this.#cycleThroughAxes(MODE_AXES[this.#controls.mode], direction);
426
432
  }
427
433
  /**
428
- * Moves the active axis through a candidate axis list.
434
+ * Moves the active axis through candidates permitted after end callbacks.
429
435
  *
430
- * @param axes - Candidate axes to cycle through.
436
+ * @param candidates - Unfiltered candidate axes to cycle through.
431
437
  * @param direction - `1` for next axis, `-1` for previous axis.
432
438
  */
433
- #cycleThroughAxes(axes, direction) {
439
+ #cycleThroughAxes(candidates, direction) {
434
440
  this.#endTransform(false);
435
441
  if (!this.#canApplyInput()) return;
442
+ const axes = this.#getVisibleAxes(candidates);
436
443
  if (axes.length === 0) {
437
444
  this.#setActiveAxis(null);
438
445
  return;
@@ -457,11 +464,16 @@ var GamepadTransformControls = class extends GamepadControls {
457
464
  return current !== null && validAxes.includes(current) ? current : validAxes[0] ?? null;
458
465
  }
459
466
  /**
460
- * Updates both the remembered axis for the current mode and the control axis.
467
+ * Revalidates a candidate after end callbacks before updating axis memory
468
+ * and the control. An invalidated candidate interrupts this update.
461
469
  *
462
470
  * @param axis - Axis to activate, or `null` to clear selection.
463
471
  */
464
472
  #setActiveAxis(axis) {
473
+ if (axis !== null && !this.#isAxisAllowed(this.#controls.mode, axis)) {
474
+ this.#interrupted = true;
475
+ return;
476
+ }
465
477
  this.#activeAxisByMode[this.#controls.mode] = axis;
466
478
  if (this.#controls.axis !== axis) this.#writeProperty("axis", axis);
467
479
  }
@@ -496,7 +508,8 @@ var GamepadTransformControls = class extends GamepadControls {
496
508
  return MODE_AXES[mode].includes(axis) && this.#isAxisVisible(axis);
497
509
  }
498
510
  /**
499
- * Reads TransformControls visibility flags for an axis or plane.
511
+ * Reads the native helper's explicit axis and plane visibility flags.
512
+ * Camera-alignment hiding does not prohibit gamepad selection.
500
513
  *
501
514
  * @param axis - Axis whose visibility should be checked.
502
515
  * @returns `true` when all components required by the axis are visible.
@@ -510,9 +523,9 @@ var GamepadTransformControls = class extends GamepadControls {
510
523
  case "XY": return controls.showX && controls.showY && controls.showXY;
511
524
  case "YZ": return controls.showY && controls.showZ && controls.showYZ;
512
525
  case "XZ": return controls.showX && controls.showZ && controls.showXZ;
513
- case "XYZ":
514
- case "XYZE": return controls.showX && controls.showY && controls.showZ;
515
- case "E": return true;
526
+ case "XYZ": return controls.showX && controls.showY && controls.showZ && controls.showXY && controls.showYZ;
527
+ case "XYZE": return controls.showX && controls.showY && controls.showZ && controls.showXY && controls.showYZ && controls.showXYZE;
528
+ case "E": return controls.showX && controls.showY && controls.showZ && controls.showE;
516
529
  }
517
530
  }
518
531
  /**
@@ -1064,5 +1077,4 @@ var GamepadTransformControls = class extends GamepadControls {
1064
1077
  return startedButtons;
1065
1078
  }
1066
1079
  };
1067
- //#endregion
1068
1080
  export { GamepadTransformControls };
@@ -1,4 +1,4 @@
1
- //#region src/three-utils.ts
1
+ // src/three-utils.ts
2
2
  /**
3
3
  * Reads the effective viewport dimensions at a world-space point.
4
4
  *
@@ -23,5 +23,4 @@ const getCameraViewSize = (camera, worldPosition, target, cameraPosition) => {
23
23
  }
24
24
  return target.set(1, 1);
25
25
  };
26
- //#endregion
27
26
  export { getCameraViewSize };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "three-gamepad-controls",
3
3
  "description": "Gamepad support for Three.js controls.",
4
- "version": "0.25.3",
4
+ "version": "0.25.5",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/luckasnix/three-gamepad-controls#readme",
7
7
  "author": {
@@ -46,20 +46,20 @@
46
46
  }
47
47
  },
48
48
  "devDependencies": {
49
- "@biomejs/biome": "2.5.14",
50
- "@commitlint/cli": "21.2.3",
51
- "@commitlint/config-conventional": "21.2.3",
49
+ "@biomejs/biome": "2.6.3",
50
+ "@commitlint/cli": "21.2.4",
51
+ "@commitlint/config-conventional": "21.2.4",
52
52
  "@commitlint/types": "21.2.3",
53
- "@types/node": "24.13.3",
53
+ "@types/node": "24.19.2",
54
54
  "@types/three": "0.186.0",
55
- "@vitest/browser-playwright": "5.0.2",
56
- "@vitest/coverage-v8": "5.0.2",
55
+ "@vitest/browser-playwright": "5.0.5",
56
+ "@vitest/coverage-v8": "5.0.5",
57
57
  "husky": "9.1.7",
58
- "playwright": "1.63.0",
58
+ "playwright": "1.64.1",
59
59
  "three": "0.186.0",
60
- "tsdown": "0.23.0",
60
+ "tsdown": "0.23.3",
61
61
  "typescript": "7.0.2",
62
- "vitest": "5.0.2"
62
+ "vitest": "5.0.5"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "@types/three": "~0.186.0",