threlte logo
@threlte/extras

<Gizmo>

A gizmo for snap-to camera controls. The gizmo is rendered on top of the scene using an orthographic camera and controls the camera when clicked.

<script lang="ts">
  import { Canvas, T, currentWritable, type CurrentWritable } from '@threlte/core'
  import { Gizmo, OrbitControls } from '@threlte/extras'
  import {
    Checkbox,
    Color,
    Folder,
    List,
    Pane,
    Ring,
    Slider,
    ThemeUtils
  } from 'svelte-tweakpane-ui'
  import { OrbitControls as ThreeOrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
  import Scene from './Scene.svelte'

  let turnRate = 2 * Math.PI
  let verticalPlacement: 'top' | 'bottom' = 'bottom'
  let horizontalPlacement: 'left' | 'right' = 'left'
  let xColor = '#ff3653'
  let yColor = '#8adb00'
  let zColor = '#2c8fff'
  let toneMapped = false
  let size = 128
  let paddingX = 20
  let paddingY = 20

  let orbitControls: ThreeOrbitControls
  let center: CurrentWritable<[number, number, number]> = currentWritable([0, 0, 0])
</script>

<Pane
  theme={ThemeUtils.presets.light}
  position="fixed"
  title="Gizmo"
>
  <Folder title="Mechanics">
    <Ring
      label="turnRate"
      bind:value={turnRate}
      min={0.1}
      max={20}
      wide
    />
  </Folder>

  <Folder title="Colors">
    <Color
      bind:value={xColor}
      label="xColor"
    />
    <Color
      bind:value={yColor}
      label="yColor"
    />
    <Color
      bind:value={zColor}
      label="zColor"
    />
    <Checkbox
      bind:value={toneMapped}
      label="toneMapped"
    />
  </Folder>

  <Folder title="Placement">
    <List
      label="verticalPlacement"
      bind:value={verticalPlacement}
      options={{
        top: 'top',
        bottom: 'bottom'
      }}
    />
    <List
      label="horizontalPlacement"
      bind:value={horizontalPlacement}
      options={{
        left: 'left',
        right: 'right'
      }}
    />
    <Slider
      label="size"
      bind:value={size}
      min={20}
      max={350}
      step={1}
    />
    <Slider
      label="paddingX"
      bind:value={paddingX}
      min={0}
      max={50}
      step={1}
    />
    <Slider
      label="paddingY"
      bind:value={paddingY}
      min={0}
      max={50}
      step={1}
    />
  </Folder>
</Pane>

<div style="position:relative; height:100%; width:100%; background-color: rgb(14,22,37)">
  <Canvas>
    <T.PerspectiveCamera
      makeDefault
      position={[20, 20, 20]}
      fov={36}
      target={[0, 0, 0]}
    >
      <OrbitControls
        bind:ref={orbitControls}
        on:change={() => {
          center.set([orbitControls.target.x, orbitControls.target.y, orbitControls.target.z])
        }}
      />
    </T.PerspectiveCamera>

    <Scene center={$center} />

    <Gizmo
      center={$center}
      {turnRate}
      {verticalPlacement}
      {horizontalPlacement}
      {xColor}
      {yColor}
      {zColor}
      {toneMapped}
      {size}
      {paddingX}
      {paddingY}
    />
  </Canvas>
</div>
<script lang="ts">
  import { T } from '@threlte/core'
  import { Grid } from '@threlte/extras'

  export let center: [number, number, number]

  const red = [1, 0, 0]
  const green = [0, 1, 0]
  const blue = [0, 0, 1]

  const colors = new Float32Array([
    ...red,
    ...red,
    ...red,
    ...red,
    ...red,
    ...red,
    ...red,
    ...red,
    ...green,
    ...green,
    ...green,
    ...green,
    ...green,
    ...green,
    ...green,
    ...green,
    ...blue,
    ...blue,
    ...blue,
    ...blue,
    ...blue,
    ...blue,
    ...blue,
    ...blue
  ])
</script>

<T.AxesHelper
  args={[5]}
  renderOrder={1}
/>

<Grid
  sectionSize={0}
  cellColor="#eee"
/>

<T.Mesh position={center}>
  <T.BoxGeometry>
    <T.BufferAttribute
      args={[colors, 3]}
      attach={(parent, self) => {
        parent.setAttribute('color', self)
      }}
    />
  </T.BoxGeometry>
  <T.MeshBasicMaterial vertexColors />
</T.Mesh>

Component Signature

Props

name
type
required
default
description

animationTask
TaskOptions
no
Options for the task to animate the gizmo when the user clicks one of the handles. By default, this task is added to the `mainStage`.

center
[number, number, number]
no
[0, 0, 0]
The center or target of the control (such as an orbit controller), if it exists.

horizontalPlacement
'left' | 'right'
no
'right'

paddingX
number
no
0
The padding to the edge defined by `horizontalPlacement`.

paddingY
number
no
0
The padding to the edge defined by `verticalPlacement`.

renderTask
TaskOptions
no
Options for the task to render the gizmo scene in the viewport. By default, this happens after the `autoRenderTask`.

size
number
no
128

toneMapped
boolean
no
false
Whether the gizmo should be rendered with tone mapping applied. If set to `true`, the tone mapping declared on `<Canvas>` is used.

turnRate
number
no
2 * Math.PI
Turn animation rate in angles per second

verticalPlacement
'top' | 'bottom'
no
'bottom'

xColor
number
no
0xff3653

yColor
number
no
0x8adb00

zColor
number
no
0x2c8fff