Create controls manager for camera interaction.
Camera to control (perspective or orthographic)
DOM element for mouse/touch input (typically canvas)
Optional_scene: Scene<Object3DEventMap>
Optional scene reference
PrivatecameraPrivatedomPrivatecurrentPrivatecontrolCleanup group for the active controls' event forwarders and gesture interruption listener. Rebuilt on every switch so disposing the previous group detaches the old listeners atomically.
PrivatecurrentPrivategestureTracks whether a pointer gesture (drag, pinch, press-and-hold) is in
progress on the active controls. Read by the
AnimationController's idle check: a button or finger held still for longer
than idleTimeoutMs must not pause the render loop, because the drag that
follows feeds rotate/pan/zoom deltas into the controls that only
update() — a per-frame call — ever applies.
PrivateconfigPrivatescenePrivatestoredPrivatestoredPrivatesavedPrivatesavedPrivatesavedPrivatesavedPrivateclockUpdate internal camera reference (e.g., when swapping between perspective and orthographic). Must be called BEFORE setControlType when the camera object itself changes.
Get currently active control type.
Get current controls instance.
Undo a LIVE dolly offset before the active controls are abandoned, so a transient mid-swing position is not baked into the saved camera state and carried into the next control instance.
Only while the dolly is actually running. Once it has been switched off
the camera's position is the user's chosen framing (see
LuxarOrbitControls.autoDolly), and a mode switch must preserve it like
any other.
PrivatemakePrivatecreatePrivatecreatePrivatecreatePrivatemakePrivateminSmallest camera-to-pivot distance the orbit system itself allows: the auto-frame min distance limit when one is set, capped at sceneScale·1e-3 (the scale-derived orbit floor). The fly-mode focus-target derivation floors the reused pivot depth here — auto-frame limits can legitimately put the orbit distance below sceneScale·1e-3 (fit distance / ZOOM_IN_FACTOR shrinks with wide FOVs), and a pivot depth the user could legally reach must survive a no-interaction mode round trip exactly.
PrivatesavePrivaterestorePrivateattachPrivatedisposeSet the camera-frame or fixed scene turntable axis (see AutoRotateAxis). Applies to the live instance when it is an orbit/ortho control so the change is visible on the next frame without a mode switch.
Enable/disable the auto-dolly. Applies to the live instance so the change takes effect on the next frame without a mode switch.
Set the dolly amplitude from a user-facing PERCENT (15 → ±15% of the viewing distance). The control itself stores the fraction; this is one of the three seams that cross that boundary, and all of them go through dollyAmplitudeFromPercent.
Set the dolly period in seconds (one full in-and-out oscillation).
Toggle the orbit-mode LEFT ↔ RIGHT mouse-button mapping. Updates stored config and, only when the active control is orbit (3D), mutates the live mouseButtons in place so the change applies immediately without a mode switch. Ortho and fly are intentionally ignored: ortho uses its own RIGHT=null mapping, fly doesn't use mouseButtons at all.
Whether auto-rotation can currently move the camera. Ortho carries the turntable settings for persistence, but disables rotation.
Whether a pointer gesture is in progress on the active controls.
Whether the auto-dolly can currently move the camera. Gated on
enableZoom rather than enableRotate: unlike the turntable, the dolly
is alive in ortho mode, where it modulates camera.zoom. An inert
amplitude or period counts as inactive so the render loop is not held
awake by an oscillation of size zero.
The live turntable axis, falling back to the stored config when the active control is fly (which has no turntable) — never a silent 'vertical', so a mode round-trip cannot quietly reset the user's choice.
Orbit wheel-zoom speed. zoomSpeed is read live per wheel event, so
mutating the field applies immediately. Also affects ortho mode (same
LuxarOrbitControls class) — one shared zoom feel across both.
Orbit damping factor (camera "weight"). dampingFactor is read live
per frame; applies immediately. Shared with ortho like the zoom speed.
Stop residual user-input damping without changing the current pose.
Set the orbit target without triggering an update. Use this when you also need to reinitialize() afterward (e.g., after auto-frame). For fly controls, instantly orients the camera toward the target.
Re-derive internal orbit state (distance, orientation) from the current camera position and target. Must be called after externally setting camera.position to avoid the next update() snapping the camera back to the old distance.
Set orbit distance limits (perspective camera zoom range). Called after auto-framing with the scene-fitting distance to give an asymmetric zoom range (ZOOM_IN_FACTOR in, ZOOM_OUT_FACTOR out). Persisted across mode switches so limits survive control recreation.
Set ortho zoom limits (orthographic camera zoom range). Called after auto-framing with the scene-fitting zoom to give an asymmetric zoom range (ZOOM_IN_FACTOR in, ZOOM_OUT_FACTOR out). Persisted across mode switches so limits survive control recreation.
Coordinates the three camera control modes behind one stable interface.
Owns the currently active control instance (orbit, fly, or ortho), swaps between them on request, and preserves camera position/orientation/target across each swap so switching modes never jumps the view. Also brokers the per-frame update tick (feeding delta time from an internal
THREE.Timer), forwardschange/start/endevents from the active control, and persists scale-derived and auto-frame limits so they survive control recreation.Emits
change(with the newcontrolTypeon a mode switch),start, andend. Most setters mutate the live control instance in place when its type matches, so config changes apply immediately without a mode switch.See