@threlte/xr
<TeleportControls>
<TeleportControls />
creates teleportation controls similar to many native XR experiences.
<TeleportControls
handedness={'left' | 'right'}
maxDistance={10}
on:teleport={(event) => {}}
>
<T.Mesh teleportSurface>
<T.CylinderGeometry args={[20, 0.01]} />
<T.MeshStandardMaterial />
</T.Mesh>
</TeleportControls>
This component will set up a raycasting-based teleport behavior once the user pressed a thumbstick forward on the designated controller.
<TeleportControls />
can have an arbitrary number of children, but any child mesh with a teleportSurface
attribute will be registered as a navigation mesh that can be teleported to.
<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 * as THREE from 'three'
import { T, useThrelte } from '@threlte/core'
import { XR, TeleportControls, Controller, Hand, useTeleport } from '@threlte/xr'
import { colorOptions } from './colors'
const { camera, renderer } = useThrelte()
const teleport = useTeleport()
renderer.setClearColor(0x000000)
camera.current.position.z = 1.75
camera.current.lookAt(0, 1.75, 1)
teleport(new THREE.Vector3(0.5, 0, 0.5))
const pointOnCircle = (radius: number, theta: number) => {
const x = radius * Math.cos(theta)
const y = radius * Math.sin(theta)
return { x, y }
}
const randomColor = () => {
return colorOptions[Math.trunc(Math.random() * colorOptions.length)]!
}
const cylinders = Array.from({ length: 14 }).map((_, index) => {
return {
point: pointOnCircle(5, index / 2),
color: randomColor(),
}
})
</script>
<XR>
<Controller left />
<Controller right />
<Hand left />
<Hand right />
</XR>
<TeleportControls>
<T.Mesh
teleportSurface
receiveShadow
rotation={[-Math.PI / 2, 0, 0]}
>
<T.CircleGeometry args={[20]} />
<T.MeshStandardMaterial color='#BDC3C7' />
</T.Mesh>
{#each cylinders as { point, color }, index}
<T.Mesh
name='cylinder {index}'
teleportSurface
position={[point.x, index / 2, point.y]}
castShadow
receiveShadow
>
<T.CylinderGeometry args={[1, 1, 0.1]} />
<T.MeshStandardMaterial {color} />
</T.Mesh>
{/each}
</TeleportControls>
<T.AmbientLight />
<T.DirectionalLight
position={[5, 5, 1]}
castShadow
shadow.camera.top={50}
shadow.camera.right={50}
shadow.camera.left={-50}
shadow.camera.bottom={-50}
shadow.mapSize.width={1024}
shadow.mapSize.height={1024}
/>
<T.PerspectiveCamera
makeDefault
position.y={1.8}
position.z={15}
/>
// Flat UI colors
export const colorOptions = [
'#1ABC9C',
'#2ECC71',
'#3498DB',
'#9B59B6',
'#34495E',
'#16A085',
'#27AE60',
'#2980B9',
'#8E44AD',
'#2C3E50',
'#F1C40F',
'#E67E22',
'#E74C3C',
'#ECF0F1',
'#95A5A6',
'#F39C12',
'#D35400',
'#C0392B',
'#BDC3C7',
'#7F8C8D'
]