5.3.3

Declarative Properties

Learn how TresJS maps Vue props to Three.js object properties for a declarative 3D development experience.

From Imperative to Declarative

In vanilla Three.js, you set properties imperatively:

const mesh = new THREE.Mesh(geometry, material)
mesh.position.set(1, 2, 3)
mesh.rotation.set(0, Math.PI, 0)
mesh.visible = true
mesh.castShadow = true

TresJS lets you declare these properties directly on components:

<template>
  <TresMesh
    :position="[1, 2, 3]"
    :rotation="[0, Math.PI, 0]"
    :visible="true"
    :cast-shadow="true"
  >
    <TresBoxGeometry />
    <TresMeshStandardMaterial />
  </TresMesh>
</template>

Property Mapping Rules

TresJS automatically maps props to Three.js properties using these conventions:

1. Direct Properties

Props map directly to properties of the same name:

<template>
  <!-- mesh.visible = true -->
  <TresMesh :visible="true" />

  <!-- mesh.castShadow = true -->
  <TresMesh :cast-shadow="true" />

  <!-- material.transparent = true -->
  <TresMeshStandardMaterial :transparent="true" :opacity="0.5" />
</template>

2. Properties with .set() Methods

When a property has a .set() method (like Vector3, Euler, Color), TresJS automatically calls it with array values:

<template>
  <!-- Calls: mesh.position.set(1, 2, 3) -->
  <TresMesh :position="[1, 2, 3]" />

  <!-- Calls: mesh.rotation.set(0, Math.PI, 0) -->
  <TresMesh :rotation="[0, Math.PI, 0]" />

  <!-- Calls: mesh.scale.set(2, 2, 2) -->
  <TresMesh :scale="[2, 2, 2]" />

  <!-- Calls: material.color.set('#ff6b35') -->
  <TresMeshStandardMaterial color="#ff6b35" />
</template>

3. Scalar Shorthand

For uniform scaling, pass a single number:

<template>
  <!-- Calls: mesh.scale.set(2, 2, 2) -->
  <TresMesh :scale="2" />
</template>

4. kebab-case Conversion

Vue's kebab-case props are converted to camelCase properties:

<template>
  <!-- mesh.castShadow = true -->
  <TresMesh :cast-shadow="true" />

  <!-- mesh.receiveShadow = true -->
  <TresMesh :receive-shadow="true" />

  <!-- material.flatShading = true -->
  <TresMeshStandardMaterial :flat-shading="true" />
</template>

Pierced Props (Nested Properties)

TresJS supports setting nested properties using dash notation:

Transform Axes

<template>
  <!-- mesh.position.x = 1, mesh.position.y = 2 -->
  <TresMesh :position-x="1" :position-y="2" />

  <!-- mesh.rotation.y = Math.PI -->
  <TresMesh :rotation-y="Math.PI" />

  <!-- mesh.scale.x = 2 -->
  <TresMesh :scale-x="2" />
</template>

Color Channels

<template>
  <!-- material.color.r = 1, material.color.g = 0.5 -->
  <TresMeshStandardMaterial :color-r="1" :color-g="0.5" :color-b="0" />
</template>

Deep Nesting

<template>
  <!-- light.shadow.camera.near = 0.5 -->
  <TresDirectionalLight :shadow-camera-near="0.5" :shadow-camera-far="500" />

  <!-- light.shadow.mapSize.width = 2048 -->
  <TresDirectionalLight :shadow-map-size-width="2048" />
</template>

Special Props

lookAt

The lookAt prop calls the object's .lookAt() method:

<template>
  <!-- camera.lookAt(0, 0, 0) -->
  <TresPerspectiveCamera :position="[5, 5, 5]" :look-at="[0, 0, 0]" />
</template>

attach

Controls how children attach to parents (used for geometries and materials):

<template>
  <TresMesh>
    <!-- Attaches as mesh.geometry -->
    <TresBoxGeometry attach="geometry" />

    <!-- Attaches as mesh.material -->
    <TresMeshStandardMaterial attach="material" />
  </TresMesh>
</template>
Geometries and materials auto-attach - you rarely need to specify attach manually.

Reactivity

All props are reactive by default. When a prop value changes, TresJS updates the Three.js property:

<script setup lang="ts">
const positionY = ref(0)
const color = ref('#ff6b35')
</script>

<template>
  <TresMesh :position-y="positionY">
    <TresBoxGeometry />
    <TresMeshStandardMaterial :color="color" />
  </TresMesh>

  <input type="range" v-model="positionY" min="-5" max="5" step="0.1" />
  <input type="color" v-model="color" />
</template>
For high-frequency updates (animations at 60fps), use template refs instead of reactive props. See Reactivity for performance patterns.

Common Patterns

Complete Mesh Example

<template>
  <TresMesh
    :position="[0, 1, 0]"
    :rotation="[0, Math.PI / 4, 0]"
    :scale="1.5"
    :cast-shadow="true"
    :receive-shadow="true"
    name="my-mesh"
  >
    <TresBoxGeometry :args="[1, 1, 1]" />
    <TresMeshStandardMaterial
      color="#ff6b35"
      :metalness="0.3"
      :roughness="0.7"
    />
  </TresMesh>
</template>

Light with Shadows

<template>
  <TresDirectionalLight
    :position="[10, 10, 10]"
    :intensity="1.5"
    :cast-shadow="true"
    :shadow-map-size-width="2048"
    :shadow-map-size-height="2048"
    :shadow-camera-near="0.5"
    :shadow-camera-far="500"
    :shadow-camera-left="-10"
    :shadow-camera-right="10"
    :shadow-camera-top="10"
    :shadow-camera-bottom="-10"
  />
</template>

Key Takeaways

Array for Vectors

Use arrays for position, rotation, scale - TresJS calls .set() automatically.

Pierced Props

Access nested properties with dash notation: :position-x, :shadow-camera-near.

Auto Conversion

kebab-case props convert to camelCase Three.js properties automatically.

Reactive by Default

Props update Three.js properties reactively - be mindful of performance.