@threlte/core
useLoader
A hook to load data with an arbitrary THREE
loader class. The result of load
is cached and subsequent calls with the same arguments will yield the same
return value (i.e. the same reference) across the entire Threlte app. The hook
can use async loaders (using loader.loadAsync
) as well as sync/callback-based
loaders (using loader.load
) and will default to the async version if
available.
const loader = useLoader(AudioLoader)
const soundA = loader.load('audio/ambient_ocean.ogg')
// -> `soundA` is an AsyncWritable<AudioBuffer> that
// resolves/is populated once the asset is loaded.
// somewhere else …
const soundB = loader.load('audio/ambient_ocean.ogg')
// -> `soundB` is also an AsyncWritable<AudioBuffer>
// that resolves/is populated with the same reference
// as `soundA` once the asset is loaded.
Instantiating A Loader
A loader must always be instantiated at the top level of a component. This is because the loader is depending on an application-wide cache:
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const loader = useLoader(TextureLoader)
</script>
A loader can be extended, to add custom features:
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const loader = useLoader(CustomTextureLoader, {
extend: (loader) => {
// do something with the loader, e.g. add DRACO support for
// GLTFLoader or add custom headers for TextureLoader.
}
})
</script>
If the constructor of a particular loader accepts arguments, they must be passed
as an array to the option args
of the second argument to useLoader
:
<script>
import { useLoader, useThrelte } from '@threlte/core'
import { SplatLoader } from '@pmndrs/vanilla'
const { renderer } = useThrelte()
const loader = useLoader(SplatLoader, {
args: [renderer]
})
// This resembles the following:
// const loader = new SplatLoader(renderer)
</script>
Loading An Asset
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const texture = useLoader(TextureLoader).load('path/to/texture.png')
// A loader must always be instantiated at the top level of a component.
const { load } = useLoader(TextureLoader)
const onSomeEvent = () => {
// To load an asset outside of the top level, use the `load` method.
const texture = load('path/to/texture.png')
}
</script>
The return type of load
is a custom Threlte store called
AsyncWritable
and can be used
as a regular Svelte store. Its initial value is undefined
and will be updated
once the asset is loaded.
The store also exposes the underlying promise methods then
and catch
and can therefore be directly awaited:
<script>
import { useLoader, T } from '@threlte/core'
import { TextureLoader } from 'three'
const { load } = useLoader(TextureLoader)
const onSomeEvent = async () => {
// Load an asset and await the result.
const texture = await load('path/to/texture.png')
}
</script>
<!-- Or make use of Svelte's await block -->
{#await load('path/to/texture.png') then map}
<T.MeshStandardMaterial {map} />
{/await}
Loading Multiple Assets
The function load
of useLoader
also accepts an array of paths in which case the return value is an array of loaded assets:
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const { load } = useLoader(TextureLoader)
const textures = load(['texture1.png', 'texture2.png'])
$: console.log($textures) // [Texture, Texture]
</script>
Keep in mind that the store will be updated and the promise resolves once all assets are loaded.
You can also provide a map of paths to load multiple assets at once. In this case the return value is a map of the loaded assets:
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const { load } = useLoader(TextureLoader)
const textures = load({
texture1: 'texture1.png',
texture2: 'texture2.png'
})
$: console.log($textures) // { texture1: Texture, texture2: Texture }
</script>
Transforming The Result
Caching
The result of the transformation is cached and subsequent calls will return the same result.
The load
method accepts an optional second argument to transform the result of the loader:
<script>
import { useLoader } from '@threlte/core'
import { TextureLoader } from 'three'
const { load } = useLoader(TextureLoader)
const texture = load('path/to/texture.png', {
transform: (texture) => {
// do something with the texture
return texture
}
})
</script>
The return type of the transformation is used to infer the return type of the load
method.