@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>