title: Your First Scene description: Learn how to create your first 3D scene with TresJS with this step-by-step guide. navigation:
By the end of this guide, you'll have created:
::examples-my-first-scene ::
::steps{level="2"}
First, let's create the main canvas component that will host our 3D scene. This component will contain the TresCanvas
and handle the overall scene setup.
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import FirstExperience from './components/FirstExperience.vue'
</script>
<template>
<TresCanvas
clear-color="#82DBC5"
window-size
>
<FirstExperience />
</TresCanvas>
</template>
::note
The TresCanvas
component is the root container for your 3D scene. The clear-color
prop sets the background color, and window-size
makes the canvas automatically fill the entire window without needing a parent container.
::
Let's start by creating the experience component with just a camera. This will allow us to see the clear background color of our canvas.
::tip
Best Practice: We recommend separating your TresCanvas
component from your 3D experience. This pattern helps with organization, reusability, and makes your code easier to maintain.
::
<script setup lang="ts">
// No imports needed! TresJS components are available globally
</script>
<template>
<!-- Camera Setup -->
<TresPerspectiveCamera
:position="[7, 7, 7]"
:look-at="[0, 0, 0]"
/>
</template>
What you should see: A solid turquoise background (#82DBC5
) filling your entire window.
::note
Common Mistake: A common mistake is not setting the camera position, which defaults to [0, 0, 0]
(the center of the scene). Always position your camera away from the origin to have a proper viewpoint of your 3D objects.
::
The camera defines the viewpoint of your scene:
position="[7, 7, 7]"
places the camera at coordinates X=7, Y=7, Z=7 in 3D spacelook-at="[0, 0, 0]"
points the camera toward the center of the sceneBefore adding our donut, let's add some visual helpers to better understand the 3D space. These helpers will show us the coordinate axes and a grid.
<script setup lang="ts">
// No imports needed! TresJS components are available globally
</script>
<template>
<!-- Camera Setup -->
<TresPerspectiveCamera
:position="[7, 7, 7]"
:look-at="[0, 0, 0]"
/>
<!-- Visual Helpers -->
<TresAxesHelper />
<TresGridHelper />
</template>
What you should see: A turquoise background with red, green, and blue arrows showing the X, Y, Z axes, plus a grid on the ground plane.
TresAxesHelper
: Shows the coordinate system with colored arrows
TresGridHelper
: Shows a grid on the XZ plane (ground)
::tip Development Tip: These helpers are invaluable for development and debugging. Remove them when your scene is ready for production! ::
Now let's add our 3D donut to the scene. In TresJS, 3D objects are created using a TresMesh
component with geometry and material as children.
<script setup lang="ts">
// No imports needed! TresJS components are available globally
</script>
<template>
<!-- Camera Setup -->
<TresPerspectiveCamera
:position="[7, 7, 7]"
:look-at="[0, 0, 0]"
/>
<!-- The Donut -->
<TresMesh :position="[0, 2, 0]">
<TresTorusGeometry :args="[1, 0.4, 16, 32]" />
<TresMeshBasicMaterial color="#ff6b35" />
</TresMesh>
<!-- Visual Helpers -->
<TresAxesHelper />
<TresGridHelper />
</template>
What you should see: A bright orange donut shape in the center of your scene!
In TresJS, 3D objects follow a slot-based pattern:
TresMesh
is the container that represents a 3D objectGeometry Parameters:
TresTorusGeometry
creates the donut shape with an array of parameters [radius, tube, radialSegments, tubularSegments]
:
radius: 1
- Overall size of the donuttube: 0.4
- Thickness of the donut tuberadialSegments: 16
- How smooth the donut curve istubularSegments: 32
- How smooth the tube surface isMaterial Types:
TresMeshBasicMaterial
- Simple material that doesn't require lightingFinally, let's make our donut rotate! We'll use TresJS's useLoop
composable to create smooth animations.
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { ref } from 'vue'
// Reference to our donut mesh for animation
const donutRef = ref()
// Animation loop
const { onBeforeRender } = useLoop()
onBeforeRender(({ elapsed }) => {
if (donutRef.value) {
// Rotate the donut on both X and Y axes
donutRef.value.rotation.x = elapsed * 0.5
donutRef.value.rotation.y = elapsed * 0.3
}
})
</script>
<template>
<!-- Camera Setup -->
<TresPerspectiveCamera
:position="[4, 4, 4]"
:look-at="[0, 0, 0]"
/>
<!-- The Donut -->
<TresMesh ref="donutRef">
<TresTorusGeometry :args="[1, 0.4, 16, 32]" />
<TresMeshBasicMaterial color="#ff6b35" />
</TresMesh>
</template>
What you should see: Your donut now rotates smoothly on both the X and Y axes!
The animation (system) consists of:
ref="donutRef"
creates a reference to the mesh objectElapsed Time: elapsed
parameter gives us the total time since animation started
onBeforeRender(({ elapsed }) => {
if (donutRef.value) {
donutRef.value.rotation.x = elapsed * 0.5 // Rotates on X-axis
donutRef.value.rotation.y = elapsed * 0.3 // Rotates on Y-axis (different speed)
}
})
::note
Using elapsed
time creates smooth, time-based animations that run consistently regardless of frame rate. The multipliers (0.5 and 0.3) control the rotation speed on each axis.
::
Your scene is now complete! Since we've set up everything in app.vue
, your 3D scene will automatically render when you start your application. The window-size
prop ensures the canvas fills the entire viewport automatically.
::
Here's the complete file structure and code for your first TresJS scene:
:::code-tree{default-value="components/FirstExperience.vue"}
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import FirstExperience from './components/FirstExperience.vue'
</script>
<template>
<TresCanvas
clear-color="#82DBC5"
window-size
>
<FirstExperience />
</TresCanvas>
</template>
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { ref } from 'vue'
// Reference to our donut mesh for animation
const donutRef = ref()
// Animation loop
const { onBeforeRender } = useLoop()
onBeforeRender(({ elapsed }) => {
if (donutRef.value) {
// Rotate the donut on both X and Y axes
donutRef.value.rotation.x = elapsed * 0.5
donutRef.value.rotation.y = elapsed * 0.3
}
})
</script>
<template>
<!-- Camera Setup -->
<TresPerspectiveCamera
:position="[7, 7, 7]"
:look-at="[0, 0, 0]"
/>
<!-- The Donut -->
<TresMesh ref="donutRef" :position="[0, 2, 0]">
<TresTorusGeometry :args="[1, 0.4, 16, 32]" />
<TresMeshBasicMaterial color="#ff6b35" />
</TresMesh>
<!-- Visual Helpers -->
<TresAxesHelper />
<TresGridHelper />
</template>
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
{
"name": "my-first-scene",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"@tresjs/core": "latest",
"three": "^0.158.0",
"vue": "^3.3.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.4.0",
"typescript": "^5.0.2",
"vite": "^4.4.5",
"vue-tsc": "^1.8.5"
}
}
import { templateCompilerOptions } from '@tresjs/core'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue({
// Other config
...templateCompilerOptions
}),
],
})
:::
:::card-group
::card{title="Component Separation" icon="i-lucide-layers"}
Separating TresCanvas
from your 3D experience improves code organization and reusability.
::
::card{title="Objects and Materials" icon="i-lucide-donut"}
In TresJS, 3D objects are created using a TresMesh
component with geometry and material as children.
::
::card{title="Animation Loop" icon="i-lucide-rotate-cw"}
Using useLoop
provides a clean way to handle animations and updates in your 3D scene.
::
::card{title="Template Refs" icon="i-lucide-link"} Using Vue's template refs allows you to directly manipulate 3D objects in your animations. :: :::
Now that you have your first scene running, you can:
TheDonut.vue
component to practice component composition::tip Check out our Cookbook section to see more complex scenes and learn advanced techniques! ::
::callout{icon="i-lucide-grid-3x3"} Related Examples Placeholder: Add a component here showing cards with related examples like "Basic Primitives", "Lighting Setup", "Animation Patterns", etc. ::