Turns the camera into an interactive turntable — orbit, pan, zoom, and auto-fit around a pivot — so you frame a scene without hand-placing the camera.
Declarative element:
<sk-camera-orbit-control>
Global: available as sk.CameraOrbitControl inside a scene <script>.
This is the camera-control companion to the AbstractCamera family: rather
than a camera itself, it takes over aiming one. Presence of a camera-orbit-control
alongside the camera opts the scene into interactive orbit / pan / zoom plus an
optional auto-fit that frames the scene for you — the easy way to get a good shot,
since a bare camera has to be positioned and rotated by hand.
Key attributes. The pose is azimuth (turn around the pivot), elevation
(height above it), and radius (distance from it) — all animatable, so an animation
can sweep the camera on a turntable. fit-targets / fit-margin turn on the
auto-fit that keeps the subject framed, and orient-toward-pivot keeps the camera
aimed at the pivot as it moves. Reflection and animation are handled by
the shared SkenraAnimatable machinery, and orbit-pose writes drive the
camera through the underlying Orbit node; the fit-backed properties re-arm
the auto-fit at runtime.
Lifecycle: The browser upgrade path constructs the element with NO
arguments, so it must be valid uninitialized — it has no camera until
attachCamera binds one (the declarative scene bootstrap or an
imperative caller). The canonical Orbit node is created lazily on
connect (so an animation always has a real animatable to
target) and survives camera detach/re-attach, preserving its identity and
pose subscription.
Animation: an animation on this control is redirected onto the canonical
Orbit (see _resolveAnimationEffectTarget), the true
animatable owning azimuth / elevation / radius. Fit-backed properties
(fitTargets, fitMargin, freezeOnFit, pivot, panX, panY,
zoomFactor) are live and scriptable but NOT animatable.
Interactive input composes with animation. Orbit drag, zoom, and inertia
contribute a persistent additive offset through the same effect stack the
animation uses (see CameraOrbitUserOffset), so you can grab and orbit
the camera while a turntable animation is playing and the gesture simply
shifts the framing — the animation keeps running underneath without a
frame-to-frame fight. Because the gesture is a separate effect layer, a drag
does NOT rewrite the authored azimuth / elevation / radius attributes;
the authored pose stays the base the animation and the offset compose onto.
resetView and setViewDirection clear the accumulated offset.
This class owns the orbit setup/lifecycle, pivot management, zoom/radius state, reset state, pan-direction vector extraction, sensitivity configs, and min/max clamping. It owns NO DOM event listeners and has no knowledge of pointer/wheel/touch events.
constructor(config?: { camera?: AbstractCamera; orbitSensitivity?: number; panSensitivity?: number; zoomSensitivity?: number; minZoom?: number; maxZoom?: number; orientationAxis?: '-x' | '+x' | '-y' | '+y' | '-z' | '+z'; pivotNode?: SceneNode; orbitNode?: Orbit })
Inherited from: SkenraAnimatable
— see those pages for inherited members.
| Property | Type | Default | Description | Declared by |
|---|---|---|---|---|
cameraconfig-only |
AbstractCamera |
— | A camera to attach to at construction (imperative sugar for CameraOrbitControl.attachCamera). |
CameraOrbitControlInit |
orbitSensitivity |
number |
0.005 |
Orbit drag sensitivity (radians per pixel). Consumed by the viewport input handler. | CameraOrbitControl |
panSensitivity |
number |
0.01 |
Pan drag sensitivity. | CameraOrbitControl |
zoomSensitivity |
number |
0.005 |
Zoom drag sensitivity (scale factor per pixel). | CameraOrbitControl |
minZoom |
number |
1 |
Minimum zoom level (orthographic height or perspective orbit distance). | CameraOrbitControl |
maxZoom |
number |
500 |
Maximum zoom level (orthographic height or perspective orbit distance). | CameraOrbitControl |
orientationAxis |
'-x' | '+x' | '-y' | '+y' | '-z' | '+z' |
"-z" |
Which camera axis points at the pivot when orienting. | CameraOrbitControl |
pivotNode |
SceneNode |
— | The SceneNode the camera currently orbits around: an explicit pivot |
CameraOrbitControl |
orbitNoderead-only |
Orbit |
— | Get the Orbit attached to the camera. | CameraOrbitControl |
| Property | Type | Default | Description | Declared by |
|---|---|---|---|---|
azimuthanimatable |
number |
0 |
Initial/horizontal orbit angle (radians); animatable. | CameraOrbitControl |
elevationanimatable |
number |
0 |
Initial/vertical orbit angle (radians); animatable. | CameraOrbitControl |
radiusanimatable |
number |
10 |
Orbit radius (distance from pivot); animatable. | CameraOrbitControl |
orientTowardPivot |
boolean |
false |
When true, the camera faces the pivot. | CameraOrbitControl |
fitTargets |
"none" | "auto" | readonly string[] |
"none" |
Nodes whose bounds drive an auto-fit: 'auto', 'none', or id list. |
CameraOrbitControl |
fitMargin |
number |
0 |
Padding fraction applied around fitted bounds. | CameraOrbitControl |
freezeOnFit |
boolean |
true |
Stop the fit observer after the first frame with real bounds. | CameraOrbitControl |
pivot |
string | null |
— | The point the camera orbits around, as an element id reference (#id), |
CameraOrbitControl |
panX |
string | null |
— | Post-fit horizontal pan (CSS length string), or null. | CameraOrbitControl |
panY |
string | null |
— | Post-fit vertical pan (CSS length string), or null. | CameraOrbitControl |
zoomFactor |
number |
1 |
Post-fit zoom multiplier (1 = no change). | CameraOrbitControl |
enabled |
boolean |
true |
Whether camera controls are enabled. | CameraOrbitControl |
enableInertia |
boolean |
true |
Whether inertia/momentum is enabled after pointer release. | CameraOrbitControl |
inertiaFactor |
number |
0.05 |
Decay factor per frame for inertia. Higher values = more damping (stops faster). | CameraOrbitControl |
inertiaThreshold |
number |
0.0001 |
Velocity magnitude below which inertia stops. | CameraOrbitControl |
hasActiveInertiaread-only |
boolean |
— | Whether there is currently active inertia motion. | CameraOrbitControl |
zoomLevelread-only |
number |
— | Get the current zoom level. | CameraOrbitControl |
orbitConstraintread-only |
OrbitConstraint | null |
— | Get the OrbitConstraint attached to the camera. | CameraOrbitControl |
sceneread-only |
any |
— | Gets the Scene this animatable belongs to, if any. | SkenraAnimatable |
animationsread-only |
SkenraAnimation[] |
— | Public getter for the animations affecting this target. | SkenraAnimatable |
| Method | Description | Declared by |
|---|---|---|
attachCamera(camera: AbstractCamera, config?: CameraOrbitControlOptions): this |
Binds this control to a live camera and installs the orbit runtime | CameraOrbitControl |
setCamera(camera: AbstractCamera): void |
Sets a new camera for this controller. | CameraOrbitControl |
dispose(): void |
Terminal teardown. Detaches the camera runtime, then permanently drops | CameraOrbitControl |
update(): void |
Per-frame update entrypoint. | CameraOrbitControl |
orbit(deltaAzimuth: number, deltaElevation: number): void |
Orbit the camera by adjusting azimuth and elevation. | CameraOrbitControl |
pan(deltaX: number, deltaY: number): void |
Pan the camera by moving the pivot point in screen-aligned directions. | CameraOrbitControl |
zoom(factor: number): void |
Zoom the camera by a given factor. | CameraOrbitControl |
handleWheelZoom(deltaY: number): void |
Handle mouse wheel zoom. | CameraOrbitControl |
startOrbitInertia(velocityAzimuth: number, velocityElevation: number): void |
Start orbit inertia with the given angular velocity. | CameraOrbitControl |
startPanInertia(velocityX: number, velocityY: number): void |
Start pan inertia with the given pixel velocity. | CameraOrbitControl |
stopInertia(): void |
Immediately stop any active inertia. | CameraOrbitControl |
updateInertia(): void |
Update inertia state for the current frame. | CameraOrbitControl |
setViewDirection(direction: 'front' | 'back' | 'left' | 'right' | 'top' | 'bottom'): void |
Set the camera to a predefined view direction. | CameraOrbitControl |
resetView(): void |
Reset the camera to its initial state. | CameraOrbitControl |
fitToNode(node: SceneNode): void |
Fits the camera to the given node's bounding box. | CameraOrbitControl |
setFitTarget(target: SceneNode | ReadonlyArray<SceneNode> | 'auto' | 'none', options?: SetFitTargetOptions): void |
Schedules an auto-fit of the camera to one or more targets, deferred | CameraOrbitControl |
getConfig(): CameraOrbitControlConfig |
Returns the resolved configuration with defaults applied. | CameraOrbitControl |
animate(firstArg: TypedKeyframe<this>[] | TypedPropertyIndexedKeyframes<this> | Record<string, any> | globalThis.Keyframe[] | globalThis.PropertyIndexedKeyframes | null, secondArg?: number | KeyframeAnimationOptions | globalThis.KeyframeAnimationOptions): SkenraAnimation & Animation |
Creates a new SkenraAnimation for this target per Web Animations API. | SkenraAnimatable |
removeAnimation(animation: SkenraAnimation): boolean |
Removes a specific animation from this object. | SkenraAnimatable |
constrain(type: K, config: ConstraintConfigMap[K]): ConstraintReturnMap[K] |
Creates a constraint on this Animatable using a fluent API. | SkenraAnimatable |
import { CameraOrbitControl } from '/js/skenra/camera/camera-orbit-control.js';
const controller = new CameraOrbitControl({ camera: camera,
panSensitivity: 0.02
});
controller.radius = 15; // camera-to-pivot distance
controller.orbit(Math.PI / 4, 0); // Orbit 45° horizontally
controller.pan(10, 5); // Pan 10px right, 5px up
controller.zoom(0.5); // Zoom in by 50%
controller.resetView(); // Reset to initial state
controller.dispose();
Used in guides: Scene basics