threlte logo
@threlte/extras

<TransformControls>

This component can be used to transform objects in 3D space by adapting a similar interaction model of DCC tools like Blender. Unlike other controls, it is not intended to transform the scene’s camera.

The component <TransformControls> needs to be the parent of the component to be transformed.

<script lang="ts">
  import { Canvas } from '@threlte/core'

  import Scene from './Scene.svelte'
  import Settings from './Settings.svelte'

  let controls = $state<'<OrbitControls>' | '<TrackballControls>' | '<CameraControls>'>(
    '<OrbitControls>'
  )
  let autoPauseControls = $state(true)
</script>

<div>
  <Canvas>
    <Scene
      {controls}
      {autoPauseControls}
    />
  </Canvas>
</div>

<Settings
  bind:controls
  bind:autoPauseControls
/>

<style>
  div {
    position: relative;
    height: 100%;
    width: 100%;
    background-color: rgb(14, 22, 37);
  }
</style>
<script lang="ts">
  import { T } from '@threlte/core'
  import {
    CameraControls,
    OrbitControls,
    TrackballControls,
    TransformControls
  } from '@threlte/extras'
  import { PerspectiveCamera } from 'three'

  interface Props {
    controls?: '<OrbitControls>' | '<TrackballControls>' | '<CameraControls>'
    autoPauseControls?: boolean
  }

  let { controls = '<OrbitControls>', autoPauseControls = true }: Props = $props()

  let camera = $state.raw<PerspectiveCamera>()
</script>

{#key controls}
  <T.PerspectiveCamera
    makeDefault
    position={[10, 5, 10]}
    bind:ref={camera}
  >
    {#if controls === '<TrackballControls>'}
      <TrackballControls />
    {:else if controls === '<OrbitControls>'}
      <OrbitControls />
    {:else if controls === '<CameraControls>'}
      <CameraControls />
    {/if}
  </T.PerspectiveCamera>
{/key}

<T.DirectionalLight
  position.y={10}
  position.z={10}
/>
<T.AmbientLight intensity={0.3} />

<T.GridHelper args={[10, 10]} />

<TransformControls
  {autoPauseControls}
  translationSnap={1}
  position.y={1}
>
  <T.Mesh>
    <T.BoxGeometry args={[2, 2, 2]} />
    <T.MeshStandardMaterial />
  </T.Mesh>
</TransformControls>
<script lang="ts">
  import { Pane, List, Checkbox, ThemeUtils } from 'svelte-tweakpane-ui'

  interface Props {
    controls?: '<OrbitControls>' | '<TrackballControls>' | '<CameraControls>'
    autoPauseControls?: boolean
  }

  let { controls = $bindable('<OrbitControls>'), autoPauseControls = $bindable(true) }: Props =
    $props()
</script>

<Pane
  theme={ThemeUtils.presets.light}
  position="fixed"
  title="TransformControls"
>
  <List
    label="Camera Controls"
    bind:value={controls}
    options={{
      '<OrbitControls>': '<OrbitControls>',
      '<TrackballControls>': '<TrackballControls>',
      '<CameraControls>': '<CameraControls>'
    }}
  />
  <Checkbox
    label="autoPauseControls"
    bind:value={autoPauseControls}
  />
</Pane>

Camera Controls

When using camera controls alongside <TransformControls>, dragging a transform gizmo would also move the camera. To prevent this, <TransformControls> automatically pauses any registered camera controls while dragging.

The following controls are handled automatically (no extra setup needed):

  • <OrbitControls>
  • <TrackballControls>
  • <CameraControls>

You can disable this with autoPauseControls={false}.

Third-party controls

For custom or third-party controls, pass them via the cameraControls prop. Any object with an enabled property works:

<script>
  import { TransformControls } from '@threlte/extras'
  import { MyCustomControls } from './MyCustomControls'

  let customControls = $state()
</script>

<MyCustomControls bind:ref={customControls} />

<TransformControls cameraControls={customControls}>
  <T.Mesh>
    <T.BoxGeometry />
    <T.MeshStandardMaterial />
  </T.Mesh>
</TransformControls>

Examples

Basic usage

Scene.svelte
<script>
  import { T } from '@threlte/core'
  import { TransformControls } from '@threlte/extras'
  import { MeshStandardMaterial, BoxGeometry } from 'three'
</script>

<TransformControls>
  <T.Mesh
    geometry={new BoxGeometry()}
    material={new MeshStandardMaterial()}
  />
</TransformControls>

Transforming an external object

The <TransformControls> component can also transform an object passed to it:

Scene.svelte
<script>
  import { T } from '@threlte/core'
  import { TransformControls } from '@threlte/extras'
  import { MeshStandardMaterial, BoxGeometry } from 'three'
</script>

<T.Mesh
  geometry={new BoxGeometry()}
  material={new MeshStandardMaterial()}
>
  {#snippet children({ ref })}
    <TransformControls object={ref} />
  {/snippet}
</T.Mesh>

<TransformControls object={someObject} />

Component Signature

The component <TransformControls> extends both <T.TransformControls> and <T.Group>. You may pass any property of either of these components to the component <TransformControls>.

Props

name
type
required
default

autoPauseControls
boolean
no
true

cameraControls
{ enabled: boolean }
no

object
THREE.Object3D
no

Bindings

name
type

controls
THREE.TransformControls

group
THREE.Group