threlte logo
@threlte/extras

<Gizmo>

A gizmo for snap-to camera controls.

Uses the Three Viewport Gizmo library.

<script lang="ts">
  import { Canvas, T, currentWritable, type CurrentWritable } from '@threlte/core'
  import { Gizmo, type GizmoOptions, 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 type = $state('sphere')
  let speed = $state(1)
  let placement: GizmoOptions['placement'] = $state('bottom-left')
  let size = $state(86)
  let left = $state(10)
  let top = $state(10)
  let right = $state(10)
  let bottom = $state(10)
  let center: [number, number, number] = $state([0, 0, 0])
</script>

<Pane
  theme={ThemeUtils.presets.light}
  position="fixed"
  title="Gizmo"
>
  <List
    label="type"
    bind:value={type}
    options={{
      sphere: 'sphere',
      cube: 'cube'
    }}
  />
  <Slider
    label="speed"
    bind:value={speed}
    min={0.1}
    max={1}
  />
  <List
    label="placement"
    bind:value={placement}
    options={[
      'top-left',
      'top-center',
      'top-right',
      'center-left',
      'center-center',
      'center-right',
      'bottom-left',
      'bottom-center',
      'bottom-right'
    ]}
  />
  <Slider
    label="size"
    bind:value={size}
    min={20}
    max={350}
    step={1}
  />

  <Folder
    title="offset"
    expanded={false}
  >
    <Slider
      label="top"
      bind:value={top}
      min={0}
      max={50}
      step={1}
    />
    <Slider
      label="left"
      bind:value={left}
      min={0}
      max={50}
      step={1}
    />
    <Slider
      label="right"
      bind:value={right}
      min={0}
      max={50}
      step={1}
    />
    <Slider
      label="bottom"
      bind:value={bottom}
      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
        onchange={(event) => {
          center = event.target.target.toArray()
        }}
      >
        <Gizmo
          {type}
          {speed}
          {placement}
          {size}
          offset={{
            top,
            left,
            bottom,
            right
          }}
        />
      </OrbitControls>
    </T.PerspectiveCamera>

    <Scene {center} />
  </Canvas>
</div>
<script lang="ts">
  import { T } from '@threlte/core'
  import { Grid } from '@threlte/extras'

  type Props = {
    center: [number, number, number]
  }

  let { center }: Props = $props()

  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, ref }) => {
        parent.setAttribute('color', ref)
      }}
    />
  </T.BoxGeometry>
  <T.MeshBasicMaterial vertexColors />
</T.Mesh>

Three’s OrbitControls or yomotsu’s CameraControls can be provided as a controls prop.

Alternatively, the <Gizmo> can be placed as a child of a controls component.

<OrbitControls>
  <!-- Will attach itself to this OrbitControls -->
  <Gizmo />
</OrbitControls>

In addition to the props listed below, <Gizmo> can accept any of the options from the underlying Three Viewport Gizmo instance as a prop.

These props cause the gizmo to rebuild itself, so update them sparingly.

Component Signature

Props

name
type
required
description

controls
OrbitControls | CameraControls
no

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

Events

name
payload
description

start
Event<'start', ViewportGizmo>
Triggered when a view change interaction begins.

change
Event<'change', ViewportGizmo>
Triggered during view changes.

end
Event<'end', ViewportGizmo>
Triggered when a view change interaction ends.