@threlte/xr
<Controller>
<Controller />
represents a THREE.XRTargetRaySpace
, a THREE.XRGripSpace
, and a controller model for a specified hand.
<Controller left />
<Controller right />
It will by default load a controller model that attempts to match the physical controller.
Default controller models are fetched from the immersive web group’s webxr input profile repo. If you are developing an offline app, you should download and provide any anticipated models.
<Controller>
can accept three slots.
If a default slot is provided, the default controller model will not be rendered, and will be replaced with the slot content.
<Controller left>
<T.Mesh>
<T.IcosahedronGeometry args={[0.2]} />
<T.MeshStandardMaterial color='turquoise' />
</T.Mesh>
</Controller>
Two additional slots exist to place children in the controller’s grip space and the controller’s target ray space.
<Controller left>
<T.Mesh slot='grip'>
<T.IcosahedronGeometry args={[0.2]} />
<T.MeshStandardMaterial color='hotpink' />
</T.Mesh>
<T.Mesh slot='target-ray'>
<T.IcosahedronGeometry args={[0.2]} />
<T.MeshStandardMaterial color='orange' />
</T.Mesh>
</Controller>
<script lang='ts'>
import { Canvas } from '@threlte/core'
import { VRButton } from '@threlte/xr'
import Scene from './Scene.svelte'
</script>
<Canvas>
<Scene />
</Canvas>
<VRButton />
<script lang='ts'>
import { T, useFrame, useThrelte } from '@threlte/core'
import { XR, Hand, Controller } from '@threlte/xr'
const { renderer } = useThrelte()
renderer.setClearColor('#000')
const hands = ['left', 'right'] as const
let colors = { left: 'white', right: 'white' }
const setState = (hand: 'left' | 'right', state: string) => {
colors[hand] = {
connected: 'green',
disconnected: 'crimson',
selectstart: 'darkorchid',
selectend: 'darkmagenta',
squeezestart: 'lightcoral',
squeezeend: 'indianred',
pinchstart: 'lightcyan',
pinchend: 'lightblue',
}[state]!
}
</script>
<XR>
{#each hands as hand (hand)}
<Controller
left={hand === 'left'}
right={hand === 'right'}
on:connected={() => setState(hand, 'connected')}
on:disconnected={() => setState(hand, 'disconnected')}
on:selectstart={() => setState(hand, 'selectstart')}
on:selectend={() => setState(hand, 'selectend')}
on:squeezestart={() => setState(hand, 'squeezestart')}
on:squeezeend={() => setState(hand, 'squeezeend')}
/>
<Hand
left={hand === 'left'}
right={hand === 'right'}
on:connected={() => setState(hand, 'connected')}
on:disconnected={() => setState(hand, 'disconnected')}
on:pinchstart={() => setState(hand, 'pinchstart')}
on:pinchend={() => setState(hand, 'pinchend')}
/>
{/each}
</XR>
<T.Mesh position.y={1.5} position.x={-0.5}>
<T.IcosahedronGeometry args={[0.3]} />
<T.MeshStandardMaterial color={colors.left} />
</T.Mesh>
<T.Mesh position.y={1.5} position.x={0.5}>
<T.IcosahedronGeometry args={[0.3]} />
<T.MeshStandardMaterial color={colors.right} />
</T.Mesh>
<T.AmbientLight />
<T.DirectionalLight />