Appearance
TransformControlsService
Wraps Three.js TransformControls to provide interactive translate, rotate, and scale gizmos in the scene. Automatically attaches to the selected object when selection changes to a single object, and detaches on multi-selection or clear. Camera orbit controls are disabled while a drag is in progress.
Access
Registered under the name "transformcontrols". Depends on "selection" and "camera".
TransformControlsService is not exported from the SDK entry point. Reach it by its registered name and use the class only as a type.
ts
import type { TransformControlsService } from "@optellix/xviewr-sdk";
await viewer.ready();
const tc = viewer.getService<TransformControlsService>("transformcontrols");
tc?.setMode("rotate");The service activates automatically on init. Attach and detach happen through selection events, but you can also call attachToObject directly.
Public API
Lifecycle
init(context: ServiceContext): Promise<void>destroy(): Promise<void>getStatus(): ServiceStatus
Activation
activate(): void— enables controls, adds the helper to the scene, and subscribes to selection events.deactivate(): void— disables controls, detaches from any target, and unsubscribes selection listeners.isTransformActive(): boolean
Attachment
attachToObject(object: THREE.Object3D): void— attaches the gizmo toobject. Activates controls if not already active.detachFromObject(): void— detaches the gizmo from the current target.getCurrentTarget(): THREE.Object3D | null
Mode and space
setMode(mode: TransformMode): void— sets the active gizmo type:"translate","rotate", or"scale".getMode(): TransformModesetSpace(space: TransformSpace): void— sets the coordinate frame:"world"or"local".getSpace(): TransformSpace
Appearance
setSize(size: number): void— scales the gizmo. Default1.getSize(): numbersetAxisVisibility(axis: "x" | "y" | "z", visible: boolean): void— shows or hides individual axis handles.
Snapping
setTranslationSnap(snap: number | null): void— snaps translation in world units.nulldisables snapping.setRotationSnap(snap: number | null): void— snaps rotation in radians.setScaleSnap(snap: number | null): void
Configuration
updateConfig(newConfig: Partial<TransformControlsConfig>): void— bulk-update config and reapply all settings.getConfig(): TransformControlsConfig
Transform data
getTransformData(): TransformData | null— returns a snapshot of the current target's position, rotation, scale, and quaternion. Returnsnullif no target is attached.applyTransformData(data: TransformData): void— applies a previously captured transform to the current target.resetTransform(): void— resets the current target to identity (position0,0,0, rotation0,0,0, scale1,1,1).
Types
TransformControlsConfig
ts
interface TransformControlsConfig {
mode: TransformMode;
size: number;
space: TransformSpace;
enabled: boolean;
showX: boolean;
showY: boolean;
showZ: boolean;
translationSnap: number | null;
rotationSnap: number | null;
scaleSnap: number | null;
}TransformData
ts
interface TransformData {
position: THREE.Vector3;
rotation: THREE.Euler;
scale: THREE.Vector3;
quaternion: THREE.Quaternion;
}TransformMode / TransformSpace
ts
type TransformMode = "translate" | "rotate" | "scale";
type TransformSpace = "world" | "local";Events
| Event | Payload |
|---|---|
transformcontrols:service-ready | {} |
transformcontrols:activated | {} |
transformcontrols:deactivated | {} |
transformcontrols:attached | { object: THREE.Object3D } |
transformcontrols:detached | { object: THREE.Object3D } |
transformcontrols:changed | { object: THREE.Object3D | null; transformData: TransformData | null } |
transformcontrols:dragging-changed | { dragging: boolean; object: THREE.Object3D | null } |
transformcontrols:object-changed | { object: THREE.Object3D | null; transformData: TransformData | null } |
transformcontrols:mode-changed | { mode: TransformMode } |
transformcontrols:space-changed | { space: TransformSpace } |
transformcontrols:size-changed | { size: number } |
transformcontrols:axis-visibility-changed | { axis: "x" | "y" | "z"; visible: boolean } |
transformcontrols:translation-snap-changed | { snap: number | null } |
transformcontrols:rotation-snap-changed | { snap: number | null } |
transformcontrols:scale-snap-changed | { snap: number | null } |
transformcontrols:config-updated | { config: TransformControlsConfig } |
transformcontrols:reset | { object: THREE.Object3D | null } |
transformcontrols:transform-applied | { object: THREE.Object3D | null; data: TransformData } |
Example
ts
const tc = viewer.getService<TransformControlsService>("transformcontrols");
if (!tc) return;
// Switch to rotate mode with 15-degree snapping
tc.setMode("rotate");
tc.setRotationSnap(Math.PI / 12);
// Work in local space
tc.setSpace("local");
// Attach directly to a known object
const mesh = viewer.getService("mesh")?.getById("hinge-001");
if (mesh) tc.attachToObject(mesh);
// Save transform before edit and restore on undo
const before = tc.getTransformData();
// ... user drags ...
tc.applyTransformData(before!); // undo
// Listen for every incremental change
viewer.on("transformcontrols:object-changed", ({ transformData }) => {
console.log("position:", transformData?.position);
});