Controls API ReferenceThe controls module provides camera and object interaction controls.

Controls API Reference

The controls module provides camera and object interaction controls.

Overview

import io.materia.controls.*

OrbitControls

Orbiting camera controls for rotating around a target.

Constructor

class OrbitControls(
    camera: Camera,
    config: ControlsConfig = ControlsConfig()
)

Input adapters call onPointerDown, onPointerMove, onPointerUp, onWheel, and the keyboard handlers. Call update(deltaSeconds) exactly once before each render.

Configuration

PropertyTypeDefaultDescription
minDistanceFloat1Minimum zoom distance
maxDistanceFloat1000Maximum zoom distance
minPolarAngleFloat0Minimum vertical angle
maxPolarAngleFloatPIMaximum vertical angle
minAzimuthAngleFloat-InfinityMinimum horizontal angle
maxAzimuthAngleFloatInfinityMaximum horizontal angle
enableDampingBooleantrueSmoothly converge to requested poses
dampingTimeFloat0.04Frame-rate-independent convergence time in seconds
settleEpsilonFloat0.0001Threshold for snapping to a stable pose
maxDeltaTimeFloat0.05Clamp used after stalls or hidden tabs
enableZoomBooleantrueEnable zooming
zoomSpeedFloat1.0Zoom sensitivity
enableRotateBooleantrueEnable rotation
rotateSpeedFloat1.0Rotation sensitivity
enablePanBooleantrueEnable panning
panSpeedFloat1.0Pan sensitivity
autoRotateBooleanfalseAuto-rotate
autoRotateSpeedFloat2.0Auto-rotate speed
enableKeysBooleantrueEnable keyboard

Methods

fun update(deltaTime: Float)
fun reset()
fun moveTo(position: Vector3, target: Vector3, duration: Float = 1f)
fun setPose(position: Vector3, target: Vector3)
fun cancelAnimation()
fun cancelMomentum()
fun isSettled(): Boolean
fun saveState(): ControlsState
fun restoreState(savedState: ControlsState)
fun getPolarAngle(): Float
fun getAzimuthalAngle(): Float
fun getDistance(): Float

Events

controls.addEventListener(object : ControlsEventListener {
    override fun onControlsChange() = requestRender()
    override fun onControlsStart() = capturePointer()
    override fun onControlsEnd() = releasePointer()
})

Example

val controls = OrbitControls(
    camera,
    ControlsConfig(
        minDistance = 2f,
        maxDistance = 50f,
        maxPolarAngle = PI / 2,
        enablePan = false,
        dampingTime = 0.04f
    )
)

fun frame(deltaSeconds: Float) {
    controls.update(deltaSeconds)
    renderer.render(scene, camera)
}

controls.moveTo(
    position = Vector3(8f, 6f, 10f),
    target = mesh.position,
    duration = 0.6f
)

MapControls

Extends OrbitControls for map-style navigation (pan with left mouse).

Constructor

class MapControls(
    camera: Camera,
    domElement: HTMLElement
)

Differences from OrbitControls

  • Left mouse button pans
  • Right mouse button rotates
  • Good for top-down views

Example

val controls = MapControls(camera, renderer.domElement)
controls.enableDamping = true
controls.screenSpacePanning = false  // Pan parallel to ground
controls.maxPolarAngle = PI / 2

TrackballControls

Unconstrained rotation controls (no up direction).

Constructor

