threlte logo
Basics

Loading Assets

There are a number of different asset types you might like to use in your Threlte application. Three.js has a ton of different loaders that Threlte integrates well with. You’re recommended to use the useLoader hook which will cache any asset it loads and wrap the asset in an asyncWritable for convenience. Caching assets will reduce network requests, bandwidth, and memory usage, which will improve the performance of your application.

This section assumes you placed your assets in your public folder or in a place in your application where you can import them easily.

Models

Models come in many different formats, but .gltfs are usually the best fit for the web. You can use Three.js’ GLTFLoader to load a .gltf model.

<script>
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
  import { useLoader } from '@threlte/core'

  const gltf = useLoader(GLTFLoader).load('/assets/model.gltf')
</script>

{#if $gltf}
  <T is={$gltf.scene} />
{/if}

The <GLTF/> component is roughly equivalent to the example above.

useGltf hook

@threlte/extras provides a handy hook for loading .gltf models called useGltf:

<script>
  import { useGltf } from '@threlte/extras'
</script>

{#await useGltf('/assets/model.gltf') then gltf}
  <T is={gltf.scene} />
{/await}

Adjusting and resusing models

You may run into the following challenges when working with models in Threlte:

  • Your model may have multiple parts that you’d like to adjust individually but there’s no easy way to declaritively achieve that with only one <T/> component.
  • You can’t seem to place multiple copies in your scene.

To address both of these issues, you can use Threlte’s CLI tool @threlte/gltf to generate a Svelte component for your model. The generated component has <T/> components for all of your models parts. Adjust the component to your liking, then import and reuse it as much as you’d like.

Animations

Three.js uses AnimationMixer to drive animations. Threlte provides a convenient useGltfAnimations hook for gltfs. See the animation Three.js example for how to setup a model for your animation needs.

The Threlte docs also have an animation example to help you get started.

Common mistakes

Sometimes you’ll load a model and still just see a blank screen. Here are a few common mistakes that can cause this.

  1. Make sure your scene has lights.
  2. Make sure the model is not too small or not too big for your camera to see it.
  3. Make sure your camera is looking at the model
  4. Does the model render in a viewer like gltf-viewer?

Textures

The TextureLoader is another loader from Three.js that is used for textures.

<script>
  import { TextureLoader } from 'three'
  import { useLoader } from '@threlte/core'

  const texture = useLoader(TextureLoader).load('/assets/texture.png')
</script>

{#if $texture}
  <T.MeshStandardMaterial map={$texture} />
{/if}

useTexture hook

@threlte/extras provides a handy hook for loading textures called useTexture:

<script>
  import { useTexture } from '@threlte/extras'
</script>

{#await useTexture('/assets/texture.png') then texture}
  <T.MeshStandardMaterial map={texture} />
{/await}

Multiple textures

Sometimes you’ll want your materials to be composed of multiple textures. useLoader provides a way to load multiple textures at once and spread the loaded textures on a material.

Loading two textures for the map and normalMap channels can be done like this:

const textures = useLoader(TextureLoader).load({
  map: '/assets/texture.png',
  normalMap: '/assets/normal.png'
})

or with the useTexture hook:

const textures = useTexture({
  map: '/assets/texture.png',
  normalMap: '/assets/normal.png'
})

Then spread on a material:

{#if $textures}
  <T.MeshStandardMaterial {...$textures} />
{/if}

If multiple textures are given, the promise only resolves once all textures have loaded.

Applying multiple textures to different mesh faces

To declaratively apply different textures to multiple faces of a BoxGeometry, set the attach prop to a function.

<T.Mesh>
  <T.BoxGeometry />
  <T.MeshStandardMaterial
    map={texture1}
    attach={({ parent, ref }) => {
      if (Array.isArray(parent.material)) {
        parent.material = [...parent.material, ref]
      } else {
        parent.material = [ref]
      }
    }}
  />
  <T.MeshStandardMaterial
    map={texture2}
    attach={({ parent, ref }) => {
      if (Array.isArray(parent.material)) {
        parent.material = [...parent.material, ref]
      } else {
        parent.material = [ref]
      }
    }}
  />
</T.Mesh>

Other asset types

Threlte provides many components to help get started with many other asset types (like audio), but it doesn’t have components and hooks for all of them. Checkout Three.js examples to see what models, techniques and effects you can achieve, then use those examples as a guide for your own custom components.

Async loading

The return value from useLoader is an AsyncWritable custom store. Its value will be undefined until the asset has loaded.

Since the underlying store’s value is a promise, you can use it within a Svelte #await block:

{#await $texture then value}
  <T.MeshStandardMaterial map={value} />
{/await}

Assets can also be loaded after initialization by calling the loader.load method:

<script>
  import { AudioLoader } from 'three'
  import { useLoader } from '@threlte/core'

  // Instantiate the loader at component initialization
  const loader = useLoader(AudioLoader)

  const onSomeEvent = async () => {
    // Load the asset when needed
    const audioBuffer = await loader.load('/assets/sound.mp3')
  }
</script>

The Suspense component can additionally help orchestrate loading multiple assets before displaying your scene.

Context Awareness

The useLoader hook, and other hooks like useTexture, use Svelte contexts. The assets loaded with them are only available for child components of your <Canvas> component.