threlte logo
@threlte/extras

useProgress

Convenience hook that wraps THREE.DefaultLoadingManager.

<script lang="ts">
	import { Canvas } from '@threlte/core'
	import { useProgress } from '@threlte/extras'
	import { tweened } from 'svelte/motion'
	import { fade } from 'svelte/transition'
	import Scene from './Scene.svelte'

	const { progress } = useProgress()

	const tweenedProgress = tweened($progress, {
		duration: 800
	})
	$: tweenedProgress.set($progress)
</script>

{#if $tweenedProgress < 1}
	<div
		transition:fade|local={{
			duration: 200
		}}
		class="wrapper"
	>
		<p class="loading">Loading</p>
		<div class="bar-wrapper">
			<div class="bar" style="width: {$tweenedProgress * 100}%" />
		</div>
	</div>
{/if}

<Canvas>
	<Scene />
</Canvas>

<style>
	.wrapper {
		position: absolute;
		width: 100%;
		height: 100%;
		top: 0;
		left: 0;
		background-color: white;
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
		align-items: center;
		justify-content: center;
		color: black;
	}

	.loading {
		font-size: 0.875rem;
		line-height: 1.25rem;
	}

	.bar-wrapper {
		width: 33.333333%;
		height: 10px;
		border: 1px solid black;
		position: relative;
	}

	.bar {
		height: 100%;
		background-color: black;
	}
</style>
<script lang="ts">
  import { T, useFrame } from '@threlte/core'
  import { Environment, useGltf } from '@threlte/extras'
  import { derived } from 'svelte/store'

  let rotation = 0
  useFrame(() => {
    rotation += 0.01
  })

  const gltf = useGltf<'node_damagedHelmet_-6514', 'Material_MR'>(
    '/models/helmet/DamagedHelmet.gltf?v=' + Math.random().toString() // force a reload on every pageload
  )

  const helmet = derived(gltf, (gltf) => {
    if (!gltf || !gltf.nodes['node_damagedHelmet_-6514']) return
    return gltf.nodes['node_damagedHelmet_-6514']
  })
</script>

<Environment
  path="/hdr/"
  files="shanghai_riverside_1k.hdr"
/>

<T.PerspectiveCamera
  makeDefault
  position.z={10}
  fov={20}
/>

<T.DirectionalLight
  position.y={10}
  position.z={10}
/>

<T.Group rotation.y={rotation}>
  {#if $helmet}
    <T is={$helmet} />
  {/if}
</T.Group>

Model: Battle Damaged Sci-fi Helmet by theblueturtle_

Examples

Basic Example

You can use and place this hook anywhere. Typically you would use this hook outside of your <Canvas> component to show a loading indicator in your DOM.

<script lang="ts">
  // `useProgress` returns readable stores
  const {
    active, // Readable<boolean> – if the DefaultLoadingManager is active
    item, // Readable<string | undefined> – the currently loading item
    loaded, // Readable<number> - amount of items loaded
    total, // Readable<number> - total amount of items to load
    errors, // Readable<string[]> - all error messages
    progress, // Readable<number> - normalized (0-1) loading progress
    finishedOnce // Readable<boolean> – whether a progress of 1 has been achieved ever.
  } = useProgress()
</script>