three-gamepad-controls 0.25.6 → 0.25.8
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/gamepad-arcball-controls.d.ts +3 -0
- package/dist/gamepad-arcball-controls.js +59 -3
- package/dist/gamepad-map-controls.d.ts +2 -2
- package/dist/gamepad-map-controls.js +2 -2
- package/dist/gamepad-orbit-controls.d.ts +4 -1
- package/dist/gamepad-orbit-controls.js +123 -26
- package/package.json +1 -1
|
@@ -76,6 +76,9 @@ export type GamepadArcballControlsOptions = GamepadControlsOptions & {
|
|
|
76
76
|
* needed after manual camera or target changes, matching Arcball's native API.
|
|
77
77
|
* Gamepad `start`, `change`, and `end` events are dispatched on the native controls.
|
|
78
78
|
* The balanced session belongs to this wrapper, including isolated focus commands.
|
|
79
|
+
* Zoom and focus preserve native `adjustNearFar` clipping and projection behavior,
|
|
80
|
+
* including restoration of the native initial planes on the next scale operation
|
|
81
|
+
* after adjustment is disabled. Focus without zoom leaves clipping unchanged.
|
|
79
82
|
*/
|
|
80
83
|
export declare class GamepadArcballControls extends GamepadControls {
|
|
81
84
|
#private;
|
|
@@ -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
|
-
import { Vector2, Vector3 } from "three";
|
|
4
|
+
import { Box3, Matrix4, Sphere, Vector2, Vector3 } from "three";
|
|
5
5
|
// src/gamepad-arcball-controls.ts
|
|
6
6
|
const DEFAULT_ARCBALL_OPTIONS = {
|
|
7
7
|
rotateSpeed: 1,
|
|
@@ -34,6 +34,9 @@ const ZOOM_NOTCHES_PER_SECOND = 8;
|
|
|
34
34
|
* needed after manual camera or target changes, matching Arcball's native API.
|
|
35
35
|
* Gamepad `start`, `change`, and `end` events are dispatched on the native controls.
|
|
36
36
|
* The balanced session belongs to this wrapper, including isolated focus commands.
|
|
37
|
+
* Zoom and focus preserve native `adjustNearFar` clipping and projection behavior,
|
|
38
|
+
* including restoration of the native initial planes on the next scale operation
|
|
39
|
+
* after adjustment is disabled. Focus without zoom leaves clipping unchanged.
|
|
37
40
|
*/
|
|
38
41
|
var GamepadArcballControls = class extends GamepadControls {
|
|
39
42
|
#controls;
|
|
@@ -45,6 +48,9 @@ var GamepadArcballControls = class extends GamepadControls {
|
|
|
45
48
|
#cameraForward;
|
|
46
49
|
#cameraRight;
|
|
47
50
|
#previousUp;
|
|
51
|
+
#scaleMatrix = new Matrix4();
|
|
52
|
+
#gizmoBounds = new Box3();
|
|
53
|
+
#gizmoSphere = new Sphere();
|
|
48
54
|
/** Whether this wrapper owns an active gamepad interaction. */
|
|
49
55
|
#wasInteracting = false;
|
|
50
56
|
/** Blocks recursive updates while a frame is being processed. */
|
|
@@ -274,7 +280,8 @@ var GamepadArcballControls = class extends GamepadControls {
|
|
|
274
280
|
controls.updateMatrixState();
|
|
275
281
|
const transformation = controls.scale(size, controls._gizmos.position);
|
|
276
282
|
if (transformation === void 0) return false;
|
|
277
|
-
this.#
|
|
283
|
+
this.#applyScaleTransform(transformation);
|
|
284
|
+
controls.updateMatrixState();
|
|
278
285
|
return true;
|
|
279
286
|
}
|
|
280
287
|
/**
|
|
@@ -303,7 +310,19 @@ var GamepadArcballControls = class extends GamepadControls {
|
|
|
303
310
|
if (point === null) return false;
|
|
304
311
|
const controls = this.#controls;
|
|
305
312
|
controls.updateMatrixState();
|
|
306
|
-
|
|
313
|
+
const descriptor = Object.getOwnPropertyDescriptor(controls, "applyTransformMatrix");
|
|
314
|
+
const applyScale = (transformation) => {
|
|
315
|
+
this.#applyScaleTransform(transformation);
|
|
316
|
+
};
|
|
317
|
+
controls.applyTransformMatrix = applyScale;
|
|
318
|
+
try {
|
|
319
|
+
controls.focus(point, controls.scaleFactor);
|
|
320
|
+
} finally {
|
|
321
|
+
if (controls.applyTransformMatrix === applyScale) {
|
|
322
|
+
if (descriptor) Object.defineProperty(controls, "applyTransformMatrix", descriptor);
|
|
323
|
+
else Reflect.deleteProperty(controls, "applyTransformMatrix");
|
|
324
|
+
}
|
|
325
|
+
}
|
|
307
326
|
controls.updateMatrixState();
|
|
308
327
|
return true;
|
|
309
328
|
}
|
|
@@ -317,6 +336,43 @@ var GamepadArcballControls = class extends GamepadControls {
|
|
|
317
336
|
this.#controls.updateMatrixState();
|
|
318
337
|
}
|
|
319
338
|
/**
|
|
339
|
+
* Applies native scale matrices and geometric side effects exactly once.
|
|
340
|
+
* Arcball's own applicator gates these effects on inaccessible state Symbols.
|
|
341
|
+
* Reproduce its scale/focus branch without entering or borrowing pointer state;
|
|
342
|
+
* native scale() and focus() still own the transformation and limit calculations.
|
|
343
|
+
* Cached baselines must stay intact until focus() restores its temporary ones.
|
|
344
|
+
*
|
|
345
|
+
* @param transformation - Native camera and gizmo scale transformations.
|
|
346
|
+
*/
|
|
347
|
+
#applyScaleTransform(transformation) {
|
|
348
|
+
const controls = this.#controls;
|
|
349
|
+
const camera = controls.object;
|
|
350
|
+
const gizmos = controls._gizmos;
|
|
351
|
+
if (transformation.camera !== null) {
|
|
352
|
+
this.#scaleMatrix.copy(controls._cameraMatrixState).premultiply(transformation.camera).decompose(camera.position, camera.quaternion, camera.scale);
|
|
353
|
+
camera.updateMatrix();
|
|
354
|
+
}
|
|
355
|
+
if (transformation.gizmos !== null) {
|
|
356
|
+
this.#scaleMatrix.copy(controls._gizmoMatrixState).premultiply(transformation.gizmos).decompose(gizmos.position, gizmos.quaternion, gizmos.scale);
|
|
357
|
+
gizmos.updateMatrix();
|
|
358
|
+
}
|
|
359
|
+
controls._tbRadius = controls.calculateTbRadius(camera);
|
|
360
|
+
if (controls.adjustNearFar) {
|
|
361
|
+
const distance = camera.position.distanceTo(gizmos.position);
|
|
362
|
+
this.#gizmoBounds.setFromObject(gizmos).getBoundingSphere(this.#gizmoSphere);
|
|
363
|
+
const { radius, center } = this.#gizmoSphere;
|
|
364
|
+
const adjustedNear = Math.max(controls._nearPos0, radius + center.length());
|
|
365
|
+
const adjustedFar = Math.min(controls._farPos0, -radius + center.length());
|
|
366
|
+
camera.near = distance - Math.min(adjustedNear, distance - controls._initialNear);
|
|
367
|
+
camera.far = distance - Math.min(adjustedFar, distance - controls._initialFar);
|
|
368
|
+
camera.updateProjectionMatrix();
|
|
369
|
+
} else if (camera.near !== controls._initialNear || camera.far !== controls._initialFar) {
|
|
370
|
+
camera.near = controls._initialNear;
|
|
371
|
+
camera.far = controls._initialFar;
|
|
372
|
+
camera.updateProjectionMatrix();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
320
376
|
* Consumes a focus-button press and resolves the viewport center hit point.
|
|
321
377
|
*
|
|
322
378
|
* @param buttonFocus - Button index configured for focus.
|
|
@@ -7,8 +7,8 @@ import { MapControls } from "three/addons/controls/MapControls.js";
|
|
|
7
7
|
* mouse conventions. All options from {@link GamepadOrbitControlsOptions} are available.
|
|
8
8
|
*
|
|
9
9
|
* Call `update()` inside the render loop **before** `MapControls.update()`.
|
|
10
|
-
* Gamepad interaction events, pause semantics,
|
|
11
|
-
* are inherited from {@link GamepadOrbitControls}.
|
|
10
|
+
* Gamepad interaction events, pause semantics, combined native/wrapper speeds,
|
|
11
|
+
* and automatic-rotation suspension are inherited from {@link GamepadOrbitControls}.
|
|
12
12
|
*/
|
|
13
13
|
export declare class GamepadMapControls extends GamepadOrbitControls {
|
|
14
14
|
/**
|
|
@@ -18,8 +18,8 @@ const DEFAULT_MAP_OPTIONS = {
|
|
|
18
18
|
* mouse conventions. All options from {@link GamepadOrbitControlsOptions} are available.
|
|
19
19
|
*
|
|
20
20
|
* Call `update()` inside the render loop **before** `MapControls.update()`.
|
|
21
|
-
* Gamepad interaction events, pause semantics,
|
|
22
|
-
* are inherited from {@link GamepadOrbitControls}.
|
|
21
|
+
* Gamepad interaction events, pause semantics, combined native/wrapper speeds,
|
|
22
|
+
* and automatic-rotation suspension are inherited from {@link GamepadOrbitControls}.
|
|
23
23
|
*/
|
|
24
24
|
var GamepadMapControls = class extends GamepadOrbitControls {
|
|
25
25
|
/**
|
|
@@ -55,6 +55,8 @@ export type GamepadOrbitControlsOptions = GamepadControlsOptions & {
|
|
|
55
55
|
* Bindings and speeds are configurable via {@link GamepadOrbitControlsOptions}.
|
|
56
56
|
* The wrapper dispatches balanced gamepad `start` and `end` events on the native
|
|
57
57
|
* controls; native operations and damping remain responsible for `change`.
|
|
58
|
+
* Accepted input suspends automatic rotation through every native update in the
|
|
59
|
+
* frame, preserving autoRotate configuration, pointer state, and residual damping.
|
|
58
60
|
*/
|
|
59
61
|
export declare class GamepadOrbitControls extends GamepadControls {
|
|
60
62
|
#private;
|
|
@@ -81,7 +83,8 @@ export declare class GamepadOrbitControls extends GamepadControls {
|
|
|
81
83
|
protected onUpdate(deltaTime: number): void;
|
|
82
84
|
/**
|
|
83
85
|
* Removes gamepad listeners and ends only this wrapper's active interaction.
|
|
84
|
-
*
|
|
86
|
+
* Restores the owned native update adapter even when an end listener throws.
|
|
87
|
+
* Repeated calls are safe and disposal is terminal; native damping is preserved.
|
|
85
88
|
*/
|
|
86
89
|
dispose(): void;
|
|
87
90
|
/**
|
|
@@ -27,10 +27,18 @@ const DEFAULT_ORBIT_OPTIONS = {
|
|
|
27
27
|
* Bindings and speeds are configurable via {@link GamepadOrbitControlsOptions}.
|
|
28
28
|
* The wrapper dispatches balanced gamepad `start` and `end` events on the native
|
|
29
29
|
* controls; native operations and damping remain responsible for `change`.
|
|
30
|
+
* Accepted input suspends automatic rotation through every native update in the
|
|
31
|
+
* frame, preserving autoRotate configuration, pointer state, and residual damping.
|
|
30
32
|
*/
|
|
31
33
|
var GamepadOrbitControls = class extends GamepadControls {
|
|
32
34
|
#controls;
|
|
33
35
|
#options;
|
|
36
|
+
#originalUpdate;
|
|
37
|
+
#originalUpdateDescriptor;
|
|
38
|
+
#nativeUpdate;
|
|
39
|
+
#autoRotationFrame = null;
|
|
40
|
+
#nativeUpdating = false;
|
|
41
|
+
#disposed = false;
|
|
34
42
|
/** Whether this wrapper owns an active gamepad interaction. */
|
|
35
43
|
#interacting = false;
|
|
36
44
|
/** Blocks recursive updates while a frame is being processed. */
|
|
@@ -51,6 +59,10 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
51
59
|
rotateStick: resolveGamepadStickBinding(DEFAULT_ORBIT_OPTIONS.rotateStick, options?.rotateStick),
|
|
52
60
|
panStick: resolveGamepadStickBinding(DEFAULT_ORBIT_OPTIONS.panStick, options?.panStick)
|
|
53
61
|
};
|
|
62
|
+
this.#originalUpdate = controls.update;
|
|
63
|
+
this.#originalUpdateDescriptor = Object.getOwnPropertyDescriptor(controls, "update");
|
|
64
|
+
this.#nativeUpdate = (delta) => this.#updateNative(delta);
|
|
65
|
+
controls.update = this.#nativeUpdate;
|
|
54
66
|
}
|
|
55
67
|
/**
|
|
56
68
|
* Polls the gamepad and applies input, ignoring updates from synchronous listeners.
|
|
@@ -60,10 +72,14 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
60
72
|
* @param deltaTime - Seconds since the last frame.
|
|
61
73
|
*/
|
|
62
74
|
update(deltaTime) {
|
|
63
|
-
if (this.#updating || this.#ending) return;
|
|
75
|
+
if (this.#updating || this.#ending || this.#nativeUpdating || this.#disposed) return;
|
|
76
|
+
this.#autoRotationFrame = null;
|
|
64
77
|
this.#updating = true;
|
|
65
78
|
try {
|
|
66
79
|
super.update(deltaTime);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
this.#autoRotationFrame = null;
|
|
82
|
+
throw error;
|
|
67
83
|
} finally {
|
|
68
84
|
this.#updating = false;
|
|
69
85
|
}
|
|
@@ -81,59 +97,77 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
81
97
|
}
|
|
82
98
|
const { rotateStick, panStick, buttonDeadzone, buttonDollyIn, buttonDollyOut } = this.#options;
|
|
83
99
|
const input = this.gamepadInput;
|
|
100
|
+
const gamepad = input.gamepad;
|
|
101
|
+
const object = this.#controls.object;
|
|
84
102
|
const rotate = input.stick(rotateStick.xAxis, rotateStick.yAxis, rotateStick.pipeline);
|
|
85
103
|
const pan = input.stick(panStick.xAxis, panStick.yAxis, panStick.pipeline);
|
|
86
104
|
const triggerIn = input.buttonValue(buttonDollyIn);
|
|
87
105
|
const triggerOut = input.buttonValue(buttonDollyOut);
|
|
88
106
|
const frame = {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
107
|
+
gamepad,
|
|
108
|
+
object,
|
|
109
|
+
delta: deltaTime,
|
|
110
|
+
input: {
|
|
111
|
+
rotateX: rotate.x,
|
|
112
|
+
rotateY: rotate.y,
|
|
113
|
+
panX: pan.x,
|
|
114
|
+
panY: pan.y,
|
|
115
|
+
dollyIn: triggerIn > buttonDeadzone ? triggerIn : 0,
|
|
116
|
+
dollyOut: triggerOut > buttonDeadzone ? triggerOut : 0
|
|
117
|
+
}
|
|
95
118
|
};
|
|
96
|
-
let actions = this.#acceptActions(frame
|
|
119
|
+
let actions = this.#acceptActions(frame);
|
|
97
120
|
if (actions === null) return;
|
|
98
121
|
if (!this.#interacting) {
|
|
99
122
|
this.#interacting = true;
|
|
100
123
|
this.#controls.dispatchEvent({ type: "start" });
|
|
101
|
-
actions = this.#acceptActions(frame
|
|
124
|
+
actions = this.#acceptActions(frame);
|
|
102
125
|
if (actions === null) return;
|
|
103
126
|
}
|
|
104
127
|
const controls = this.#controls;
|
|
105
128
|
if (actions.rotateX !== 0) {
|
|
106
129
|
controls.rotateLeft(actions.rotateX);
|
|
107
|
-
actions = this.#acceptActions(frame
|
|
130
|
+
actions = this.#acceptActions(frame);
|
|
108
131
|
if (actions === null) return;
|
|
109
132
|
}
|
|
110
133
|
if (actions.rotateY !== 0) {
|
|
111
134
|
controls.rotateUp(actions.rotateY);
|
|
112
|
-
actions = this.#acceptActions(frame
|
|
135
|
+
actions = this.#acceptActions(frame);
|
|
113
136
|
if (actions === null) return;
|
|
114
137
|
}
|
|
115
138
|
if (actions.panX !== 0 || actions.panY !== 0) {
|
|
116
139
|
controls.pan(actions.panX, actions.panY);
|
|
117
|
-
actions = this.#acceptActions(frame
|
|
140
|
+
actions = this.#acceptActions(frame);
|
|
118
141
|
if (actions === null) return;
|
|
119
142
|
}
|
|
120
143
|
if (actions.dollyIn !== 0) {
|
|
121
144
|
controls.dollyIn(1 / (1 + actions.dollyIn));
|
|
122
|
-
actions = this.#acceptActions(frame
|
|
145
|
+
actions = this.#acceptActions(frame);
|
|
123
146
|
if (actions === null) return;
|
|
124
147
|
}
|
|
125
148
|
if (actions.dollyOut !== 0) {
|
|
126
149
|
controls.dollyOut(1 / (1 + actions.dollyOut));
|
|
127
|
-
this.#acceptActions(frame
|
|
150
|
+
this.#acceptActions(frame);
|
|
128
151
|
}
|
|
129
152
|
}
|
|
130
153
|
/**
|
|
131
154
|
* Removes gamepad listeners and ends only this wrapper's active interaction.
|
|
132
|
-
*
|
|
155
|
+
* Restores the owned native update adapter even when an end listener throws.
|
|
156
|
+
* Repeated calls are safe and disposal is terminal; native damping is preserved.
|
|
133
157
|
*/
|
|
134
158
|
dispose() {
|
|
159
|
+
if (this.#disposed) return;
|
|
160
|
+
this.#disposed = true;
|
|
161
|
+
this.#autoRotationFrame = null;
|
|
135
162
|
super.dispose();
|
|
136
|
-
|
|
163
|
+
try {
|
|
164
|
+
this.#endInteraction();
|
|
165
|
+
} finally {
|
|
166
|
+
if (this.#controls.update === this.#nativeUpdate) {
|
|
167
|
+
if (this.#originalUpdateDescriptor === void 0) Reflect.deleteProperty(this.#controls, "update");
|
|
168
|
+
else Object.defineProperty(this.#controls, "update", this.#originalUpdateDescriptor);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
137
171
|
}
|
|
138
172
|
/**
|
|
139
173
|
* Ends the owned interaction before forwarding the active gamepad's disconnection.
|
|
@@ -149,17 +183,29 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
149
183
|
* Native disable or lack of actionable input ends the owned session; a wrapper
|
|
150
184
|
* pause stops application while retaining it. Geometric limits do not erase intent.
|
|
151
185
|
*
|
|
152
|
-
* @param
|
|
153
|
-
* @param delta - Frame duration in seconds.
|
|
186
|
+
* @param frame - Cached input and the destination that owns it.
|
|
154
187
|
* @returns Accepted frame deltas, or `null` when input application must stop.
|
|
155
188
|
*/
|
|
156
|
-
#acceptActions(
|
|
157
|
-
|
|
158
|
-
if (!controls.enabled) {
|
|
189
|
+
#acceptActions(frame) {
|
|
190
|
+
if (!this.#controls.enabled) {
|
|
159
191
|
this.#endInteraction();
|
|
160
192
|
return null;
|
|
161
193
|
}
|
|
162
|
-
if (!this
|
|
194
|
+
if (!this.#ownsFrame(frame)) {
|
|
195
|
+
this.#autoRotationFrame = null;
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
const actions = this.#resolveActions(frame.input, frame.delta);
|
|
199
|
+
if (actions === null) {
|
|
200
|
+
this.#endInteraction();
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
this.#autoRotationFrame = frame;
|
|
204
|
+
return actions;
|
|
205
|
+
}
|
|
206
|
+
/** Resolves current permissions and gains without events or pipeline reads. */
|
|
207
|
+
#resolveActions(input, delta) {
|
|
208
|
+
const controls = this.#controls;
|
|
163
209
|
const rotate = controls.enableRotate ? controls.rotateSpeed * this.#options.rotateSpeed * delta * Math.PI : 0;
|
|
164
210
|
const pan = controls.enablePan ? controls.panSpeed * this.#options.panSpeed * delta * 500 : 0;
|
|
165
211
|
const zoom = controls.enableZoom ? controls.zoomSpeed * this.#options.zoomSpeed * delta : 0;
|
|
@@ -171,17 +217,68 @@ var GamepadOrbitControls = class extends GamepadControls {
|
|
|
171
217
|
dollyIn: input.dollyIn * zoom,
|
|
172
218
|
dollyOut: input.dollyOut * zoom
|
|
173
219
|
};
|
|
174
|
-
if (!Object.values(actions).some((value) => value !== 0))
|
|
175
|
-
this.#endInteraction();
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
220
|
+
if (!Object.values(actions).some((value) => value !== 0)) return null;
|
|
178
221
|
return actions;
|
|
179
222
|
}
|
|
223
|
+
/** Checks the live wrapper, selected snapshot, and camera after callbacks. */
|
|
224
|
+
#ownsFrame(frame) {
|
|
225
|
+
return !this.#disposed && this.enabled && this.gamepad === frame.gamepad && this.#controls.object === frame.object;
|
|
226
|
+
}
|
|
227
|
+
/** Releases invalid intent without ending a paused interaction or repolling. */
|
|
228
|
+
#suppressAutoRotation() {
|
|
229
|
+
const frame = this.#autoRotationFrame;
|
|
230
|
+
if (frame === null) return false;
|
|
231
|
+
if (!this.#controls.enabled || !this.#ownsFrame(frame) || this.#resolveActions(frame.input, frame.delta) === null) {
|
|
232
|
+
this.#autoRotationFrame = null;
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Masks only the automatic angle for this call, retaining intent for subsequent
|
|
239
|
+
* internal and external updates. Native pointer gating and damping stay intact.
|
|
240
|
+
* Restores owned descriptors and makes retained masks inert even on failure.
|
|
241
|
+
*/
|
|
242
|
+
#updateNative(delta) {
|
|
243
|
+
if (this.#nativeUpdating) return false;
|
|
244
|
+
const controls = this.#controls;
|
|
245
|
+
this.#nativeUpdating = true;
|
|
246
|
+
try {
|
|
247
|
+
if (!this.#suppressAutoRotation()) return this.#originalUpdate.call(controls, delta);
|
|
248
|
+
const descriptor = Object.getOwnPropertyDescriptor(controls, "_getAutoRotationAngle");
|
|
249
|
+
const original = controls._getAutoRotationAngle;
|
|
250
|
+
const enumerable = descriptor?.enumerable ?? false;
|
|
251
|
+
let masking = true;
|
|
252
|
+
const angle = (delta) => masking && this.#suppressAutoRotation() ? 0 : original.call(controls, delta);
|
|
253
|
+
Object.defineProperty(controls, "_getAutoRotationAngle", {
|
|
254
|
+
configurable: true,
|
|
255
|
+
enumerable,
|
|
256
|
+
writable: true,
|
|
257
|
+
value: angle
|
|
258
|
+
});
|
|
259
|
+
try {
|
|
260
|
+
return this.#originalUpdate.call(controls, delta);
|
|
261
|
+
} finally {
|
|
262
|
+
masking = false;
|
|
263
|
+
const current = Object.getOwnPropertyDescriptor(controls, "_getAutoRotationAngle");
|
|
264
|
+
if (current?.value === angle && current.configurable === true && current.enumerable === enumerable && current.writable === true) {
|
|
265
|
+
if (descriptor === void 0) Reflect.deleteProperty(controls, "_getAutoRotationAngle");
|
|
266
|
+
else Object.defineProperty(controls, "_getAutoRotationAngle", descriptor);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
} catch (error) {
|
|
270
|
+
this.#autoRotationFrame = null;
|
|
271
|
+
throw error;
|
|
272
|
+
} finally {
|
|
273
|
+
this.#nativeUpdating = false;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
180
276
|
/**
|
|
181
277
|
* Releases session ownership before dispatching the native `end` event once.
|
|
182
278
|
* Blocks recursive updates during finalization without clearing native input or damping.
|
|
183
279
|
*/
|
|
184
280
|
#endInteraction() {
|
|
281
|
+
this.#autoRotationFrame = null;
|
|
185
282
|
if (!this.#interacting) return;
|
|
186
283
|
this.#interacting = false;
|
|
187
284
|
this.#ending = true;
|
package/package.json
CHANGED