threlte logo
Advanced

Migration Guide

Threlte 6 provides a much more mature and feature-rich APi and developer experience than its predecessor at the cost of a lot of breaking changes. This guide will help you migrate your Threlte 5 project to Threlte v6.

This document is a work in progress and will be updated up until the point of the first release of Threlte 6. There are probably more breaking changes than listed here. Your Editor will help you migrating with autocompletions and type checking.

Preprocessing

Preprocessing is not needed anymore starting from Threlte 6. This means you may remove the preprocessor @threlte/preprocess from your project as well as its configuration in svelte.config.js. You can now use the component <T> directly.

<Three> is now <T>

Threlte 6 merges the <Three> and <T> components into a single component. The property type was renamed to is to also properly reflect the fact that it can be used with already instantiated objects.

@threlte/core is only about the <T> component

The @threlte/core package is now only about the <T> component. It does not provide any abstractions that have been part of the core package before. Some of these abstractions (<TransformControls>, <OrbitControls>, audio components and several hooks) have been moved to @threlte/extras as this is the new home for commonly used abstractions.

Prop types

Threlte 6 heavily relies on prop types that Three.js naturally understands. As such, the prop types you may have previously used to define for example the position of an object changed. Threlte v5 provided its own prop types Position (e.g. { x, y, z }), Rotation and others which are now removed or deprecated. While not yet all abstractions fully make use of the new prop types, we’re working on it. Your editor should be able to provide you with the correct prop types for the components you’re using.

Interactivity

Interactivity is now handled by a plugin that’s available at @threlte/extras. It’s much more mature and flexible in terms of event handling. For instance – as some of you requested – you may now define on what object the main event listener is placed. Check out its documentation to learn more.

useLoader now returns a store

The hook useLoader now returns a custom Svelte store called AsyncWritable. This store allows you to await the loading of the resource while also implementing a regular Svelte store. It also now caches the results of the loader function so that it’s not called multiple times for the same resource. You will most likely benefit from quite a performance boost in applications that rely heavily on external resources.

useThrelteRoot has been removed

The hook useThrelteRoot has been removed and its properties have partially been merged into useThrelte as well as a new internal context which is not exposed. All other contexts (which were used internally) have also been merged or removed.

<Pass> and the default effects rendering are removed

In the effort of clear separation of concerns, the component <Pass> as well as the rendering with Three.js default EffectComposer have been removed. Threlte 6 now provides a hook called useRender which allows you to easily set up sophisticated rendering pipelines. As soon as a useRender hook is implemented, Threlte’s default render pipeline is disabled. useRender callbacks will be invoked after all callback to useFrame have been invoked. This means that you can use useFrame to update your objects and useRender to render it. useRender also has the option of ordering callbacks to orchestrate the rendering pipeline across multiple components.

Threlte’s main context types

Thelte’s main context contains Svelte stores. These stores are now a custom Threlte store called CurrentWritable which is a store that contains a current value with a reference to the current value of the store. This means it does not need to be unwrapped manually (and expensively!) in non-reactive places such as loops. For instance, let’s have a look at its usage in the hook useFrame where the context is available as the first argument to the callback:

useFrame(({ camera, colorSpace }) => {
  // instead of get(camera) we now can …
  camera.current // THREE.Camera
  colorSpace.current // THREE.ColorSpace
})

The full type definition is currently listed here.

useGltfAnimations Signature

The signature of the hook useGltfAnimations has changed. It no longer provides a callback that is invoked when the gltf store has been populated and the actions store has been set. This is because it with the option to set a custom root for the THREE.AnimationAction, the callback could be triggered multiple times, leading to an unpredictable behavior. You should reside to using the actions store returned from the hook instead.

const { actions } = useGltfAnimations(gltf)
// this animation will play when the gltf store has been populated
// and the actions store has been set, effectively replacing the
// callback.
$: $actions.Greet?.play()

Check out the hooks documentation for more information.

@threlte/rapier

Transform props

In an effort to clearly separate concerns, the components <Collider>, <AutoColliders> and <RigidBody> no longer offer transform props (position, rotation, scale and lookAt). Instead, you should wrap these components in for instance <T.Group> components and apply transforms on these.

Before.svelte
<Collider
  position={[0, 1, 0]}
  rotation={[0, 45 * DEG2RAD, 0]}
>
  <T.Mesh>
    <T.BoxBufferGeometry />
    <T.MeshStandardMaterial />
  </T.Mesh>
</Collider>
After.svelte
<T.Group
  position={[0, 1, 0]}
  rotation={[0, 45 * DEG2RAD, 0]}
>
  <Collider>
    <T.Mesh>
      <T.BoxBufferGeometry />
      <T.MeshStandardMaterial />
    </T.Mesh>
  </Collider>
</T.Group>