3.your-first-scene.md 10 KB


title: Your First Scene description: Learn how to create your first 3D scene with TresJS with this step-by-step guide. navigation:

icon: i-lucide-donut

What You'll Build

By the end of this guide, you'll have created:

  • A 3D scene with a rotating donut
  • A reusable component structure
  • Animation using TresJS composables

::examples-my-first-scene ::

::steps{level="2"}

Step 1: Set Up the Canvas Component

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. ::

Step 2: Set Up the Camera

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 space
  • look-at="[0, 0, 0]" points the camera toward the center of the scene

Step 3: Add Visual Helpers

Before 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.

Understanding the Helpers

  • TresAxesHelper: Shows the coordinate system with colored arrows

    • Red arrow: X-axis (left/right)
    • Green arrow: Y-axis (up/down)
    • Blue arrow: Z-axis (forward/backward)
  • TresGridHelper: Shows a grid on the XZ plane (ground)

    • Helps visualize object positioning and scale
    • The grid center is at the origin (0, 0, 0)

::tip Development Tip: These helpers are invaluable for development and debugging. Remove them when your scene is ready for production! ::

Step 4: Add the Donut

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!

Understanding the Mesh Structure

In TresJS, 3D objects follow a slot-based pattern:

  • TresMesh is the container that represents a 3D object
  • The first child defines the geometry (shape)
  • The second child defines the material (appearance)

Geometry Parameters:

  • TresTorusGeometry creates the donut shape with an array of parameters [radius, tube, radialSegments, tubularSegments]:
    • radius: 1 - Overall size of the donut
    • tube: 0.4 - Thickness of the donut tube
    • radialSegments: 16 - How smooth the donut curve is
    • tubularSegments: 32 - How smooth the tube surface is

Material Types:

  • TresMeshBasicMaterial - Simple material that doesn't require lighting
  • Perfect for beginners and solid colors

Step 5: Add Animation

Finally, 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!

Understanding Animation

The animation (system) consists of:

  1. Template Ref: ref="donutRef" creates a reference to the mesh object
  2. useLoop Hook: Provides access to the render loop
  3. onBeforeRender: Runs before each frame is rendered
  4. Elapsed 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. ::

Step 6: Running Your Scene

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.

::

Final Project Structure

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
    }),
  ],
})

:::

Key Concepts Learned

:::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. :: :::

Next Steps

Now that you have your first scene running, you can:

  • Extract the donut into its own component - Create a TheDonut.vue component to practice component composition
  • Experiment with different geometries and materials
  • Add more objects to your scene (Get inspired by Three.js's Geometries and Materials)
  • Try different camera positions and angles
  • Explore more complex animations

::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. ::