class TrackballControls(
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
enabledBooleantrueEnable controls
rotateSpeedFloat1.0Rotation speed
zoomSpeedFloat1.2Zoom speed
panSpeedFloat0.3Pan speed
noRotateBooleanfalseDisable rotation
noZoomBooleanfalseDisable zoom
noPanBooleanfalseDisable pan
staticMovingBooleanfalseNo inertia
dynamicDampingFactorFloat0.2Inertia damping
minDistanceFloat0Min distance
maxDistanceFloatInfinityMax distance

Methods

fun update()
fun reset()
fun dispose()

FlyControls

Flight simulator-style controls.

Constructor

class FlyControls(
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
movementSpeedFloat1.0Movement speed
rollSpeedFloat0.005Roll speed
dragToLookBooleanfalseRequire drag to look
autoForwardBooleanfalseAlways move forward

Methods

fun update(delta: Float)
fun dispose()

Example

val controls = FlyControls(camera, renderer.domElement)
controls.movementSpeed = 10f
controls.rollSpeed = PI / 24

fun animate(deltaTime: Float) {
    controls.update(deltaTime)
    renderer.render(scene, camera)
}

FirstPersonControls

First-person shooter-style controls.

Constructor

class FirstPersonControls(
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
enabledBooleantrueEnable controls
movementSpeedFloat1.0Movement speed
lookSpeedFloat0.005Look sensitivity
lookVerticalBooleantrueAllow vertical look
autoForwardBooleanfalseAuto move forward
activeLookBooleantrueMouse look
heightSpeedBooleanfalseHeight affects speed
heightCoefFloat1.0Height coefficient
heightMinFloat0Minimum height
heightMaxFloat1.0Maximum height
constrainVerticalBooleanfalseLimit vertical angle
verticalMinFloat0Min vertical angle
verticalMaxFloatPIMax vertical angle

Methods

fun update(delta: Float)
fun lookAt(target: Vector3)
fun dispose()

PointerLockControls

First-person controls with pointer lock (mouse capture).

Constructor

class PointerLockControls(
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
isLockedBooleanfalseIs pointer locked
minPolarAngleFloat0Min vertical angle
maxPolarAngleFloatPIMax vertical angle

Methods

// Lock pointer
fun lock()

// Unlock pointer
fun unlock()

// Connect/disconnect events
fun connect()
fun disconnect()

// Get look direction
fun getDirection(target: Vector3): Vector3

// Movement
fun moveForward(distance: Float)
fun moveRight(distance: Float)

fun dispose()

Events

controls.addEventListener("lock") {
    instructions.style.display = "none"
}

controls.addEventListener("unlock") {
    instructions.style.display = "block"
}

Example

val controls = PointerLockControls(camera, document.body)
scene.add(controls.getObject())  // Add camera to scene

// Click to lock
document.body.addEventListener("click") {
    controls.lock()
}

// Movement
val velocity = Vector3()
val direction = Vector3()

var moveForward = false
var moveBackward = false
var moveLeft = false
var moveRight = false

document.addEventListener("keydown") { event ->
    when (event.code) {
        "KeyW" -> moveForward = true
        "KeyS" -> moveBackward = true
        "KeyA" -> moveLeft = true
        "KeyD" -> moveRight = true
    }
}

document.addEventListener("keyup") { event ->
    when (event.code) {
        "KeyW" -> moveForward = false
        "KeyS" -> moveBackward = false
        "KeyA" -> moveLeft = false
        "KeyD" -> moveRight = false
    }
}

fun animate(delta: Float) {
    if (controls.isLocked) {
        direction.z = (if (moveForward) 1 else 0) - (if (moveBackward) 1 else 0)
        direction.x = (if (moveRight) 1 else 0) - (if (moveLeft) 1 else 0)
        direction.normalize()
        
        velocity.x -= velocity.x * 10f * delta
        velocity.z -= velocity.z * 10f * delta
        
        if (moveForward || moveBackward) velocity.z -= direction.z * 400f * delta
        if (moveLeft || moveRight) velocity.x -= direction.x * 400f * delta
        
        controls.moveRight(-velocity.x * delta)
        controls.moveForward(-velocity.z * delta)
    }
    
    renderer.render(scene, camera)
}

TransformControls

Gizmo for translating, rotating, and scaling objects.

Constructor

class TransformControls(
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
enabledBooleantrueEnable controls
modeString"translate"Transform mode
spaceString"world"Coordinate space
sizeFloat1Gizmo size
axisString?nullActive axis
showXBooleantrueShow X axis
showYBooleantrueShow Y axis
showZBooleantrueShow Z axis
translationSnapFloat?nullTranslation snap
rotationSnapFloat?nullRotation snap
scaleSnapFloat?nullScale snap
draggingBooleanfalseIs dragging

Modes

// Translation (move)
controls.setMode("translate")

// Rotation
controls.setMode("rotate")

// Scale
controls.setMode("scale")

Spaces

// World space
controls.setSpace("world")

// Local space (object-relative)
controls.setSpace("local")

Methods

// Attach to object
fun attach(object3d: Object3D): TransformControls

// Detach from object
fun detach(): TransformControls

// Set mode
fun setMode(mode: String)

// Set space
fun setSpace(space: String)

// Set size
fun setSize(size: Float)

// Get raycaster
fun getRaycaster(): Raycaster

fun dispose()

Events

controls.addEventListener("change") {
    renderer.render(scene, camera)
}

controls.addEventListener("dragging-changed") { event ->
    orbitControls.enabled = !event.value
}

controls.addEventListener("objectChange") {
    // Object was transformed
}

Example

val transformControls = TransformControls(camera, renderer.domElement)
scene.add(transformControls)

// Attach to selected object
transformControls.attach(selectedMesh)

// Keyboard shortcuts
document.addEventListener("keydown") { event ->
    when (event.key) {
        "g" -> transformControls.setMode("translate")
        "r" -> transformControls.setMode("rotate")
        "s" -> transformControls.setMode("scale")
        "x" -> transformControls.showX = !transformControls.showX
        "y" -> transformControls.showY = !transformControls.showY
        "z" -> transformControls.showZ = !transformControls.showZ
        " " -> transformControls.setSpace(
            if (transformControls.space == "local") "world" else "local"
        )
    }
}

// Disable orbit controls while transforming
transformControls.addEventListener("dragging-changed") { event ->
    orbitControls.enabled = !event.value
}

DragControls

Drag objects in the scene.

Constructor

class DragControls(
    objects: List<Object3D>,
    camera: Camera,
    domElement: HTMLElement
)

Properties

PropertyTypeDefaultDescription
enabledBooleantrueEnable controls
transformGroupBooleanfalseTransform group

Events

controls.addEventListener("dragstart") { event ->
    event.`object`.material.emissive.set(0xaaaaaa)
}

controls.addEventListener("drag") { event ->
    // Object being dragged
}

controls.addEventListener("dragend") { event ->
    event.`object`.material.emissive.set(0x000000)
}

controls.addEventListener("hoveron") { event ->
    // Hovering over object
}

controls.addEventListener("hoveroff") { event ->
    // No longer hovering
}

Example

val draggableObjects = listOf(cube1, cube2, cube3)
val dragControls = DragControls(draggableObjects, camera, renderer.domElement)

// Disable orbit while dragging
dragControls.addEventListener("dragstart") {
    orbitControls.enabled = false
}

dragControls.addEventListener("dragend") {
    orbitControls.enabled = true
}

ArcballControls

Arcball-style rotation controls.

Constructor

class ArcballControls(
    camera: Camera,
    domElement: HTMLElement,
    scene: Scene? = null
)

Properties

Similar to OrbitControls with additional:

PropertyTypeDescription
cursorZoomBooleanZoom at cursor position
scaleFactorFloatZoom scale factor
focusAnimationTimeFloatFocus animation duration

See Also

Architected in Kotlin. Rendered with Materia. Powered by Aether.
© 2026 Yousef.