# Threlte 8
> Threlte is an open-source 3D framework for Svelte. Build interactive 3D apps for the web with declarative, reactive components powered by Three.js.
These docs describe Threlte 8, the current stable major version. Threlte 7 docs are archived at https://v7.threlte.xyz.
# Learn
---
## Introduction
Category: Getting Started
URL: https://threlte.xyz/docs/learn/getting-started/introduction
If you're looking for the documentation for Threlte 7, head to
[v7.threlte.xyz](https://v7.threlte.xyz).
Threlte brings Three.js to Svelte in a **declarative** and **state-driven** way.
It provides strictly typed components for deep **reactivity** and **interactivity** out-of-the-box.
Threlte is split into distinct packages so you can import only what you need:
- [@threlte/core](/docs/reference/core/getting-started) provides simple, transparent Svelte binding to Three.js:
- [``](/docs/reference/core/t) is the **main building block** of any Threlte application. It is a thin, declarative wrapper for any Three.js class.
- [Plugins](/docs/learn/advanced/plugins) extend behavior for `` components.
- [@threlte/extras](/docs/reference/extras/getting-started) is a collection of plugins and components that add additional functionality.
- [@threlte/gltf](/docs/reference/gltf/getting-started) is a command-line tool that turns GLTF assets into declarative and re-usable Threlte components.
- [@threlte/rapier](/docs/reference/rapier/getting-started) provides components to enable performant physics in your Threlte application through the [Rapier engine](https://rapier.rs/).
- [@threlte/theatre](/docs/reference/theatre/getting-started) provides components to enable animations in your Threlte application through the [Theatre.js animation library](https://www.theatrejs.com/).
- [@threlte/xr](/docs/reference/xr/getting-started) provides components for VR and AR.
- [@threlte/flex](/docs/reference/flex/getting-started) provides components to easily use the flex engine [`yoga-layout`](https://yogalayout.com/) with Threlte.
---
## App Structure
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/app-structure
Threlte uses Svelte's [Context API](https://svelte.dev/tutorial/svelte/context-api) to share `renderer`, `camera`, [and others](/docs/reference/core/use-threlte#usage) to any child component.
Hooks like `useThrelte()` read from this context, so anything that needs it must be inside ``.
```svelte title="SomeComponent.svelte"
```
## Recommended app structure
Wrap your 3D app in a single `` and give it one direct child: `Scene.svelte`.
Put all 3D content under that node to access Threlte hooks.
```svelte title="App.svelte"
```
```svelte title="Scene.svelte"
```
## Context not available
The following app structure is deceiving. It looks like it should work, but **it
will not**. The problem is that the `useTask` hook is called *outside* of the
`` component, so the main Threlte context is not available. Usually hooks
relying on some context will tell you with descriptive error messages when they
are used outside of their context.
```svelte title="App.svelte"
```
## Using a single ``
In a larger Svelte app or when using SvelteKit, prefer a single `` to avoid the WebGL error
“Too many active WebGL contexts. Oldest context will be lost.”
We can use [Svelte 5
Snippets](https://svelte.dev/docs/svelte/snippet) to easily _portal_ our 3D
content to a global ``. For that, let's first create a component that
renders portal content:
```svelte title="src/lib/components/CanvasPortalTarget.svelte"
{#each snippets as snippet}
{@render snippet()}
{/each}
```
Then implement this component in the root +layout.svelte component:
```svelte title="src/routes/+layout.svelte"
{@render children()}
```
All we need is another component that we can utilize to easily portal 3D content
into the global canvas:
```svelte title="src/lib/components/CanvasPortal.svelte"
```
Now we can use this component to portal 3D content into the global canvas from
anywhere in our app all while using regular DOM elements alongside our 3D
content:
```svelte title="src/routes/+page.svelte"
Click me
```
---
## Loading Assets
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/loading-assets
Threlte works seamlessly with Three.js loaders, and provides a hook,
[useLoader](/docs/reference/core/use-loader), to help solve common loading issues.
It caches results to prevent duplicate fetch/parse work and returns an async store,
[asyncWritable](/docs/reference/core/utilities#asyncwritable) for convenient usage in Svelte.
Caching cuts network requests, bandwidth, and memory, improving app performance.
This section assumes you placed your assets in your public folder or in a place in your
application where you can import them easily.
We recommend using SvelteKit's [asset function](https://svelte.dev/docs/kit/$app-paths#asset) to
help catch common loading problems. There are other equivalent Vite plugins if you're not using
SvelteKit.
## Models
Models come in many different formats, but `.gltf`s are usually the best fit
for the web. You can use Three.js' `GLTFLoader` to load a `.gltf` model.
```svelte
{#if $gltf}
{/if}
```
The [` `](/docs/reference/extras/gltf) component is roughly equivalent to
the example above.
### `useGltf` hook
`@threlte/extras` provides a handy hook for loading `.gltf` models called
[useGltf](/docs/reference/extras/use-gltf):
```svelte
{#await useGltf('/assets/model.gltf') then gltf}
{/await}
```
### Adjusting and reusing 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 declaratively achieve that with only one ` `
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](/docs/reference/gltf/getting-started) to generate a Svelte
component for your model. The generated component has ` ` components for all
of your model's parts. [Adjust the component](/docs/learn/advanced/custom-abstractions) to your liking, then
import and reuse it as much as you'd like.
### Animations
Three.js uses [AnimationMixer](https://threejs.org/docs/index.html#api/en/animation/AnimationMixer)
to drive animations. Threlte provides a convenient
[useGltfAnimations](/docs/reference/extras/use-gltf-animations) hook for gltfs.
See the animation [Three.js example](https://threejs.org/examples/?q=animation)
for how to setup a model for your animation needs.
The Threlte docs also have an [animation example](/docs/examples/animation/animation-transitions) 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](https://gltf-viewer.donmccurdy.com/)?
## Textures
The `TextureLoader` is another loader from Three.js that is used for textures.
```svelte
{#if $texture}
{/if}
```
### `useTexture` hook
`@threlte/extras` provides a handy hook for loading textures called
[useTexture](/docs/reference/extras/use-texture):
```svelte
{#await useTexture('/assets/texture.png') then 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](https://learn.svelte.dev/tutorial/spread-props) the loaded textures on
a material.
Loading two textures for the `map` and `normalMap` channels can be done like
this:
```ts
const textures = useLoader(TextureLoader).load({
map: '/assets/texture.png',
normalMap: '/assets/normal.png'
})
```
or with the `useTexture` hook:
```ts
const textures = useTexture({
map: '/assets/texture.png',
normalMap: '/assets/normal.png'
})
```
Then spread on a material:
```svelte
{#if $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.
```svelte
{
if (Array.isArray(parent.material)) {
parent.material = [...parent.material, ref]
} else {
parent.material = [ref]
}
}}
/>
{
if (Array.isArray(parent.material)) {
parent.material = [...parent.material, ref]
} else {
parent.material = [ref]
}
}}
/>
```
## Other asset types
Threlte provides many components to help get started with many other asset
types (like [audio](/docs/reference/extras/audio)), but it doesn't have
components and hooks for all of them. Checkout [Three.js
examples](https://threejs.org/examples/) to see what models, techniques and
effects you can achieve, then use those examples as a guide for your own
[custom components](/docs/learn/advanced/custom-abstractions).
## Async loading
The return value from [useLoader](/docs/reference/core/use-loader) 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:
```svelte
{#await $texture then value}
{/await}
```
Assets can also be loaded after initialization by calling the `loader.load`
method:
```svelte
```
The [Suspense](/docs/reference/extras/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
`` component.
---
## Handling Events
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/handling-events
Most events work the same as any other Svelte application. There's the DOM events you know from
HTML, some Svelte [component props](https://svelte.dev/docs/svelte/basic-markup#Component-props)
but also raycasting which is specific to 3D applications.
## DOM events
The [`useThrelte`](/docs/reference/core/use-threlte) hook provides you with
direct access to Threlte's wrapper div called the `dom`. The `canvas` element is
also available if needed.
## Prop events
The `` component has its own [events](/docs/reference/core/t#events). It can even pick up
on events coming from the [underlying Three.js objects](/docs/reference/core/t#object-events).
## Raycasting events
Casting rays may end up being a big part of your 3D application. They're
required for creating [`interactivity`](/docs/reference/extras/interactivity)
(click, pointer, mouseover etc...) on your scene's meshes.
Raycasting can become expensive on complex shapes or if you have a high number
of objects. This can be mitigated by either:
- Raycasting against a simpler, invisible object (as is done by [mesh bounds](/docs/reference/extras/mesh-bounds)).
- And/or introducing a better raycasting algorithm such as Bounding Volume Hierarchies ([BVH](/docs/reference/extras/bvh)).
For simple use cases, Three.js's default raycaster works well.
---
## Scheduling Tasks
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/scheduling-tasks
In 3D apps and games, a lot of work is done in functions that run on every frame.
Web-based apps rely on the browser's `requestAnimationFrame` that runs a callback
function when a new frame is rendered. When encapsulating logic into smaller
parts (i.e. _components_), we often need to run multiple
callbacks that may be dependent on each other. For instance, we
may want to update the position of an object based on user input and then render
the scene with the updated position.
In Threlte, these functions are called **tasks** and may or may not follow a
specific order. If an order is specified, the respective task has a
**dependency** to other tasks and vice versa. Tasks are grouped into **stages**
and follow the same logic: They may or may not have dependencies to other stages
to be executed in a specific order. A Threlte app is managed by a single
**scheduler**.
In this section, we will learn how to use the easy-to-use tools that the
**Threlte Task Scheduling System** provides to create and orchestrate stages
and tasks.
Figure: A schedule of multiple stages with tasks
## Scheduler
Every Threlte app has a single scheduler. It is accessible via [`useThrelte()`](/docs/reference/core/use-threlte):
```ts
const { scheduler } = useThrelte()
```
Usually you won't need to interact with the scheduler directly. It is used internally by Threlte.
However, you can use it to create stages and run tasks manually for more advanced use cases.
## Stages
Stages are **groups of tasks**. They are executed in a specific order.
### Default Stages
By default, Threlte will create two stages for you:
- **`mainStage`**: This stage holds all the tasks that are not assigned to any
other stage.
- **`renderStage`**: This stage will be executed after the `mainStage`. It is
used to render the scene and only ever executes its tasks when a re-render is
needed.
These two stages are created automatically and are accessible via
[`useThrelte()`](/docs/reference/core/use-threlte):
```ts
const { mainStage, renderStage } = useThrelte()
```
### Creating a stage
Sometimes, you may want to create your own stage, for instance to run tasks
after rendering. You can do so by using the hook `useStage`. The hook will
create a stage if it does not exist yet, or return the existing stage if it
does.
```ts
const { renderStage } = useThrelte()
const afterRenderStage = useStage('after-render', {
after: renderStage
})
```
All tasks added to the stage `afterRenderStage` will be executed after the tasks
of the stage `renderStage`.
Be aware that `useStage` never removes a stage as that's usually not needed.
A stage decides **when and how its tasks are executed**. By default, a stage will
execute its tasks on every frame. You can change this behavior by passing a
`callback` option to `useStage`. This callback will be called every frame. The
first argument `delta` is the time elapsed since the last frame. The second
argument `runTasks` is a function that when invoked will run all the tasks of
the stage in their respective order. You can use it to run the tasks only when
needed (e.g. when a condition is met) or to run them multiple times. If a number
is passed as the first argument to runTasks, the tasks will receive that as the
delta.
```ts
const { renderStage } = useThrelte()
const conditionalStage = useStage('after-render', {
after: renderStage,
callback: (delta, runTasks) => {
// This callback will be called every frame. The first argument is the time elapsed
// since the last frame. The second argument is a function that will run all the
// tasks of the stage. You can use it to run the tasks only when needed (e.g. when
// a condition is met) or to run them multiple times. If a number is passed as the
// first argument to runTasks, the tasks will receive that as the delta.
if (condition) {
runTasks()
}
}
})
```
### Removing a Stage
You can remove a stage by calling the `remove` method of the scheduler. The first
argument is the stage or the key of the stage to remove.
```ts
const { scheduler } = useThrelte()
scheduler.removeStage(afterRenderStage)
```
Be aware that removing a stage will also remove all the tasks in that stage. Usually, you won't
need to remove a stage.
## Tasks
Tasks are functions that are executed on every frame. They are grouped in
stages. You can add a task to a stage by using the hook `useTask`. The hook will
create a task and add it to a stage.
### Default Tasks
By default, Threlte will create a single task for you:
- **`autoRenderTask`**: This task is part of [Threlte's
`renderStage`](#default-stages) and will render the scene if
[`autoRender`](/docs/reference/core/canvas) is set to `true`.
This task is created automatically and is accessible via
[`useThrelte()`](/docs/reference/core/use-threlte):
```ts
const { autoRenderTask } = useThrelte()
```
### Creating an Anonymous Task
In its most basic form, `useTask` takes a function as its first argument. This
function will be executed on every frame, starting on the next frame and
receives the delta time representing the time since the last frame as its first
argument. By default, the created task is added to [Threlte's
`mainStage`](#default-stages) in an arbitrary order (i.e. without dependencies).
```ts
const { task, started } = useTask((delta) => {
// This function will be executed on every frame
})
```
It returns an object with the following properties:
- `start`: A function that starts the task. It will be executed on the next
frame. Note that by default a task is started automatically.
- `stop`: A function that stops the task. It will not be executed on the next
frame.
- `started`: A boolean Svelte `Readable` store indicating whether the task is
started or not.
- `task`: The task itself. You can use it to indicate a dependency to this task
on another task.
### Creating a Keyed Task
You can _key_ a task by passing it as the first argument to `useTask`. This
makes referencing this task easier across your app. The key can be any `string`
or `symbol` value that is unique across all tasks in the stage it is added to.
```ts
const { task, started } = useTask('some-task', (delta) => {
// This function will be executed on every frame
})
```
### Creating a Task in a Stage
You can also pass a stage that the task should be added to as an option to
`useTask`:
```ts
useTask(
(delta) => {
// This function will be executed on every frame as a
// task in the stage `afterRenderStage`.
},
{ stage: afterRenderStage }
)
```
### Task Dependencies
A common use case for tasks is to run code after another task has been executed. Imagine
a game where an object is transformed by user input in one task and a camera follows that
object in another task. The camera task should be executed after the object has been
transformed.
To control the order in which tasks are executed in a stage, you can pass a
`before` and `after` option to `useTask`. The tasks passed to these options are
called **dependencies** and can be a task itself, the key of a task or an array
of tasks or keys. The referenced tasks must be in the same stage as the task you
are creating.
Task dependencies **do not need to be created yet** if they are passed by key.
The declared dependencies will be taken into account when they are created later
on.
#### Examples
```ts
// Execute a task after a single task passed by reference
useTask(
(delta) => {
// …
},
{ after: someTask }
)
```
```ts
// Execute a task after a single task passed by key
useTask(
(delta) => {
// …
},
{ after: 'some-task' }
)
```
```ts
// Execute a task after multiple tasks passed by reference
useTask(
(delta) => {
// …
},
{ after: [someTask, someOtherTask] }
)
```
```ts
// Execute a task after a certain task but before another one
useTask(
(delta) => {
// …
},
{ after: someTask, before: someOtherTask }
)
```
```ts
// Reference a task as a dependency that hasn't been created yet
useTask(
(delta) => {
// If a task with the key `some-task` is created later on,
// this task will be executed after it.
},
{ before: 'some-task' }
)
useTask('some-task', (delta) => {
// …
})
```
If a task is passed by reference to the `before` or `after` option, the task created by `useTask`
will automatically be added to the same stage as the task it depends on. If you pass a key instead
and the task you want to reference is **not** in [Threlte's `mainStage`](#default-stages), you
will also need to pass the stage, either by value or key.
## Reviewing the schedule
To debug the execution order, you can use the `getSchedule` method of the scheduler at any
time.
```ts
const { scheduler } = useThrelte()
scheduler.getSchedule({
tasks: true
})
```
```json title="Result"
{
"stages": [
{
"key": "physics stage",
"tasks": ["physics"]
},
{
"key": "main stage",
"tasks": ["move object", "move camera"]
},
{
"key": "render stage",
"tasks": ["render"]
}
]
}
```
In this example, the effective task execution order is:
1. `physics`
2. `move object`
3. `move camera`
4. `render`
---
The design of the Threlte Task Scheduling System is a collaborative effort of
the Threlte team, [Kris Baumgarter](https://github.com/krispya) and [Akshay
Dhalwala](https://github.com/akdjr).
---
## Render Modes
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/render-modes
Threlte offers three different render modes to optimize the performance and
power usage of your Threlte app. Ideally, you only want to render the scene
when it is necessary, such as when the camera moves or when objects are added or
removed from the scene. The render mode determines how and when the scene is
rendered.
In the default [`'on-demand'`](#mode-on-demand) mode, Threlte is able to
determine when a re-render is necessary by observing components. When setting
the render mode to [`'manual'`](#mode-manual) you must manually trigger a
re-render. You can tell Threlte to continuously render the scene in the
[`'always'`](#mode-always) mode.
## Mode `'on-demand'`
In the mode `'on-demand'`, Threlte renders the scene only when the current frame
is **invalidated**. This may happen [automatically when changes are
detected](#automatic-invalidation) or the frame is [manually
invalidated](#manual-invalidation). This is the default mode and the recommended
way of working with Threlte.
### Automatic invalidation
Threlte is able to automatically invalidate the current frame by observing
component props and the mounting and unmounting of components. This means that
when you e.g. change the position of a `` via component props, Threlte
will automatically invalidate the current frame and request a new frame.
```svelte
```
### Manual invalidation
In some cases, you may want to manually invalidate the current frame because
Threlte is not able to detect changes. To do this, you can use the `invalidate`
function from the [`useThrelte`](/docs/reference/core/use-threlte) hook.
```svelte
```
### `useTask`
The [`useTask`](/docs/reference/core/use-task) hook is by default configured to
automatically invalidate the current frame **on every frame**. This means that you
can use it to animate your scene without having to manually invalidate the
current frame.
```ts
import { useTask } from '@threlte/core'
useTask(() => {
// useTask will automatically invalidate the current
// frame, so you don't have to do it manually.
})
```
Sometimes you may want to manually invalidate the current frame from within a
task. To do this, you can use the `invalidate` function from the
[`useThrelte`](/docs/reference/core/use-threlte) hook and set the `autoInvalidate`
option to `false`:
```ts
import { useTask, useThrelte } from '@threlte/core'
const { invalidate } = useThrelte()
useTask(
() => {
// Because `autoInvalidate` is set to `false`, the current
// frame will not be invalidated automatically and you can
// conditionally invalidate the current frame.
invalidate()
},
{ autoInvalidate: false }
)
```
## Mode `'manual'`
In the manual mode, you must manually trigger a re-render:
```ts
const { advance } = useThrelte()
advance()
```
This mode is useful when you want to have full control over when the scene is
rendered. For example, you may want to render the scene only when the user
interacts with the scene.
## Mode `'always'`
In the `'always'` mode, Threlte continuously renders the scene. This mode is the
easiest to use, but it is also the most resource intensive and should only be
used when necessary.
## Setting the render mode
### `` prop
You can set the render mode by setting the property `renderMode` on the
[``](/docs/reference/core/canvas) component:
```svelte
```
### `useThrelte` hook
You can also set the render mode from anywhere within your Threlte app using the
[`useThrelte`](/docs/reference/core/use-threlte) hook:
```ts
const { renderMode } = useThrelte()
renderMode.set('on-demand')
```
The renderMode property can be changed at any time, but it will only take effect on the next
frame.
## Render modes and custom rendering
By default, Threlte will automatically render the scene for you. In some cases,
you may want to render the scene yourself, for example when using [postprocessing](/docs/examples/postprocessing/outlines).
1. Set `autoRender` to `false` on the [``](/docs/reference/core/canvas)
component. This will prevent Threlte from automatically rendering the scene
and you can render the scene yourself.
```svelte
```
2. Set up a task that renders the scene. There are two ways to do this:
- Add a task to [Threlte's default
`renderStage`](/docs/learn/basics/scheduling-tasks#default-stages). Tasks in
that stage will be executed after tasks in Threlte's `mainStage` and only
when a re-render is necessary based on the current render mode. This is the
recommended approach.
```ts
import { useTask, useThrelte } from '@threlte/core'
const { renderStage } = useThrelte()
useTask(
() => {
// render here
},
{ stage: renderStage, autoInvalidate: false }
)
```
- Use `shouldRender` from the hook
[`useThrelte`](/docs/reference/core/use-threlte). This function will evaluate
to `true` based on the current render mode. This allows for more fine-grained
control over when to render and is useful when you want to render in a task
that is not in [Threlte's default
`renderStage`](/docs/learn/basics/scheduling-tasks#default-stages).
```ts
import { useThrelte, useTask } from '@threlte/core'
const { shouldRender } = useThrelte()
useTask(
() => {
if (shouldRender()) {
// render here
}
},
{ autoInvalidate: false }
)
```
---
## Disposing Objects
Category: Basics
URL: https://threlte.xyz/docs/learn/basics/disposing-objects
Freeing resources is a [manual chore in
Three.js](https://threejs.org/docs/index.html#manual/en/introduction/How-to-dispose-of-objects),
but Svelte is aware of component lifecycles, hence Threlte will attempt to free
resources for you by calling `dispose`, if present, on all unmounted objects
that are not being used anywhere else in your scene.
## Automatic disposal
```svelte
```
Be aware that calling `dispose` on a Three.js buffer, material or geometry is merely deallocating
it from the GPU memory. If an object is used after it's disposed it will be allocated again,
resulting in a performance drop for a single frame. It will **not produce a runtime error**.
## Manual disposal
You can switch off automatic disposal by setting `dispose={false}` on
components. This disables disposal for the **entire subtree**.
```svelte
```
## Custom disposal
You can use the return function of the `oncreate` prop to dispose of objects manually.
```svelte
{
return () => {
// Do your disposal here
}
}}
/>
```
## Automatic Disposal Limitations
Be aware that automatic disposal only happens on the objects that are referenced
by a `` component.
```svelte
{#if $map}
{/if}
```
In this example, the texture will not be disposed when the material unmounts,
you will have to dispose of it manually.
---
## Plugins
Category: Advanced
URL: https://threlte.xyz/docs/learn/advanced/plugins
Plugins allow you to extend Threlte's [``](/docs/reference/core/t)
component. They can be used to add props, event handlers, custom logic and
customize the component instance. You can think of a plugin as code that
is injected into every child `` component.
Plugins can be overridden in child components.
The [interactivity plugin in
`@threlte/extras`](/docs/reference/extras/interactivity) is an example of what a
plugins can do and there are a couple of other examples below.
## When to use a plugin
A plugin has access to all props and the lifecycle of the `` component.
Use it to:
- add custom props to the `` component such as [`lookAt`](#lookat).
- add custom logic to the `` component, such as automatically add helpers for
certain objects in development mode.
- collect object references from child components for app-wide systems such as
an ECS.
- build custom integrations for external libraries.
[``'s `oncreate`](/docs/reference/core/t#create-event) shares some
similarities to a plugin but only has access to the object referenced by the
`` component. Also, it has to be defined on every `` component
individually.
You can think of `oncreate` as a [Svelte
Attachment](https://svelte.dev/docs/svelte/@attach) for `` components. Use it for
one-time setup logic that does not need access to the component's props.
## Injecting a plugin
Plugins are _injected_ to a plugin context and are **accessible to all child
`` components**.
```svelte title="Scene.svelte"
```
### Plugin internals
Plugins open up the component `` to external code that will be injected via
context into every child instance of a `` component. The callback function
receives a **reactive `args` object** that contains the `ref` of the respective
`` component, all base props (`makeDefault`, `args`, `attach`, `manual`
and `dispose`) and all props (anything else) passed to it.
```ts
import { injectPlugin } from '@threlte/core'
injectPlugin('plugin-name', (args) => {
console.log(args.ref) // e.g. a Mesh
console.log(args.props) // e.g. { position: [0, 10, 0] }
})
```
If a plugin decides via `args.ref` or `args.props` analysis that it doesn't need
to act in the context of a certain `` component, it can return early.
```ts
import { injectPlugin, isInstanceOf } from '@threlte/core'
injectPlugin('raycast-plugin', (args) => {
if (!isInstanceOf(args.ref, 'Object3D') || !('raycast' in args.props)) return
})
```
The code of a plugin **acts as if it would be part of the `` component
itself** and has access to all properties. A plugin can run arbitrary code in
lifecycle functions such as `onMount`, `onDestroy` and effects.
```ts
import { injectPlugin } from '@threlte/core'
import { onMount } from 'svelte'
injectPlugin('plugin-name', (args) => {
// Use lifecycle hooks as if it would run inside a component.
// This code runs when the `` component this plugin is injected
// into is mounted.
onMount(() => {
console.log('onMount')
})
// Use any prop that is defined on the component, in this
// example `count`:
const count = $derived(args.props.count ?? 0)
$effect(() => {
// This code runs whenever count changes.
console.log(count)
})
return {
// Claiming the property "count" so that the component
// does not act on it.
pluginProps: ['count']
}
})
```
A Plugin can also _claim properties_ so that the component `` does not act on it.
```ts
import { injectPlugin } from '@threlte/core'
injectPlugin('ecs', () => {
return {
// Without claiming the properties, would apply the
// property to the object.
pluginProps: ['entity', 'health', 'velocity', 'position']
}
})
```
Plugins are passed down by context and can be overridden to prevent the effects of a plugin for a certain tree.
```ts
import { injectPlugin } from '@threlte/core'
// this overrides the plugin with the name "plugin-name" for all child components.
injectPlugin('plugin-name', () => {})
```
### Creating a plugin
Plugins can also be _created_ for external consumption. This creates a _named plugin_. The name is used to identify the plugin and to override it.
```ts
import { createPlugin } from '@threlte/core'
export const layersPlugin = createPlugin('layers', () => {
// ... Plugin Code
})
```
```ts
// somewhere else, e.g. in a component
import { injectPlugin } from '@threlte/core'
import { layersPlugin } from '$plugins'
injectPlugin(layersPlugin)
```
## Examples
### `lookAt`
This is en example implementation that adds the property `lookAt` to all `` components, so that ` ` is possible:
### BVH raycast plugin
A Plugin that implements [BVH raycasting](https://github.com/gkjohnson/three-mesh-bvh) on all child meshes and geometries.
This plugin outlines the basic setup of the extras [bvh plugin](/docs/reference/extras/bvh).
```ts title="bvhRaycasting.svelte.ts"
import { injectPlugin, isInstanceOf } from '@threlte/core'
import type { BufferGeometry, Mesh } from 'three'
import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh'
const bvhRaycasting = () => {
injectPlugin('bvh-raycast', (args) => {
$effect(() => {
if (isInstanceOf(args.ref, 'BufferGeometry')) {
args.ref.computeBoundsTree = computeBoundsTree
args.ref.disposeBoundsTree = disposeBoundsTree
args.ref.computeBoundsTree()
}
if (isInstanceOf(args.ref, 'Mesh')) {
args.ref.raycast = acceleratedRaycast
}
return () => {
if (isInstanceOf(args.ref, 'BufferGeometry')) {
args.ref.disposeBoundsTree()
}
}
})
})
}
```
Implementing this plugin in your scene looks like this.
```svelte title="Scene.svelte"
```
## TypeScript
Using TypeScript, we can achieve **end-to-end type safety for plugins**, from
the plugin implementation to the props of the `` component. The example below
shows how to type the props of the [`lookAt` plugin](#lookat) so that the prop
`lookAt` is strictly typed on the `` component as well as in the plugin
implementation.
### Typing a plugin
The function `injectPlugin` accepts a type argument that you may use to type the
props passed to a plugin.
```ts
injectPlugin<{ lookAt?: [number, number, number] }>('lookAt', (args) => {
// args.props.lookAt is now typed as [number, number, number] | undefined
})
```
### Typing the `` component props
By default, the custom props of plugins are not present on the types of the
`` component. You can however extend the types of the `` component by
defining the `Threlte.UserProps` type in your ambient type definitions. In a
typical SvelteKit application, you can find these type definitions [in
`src/app.d.ts`](https://svelte.dev/docs/kit/types#app.d.ts).
```ts title="src/app.d.ts"
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
namespace Threlte {
interface UserProps {
lookAt?: [number, number, number]
}
}
}
export {}
```
The prop `lookAt` is now available on the `` component and is typed as
`[number, number, number] | undefined`.
```svelte title="Svelte.svelte"
```
As your app grows in size, you should consider moving these type these type definitions to a
separate file and merge all available props to a single type definition. This type may then be
used by `injectPlugin` as well as your ambient type defintions.
---
## Custom Abstractions
Category: Advanced
URL: https://threlte.xyz/docs/learn/advanced/custom-abstractions
A lot of the components you will find in the package
[@threlte/extras](/docs/reference/extras/getting-started) are abstractions on
top of the [`` component](/docs/reference/core/t). These abstractions provide
extra functionality like automatically invalidating the frame or providing
default values or extra props.
A common use case for custom abstractions is to create a component that is a
fixed entity in your Threlte app which you want to reuse in multiple places or
which exposes a specific behavior. As an example, let's create a component that
is made up from multiple `` components resembling a tile of some kind:
```svelte title="Tile.svelte"
{@render children()}
```
Let's see what implementing that component looks like:
```svelte title="Scene.svelte"
```
## Props
The `` component is now available in the scene and can be reused as many
times as you want.
Now we'd like to assign a different `position` to every `` in order to
position it in the scene. We can do that by passing a `position` prop to the
`` component:
```svelte title="Scene.svelte"
```
That doesn't work _yet_. The component `` internally needs to make use of
the `position` prop to set the position of its children. We can do that by
[spreading `rest` on the ``](https://svelte.dev/docs/svelte/$props#Rest-props)
component at the root hierarchy of ``:
```svelte title="Tile.svelte" {5}m
{@render children()}
```
## Types
The following section assumes you use TypeScript.
The last thing we need to do is to add types to our custom abstraction so that
IDEs like VS Code can provide autocompletion and type checking. We will create a
`types.ts` file next to the `Tile.svelte` file and add the following content:
```ts title="types.ts"
import type { Props } from '@threlte/core'
import type { Group } from 'three'
export type TileProps = Props
```
As of now it's necessary to declare the props in a separate file.
If you declare them inside the `
{@render children({ ref })}
```
Now we can use the `` component in our scene and get autocompletion and
type checking.
```svelte title="Scene.svelte"
{#snippet children({ ref })}
{/snippet}
```
---
## WebGPU and TSL
Category: Advanced
URL: https://threlte.xyz/docs/learn/advanced/webgpu
The WebGPU specification is still in active development. WebGPU support in Three.js is in an early
stage and is subject to frequent breaking changes. As of now, we do not recommend using WebGPU in
production.
We highly recommend targeting [version r171](https://github.com/mrdoob/three.js/releases/tag/r171)
onwards because of potential [duplication and configuration
issues](https://github.com/mrdoob/three.js/pull/29404).
## WebGPU
To use the WebGPU renderer, import it and then initialize it within your
``'s `createRenderer` prop. This will replace the default WebGL
renderer.
```svelte title="App.svelte" {4}+ {8-14}+
{
return new WebGPURenderer({
canvas,
antialias: true,
forceWebGL: false
})
}}
>
```
WebGPU is still young and has [limited availability across major
browsers](https://caniuse.com/?search=webgpu). For this reason, Three.js's WebGPU renderer
fallbacks to WebGL when WebGPU is not available.
This same approach can be used to swap out the default renderer for any other custom renderer.
The WebGPU renderer doesn't immediately render. If the renderer you provide
needs to delay rendering, you can defer rendering by initially setting the
renderMode to `manual`.
```svelte title="App.svelte"
{
const renderer = new WebGPURenderer({
canvas,
antialias: true,
forceWebGL: false
})
renderer.init().then(() => {
renderMode = 'on-demand'
})
return renderer
}}
>
```
### Vite
WebGPU uses top-level async to determine WebGPU compatibility. Vite will often
throw an error when it detects this.
To circumvent this issue, the following can be added to your Vite config.
```js title=vite.config.js
optimizeDeps: {
esbuildOptions: {
target: 'esnext'
}
},
build: {
target: 'esnext'
}
```
Alternatively,
[`vite-plugin-top-level-await`](https://github.com/Menci/vite-plugin-top-level-await)
can be used, although less success has been reported with this method.
Adapted from [this Three.js
example](https://threejs.org/examples/?q=webgpu#webgpu_performance_renderbundle).
## TSL
A question that comes up often in Three.js development is "How do I extend
Three.js materials?". External libraries such as
[three-custom-shader-material](https://www.npmjs.com/package/three-custom-shader-material)
use a find and replace solution to get this job done. Three.js has identified
that it's not an ideal solution and recommends using the [Three.js Shading
Language](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language) or
TSL for short.
The example below is an adaptation of
[this](https://threejs.org/examples/?q=tsl#webgpu_tsl_angular_slicing) Three.js
example. There are many more [TSL
examples](https://threejs.org/examples/?q=tsl) within Three.js that you can use
or adapt for your project.
### Using the `` catalogue
The `` component defaults to all the exports from `three` and will error on
webgpu things like ` `. This is because the
`MeshPhysicalNodeMaterial` class is an export of `three/webgpu` and not
`three`. Here are a few options to resolve this.
#### Option 1
Extend `` with all the definitions from `three/webgpu` by using the
[`extend`](/docs/reference/core/t#extending-the-default-component-catalogue)
function. Adding all of the definitions will increase the bundle size of
your application because both `three` and `three/webgpu` will be imported in
a non-tree-shakeable way.
```svelte title="App.svelte" {3-4}+ {6}+
{
return new THREE.WebGPURenderer({
canvas,
antialias: true,
forceWebGL: false
})
}}
>
```
#### Option 2
Use explicit imports for the objects, functions, and other classes that you
use from `three/webgpu`. You can then use ``'s
[`is`](/docs/reference/core/t#property-is) prop with those imports from
`three/webgpu`.
```svelte title="Scene.svelte" {3}+ {5}+ {10}+
```
#### Option 3
Same as option #2 but using
[`extend`](/docs/reference/core/t#extending-the-default-component-catalogue)
with the imports so that you can have ` `
etc...
```svelte title="App.svelte" {3-4}+ {6}+
{
return new WebGPURenderer({
canvas,
antialias: true,
forceWebGL: false
})
}}
>
```
```svelte title=Scene.svelte
```
Options 2 and 3 will keep the bundle size of your application small but you'll
have to keep it updated as you go.
#### Careful! `three` and `three/webgpu` don't mix well
You will need to overwrite some of the default catalogue if you use
`three/webgpu`. For example, if you're using a `MeshPhysicalNodeMaterial`, you
need to update any lighing classes you use like so:
```svelte title="App.svelte"
```
```svelte title="Scene.svelte"
```
This is because the exports from `three/webgpu` are different than those in
`three` and make use of the additional features that node materials have.
An easy option for projects is to start with option #1 and then transition to the other options
when bundle size becomes an issue or you need to ship to production.
### Nodes
The material's
[nodes](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language#nodematerial)
can be directly assigned like any other prop on the `` component.
```svelte
{
/* ... */
})()}
/>
```
Or can create the material in the script tag and use ``'s `is` prop to
attach the material.
```svelte
```
Node materials give you the ability to modify three's builtin materials. In the
sliced gear example, two nodes are modified; the `outputNode` and the
`castShadowNode`. The `outputNode` is set up in such a way that it discards any
fragments that are outside the permitted `startAngle` and `arcAngle`. If a
fragment is not discarded and it is not front-facing, it is assigned the color
in the `uColor` uniform. The material needs its `side` set to
`THREE.DoubleSide` otherwise three.js will cull them out if they are facing
away from the camera. Any fragment that is discarded in the shadowNode will not
cast shadows.
---
## Migration Guides
Category: More
URL: https://threlte.xyz/docs/learn/advanced/migration-guides
## Threlte 8
Threlte 8 adds Svelte 5 support and removes Svelte 4 support.
This upgrade contains bug fixes, better average performance, smaller bundle size, and an improved development experience.
There are a few notable breaking changes listed below.
### Automatic Disposal
[Automatic disposal](/docs/learn/basics/disposing-objects) has been improved to
only dispose of objects that are referenced by a `` component. Objects are no
longer scanned recursively for disposable objects.
```svelte
{#if $map}
{/if}
```
In this example, Threlte 7 also disposed of the texture when the material
unmounted. This is no longer the case in Threlte 8. This change is introduced to
improve performance and to make the behavior of automatic disposal more
intuitive. When looking at simple examples like the one above, this might seem
like a regression, but with scale the previous approach of deeply recursive
automatic disposal was hard to reason about and a performance bottleneck.
### Plugin API
The plugin API has been changed to allow for greater granularity and a reactivity model that is in-line with Svelte 5.
#### `createPlugin` has been removed
Threlte 7 included a function called `createPlugin` that allowed to separate a
plugin declaration from its implementation. The recommended way to create
plugins is to export a function that invokes `injectPlugin`:
```ts
import { injectPlugin } from '@threlte/core'
export const createSomePlugin = (pluginArg: string) => {
injectPlugin('some-plugin', () => {
// ... Plugin Code
})
}
```
This plugin can now be implemented like this:
```svelte title="Scene.svelte"
```
#### Plugin callbacks have been removed
In Threlte 7, plugins could return an object with several callback functions
that were invoked when:
- `ref` changed
- any prop changed (e.g. `makeDefault`, `dispose`, `attach`, etc.)
- any "rest" prop changed (e.g. `position`, `color`, etc.)
```ts title="Threlte 7"
injectPlugin('some-plugin', ({ ref, props }) => {
return {
onRefChange(newRef) {
// ...
},
onPropsChange(props) {
// ...
},
onRestPropsChange(restProps) {
// ...
}
}
})
```
These callbacks have been removed. Instead, you can use the first argument of the plugin
callback, which is a reactive object containing all properties needed:
```ts title="Threlte 8"
injectPlugin('some-plugin', (args) => {
args.ref
args.makeDefault
args.args
args.attach
args.manual
args.makeDefault
args.dispose
args.props // All other props declared on the component
})
```
The `args` object is reactive and will update whenever any of the referenced values change.
A plugin may still return an object with `pluginProps` to specify which props
the `` component should not react to.
### Events
Events will no longer work, and have been replaced with callback props.
```svelte {2,3}m
```
The signature of the `oncreate` callback prop has changed. Instead of receiving an object with a cleanup function,
you may now return a cleanup function that will run when the object is destroyed or its args change. This is more in-line with other apis in svelte 5 and threlte.
```svelte
{
return () => {
console.log('cleanup')
}
}}
>
```
The `createRawEventDispatcher` and `forwardEventHandlers` exports will no longer work.
Instead of dispatching events with `createRawEventDispatcher`, invoke callback props.
```svelte
```
Instead of using `forwardEventHandlers`, pass rest props
to the component you wish to forward events to.
```svelte
```
This will pass the new callback props mentioned in the previous section down the tree of components.
### Attach API & Trait Components
The signature and heuristic of the attach API of the `` component has
changed. The trait components `` and ``
have been removed.
#### `attach` Function Signature
```svelte
{
console.log('attaching', parent, self)
return () => {
console.log('detaching', parent, self)
}
}}
/>
{
console.log('attaching', ref, parent, parentObject3D)
return () => {
console.log('detaching', ref, parent, parentObject3D)
}
}}
/>
```
#### `attach={false}`
If `false` is passed to the `attach` prop, the component will not be automatically attached to
the parent object. This is useful if you want to attach the component manually.
```svelte
```
#### `attach={object3D}`
If an object3D instance is passed to the `attach` prop, the component will be attached to the instance, essentially acting as a portal.
Be aware that the component still acts in the given context of the parent.
```svelte
```
### Snippets
Slot props will no longer work, and must be replaced with snippets.
For example, the following components from Threlte 7 would need to be migrated from this:
```svelte
```
...to this:
```svelte
{#snippet children({ ref })}
{/snippet}
```
Any component that previously exposed a slot prop using the `let:` directive can follow this new pattern.
### Canvas component `size` prop
The `size` property on the `` component that allowed setting specific pixel dimensions has been removed.
To set a specific size of your ``, simply wrap it in an HTML element with your desired dimensions.
```svelte
```
### Canvas component `rendererParameters` prop
The `renderParameters` canvas prop has been replaced with a more powerful `createRenderer` function.
If you need to manually set renderer parameters, call the function and return a renderer.
```svelte
{
return new WebGLRenderer({
canvas,
alpha: true,
powerPreference: 'high-performance',
antialias: false,
depth: false,
premultipliedAlpha: false
})
}}
>
```
Any Three renderer can be returned when calling `createRenderer`.
### Transitions
The transitions plugin currently does not work, we're working towards a new
transition system.
### `useGltf` and ``
`useGltf` and `` no longer contain a built-in `DracoLoader`, `KTX2Loader`, or `MeshoptDecoder`.
Instead, separate hooks can be imported and passed to these tools, improving their bundle size and flexibility.
```ts
import { useGltf, useDraco, useKtx2, useMeshopt } from '@threlte/extras'
const dracoLoader = useDraco()
const ktx2Loader = useKtx2()
const meshoptDecoder = useMeshopt()
const gltf = useGltf('./path/to/model.glb', {
dracoLoader,
ktx2Loader,
meshoptDecoder
})
```
For more information, see the [`useGltf`](/docs/reference/extras/use-gltf) and [`GLTF`](/docs/reference/extras/gltf) docs.
### Rapier
#### Two Stage Physics
In order to enable fixed frame physics, the Rapier package is introducing two
[scheduler stages](/docs/learn/basics/scheduling-tasks#stages). So in the most
simple physics implementation:
```svelte
```
The scheduler plan will look like this:
```txt
scheduler
├─ threlte-main-stage
├─ simulation
│ └─ simulation
├─ synchronization
│ └─ synchronization
└─ threlte-render-stage
```
[Tasks](/docs/learn/basics/scheduling-tasks#tasks) that are added to the
`simulation` stage will be executed according to the set
[framerate](/docs/reference/rapier/framerate), i.e. the delta provided in these
tasks corresponds to the delta time between physics frames. Tasks added to the
`synchronization` stage will be executed after all tasks of the `simulation`
stage have been executed, the delta is the regular `requestAnimationFrame` frame
delta. The stages and tasks are available as part of the `RapierContext` with the `useRapier` hook:
```ts
import { useTask } from '@threlte/core'
import { useRapier } from '@threlte/rapier'
const { simulationTask } = useRapier()
useTask(
() => {
// E.g. interact with the physics world here
},
{
before: simulationStage
}
)
```
#### BasicPlayerController has been removed
The `BasicPlayerController` component has been removed. If you need a player
controller, Rapier comes with a pre-made, easy to implement [Character
Controller](https://rapier.rs/docs/user_guides/javascript/character_controller).
It's more powerful and flexible than the old component.
The reason is stated in rapier's documentation as well:
> Despite the fact that this built-in character controller is designed to be
> generic enough to serve as a good starting point for many common use-cases,
> character-control (especially for the player's character itself) is often very
> game-specific. Therefore the builtin character controller may not work
> perfectly out-of-the-box for all game types.
#### `oncreate` event signature
The `oncreate` event signature available on ``, `Collider` and
`` has been adapted to match the `oncreate` prop on ``.
```svelte
{
// ref is the created RigidBody instance
return () => {
// cleanup function
}
}}
>
```
## Threlte 7
Threlte 7 introduces a new _Task Scheduling System_ that allows you to easily
orchestrate the task execution order of your Threlte application. For details on
how to use it, see the [documentation](/docs/learn/basics/scheduling-tasks).
Before, you had the option to choose between `useFrame` and `useRender` to
orchestrate your rendering pipeline. These hooks were removed in Threlte 8.
This guide will help you migrate your application to the new Task Scheduling
System.
This update also slightly changes the signature of the `` component as
well as the Threlte context.
Also, to increase performance we're enforcing the use of constant prop types
on the `` component.
### Constant prop types on ``
The `` component now enforces the use of _constant prop types_. This means
that the type of a certain prop value must not change in the lifetime of a
component. See this example:
```svelte title="Threlte 6"
```
When `changePosition` is invoked, the prop type of the prop `position` changes
from an array of numbers to a number. This is not allowed anymore in Threlte 7.
Prop types must be constant. It's a highly unlikely scenario that rarely occurs
and a rather bad practice to start with, which allows us to optimize the
performance of the `` component by enforcing this rule. This is how you would
migrate the above example:
```svelte title="Threlte 7" {7}m
```
### Threlte context
### `` props
#### `frameloop`
`frameloop` is now called `renderMode` as it only affects the rendering of your
Threlte application. It accepts nearly the same values as before:
```ts title="Threlte 6"
```
```ts title="Threlte 7"
```
If the value is `always`, Threlte will render your scene on every frame. If the
value is `on-demand`, Threlte will only render your scene when a re-render is
needed. If the value is `manual`, Threlte will never render your scene
automatically and you have to trigger a re-render by calling `advance()` on the
Threlte context available via `useThrelte()`.
#### `autoRender`
When `autoRender` is `false`, Threlte will not render your scene automatically
and will enable you to implement a custom render pipeline using the hook
[`useTask`](/docs/reference/core/use-task). If adding a task to render the scene
to Threlte's
[`renderStage`](/docs/learn/basics/scheduling-tasks#default-stages), the task
will only be called in respect to the `renderMode` prop. Previously, this
behavior was inferred from the usage of the `useRender` hook, but we think being
explicit here is better.
### `useFrame`
The hook [`useTask`](/docs/reference/core/use-task) replaces `useFrame`. It has
a slightly different signature and allows you to to add a `task` to Threlte's
_Task Scheduling System_. A task may have dependencies to other tasks, which you
can think of as the big brother of the `order` option of `useFrame`.
#### Callback Arguments
The callback to `useTask` now only receives the delta time since the last frame.
The Threlte context previously available as the first argument to the callback
of `useFrame` should be retrieved using the hook
[`useThrelte`](/docs/reference/core/use-threlte).
```ts title="Threlte 6"
useFrame(({ camera, scene }, delta) => {
// The Threlte context was previously available as the first
// argument to the callback, followed by the delta time since the
// last frame.
})
```
```ts title="Threlte 7"
const { camera, scene } = useThrelte()
useTask((delta) => {
// The delta time since the last frame is the only
// argument to the callback.
})
```
#### `autostart` and `invalidate`
The options of `useTask` have been renamed to better reflect their purpose. The
`autostart` option is now called `autoStart` (note the **capital 'S'**),
`invalidate` is now called `autoInvalidate`.
#### If you didn't use the `order` option
Replace `useFrame` with `useTask` and adapt accessing the Threlte context.
```ts title="Threlte 6"
useFrame(({ camera, scene }, delta) => {
// ...
})
```
```ts title="Threlte 7"
const { camera, scene } = useThrelte()
useTask((delta) => {
// ...
})
```
#### If you used the `order` option
Migrate to `useTask` by referencing the key of the task you want to depend on.
```ts title="Threlte 6"
useFrame(
(_, delta) => {
// This task will be executed first
},
{ order: 0 }
)
useFrame(
(_, delta) => {
// This task will be executed second
},
{ order: 1 }
)
```
```ts title="Threlte 7"
useTask('first', (delta) => {
// ...
})
useTask(
'second',
(delta) => {
// This task will be executed after the task with the
// key 'first' has been executed.
},
{ after: 'first' }
)
```
### `useRender`
The hook [`useTask`](/docs/reference/core/use-task) also replaces `useRender`.
Previously, `useRender` allowed you to define a callback that was invoked after
all `useFrame` callbacks have been invoked to render your scene with a custom
render pipeline. This is now possible with `useTask` as well. Threlte provides a
[`renderStage`](/docs/learn/basics/scheduling-tasks#default-stages) that only
ever executes its tasks when a re-render is needed. A task added to this stage
can be used to render your scene. Be sure to set the option `autoInvalidate` to
`false` to prevent Threlte from automatically invalidating the render stage.
```ts title="Threlte 6"
useRender(() => {
// Render your scene here
})
```
```ts title="Threlte 7"
const { renderStage } = useThrelte()
useTask(
'render',
() => {
// Render your scene here
},
{ stage: renderStage, autoInvalidate: false }
)
```
#### Callback Arguments
The callback to `useTask` now only receives the delta time since the last frame.
The Threlte context previously available as the first argument to the callback
of `useRender` should be retrieved using the hook
[`useThrelte`](/docs/reference/core/use-threlte).
```ts title="Threlte 6"
useRender(({ camera, scene }, delta) => {
// The Threlte context was previously available as the first
// argument to the callback, followed by the delta time since the
// last frame.
})
```
```ts title="Threlte 7"
const { camera, scene } = useThrelte()
useTask((delta) => {
// The delta time since the last frame is the only
// argument to the callback.
})
```
#### If you didn't use the `order` option
Replace `useFrame` with `useTask` and adapt accessing the Threlte context.
```ts title="Threlte 6"
useRender((_{ camera, scene }_, delta) => {
// ...
})
```
```ts title="Threlte 7"
const { renderStage } = useThrelte()
useTask(
(delta) => {
// ...
},
{ stage: renderStage, autoInvalidate: false }
)
```
#### If you used the `order` option
Migrate to `useTask` by referencing the key of the task you want to depend on.
```ts title="Threlte 6"
useRender(
(_, delta) => {
// This task will be executed first
},
{ order: 0 }
)
useRender(
(_, delta) => {
// This task will be executed second
},
{ order: 1 }
)
```
```ts title="Threlte 7"
const { renderStage } = useThrelte()
useTask(
'first',
(delta) => {
// ...
},
{ stage: renderStage, autoInvalidate: false }
)
useTask(
'second',
(delta) => {
// This task will be executed after the task with the
// key 'first' has been executed.
},
{ after: 'first', stage: renderStage, autoInvalidate: false }
)
```
## Migrating from Threlte 5 to Threlte 6
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.
### 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 ``](/docs/reference/core/t) directly.
### `` is now ``
Threlte 6 merges the `` and `` 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 `` component
The `@threlte/core` package is now only about the `` component. It does not provide any abstractions
that have been part of the core package before. _Some_ of these abstractions (``,
``, 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](/docs/reference/extras/interactivity) to learn more.
### `useLoader` now returns a store
The hook [`useLoader`](/docs/reference/core/hooks#useloader) now returns a custom Svelte store called
[`AsyncWritable`](/docs/reference/core/utilities#asyncwritable). This store allows you to [await](https://svelte.dev/tutorial/await-blocks)
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.
### `` and the default effects rendering are removed
In the effort of clear separation of concerns, the component `` as well as the rendering with Three.js default
`EffectComposer` have been removed. Threlte 6 now provides a hook called [`useRender`](/docs/reference/core/hooks#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`](/docs/reference/core/utilities#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`](/docs/reference/core/hooks#useframe) where the context is available as the first argument
to the callback:
```ts
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](/docs/reference/core/hooks#usethrelte).
### `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.
```ts
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.
$effect(() => {
$actions.Greet?.play()
})
```
Check out the [hooks documentation](/docs/reference/extras/use-gltf-animations) for more information.
### `@threlte/rapier`
#### Transform props
In an effort to clearly separate concerns, the components ``, `` and `` **no longer
offer transform props** (`position`, `rotation`, `scale` and `lookAt`). Instead, you should wrap these components
in for instance `` components and apply transforms on these.
```svelte title="Before.svelte" {2,3}-
```
```svelte title="After.svelte" {1-4,11}+
```
---
## Installation
Category: Getting Started
URL: https://threlte.xyz/docs/learn/getting-started/installation
import ManualInstallGuide from '$components/ManualInstallGuide/ManualInstallGuide.svelte'
Install only what you need. `three` and `@threlte/core` are the minimum required to get going. The remaining packages can be added anytime.
[`@threlte/gltf`](/docs/reference/gltf/getting-started) doesn’t require installation, instead run it with `npx`.
The components generated by `@threlte/gltf` require `@threlte/extras` to be installed.
### Choose the packages you want to use
[See this comment](https://github.com/threlte/threlte/issues/8#issuecomment-1024085864) for tips
on how to reduce bundle size when working with bundlers like Vite and Three.js.
---
## Your First Scene
Category: Getting Started
URL: https://threlte.xyz/docs/learn/getting-started/your-first-scene
Understanding Svelte and Three.js is important when using Threlte. If you're new to Svelte, start
with the [official tutorial](https://svelte.dev/tutorial). If you're new to Three.js, check the
[official documentation](https://threejs.org) and guides.
## Structuring your app
First we create a new Svelte file, `App.svelte`, where we import [``](/docs/reference/core/canvas).
```svelte title="App.svelte"
```
The `` component is the root of a Threlte app: it creates a renderer and a default camera,
sets sensible defaults (like antialiasing and color management),
and provides Threlte's runtime context. To access this runtime context, we'll need to create a separate component
called `Scene.svelte` and include it in our `App.svelte` file.
## Creating objects
At this point we're just looking at a blank screen. Let's add a simple cube to it.
In `Scene.svelte`, we import the [`` component](/docs/reference/core/t), which is
the **main building block** of your Threlte application. It's **a thin, generic wrapper for any Three.js class**.
Here we'll create a
[`THREE.Mesh`](https://threejs.org/docs/index.html#api/en/objects/Mesh) with
a [`THREE.BoxGeometry`](https://threejs.org/docs/index.html#api/en/geometries/BoxGeometry) and
a [`THREE.MeshBasicMaterial`](https://threejs.org/docs/index.html#api/en/materials/MeshBasicMaterial).
We should now see a white cube on a transparent background.
```svelte title="Scene.svelte" {1-8}+
```
Behind the scenes we're using the property `attach` available on `` to **attach an object to a property of
its parent**. Binding geometries to the property `geometry` and materials to the property `material` is a common
pattern so Threlte takes care of it for you.
Learn more
We're using the property `attach` available on `` to
**attach an object to a property of its parent**. In our case we're **attaching** the underlying Three.js
object of `` to the property `geometry` of the `` component. We're also attaching
the underlying Three.js object of `` to the property `material` of the `` component.
```svelte title="Scene.svelte"
```
Binding geometries to the property `geometry` and materials to the property `material` is a common
pattern so Threlte will take care of it. It checks for the properties `isMaterial` and `isGeometry` on
the underlying Three.js object and attaches it to the correct property.
Three.js equivalent
```typescript
// creating the objects
const geometry = new THREE.BoxGeometry()
const material = new THREE.MeshBasicMaterial()
const mesh = new THREE.Mesh()
// "attaching" the objects
mesh.geometry = geometry
mesh.material = material
```
## Modifying objects
That cube is still a bit boring. Let's give it some color,
scale it up, and move it slightly upward. We can do this by
passing props to ``.
```svelte title="Scene.svelte" {5-7}m
```
Threlte automatically generates props for `` based on the underlying Three.js object. This means you can easily guess most `` props
based on the Three.js docs for the class you are using.
Three.js equivalent
```ts
const mesh = new THREE.Mesh()
const geometry = new THREE.BoxGeometry(1, 2, 1)
const material = new THREE.MeshBasicMaterial()
mesh.position.y = 1
material.color.set('hotpink')
```
The special **args** prop we use in `` corresponds to the
object's constructor arguments. Props interpreted from the underlying Three.js
object are called **auto props**, like `color` in our ``.
Leveraging Threlte's **Pierced Props**, you can directly assign to attributes
of props like `position.y` in our ``.
Learn more
#### `args`
In Three.js objects are classes that are instantiated. These classes can
receive one-time constructor arguments (`new THREE.SphereGeometry(1, 32)`). In
Threlte, constructor arguments are always passed as an array via the prop
`args`. If `args` change later on, the object must naturally get reconstructed
from scratch!
#### Auto props
For all other props, Threlte tries to automatically interpret props passed to `` component.
**Step 1.** *Find Properties* - First, Threlte will try to find the **property
on the underlying Three.js object** based on the **name of the prop**. In our
example, [`color` is a property of
`THREE.MeshBasicMaterial`](https://threejs.org/docs/index.html#api/en/materials/MeshBasicMaterial.color).
**Step 2.** *Try `set` Methods* - Next, Threlte will look for a `set` method
on that property and use it to set the new value. In our example it will call
`material.color.set('hotpink')` to set the color of our material.
**Step 3.** *Try setting the property directly* - If there's no `set` method,
it will try to set the property directly. In our example, this equated to
`mesh.position.y = 1`.
**Step 4.** *Check for array values* - When setting a property that accepts
more than one value (such as a `THREE.Vector3`: `vec3.set(1, 2, 3)`), we can
pass an array as a prop.
**Step 5.** *Keep the prop type constant for the lifetime of the component* -
If the prop value changes, Threlte will try to set the property again. If the
type of the prop value changes, Threlte won't be able to reliably do that. For
instance the type of the value of a variable that is used as a prop should not
change from a single number to an array of numbers.
#### Pierced props
Because the property `position` of our `THREE.Mesh` is a `THREE.Vector3`, it
also has `x`, `y` and `z` properties which we can set directly via
dot-notation, we call this **Pierced Props**.
From a performance perspective, it's often better to use pierced props because
[primitive](https://developer.mozilla.org/en-US/docs/Glossary/Primitive) prop values can safely be
compared for equality. This means that if the value of a prop doesn't change, Threlte will skip
any updates to the underlying Three.js object.
The type of an inferred prop (or "auto prop") must be constant. This means that the type of a prop
must not change for the lifetime of the component. For instance you can't use a variable as a prop
that is an array of numbers and then later on change the value of that variable to a single
number. This is considered a type change and therefore not allowed.
## Pointing the camera
We now want to view our cube with some perspective. To manipulate the default camera, let's add the following:
```svelte title="Scene.svelte" {5-11}+
{
ref.lookAt(0, 1, 0)
}}
/>
```
We're again using the `` component to create a [`THREE.PerspectiveCamera`](https://threejs.org/docs/index.html#api/en/cameras/PerspectiveCamera).
We're also passing a `makeDefault` prop which will make this camera the default camera of our application.
The renderer now uses this camera to render our scene.
Threlte supports listening to certain events on ` ` components . Here, we use the `create`
event to get a reference to the underlying Three.js object as soon as it's created and use the method `lookAt` to look at the cube.
## Enabling interactivity
Let's say we want to scale our cube as soon as we hover over it. We first have to import the
[`interactivity`](/docs/reference/extras/interactivity) [plugin](/docs/learn/advanced/plugins) from
[`@threlte/extras`](/docs/reference/extras/getting-started) and invoke it in our `Scene.svelte` file.
The `interactivity` plugin lets us add interaction event listeners like `pointerenter` and
`pointerleave` to our `` components. In these event handlers we'll update the value of a `Spring` from `svelte/motion`
and use its `.current` value to set the `scale` property of the `` component.
```svelte title="Scene.svelte" {3-4,6-7,20-26}+
{
ref.lookAt(0, 1, 0)
}}
/>
{
scale.target = 1.5
}}
onpointerleave={() => {
scale.target = 1
}}
>
```
You might have noticed that we're only passing a single number to the prop `scale` on ``. Threlte automatically
figures out whether you are passing an array or a number and uses the appropriate underlying Three.js method.
Learn more
The component `` will first look for a property `setScalar` on the underlying Three.js object and use that method if
only a single number is passed. This is equivalent to calling `scale.setScalar(scale.current)`.
When working with realtime apps where variables e.g. position and rotation change constantly, an
easy way observe the values is with [live
expressions](https://developer.chrome.com/docs/devtools/console/live-expressions/).
## Adding animation
Let's add some motion to our cube. We will use Threlte's [`useTask`](/docs/reference/core/use-task) hook to tap
into Threlte's **unified frame loop** and run a function on every frame. We again use a Pierced Prop to let the
cube rotate around its y-axis.
```svelte title="Scene.svelte" {2}m {10-13,25}+
{
ref.lookAt(0, 1, 0)
}}
/>
{
scale.target = 1.5
}}
onpointerleave={() => {
scale.target = 1
}}
>
```
`useTask` registers a callback that will be invoked on every frame. The callback receives the time delta since the last frame as an argument. We use
the delta to update the rotation
[independent of the frame rate](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame)
– the cube will rotate at the same speed regardless of the frame rate.
## Adjusting the lighting
We're almost done. Let's add some shading to our cube and a light source. We'll use a
`THREE.MeshStandardMaterial` on our cube and a `THREE.DirectionalLight` to illuminate our scene.
```svelte title="Scene.svelte" {38}m {24}+
{
ref.lookAt(0, 1, 0)
}}
/>
{
scale.target = 1.5
}}
onpointerleave={() => {
scale.target = 1
}}
>
```
## Casting shadows
We would like our cube to cast a shadow. To do so, we need a floor for it to cast a shadow _on_,
so we add a new `` but this time with ``. To enable shadows, we need to
set `castShadow` on both the light and our cube, and set `receiveShadow` on our new floor:
```svelte title="Scene.svelte" {26,39,45-51}+
{
ref.lookAt(0, 1, 0)
}}
/>
{
scale.target = 1.5
}}
onpointerleave={() => {
scale.target = 1
}}
castShadow
>
```
## Conclusion
Congratulations, you've just created your first Three.js scene with Threlte! It includes important
Three.js and Threlte concepts and should give you a good starting point for your first Threlte project.
---
## Resources
Category: More
URL: https://threlte.xyz/docs/learn/more/resources
The Three.js community is constantly evolving and expanding. Whether you are a beginner
looking to get started or an experienced developer seeking advanced knowledge,
there are available resources that offer a wealth of information and technologies to help.
## Threlte's underlying libraries
The following libraries are foundational to understanding Threlte's architecture, functionalities and packages:
- [Three.js](https://threejs.org/) - 3D graphics on the web. Three.js serves as the backbone for rendering and creating 3D scenes in Threlte.
- [Rapier](https://www.rapier.rs/) - A library for real-time physics simulations. Rapier helps bring your Threlte projects to life with dynamic interactions.
- [Theatre.js](https://www.theatrejs.com/) - Focuses on timeline-based animations and offers intricate control over complex animations, making it easier to manage complex state changes in Threlte.
## General
- [Three.js Resources](https://threejsresources.com/) - A hub for all things 3D. From tools to textures, lighting & more.
## Shaders
GLSL (Graphics Library Shader Language) is a critical part of shader programming, which is central to achieving high-quality visual effects in Threlte.
- [The Book of Shaders](https://thebookofshaders.com/) - This resource breaks down complex shader programming into bite-sized lessons. A great starting point for anyone new to shaders.
- [Learn OpenGL](https://learnopengl.com/) - An in-depth resource for learning OpenGL and GLSL, covering topics from beginner to advanced levels. Learn OpenGL offers tutorials that are easily applicable to Threlte's context.
We hope you find these resources valuable in your journey to mastering Threlte. Happy Learning!
# Reference
---
## Getting Started
Package: @threlte/flex
URL: https://threlte.xyz/docs/reference/flex/getting-started
Placing content and making layouts in 3D is hard. The flexbox engine
[`Yoga`](https://yogalayout.com/) is a cross-platform layout engine which
implements the flexbox spec. The package `@threlte/flex` provides components to
easily use `Yoga` in Threlte.
MatCap textures from https://github.com/emmelleppi/matcaps
## Installation
```bash
npm install @threlte/flex
```
## Usage
### Basic Example
Use the component [``](/docs/reference/flex/flex) to create a flexbox
container. Since there's no viewport to fill, you must specify the size of the
container. Add flex items with the component [``](/docs/reference/flex/box).
```svelte
```
### Flex Props
The components `` and `` accept props to configure the flexbox. If no
width or height is specified on `` components, a bounding box is used to
determine the size of the flex item. The computed width or height may be
different from what is specified on the `` component, depending on the
flexbox configuration. To make use of the calculated dimensions of a flex item, use the slot props `width` and `height`.
```svelte
{#snippet children({ width, height })}
{/snippet}
{#snippet children({ width, height })}
{/snippet}
```
### Nested Flex
Every `` component is also a flex container. Nesting `` components
allows you to create complex layouts.
```svelte
{#snippet children({ width, height })}
{#snippet children({ width, height })}
{/snippet}
{#snippet children({ width, height })}
{/snippet}
{/snippet}
{#snippet children({ width, height })}
{/snippet}
```
### Align Flex Container
The component [``](/docs/reference/extras/align) can be used to align the resulting flex container.
```svelte
{#snippet children({ align })}
{/snippet}
```
### Using the Prop `class`
The prop `class` can be used on `` and `` to easily configure the
flexbox with predefined class names just as you would do in CSS. In order to use
the prop, you need to create a `ClassParser` using the utility
[`createClassParser`](/docs/reference/flex/create-class-parser) which accepts a
single string and returns `NodeProps`. Let's assume, you want to create a parser
that supports the following class names:
```css
.container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
gap: 10px;
padding: 10px;
}
.item {
width: auto;
height: auto;
flex: 1;
}
```
You then need to create a `ClassParser` which returns the corresponding props:
```ts
import { createClassParser } from '@threlte/flex'
const classParser = createClassParser((string, props) => {
const classNames = string.split(' ')
for (const className of classNames) {
switch (className) {
case 'container':
props.flexDirection = 'Row'
props.justifyContent = 'Center'
props.alignItems = 'Stretch'
props.gap = 10
props.padding = 10
break
case 'item':
props.width = 'auto'
props.height = 'auto'
props.flex = 1
}
}
return props
})
```
Now you can use the prop `class` on `` and `` to configure the flexbox:
```svelte
```
`@threlte/flex` ships with a [default `ClassParser` which supports Tailwind-like
class names](/docs/reference/flex/tailwind-parser).
---
## Getting Started
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/getting-started
The package `@threlte/xr` provides tools and abstractions to more easily create
VR and AR experiences.
## Installation
```bash title="Terminal"
npm install @threlte/xr
```
## Usage
### Setup
The following adds a button to start your session and controllers inside an XR
manager to prepare your scene for WebXR rendering and interaction.
```svelte title="Scene.svelte" {3,11}+
```
Then, in `scene.svelte`:
```svelte
```
This will set up your project to be able to enter a VR session with controllers
and hand inputs added.
If you want hands, controllers, or any other objects to be added to your
`THREE.Scene` only when the XR session starts, make them children of the ``
component:
```svelte
```
The ``, ``, and `` components can provide a powerful
foundation when composed with other Threlte components.
### HTML
HTML cannot be rendered inside an XR environment, this is just a limitation of
the WebXR API. An alternative approach for creating an HTML-like UI within your
XR session is to use the
[threlte-uikit](https://github.com/michealparks/threlte-uikit) package.
---
## Getting Started
Package: @threlte/core
URL: https://threlte.xyz/docs/reference/core/getting-started
The package `@threlte/core` is the core package of the Threlte framework. It provides the basic
functionality of the framework, such as the `` and `` components, and hooks to interact
with the Threlte state.
## Installation
```bash title="Terminal"
npm install @threlte/core three @types/three
```
## Usage
Every Threlte application must be wrapped in a [`` component](/docs/reference/core/canvas). This component is responsible
for creating `THREE.WebGLRenderer` and providing a state for every child component.
```svelte title="App.svelte"
```
The main building block of a Threlte application is the [`` component](/docs/reference/core/t). Use this component to instantiate
any Three.js object available in the `THREE` namespace.
```svelte title="Scene.svelte"
{
ref.lookAt(0, 0, 0)
}}
/>
```
---
## Examples
Package: @threlte/flex
URL: https://threlte.xyz/docs/reference/flex/examples
The package `@threlte/flex` is well suited for building responsive layouts.
Especially in an XR context, where using the [DOM is (currently) not
possible](https://www.w3.org/TR/webxr-dom-overlays-1/) you have to rely on
solutions that are native to WebGL.
The following examples show how to use the `@threlte/flex` package to build
responsive layouts in WebGL.
The left side is the CSS implementation, the right side is using `@threlte/flex`.
---
##
Package: @threlte/core
URL: https://threlte.xyz/docs/reference/core/canvas
The `` component is the root of your Threlte scene. It provides contexts
that all other components and many hooks depend on. This means they need to be
**child components** to the `` component.
Check out our [guide on structuring your app](/docs/learn/basics/app-structure) for a fail-safe
app architecture recipe.
## Size
By default, the `` (the **DOM element** inside ``) that is being
rendered into takes up 100% of the width and height of its parent element and
reacts to changes in the parent element's size. This means that – simply put –
you define the size of the `` element by layouting the parent element.
```svelte title="App.svelte"
```
When taking the parent's size into account, [`offsetWidth` and
`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements#how_much_room_does_it_use_up)
are used.
## DOM reference
The context provided by the `` component contains a `dom` element. It
refers to the DOM element that a particular view is rendered into. In the most
common case, this is the wrapper of the `canvas` element provided by Threlte.
---
##
Package: @threlte/flex
URL: https://threlte.xyz/docs/reference/flex/flex
The component `` is used to create the root of a flex layout. It creates
the root node for [Yoga](https://yogalayout.com) and provides a context for all
child [``](/docs/reference/flex/box) components to resolve their layout.
## Usage
The `` component resembles the root `display: flex` container in CSS. It
can be used to create a flex layout with the child components ``.
Since there's no viewport to fill, you must specify the size of the container
with the props `width` and `height`.
```svelte
```
### Layout Direction
Layout direction specifies the direction in which children and text in a
hierarchy should be laid out. Layout direction also effects what edge `start` and
`end` refer to. By default Yoga lays out with LTR layout direction.
```svelte
```
### Layout precision
Yoga uses integers for layout computation. Because in Three.js we're dealing
with floating point numbers, all values are internally multiplied by a
`scaleFactor` of `1000` to increase precision which is suitable for most use
cases. Depending on the size of your layout, you might need to increase the
`scaleFactor` to `10000` or `100000` to avoid layout issues.
```svelte
```
### Using CSS Classes
A `classParser` can be used to resolve Yoga Node Props based on classes passed
to `` and `` components. This is useful if you want to use a CSS-like
syntax to define your layout. You can define your own `ClassParser` using the
method [`createClassParser`](/docs/reference/flex/create-class-parser) or by
using a parser provided, for instance the Tailwind CSS parser
[`tailwindParser`](/docs/reference/flex/tailwind-parser).
```svelte
```
### Layout Orientation
Yoga computes the layout on a 2D plane. The elements will be positioned in the
2D plane given by the two axes. By default, the layout plane is the `xy` plane.
You can change the layout plane to `yz` or `xz` by setting the prop `plane`.
```svelte
```
### Layout Reflow
[Yoga](https://yogalayout.com) is a layout engine that computes the layout of a
node tree. If a node (i.e. a [``](/docs/reference/flex/box) component) is added or removed
from the tree, or if a node changes its properties, the layout of the component
tree needs to be recomputed. This is called a **reflow**.
A reflow is triggered automatically when:
- `` props changes (`width`, `height`, `justifyContent`, …)
- `` props changes (`justifyContent`, `flex`, …)
- A `` component mounts or unmounts
Because the width and height of a flex layout item may be calculated from its
bounding box, the initial layout may be incorrect, for instance if a model loads
into view after the initial layout has been computed. To manually request a
reflow, you can use the snippet prop `reflow`:
```svelte
{#snippet children({ reflow })}
reflow()}
/>
{/snippet}
```
The `reflow` snippet prop is also available on `` components to enable
encapsulated child components to easily request a reflow.
You may also use the hook [`useReflow`](/docs/reference/flex/use-reflow) to request
a reflow.
### Reflow Stage
By default, the reflow of the layout is happening in [Threlte's
mainStage](/docs/learn/basics/scheduling-tasks#default-stages). To change in
what stage the layout should reflow, use the prop `reflowStage`:
```svelte
```
### Content Dimensions
Although the width and the height of the `` component are required, the
**dimensions of the contents** of the `` component will be measured after a
[layout reflow](#layout-reflow) and can be retrieved using the following methods:
- Using the hook [`useDimensions`](/docs/reference/flex/use-dimensions)
- Using the snippet props `width` and `height`
```svelte
{#snippet children({ width, height })}
{/snippet}
```
- Using the `reflow` event
```svelte
{
console.log(width, height)
}}
>
```
---
## Getting Started
Package: @threlte/gltf
URL: https://threlte.xyz/docs/reference/gltf/getting-started
A small command-line tool that turns GLTF assets into declarative and re-usable Threlte components.
## The GLTF workflow on the web is not ideal.
- GLTF is thrown wholesale into the scene which prevents re-use, in Three.js objects can only be mounted once
- Contents can only be found by traversal which is cumbersome and slow
- Changes to queried nodes are made by mutation, which alters the source data and prevents re-use
- Re-structuring content, making nodes conditional or adding/removing is cumbersome
- Model compression is complex and not easily achieved
- Models often have unnecessary nodes that cause extra work and matrix updates
## `@threlte/gltf` fixes that.
- It creates a **virtual graph** of all objects and materials. Now you can easily alter contents and re-use.
- The graph gets pruned (empty groups, unnecessary transforms, ...) for **better performance**.
- It will optionally compress your model with up to **70%-90% size reduction**.
## Usage
```bash
npx @threlte/gltf@latest /path/to/Model.glb [options]
```
You can also use `pnpm dlx`, `bunx`, or any other package runner.
### Options
| Option | Description |
| --------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `--output, -o` | Output file name/path |
| `--types, -t` | Add Typescript definitions |
| `--keepnames, -k` | Keep original names |
| `--keepgroups, -K` | Keep (empty) groups, disable pruning |
| `--meta, -m` | Include metadata (as `userData`) |
| `--shadows, -s` | Let meshes cast and receive shadows |
| `--printwidth, -w` | Prettier `printWidth` (default: 120) |
| `--precision, -p` | Number of fractional digits (default: 2) |
| `--draco, -d` | Draco binary path |
| `--preload -P` | Add preload method to module script |
| `--suspense -u` | Make the component [suspense-ready](/docs/reference/extras/suspense) |
| `--isolated, -i` | Output as isolated module (no prop spreading) |
| `--root, -r` | Sets directory from which .gltf file is served |
| `--transform, -T` | Transform the asset for the web (draco, prune, resize) |
| `--resolution, -R` | Transform resolution for texture resizing (default: 1024) |
| `--keepmeshes, -j` | Do not join compatible meshes |
| `--keepmaterials, -M` | Do not palette join materials |
| `--format, -f` | Texture format (default: "webp") |
| `--simplify, -S` | Transform simplification (default: false, experimental) |
| `--weld` | Weld tolerance (default: 0.0001) |
| `--ratio` | Simplifier ratio (default: 0.75) |
| `--error` | Simplifier error threshold (default: 0.001) |
| `--debug, -D` | Debug output |
## Example
This example assumes you have your model set up and exported from an application like
[Blender](https://www.blender.org/) as a GLTF file.
First, run your model through `@threlte/gltf`. `npx` allows you to use npm
packages without installing them.
```bash
npx @threlte/gltf@latest model.glb --transform
```
This will create a `Model.svelte` file that plots out all of the assets
contents.
```svelte
{#await gltf}
{@render fallback?.()}
{:then gltf}
{:catch err}
{@render error?.({ error: err })}
{/await}
{@render children?.({ ref })}
```
Add your model to your `/static` folder as you would normally do. With the
`--transform` flag it has created a compressed copy of it (in the above case
`model-transformed.glb`). Without the flag just copy the original model.
```text
static/
model-transformed.glb
```
The component can now be dropped into your scene.
```svelte
```
You can re-use it, it will re-use geometries and materials out of the box:
```svelte
```
Or make the model dynamic. Change its colors for example:
```svelte
```
Or exchange materials:
```svelte
```
Make contents conditional:
```svelte
{#if condition}
{/if}
```
## DRACO Compression
You don't need to do anything if your models are draco compressed, since
`useGltf` defaults to a [draco CDN](https://www.gstatic.com/draco/v1/decoders/).
By adding the `--draco` flag you can refer to [local
binaries](https://github.com/mrdoob/three.js/tree/dev/examples/jsm/libs/draco/gltf)
which must reside in your /public folder.
## Auto-Transform
With the `--transform` flag it creates a binary-packed, draco-compressed,
texture-resized (1024x1024), webp compressed, deduped and pruned
\*.glb ready to be consumed on a web site. It uses
[glTF-Transform](https://github.com/donmccurdy/glTF-Transform). This can reduce
the size of an asset by 70%-90%.
It will not alter the original but create a copy and append
`[modelname]-transformed.glb`.
## Type-Safety
Add the `--types` flag and your component will be typesafe.
```svelte
{#await gltf}
{@render fallback?.()}
{:then gltf}
{:catch err}
{@render error?.({ error: err })}
{/await}
{@render children?.({ ref })}
```
## Animations
If your GLTF contains animations it will add [@threlte/extras's
`useGltfAnimations`](/docs/reference/extras/use-gltf-animations) hook, which
extracts all clips and prepares them as actions:
```ts
const gltf = useGltf('/stacy.glb')
export const { actions, mixer } = useGltfAnimations(gltf, ref)
```
If you want to play an animation you can do so at any time:
```ts
const onEvent = () => {
$actions.jump.play()
}
```
## Skinned Meshes
`useGltf` caches results by URL. This means all instances of a generated
component share the same geometry, materials, skeletons, and bones. For regular
meshes this is ideal — geometry and materials can be shared across instances
without duplicating GPU memory.
However, `SkinnedMesh` bones and skeletons are `Object3D` instances that can
only have one parent at a time. If you mount multiple instances of a component
that contains skinned meshes, only the last one will render correctly because it
"steals" the shared bones from previous instances.
`@threlte/gltf` handles this automatically. When your model contains skinned
meshes, the generated component uses
[`SkeletonUtils.clone`](https://threejs.org/docs/#examples/en/utils/SkeletonUtils)
to clone the bone hierarchy per instance while still sharing geometry and
materials from the cache:
```svelte
{:then gltf}
{@const clonedNodes = cloneScene(gltf.scene)}
{/then}
```
This gives each component instance its own skeleton and bones, while geometry and
materials remain shared — no duplicated GPU memory.
Model:
[RobotExpressive](https://github.com/mrdoob/three.js/tree/dev/examples/models/gltf/RobotExpressive)
from the Three.js examples
## Suspense
If you want to use the component [``](/docs/reference/extras/suspense)
to suspend the rendering of loading components (and therefore models) and
optionally show a fallback in a parent component, you can do so by
passing the flag `--suspense` to make the generated Threlte component
_suspense-ready_:
```svelte
{#snippet fallback()}
{/snippet}
```
## Asset Pipeline
In larger projects with a lot of models and assets, it's recommended to set up
an asset pipeline with tools like
[`npm-watch`](https://www.npmjs.com/package/npm-watch) and Node.js scripts to
automatically transform models to Threlte components and copy them to the right
place as this makes iterating over models and assets much faster. Here's an
example script that you can use as a starting point:
```ts
import { execSync } from 'node:child_process'
import { existsSync, mkdirSync, readdirSync } from 'node:fs'
import { join, parse, resolve } from 'node:path'
/**
* Transforms GLTF/GLB files into Threlte components using @threlte/gltf.
* Source models are read from sourceDir, and generated Svelte components
* are written directly to targetDir via the --output flag.
*/
const config = {
sourceDir: resolve('static', 'models'),
targetDir: resolve('src', 'lib', 'components', 'models'),
overwrite: true,
root: '/models/',
types: true,
keepnames: true,
meta: false,
shadows: false,
printwidth: 120,
precision: 2,
draco: '',
preload: false,
suspense: false,
isolated: true,
transform: {
enabled: false,
resolution: 1024,
format: 'webp',
keepmeshes: false,
keepmaterials: false,
simplify: {
enabled: false,
weld: 0.0001,
ratio: 0.75,
error: 0.001
}
}
}
mkdirSync(config.targetDir, { recursive: true })
if (!existsSync(config.sourceDir)) {
throw new Error(`Source directory ${config.sourceDir} doesn't exist.`)
}
const gltfFiles = readdirSync(config.sourceDir).filter((file) => {
return (
(file.endsWith('.glb') || file.endsWith('.gltf')) &&
!file.endsWith('-transformed.gltf') &&
!file.endsWith('-transformed.glb')
)
})
if (gltfFiles.length === 0) {
console.log('No gltf or glb files found.')
process.exit()
}
for (const file of gltfFiles) {
const inputPath = join(config.sourceDir, file)
const outputPath = join(config.targetDir, `${parse(file).name}.svelte`)
if (!config.overwrite && existsSync(outputPath)) {
console.log(`${outputPath} already exists, skipping.`)
continue
}
const args: string[] = [`--output ${outputPath}`]
if (config.root) args.push(`--root ${config.root}`)
if (config.types) args.push('--types')
if (config.keepnames) args.push('--keepnames')
if (config.meta) args.push('--meta')
if (config.shadows) args.push('--shadows')
args.push(`--printwidth ${config.printwidth}`)
args.push(`--precision ${config.precision}`)
if (config.draco) args.push(`--draco ${config.draco}`)
if (config.preload) args.push('--preload')
if (config.suspense) args.push('--suspense')
if (config.isolated) args.push('--isolated')
if (config.transform.enabled) {
args.push('--transform')
args.push(`--resolution ${config.transform.resolution}`)
args.push(`--format ${config.transform.format}`)
if (config.transform.keepmeshes) args.push('--keepmeshes')
if (config.transform.keepmaterials) args.push('--keepmaterials')
if (config.transform.simplify.enabled) {
args.push('--simplify')
args.push(`--weld ${config.transform.simplify.weld}`)
args.push(`--ratio ${config.transform.simplify.ratio}`)
args.push(`--error ${config.transform.simplify.error}`)
}
}
const cmd = `npx @threlte/gltf@latest ${inputPath} ${args.join(' ')}`
try {
execSync(cmd, { cwd: config.sourceDir })
console.log(`Generated ${outputPath}`)
} catch (error) {
console.error(`Error transforming ${file}: ${error}`)
}
}
```
Place this script in `scripts/transform-models.ts` and run it with `npx tsx scripts/transform-models.ts`.
---
## Getting Started
Package: @threlte/rapier
URL: https://threlte.xyz/docs/reference/rapier/getting-started
[Rapier](https://rapier.rs/) is a fast physics engine written in Rust. This package provides easy to use components and hooks to use the Rapier physics engine in Threlte.
To start off, it's best to get yourself comfortable with the [basic concepts of rapier](https://rapier.rs/docs/).
This package is under heavy development and its API is subject to change. Also be aware that
currently only one Rapier-enabled Threlte instance is possible.
### Installation
Make sure to have `@threlte/core` installed.
```bash copy
npm install @threlte/rapier @dimforge/rapier3d-compat
```
---
## Getting Started
Package: @threlte/studio
URL: https://threlte.xyz/docs/reference/studio/getting-started
Threlte Studio is a **spatial programming toolset**.
It consists of two main parts: A GUI to inspect and edit your scene and a
vite plugin to sync the changes in real-time to your code. It is made to be
[extendable](./authoring-extensions), so you can create your own custom
components to interact with your scene and hook into the Threlte Studio API and
GUI.
## Installation
```bash copy
npm install @threlte/studio
```
## Quick Start
To get started, encapsulate your whole scene in the [``](./studio) component.
```svelte title=App.svelte {3,8,10}+
```
To use auto-sync, in your vite config, insert the Threlte Studio vite plugin
**before any other plugin**.
```js title=vite.config.js {2}+ {5}m
import { sveltekit } from '@sveltejs/kit/vite'
import { threlteStudio } from '@threlte/studio/vite'
export default {
plugins: [threlteStudio(), sveltekit()]
}
```
## Tips and Tricks
### Hiding from the hierarchy tree
To hide items from showing in the scene hierarchy pane, add `hideInTree` to
your object's userData.
```svelte
```
### Selectable objects
Scene objects are selectable by default. If you add `selectable` to your
objects userData and set it to `false` that object wont be selectable.
```svelte
```
---
## Getting Started
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/getting-started
[Theatre.js](https://www.theatrejs.com/) is a javascript animation library with a professional motion design toolset. It helps you create any animation, from cinematic scenes in 3D, to delightful UI interactions.
### Concepts
The `@threlte/theatre` documentation cross-references [the Theatre.js documentation](https://www.theatrejs.com/docs/latest), allowing quick reference to the underlying concepts.
### Workflow
Theatre.js combines programming in your IDE with editing in a browser-based GUI. The core workflow looks something like this:
1. **Create** your scene as usual, placing a `` and one or more `` in your ``.
2. **Identify** the elements and props you wish to edit in the ``, and place an `` component around them, then use the slotted components ``, `` or `` to add editable props.
3. **Edit** props and animations of elements in the `` in the browser; [config state](https://www.theatrejs.com/docs/latest/manual/projects#state) is autosaved to local storage.
4. **Export** the updated state [as a JSON file](https://www.theatrejs.com/docs/latest/manual/projects#state) by selecting your project in the studio and clicking export (top-right corner).
5. **Import** your scene's `state.json` and use it in your ``'s `config` prop.
### Installation
```bash copy
npm install @threlte/theatre @theatre/core @theatre/studio
```
### Quick Start
To get started quickly, encapsulate your whole scene in the component [``](./theatre).
The component `` provides a default [``](/theatre/project) and [``](/theatre/sheet) and implements [``](/theatre/studio). For a more flexible structure please consider using ``, `` and `` on their own.
```svelte title=App.svelte {3,8,10}+
```
In your Scene, add the component `` as a parent of any component you'd wish to edit or animate. The component `` provides the components ``, `` and `` that allow you to manipulate properties in Theatre.js based on your Threlte markup.
The component `` is a shortcut to add `position`, `scale` and `rotation` at once as
well as mount handy `` whenever the respective Sheet Object is selected in the studio.
```svelte title=Scene.svelte
{#snippet children({ Transform, Sync })}
{/snippet}
```
You will now see the Theatre.js studio interface. Make yourself comfortable with the controls and if you haven't done yet, please read the Theatre.js [studio manual](https://www.theatrejs.com/docs/0.5/manual/Studio) and [keyboard shortcuts](https://www.theatrejs.com/docs/0.5/manual/keyboard-shortcuts).
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/xr
The `` component prepares your scene for a WebXR session. It sets up context that is provided by the [`useXR`](/docs/reference/xr/use-xr) hook.
## Usage
```svelte
```
The `` component will set the [``](/docs/reference/core/canvas) property `renderMode="always"` when the user enters an XR session, due to being incompatible with `on-demand` or `manual`. It will set the original value once the session has ended.
Any children of the `` component will not mount until the user enters an immersive session. This is useful for adding controllers, hands, or entire scenes that should only start when the user has begun their session.
## Fallback
XR sessions have to be requested actively and you might want to show contents to the user before they have entered an immersive session. You can use the `fallback` snippet to show a fallback scene to the user.
```svelte
{#snippet fallback()}
{/snippet}
```
---
## Physics Framerate
Package: @threlte/rapier
URL: https://threlte.xyz/docs/reference/rapier/framerate
import frameRate1 from './framerate-1.svg?url'
import frameRate2 from './framerate-2.svg?url'
Threlte's `` component has a `framerate` prop that can be used to control
the framerate of the physics simulation.
## `requestAnimationFrame` Timing
By default, the physics framerate is set to vary depending on the timestamp
passed as the argument to the callback of `requestAnimationFrame`. Take this
trivial example:
```ts
const render = (time: number) => {
console.log(time)
requestAnimationFrame(render)
}
requestAnimationFrame(render)
```
Unlucky for us, the time delta between frames varies depending on several
factors such as the refresh rate of the monitor and the general load of your
computer or application. When using a `varying` framerate, this time delta is
used to _advance the physics simulation_ and while you would think that this
wouldn't make much of a difference, computers are really bad at floating point
arithmetic (`console.log(0.1 + 0.2)`): Realistically no two executions of the
same physics simulation will yield the same result. In short: it's **not
deterministic**.
For most applications, this is still the best choice since it doesn't require
you to think about the aspects of handling different framerates for physics and
rendering.
Sometimes, however, whether you're developing a game or wish to have more
control art directing the outcome, you want a physics simulation to **always
yield the same result**, e.g. to be **deterministic**. In this case, you can set
the `framerate` prop to a fixed number. A fixed framerate of `50` for example
will _step_ the physics simulation 50 times per second with a delta of exactly
`1 / 50 = 0.02` seconds – no matter the timestamp passed to
`requestAnimationFrame`.
The following example illustrates the difference:
## Fixed Framerate
In order to efficiently use a fixed framerate, it's important to understand how
Threlte is able to advance the physics simulation in a deterministic fashion
while keeping the visual output smooth and in sync.
First, let's have a look at the timing of the `requestAnimationFrame` API:
In this example we're looking at two invokations of `requestAnimationFrame`.
- **A** receives a delta of 16.35ms
- **B** receives a delta of 16.1ms
Threlte is making use of [the scheduler's
ability](http://localhost:4321/docs/learn/basics/scheduling-tasks#creating-a-stage) to run the
tasks of a stage multiple times per frame and with a fixed delta.
We'd like to advance the physics simulation 200 times per second, so 5ms per step.
In this example, the physics simulation is advanced 4 times as part of
`requestAnimationFrame` **A**. The simulation then runs **ahead of the visual
output.** After advancing the physics simulation, the visual state of the
objects is rolled back from 20ms to 16.35ms while internally maintaining the
physics state of after the 4th simulation step.
This cycle repeats in the next frame **B**: The simulation is advanced 3 times
as part of `requestAnimationFrame` **B** in order to slightly run ahead of the
render time and subsequently rolled back to match the time of the render.
The following example visualizes how the framerate correlates with the physics
simulation running ahead of the visual output.
## `usePhysicsTask`
Use the hook [`usePhysicsTask`](/docs/reference/rapier/use-physics-task) to
interact with the physics simulation. It's a wrapper around the [`useTask`
hook](/docs/reference/core/use-task) that automatically adds the handler to the
`simulation` stage and always runs _before_ the physics world is stepped.
---
##
Package: @threlte/core
URL: https://threlte.xyz/docs/reference/core/t
The component `` provides the means to use **any Three.js export** as a
Svelte component. It does this by leveraging the rigid Three.js naming and
object property structure to add and remove objects to and from the scene graph,
attach objects to parent object properties or add event listeners.
`` is the main building block of any Threlte application. Components available in `'@threlte/extras'`
are built on top of `` and may provide a more convenient API for specific Three.js classes.
## Usage types
Primer on terminology
```ts
// Class definition:
class Mesh extends THREE.Object3D {
constructor(geometry, material) {
/* … */
}
}
// Creating a class instance:
const mesh = new Mesh()
// Creating a class instance with constructor arguments:
const mesh = new Mesh(geometry, material)
```
There are two ways to use ``:
- Use dot-notation to use any Three.js class imported from `'three'`:
```svelte
```
- Pass the property `is` to ``:
```svelte
```
Both ways are **equivalent and can be used interchangeably**. The latter is more
explicit and allows you to use any class definition (even if it's not a `'three'` import),
object instance or virtually any other value.
The next section will discuss both ways in more detail.
### Dot notation
Any Three.js class imported from `'three'` can be used
as a component with full type-safety. The name of the import is the same as the
name of the component. For example, the class `THREE.Mesh` can be used with the
component ``. Let's take a look at a simple example:
```svelte
```
Let's break this down:
- The component `` creates an instance of
[`THREE.Mesh`](https://threejs.org/docs/index.html?q=mesh#api/en/objects/Mesh)
which is automatically added to the scene graph.
- The component `` creates an instance of `THREE.BoxGeometry`
which is automatically ["attached"](#attach) to the property `geometry` of the
parent `THREE.Mesh`.
- The component `` creates an instance of
`THREE.MeshBasicMaterial` which is automatically ["attached"](#attach) to the
property `material` of the parent `THREE.Mesh`.
#### Extend the default component catalogue
If you want to use a class that is not a `'three'` import with Threlte's dot-notation,
you can extend the default component catalogue. Be aware that components used this way
do not offer type-safety. Once extended, the updated catalogue is available to all
components in your application.
```svelte title="Camera.svelte" {5-7}
{#snippet children({ ref })}
{/snippet}
```
### Property `is`
To explicitly pass a class definition to the component ``, use the property
`is`. Let's take a look at the same example as above but using the property
`is`:
```svelte
```
The two examples are **equivalent** and can be used interchangeably.
The "vanilla" Three.js equivalent of both examples would be:
```ts
import { Mesh, BoxGeometry, MeshBasicMaterial } from 'three'
const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial())
scene.add(mesh)
```
Using the property `is` comes in handy when using classes that are not exported
from Three.js' main namespace `'three'`, such as the `OrbitControls` class:
```svelte
```
#### What's happening under the hood?
If a **class definition** such as `THREE.Mesh` is provided to the property `is`,
it creates an instance of that class which we call `ref` – the component's
reference to the Three.js object:
```svelte
```
If a **class instance** (such as `new THREE.Mesh()`) or **any other value** is
provided, the component uses this value as-is:
```svelte
```
Depending on the `is` property value types, Threlte makes certain assumptions:
- If the value passed to `is` is extending `THREE.Object3D` it's added to the
scene graph.
- If the value passed to `is` is a disposable, it's disposed when the component unmounts or
whenever the `args` change and a new `ref` is created.
- If the value passed to `is` is has a property `addEventListener`, you can add
[event callbacks](#events).
- If the value passed to `is` is extending `THREE.Camera`, certain
[camera-related properties](#camera-props) are available.
## Props
The `` component has a set of fixed props (namely `args`, `is`, `attach`,
`manual`, `makeDefault` and `dispose`) that are used to set up the Three.js
object. On top of that, you can use arbitrary props to reactively set any
property of the underlying Three.js object.
### Three.js object props
To understand how it works, let's have a look at a simple example. Let's say we
want to render a simple cube. We can do this by using the `` component:
```svelte
```
Using automatic [**attach**](/docs/reference/core/t#attach), the geometry as
well as the material are assigned to the mesh. What if we want to change the
color of the material to `"red"`? We can do this by using the `color` prop:
```svelte {7}m
```
Keep in mind that this property is not _hard-wired_. We can use any property of
the underlying Three.js object as a prop on the `` component. For example, we
can also set the `position` property of the `THREE.Mesh`:
```svelte {5}m
```
Because the property `position` of a `THREE.Mesh` is a `THREE.Vector3` the value
we have to provide is what is passed to the [`set`
function](https://threejs.org/docs/index.html?q=mesh#api/en/math/Vector3.set) of
the `THREE.Vector3` class. In this case, we pass an array of three numbers (`[x,
y, z]`). Using an editor like VS Code, you benefit from type hints and
auto-completion.
We only changed the `y` coordinate of the position, so we can use a **pierced
prop** to only change the `y` coordinate:
```svelte {5}m
```
This way, we get less updates of the underlying Three.js object because the
value of the prop is a primitive value which can easily be compared to the
previous value. Unfortunately with pierced props we miss out on the type hints
and auto-completion.
The type of an inferred prop (or "auto prop") must be constant. This means that the type of a prop
must not change for the lifetime of the component. For instance you can't use a variable as a prop
that is an array of numbers and then later on change the value of that variable to a single
number. This is considered a type change and therefore not allowed.
### args
Three.js objects are **class instances**. When Instantiating these objects,
they can receive one-time constructor arguments (`new THREE.SphereGeometry(1,
32)`). In Threlte, constructor arguments are always passed as an array via the
property `args`. Changing `args` later on should be avoided as that will
reconstruct the class instance.
- If a **class definition** such as `THREE.BoxGeometry` is provided to the
property `is`, the property `args` is used to instantiate the class: `` equals `new BoxGeometry(1, 2, 1)`.
### attach
Use `attach` to _attach_ objects to other objects.
The following attaches a material to the material property of a mesh and a
geometry to the geometry property:
```svelte
```
All materials receive `attach="material"`, and all geometries receive `attach="geometry"`
automatically. You do not strictly have to type it out!
- The object referenced by the `` component is "attached" to the parent object's
property.
```svelte
```
- `attach` can be a dot-notated path to a nested parent property:
```svelte
```
- `attach` can also be a function which is called when the component is created.
This function receives the parent, the closest upstream parent
`THREE.Object3D` and the value inferred from the property `is` as arguments.
It can return a function which is called whenever the component is destroyed
or the `args` change and a new `ref` is created:
```svelte
{
console.log('attaching', ref, parent, parentObject3D)
parent.shadow.camera = ref
return () => {
parent.shadow.camera = null
}
}}
/>
```
- You may also pass an object3D instance to the `attach` prop. This allows you to
attach the object to a specific parent object, essentially acting as a portal.
```svelte
```
- To disable attaching, pass `false`. This is useful if you want to attach the
object manually:
```svelte
```
### Camera props
By default Threlte is responsive and will update camera properties (aspect ratio, etc.)
on resize. Cameras can be controlled manually by setting `manual` to
`true`. This will opt out of projection matrix recalculation when the drawing
area resizes or other camera-related properties change.
```svelte
```
Use the property `makeDefault` to set a camera to the default rendering camera.
```svelte
```
A common mistake is to forget setting `makeDefault`. If you do not set a camera to be the default
camera, the scene will not be rendered through this camera but through Threlte's default camera.
## Events
### Object events
Adding an event listener to a component will also add the corresponding event
listener to the Three.js class instance. The event will be forwarded and the
native payload is available as the first argument to the event listener.
This will listen to the "change" event on the `THREE.OrbitControls`:
```svelte
console.log('change:', e)}
/>
```
### Create event
All `` components also emit the `create` event when the underlying Three.js
class instance is created. This can be used to access the instance from the
parent component or do tasks on the objects upon creation. The event handler is
called with a reference to the object. You may return a cleanup callback. It
will be invoked when the component unmounts or when the object is
re-instantiated.
```svelte
{
// Look at the center
ref.lookAt(0, 0, 0)
return () => {
// Do something when the camera is disposed
}
}}
/>
```
### Interaction events
By default, `` doesn't have any click, pointer or wheel events; however,
pointer events can be enabled using the
[`interactivity`](/docs/reference/extras/interactivity) plugin.
## Snippet props
The object referenced by the component is available as the snippet prop `ref`:
```svelte
{#snippet children({ ref: camera })}
{/snippet}
```
## Bindings
The object referenced by the component is available as the binding `ref`:
```svelte
```
## Extending the default component catalogue
By default when using the dot-notation to access Three.js objects (e.g.
``), Threlte will automatically import the corresponding class from the
namespance `'three'`. If you want to use a custom class or classes from Three.js
that are available elsewhere (like `OrbitControls`), you can **extend the default
catalogue** with the `extend` function:
```svelte
```
### Custom component catalogue types
By default, TypeScript will not pick up custom custom items added to the
catalogue by using the `extend` function.
To extend the default catalogue types, define the `Threlte.UserCatalogue` type
in your ambient type definitions. In a typical SvelteKit application, you can
find these [in `src/app.d.ts`](https://svelte.dev/docs/kit/types#app.d.ts).
```ts title="src/app.d.ts"
import type { UserCatalogue } from '@threlte/core'
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
namespace Threlte {
interface UserCatalogue {
CustomMesh: typeof CustomMesh
}
}
}
export {}
```
## Plugins
The component `` can be extended in functionality with [Threlte
Plugins](/docs/reference/core/plugins).
### Custom prop types
Plugins may add custom props to the `` component. By default, these props are
not picked up by TypeScript.
To extend the types of the `` component and define custom prop types, define
the `Threlte.UserProps` type in your ambient type definitions. In a typical
SvelteKit application, you can find these type definitions [in
`src/app.d.ts`](https://svelte.dev/docs/kit/types#app.d.ts).
```ts title="src/app.d.ts"
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
namespace Threlte {
interface UserProps {
myProp?: string
}
}
}
export {}
```
```svelte
```
---
##
Package: @threlte/flex
URL: https://threlte.xyz/docs/reference/flex/box
The component `` creates a flexbox item. It can be used as a direct child
of [``](/docs/reference/flex/flex) or as a child of another `` to
create a nested flex layout.
## Usage
```svelte
{#snippet children({ width })}
{/snippet}
```
### Content Sizing
The `` component controls element positions only. However, if you wish to
handle element dimensions based on the layout calculated by Yoga, you'll need to
manually adapt the content's size. This is because `@threlte/flex` lacks
knowledge about the inner content's sizing mechanisms. For this purpose,
`@threlte/flex` offers the _computed dimensions_ in three ways:
- Using the `width` and `height` snippet props
```svelte
{#snippet children({ width, height })}
{/snippet}
```
- Using the [`useDimensions`](/docs/reference/flex/use-dimensions) hook in a child component to ``:
```svelte title="Child.svelte"
```
- Using the `reflow` event
```svelte
{
console.log(width, height)
}}
>
```
### Layout Reflow
To trigger a [layout reflow](/docs/reference/flex/flex#layout-reflow), you can use the `reflow` slot prop:
```svelte
{#snippet children({ reflow })}
{/snippet}
```
### Item Ordering
By default, the order of a flex item is determined by the order of insertion in
the component tree. If for any reason you need to change the order of a flex
item manually, you can use the `order` prop:
```svelte
```
---
##
Package: @threlte/rapier
URL: https://threlte.xyz/docs/reference/rapier/world
This component provides the basic physics context and loads [rapier](https://rapier.rs/).
All components that rely on physics (e.g. `` or ``) must be a child of ``.
## Structure
A typical structure of a physics-enabled wrapper component might look like this:
```svelte title="Wrapper.svelte"
```
This structure ensures that all components inside the component `` have access to the physics context.
## Fallback
[rapier](https://rapier.rs/) is a Rust-based physics engine and as such bundled and used as a WASM module. If loading of rapier fails for any reason, a slot with the name `fallback` is mounted to e.g. display a fallback scene without physics.
```svelte title="Wrapper.svelte"
{#snippet fallback()}
{/snippet}
```
---
## Deploying To Production
Package: @threlte/studio
URL: https://threlte.xyz/docs/reference/studio/deploying-to-production
## Common Pattern
Typically you would want to remove the Studio from your app in production. This
can be done by wrapping the Studio component in a conditional statement that
checks if the app is in development mode:
```svelte title=App.svelte
{#if import.meta.env.MODE === 'development'}
{#await import('@threlte/studio') then { Studio }}
{/await}
{:else}
{/if}
```
This way, the Studio will only be included in your app when it is in
[development mode](https://vitejs.dev/guide/env-and-mode.html#modes).
### Vite Plugin
The Threlte Studio vite plugin is only enabled in development mode.
---
##
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/theatre
The component `` is a convenience shortcut and provides a default `` and `` to get you set up as fast as possible. It also includes a `` which can be disabled with the property `studio`: ` `
### Example
The component `` is a good choice if you want to test the waters or to quickly spin up an experiment.
```svelte
{#snippet children({ Transform })}
{/snippet}
{#snippet children({ Transform })}
{/snippet}
```
---
##
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/project
Theatre.js work is organized into projects that group animation [\](./sheet)s.
Projects also provide the means to inject configuration state exported as a JSON file from the [\](./studio) back into your code through a prop: ``.
While multiple projects may be created, one is usually sufficient for a whole Threlte application.
#### Theatre.js Docs
**Project** | [Project Manual](https://www.theatrejs.com/docs/latest/manual/projects) | [Project API Reference](https://www.theatrejs.com/docs/latest/api/core#project)
### Creating a Project
```svelte
```
### Loading a Saved State
The state of a project edited in the [\](./studio) is saved in your browser's local storage, and can be [exported from within the studio interface](https://www.theatrejs.com/docs/latest/manual/projects#state). It's a JSON file containing all animated and static properties of all sheets of the project.
```svelte
```
---
##
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/sheet
Theatre.js sheets contain one or more Theatre.js objects and optionally a [``](/docs/reference/theatre/sequence) component that allows controlling the animation.
The animated objects can adjusted in the [``](/docs/reference/theatre/studio).
#### Theatre.js Docs
**Sheet** | [Sheet Manual](https://www.theatrejs.com/docs/latest/manual/sheets) | [Sheet API Reference](https://www.theatrejs.com/docs/0.5/api/core#sheet)
## Creating Sheets
You can create a sheet by placing the component `` as a child of a [``](/theatre/project) component. If a sheet with the given name already exists, it will represent the existing sheet instead of creating a new one.
```svelte
```
## Playing a Sheet's animation
Each Theatre.js sheet has a sequence attached to it. The sequence is the heart of the Theatre.js API: it determines where we are in the animation timeline, and
provides and API to play and pause the animation in a variety of ways.
#### Using the `` component
The first way to control the sequence is using a reactive API with the [``](/docs/reference/theatre/sequence) component.
#### Using the `useSequence` hook
xxx
---
##
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/sequence
Sequences are the heart of the Theatre.js animation system. The sequence represents the animation timeline and provides an API for controlling its playback.
You can reactively control animations through the `` component, which you place inside a [``](/docs/reference/theatre/sheet).
Currently, you can only have one sequence in each sheet. Future versions of Theatre.js are expected to support multisequence sheets.
#### Theatre.js Docs
**Sequence** | [Sequence Manual](https://www.theatrejs.com/docs/latest/manual/sequences) | [Sequence API Reference](https://www.theatrejs.com/docs/0.5/api/core#sequence)
## Usage
The following example shows how `` can be used to build a simple playback controller.
## Lifecycle
Threlte provides lifecycle props to allow you to configure how the sequence playback is connected to the Svelte component lifecycle. See the `autoplay`, `autoreset` and `autopause` props below.
Note that the underlying Theatre.js sheets are persisted even when unmounting a `` component. That's why the sequence doesn't reset automatically when unmounting a ``, and why the `autoreset` options is required.
## Audio
The audio options allow you to attach a soundtrack to your animation sequence. Theatre.js achieves this using the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API). For more details, see [audio manual](https://www.theatrejs.com/docs/0.5/manual/audio) and [attach audio API reference](https://www.theatrejs.com/docs/0.5/api/core#sequence.attachaudio_opts_)
## Snippet Prop
When using the sequence in a child component, a snippet prop can come in handy.
```svelte
{#snippet children({ play })}
{#snippet children({ Transform })}
{/snippet}
{/snippet}
```
---
##
Package: @threlte/theatre
URL: https://threlte.xyz/docs/reference/theatre/studio
The `` component enables the Theatre.js studio interface in your browser. It is intended for use in development.
See the Theatre.js docs for extended instructions for using the studio interface.
#### Theatre.js Docs
**Studio** | [Studio Manual](https://www.theatrejs.com/docs/latest/manual/Studio) | [Studio keyboard Shortcuts](https://www.theatrejs.com/docs/latest/manual/keyboard-shortcuts) | [Studio API Reference](https://www.theatrejs.com/docs/latest/api/studio)
### Example
In most cases, you want the interface while editing animations or laying out scenes. While other parts of Theatre.js are performant and built for production, `@theatre/studio` is currently not, and shouldn't be included in your production bundle.
```svelte
```
### Exporting State
When editing your project in the studio, state is automatically saved to your browser's local storage. To export the state, select your project from the outline panel (top-left) and click the export in the details panel (top-right). For more information and a video, see [the Theatre.js state docs](https://www.theatrejs.com/docs/latest/manual/projects#state).
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/button-vr
` ` is an HTML ` ` that can be used to init a VR session. It will also display info about browser support.
---
##
Package: @threlte/rapier
URL: https://threlte.xyz/docs/reference/rapier/rigid-body
The real-time simulation of rigid bodies subjected to forces and contacts is the main feature of a physics engine for videogames, robotics, or animation. Rigid bodies are typically used to simulate the dynamics of non-deformable solids as well as to integrate the trajectory of solids which velocities are controlled by the user (e.g. moving platforms).
Note that rigid-bodies are only responsible for the dynamics and kinematics of the solid. Colliders can be attached to a rigid-body to specify its shape and enable collision-detection. A rigid-body without collider attached to it will not be affected by contacts (because there is no shape to compute contact against).
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/button-ar
` ` is an HTML ` ` that can be used to init an AR session. It will also display info about browser support.
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/button-xr
` ` is an HTML ` ` that can be used to init a WebXR session. It will also display info about XR session browser support.
This is aliased by the more commonly used `ARButton` and `VRButton` which provide sensible session defaults.
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/controller
` ` represents a `THREE.XRTargetRaySpace`, a `THREE.XRGripSpace`, and a controller model for a specified hand.
```svelte
```
It will by default load a controller model that attempts to match the physical controller.
Default controller models are fetched from the immersive web group's [webxr input profile
repo](https://github.com/immersive-web/webxr-input-profiles). If you are developing an offline
app, you should download and provide any anticipated models.
`` can accept three snippets.
If a children snippet is provided, the default controller model will not be rendered, and will be replaced with the children content.
```svelte {2-5}+
```
Two additional snippets exist to place children in the controller's [grip space](https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource/gripSpace) and the controller's [target ray space](https://developer.mozilla.org/en-US/docs/Web/API/XRInputSource/targetRaySpace).
```svelte
{#snippet grip()}
{/snippet}
{#snippet targetRay()}
{/snippet}
```
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/hand
` ` instantiates [XRHand](https://developer.mozilla.org/en-US/docs/Web/API/XRHand) inputs for devices that allow hand tracking.
```svelte
```
It will by default load a hand model.
Default hand models are fetched from the immersive web group's [webxr input profile
repo](https://github.com/immersive-web/webxr-input-profiles). If you are developing an offline
app, you should download and provide any anticipated models. If you want to override the default factory behavior, you can provide your own [XRHandModelFactory](https://threejs.org/docs/?q=XRHand#XRHandModelFactory) or [XRControllerModelFactory](https://threejs.org/docs/?q=XRControllerModelFactory#XRControllerModelFactory) to the `` component:
`` can accept a snippet to replace the default model.
```svelte {2-5}+
```
A snippet, `wrist`, will place any children within the wrist space of the hand:
```svelte
{#snippet wrist()}
{/snippet}
```
To trigger reactive changes based on whether hand input is or is not present, the `useXR` hook provides a [`currentWritable`](/docs/reference/core/utilities#currentwritable) store:
```ts
const { isHandTracking } = useXR()
```
Hand tracking can serve as a powerful input device, as any joint position, and not just the wrist, can be read from in real time:
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/headset
` ` provides the ability to attach objects to the pose of the user's headset.
```svelte
```
If you need to only read from the current headset pose, the [useHeadset](/docs/reference/xr/use-headset) hook is available.
Like a [Portal](/docs/reference/extras/portal), you can place it anywhere in your Threlte application.
`` will sync position and rotation with the current camera when not in an immersive XR session.
---
##
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/xr-origin
` ` represents the position of the XR user's feet in the scene. The XR camera is parented to the origin, and any `` / `` components nested inside attach here instead of the scene root. Transforming the origin (position, rotation, scale) transforms the user — useful for teleportation, dolly rigs, and resizing the user.
Only one `` may be mounted within a given [``](/docs/reference/xr/xr). Mounting multiple origins in the same XR tree throws.
```svelte
```
Without ``, controllers and hands continue to attach to the scene root.
## Dolly rig
Because `` contains a regular `THREE.Group`, it can be placed inside any transformed parent. Moving that parent moves the user:
```svelte
```
## Resizing
Scaling the origin scales the user relative to the scene.
```svelte
```
## Interaction with `useTeleport`
When used inside ``, [`useTeleport`](/docs/reference/xr/use-teleport) translates the origin group directly. When used without an origin, it falls back to mutating the underlying `XRReferenceSpace`.
This example is a good regression test for room-scale teleportation. `` is mounted inside a rotated parent rig, and clicking a pad calls `useTeleport` with a fixed world-space destination. Walk away from the middle of your playspace before teleporting: the cyan feet marker should still land in the center of the selected pad.
## Accessing the origin
Use [`useXROrigin`](/docs/reference/xr/use-xr-origin) to read the current XR tree's origin state from a child component.
---
##
Package: @threlte/rapier
URL: https://threlte.xyz/docs/reference/rapier/collider
Colliders represent the geometric shapes that generate contacts and collision events when they touch. Attaching one or multiple colliders to a rigid body allow the rigid-body to be affected by contact forces.
---
## pointerControls
Package: @threlte/xr
URL: https://threlte.xyz/docs/reference/xr/pointer-controls
The `pointerControls` plugin adds pointer events to an immersive XR session. This means that pointing at any mesh with your hand or a controller will trigger DOM-like pointer events.
To get started, import and call the plugin in a component within your app.
```svelte
```
Any mesh **within this component and all child components** will now receive events if the controller or hand with the specified handedness points at it.
```svelte
{
console.log('clicked')
}}
>
```
If you wish to add pointer controls for both hands / controllers, simply call the plugin for both hands.
```svelte
```
Pointer controls can be enabled or disabled when initialized or during runtime.
```svelte
```
### Available Events
The following events are available:
```svelte
console.log('click')}
onpointerup={(e) => console.log('up')}
onpointerdown={(e) => console.log('down')}
onpointerover={(e) => console.log('over')}
onpointerout={(e) => console.log('out')}
onpointerenter={(e) => console.log('enter')}
onpointerleave={(e) => console.log('leave')}
onpointermove={(e) => console.log('move')}
/>
```
While a controller or hand is pointed at this mesh...
- `click` fires when a user selects the primary action input. This usually means pulling a primary trigger with a controller or pinching with a hand.
- `pointerdown` fires when a primary action begins, and `pointerup` fires when it ends.
- `pointerover` and `pointerout` fire when the ray of the pointing device is moved onto an object, or onto one of its children. It bubbles, meaning it can trigger on the object that the pointer is over or any of its ancestor objects.
- `pointerenter` and `pointerleave` fire when the ray of the pointing device enters / leaves the boundaries of an object, and does not bubble. It only triggers on the exact element the pointer has entered / left.
Each controller/hand fires these events **independently**. If both hands hover the same object, you'll receive `pointerenter` twice — once with `event.handedness === 'left'` and once with `'right'`. When one hand stops hovering, its `pointerleave` fires even if the other hand is still on the object. Apps that need "is any hand hovering?" should track per-hand state and aggregate:
```svelte
(hovering[e.handedness] = true)}
onpointerleave={(e) => (hovering[e.handedness] = false)}
/>
```
To replace the default ray and cursor that are created by the plugin, the following snippets can be added to a `` or a `