@threlte/extras
<HTML>
This component is a port of dreiβs <Html>
component. It allows you to tie HTML content to any object of your scene. It will be projected to the objects whereabouts automatically.
The container of your <Canvas>
component needs to be set to position: relative | absolute | sticky | fixed
. This is because the DOM element will be mounted as a sibling to the <canvas>
element.
<script lang="ts">
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
</script>
<Canvas>
<Scene />
</Canvas>
<script lang="ts">
import { T } from '@threlte/core'
import { HTML, OrbitControls } from '@threlte/extras'
import { spring } from 'svelte/motion'
import { Color, MeshStandardMaterial } from 'three'
import { DEG2RAD } from 'three/src/math/MathUtils'
const getRandomColor = () => `#${Math.floor(Math.random() * 16777215).toString(16)}`
let material = new MeshStandardMaterial({
color: new Color(getRandomColor())
})
const onClick = () => {
material.color.set(getRandomColor())
material = material
}
let isHovering = false
let isPointerDown = false
let htmlPosZ = spring(0)
$: htmlPosZ.set(isPointerDown ? -0.15 : isHovering ? -0.075 : 0, {
hard: isPointerDown
})
</script>
<T.PerspectiveCamera
position={[10, 5, 10]}
makeDefault
fov={30}
>
<OrbitControls
target.y={0.75}
maxPolarAngle={85 * DEG2RAD}
minPolarAngle={20 * DEG2RAD}
maxAzimuthAngle={45 * DEG2RAD}
minAzimuthAngle={-45 * DEG2RAD}
enableZoom={false}
/>
</T.PerspectiveCamera>
<T.DirectionalLight position={[0, 10, 10]} />
<T.AmbientLight intensity={0.3} />
<T.GridHelper />
<T.Mesh
position.y={0.5}
{material}
>
<T.SphereGeometry args={[0.5]} />
<HTML
position.y={1.25}
position.z={$htmlPosZ}
transform
>
<button
on:pointerenter={() => (isHovering = true)}
on:pointerleave={() => {
isPointerDown = false
isHovering = false
}}
on:pointerdown={() => (isPointerDown = true)}
on:pointerup={() => (isPointerDown = false)}
on:pointercancel={() => {
isPointerDown = false
isHovering = false
}}
on:click={onClick}
class="bg-orange-500 rounded-full px-3 text-white hover:opacity-90 active:opacity-70"
>
I'm a regular HTML button
</button>
</HTML>
<HTML
position.x={0.75}
transform
pointerEvents="none"
>
<p
class="text-xs w-auto translate-x-1/2 drop-shadow-lg"
style="color: #{material.color.getHexString()}"
>
color: #{material.color.getHexString()}
</p>
</HTML>
</T.Mesh>
Examples
Basic Example
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML>
<h1>Hello World</h1>
</HTML>
Transform
transform
applies matrix3d transformations.
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML transform>
<h1>Hello World</h1>
</HTML>
Occlude
<Html>
can be occluded behind geometry using the occlude occlude
property.
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML
transform
occlude
>
<h1>Hello World</h1>
</HTML>
Visibility Change Event
Use the property occlude
and bind to the event visibilitychange
to implement a custom hide/show behaviour.
<script lang="ts">
import { HTML } from '@threlte/extras'
const onVisibilityChange = (isVisible: boolean) => {
console.log(isVisible)
}
</script>
<HTML
transform
occlude
on:visibilitychange={onVisibilityChange}
>
<h1>Hello World</h1>
</HTML>
When binding to the event visibilitychange
the contents of <HTML>
is not automatically hidden when itβs occluded.
Sprite Rendering
Use the property sprite
in transform
mode to render the contents of <HTML>
as a sprite.
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML
transform
sprite
>
<h1>Hello World</h1>
</HTML>
Center
Add a -50%/-50% css transform with center
when not in transform
mode.
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML center>
<h1>Hello World</h1>
</HTML>
Portal
Use the property portal
to mount the contents of the <HTML>
component on another HTMLElement
.
By default the contents are mounted as a sibling to the rendering <canvas>
.
<script lang="ts">
import { HTML } from '@threlte/extras'
</script>
<HTML portal={document.body}>
<h1>Hello World</h1>
</HTML>