threlte logo
@threlte/theatre

<SheetObject>

The <SheetObject> component allows you to pool the properties of a logical entity which can be a anything from a single material, multiple meshes or a complete scene. The component <SheetObject> and make them editable and animatable in the Theatre.js studio. It’s a great choice if you are making a reusable Threlte component which you want to make editable in the Theatre.js studio.

Theatre.js Docs

   
Sheet ObjectSheet Object ManualSheet Object API Reference

Overview

The <SheetObject> component offers several distinct ways to declare and syncronize props in the Theatre.js studio. Convenient auto prop APIs address common usecases and allow quick and easy prop declaration. Meanwhile, manual props APIs allow full customization of prop declaration. Many of these are offered through slot props.

<script lang="ts">
  import { Canvas } from '@threlte/core'
  import { Sequence, Theatre } from '@threlte/theatre'
  import Scene from './Scene.svelte'
  import state from './state.json'
</script>

<div>
  <Canvas>
    <Theatre
      config={{
        state
      }}
    >
      <Sequence
        autoplay
        iterationCount={Infinity}
      >
        <Scene />
      </Sequence>
    </Theatre>
  </Canvas>
</div>

<style>
  div {
    width: 100%;
    height: 100%;
  }
</style>
<script lang="ts">
  import { T } from '@threlte/core'
  import { RoundedBoxGeometry, interactivity, useCursor } from '@threlte/extras'
  import { SheetObject } from '@threlte/theatre'
  import { DEG2RAD } from 'three/src/math/MathUtils.js'

  interactivity()

  const { onPointerEnter, onPointerLeave } = useCursor()
</script>

<SheetObject key="Directional Light">
  {#snippet children({ Sync, Transform })}
    <Transform>
      <T.DirectionalLight castShadow>
        <Sync
          intensity
          color
        />
      </T.DirectionalLight>
    </Transform>
  {/snippet}
</SheetObject>

<SheetObject key="Ambient Light">
  {#snippet children({ Sync })}
    <T.AmbientLight>
      <Sync
        intensity
        color
      />
    </T.AmbientLight>
  {/snippet}
</SheetObject>

<T.PerspectiveCamera
  makeDefault
  position={[5, 5, 5]}
  oncreate={(ref) => {
    ref.lookAt(0, 0, 0)
  }}
/>

<SheetObject key="Box">
  {#snippet children({ Sync, Transform, select, deselect })}
    <Transform>
      <T.Mesh
        castShadow
        onclick={select}
        onpointerenter={onPointerEnter}
        onpointerleave={onPointerLeave}
        onpointermissed={deselect}
      >
        <RoundedBoxGeometry radius={0.1} />
        <T.MeshStandardMaterial transparent>
          {#snippet children({ ref })}
            <Sync
              type={ref}
              color
              roughness
              metalness
              side
              opacity
            />
          {/snippet}
        </T.MeshStandardMaterial>
      </T.Mesh>
    </Transform>
  {/snippet}
</SheetObject>

<T.Mesh
  receiveShadow
  position.y={-1}
  rotation.x={-90 * DEG2RAD}
>
  <T.CircleGeometry args={[1.4, 48]} />
  <T.MeshStandardMaterial />
</T.Mesh>
{
  "sheetsById": {
    "default": {
      "staticOverrides": {
        "byObject": {
          "Directional Light": {
            "intensity": 2.600000000000001,
            "position": {
              "x": 0.3394033225355889,
              "y": 2.3720157022596795,
              "z": 0.09009663353739894
            },
            "rotation": {
              "x": 0,
              "y": 0,
              "z": 0
            },
            "scale": {
              "x": 1,
              "y": 1,
              "z": 1
            },
            "color": {
              "r": 0.9372549019607843,
              "g": 0.8784313725490196,
              "b": 0.7686274509803922,
              "a": 1
            }
          },
          "Ambient Light": {
            "intensity": 1.15,
            "color": {
              "r": 0.43137254901960786,
              "g": 0.4745098039215686,
              "b": 0.7176470588235294,
              "a": 1
            }
          },
          "Box": {
            "helo": {
              "position": {
                "x": 0,
                "y": 0.028659367564094484,
                "z": 0
              },
              "rotation": {
                "x": 0,
                "y": 0,
                "z": 0
              },
              "scale": {
                "x": 1,
                "y": 1,
                "z": 1
              }
            },
            "color": {
              "r": 0.0196078431372549,
              "g": 1,
              "b": 0,
              "a": 1
            },
            "position": {
              "x": 0,
              "y": 0,
              "z": 0
            },
            "rotation": {
              "x": 0,
              "y": 0,
              "z": 0
            },
            "scale": {
              "x": 1,
              "y": 1,
              "z": 1
            },
            "side": "f",
            "opacity": 1,
            "metalness": 0.3797468354430377,
            "roughness": 0.38607594936708833
          }
        }
      },
      "sequence": {
        "subUnitsPerUnit": 30,
        "length": 4,
        "type": "PositionalSequence",
        "tracksByObject": {
          "Box": {
            "trackData": {
              "XpQldofCoc": {
                "type": "BasicKeyframedTrack",
                "__debugName": "Box:[\"position\",\"x\"]",
                "keyframes": [
                  {
                    "id": "iGoSxeB7Tg",
                    "position": 0,
                    "connectedRight": true,
                    "handles": [0.5, 1, 0.5, 0],
                    "type": "bezier",
                    "value": 0
                  }
                ]
              },
              "DIrxDuzcU2": {
                "type": "BasicKeyframedTrack",
                "__debugName": "Box:[\"position\",\"y\"]",
                "keyframes": [
                  {
                    "id": "RmM1HUOqZm",
                    "position": 0,
                    "connectedRight": true,
                    "handles": [0.5, 1, 0.455, 0.03],
                    "type": "bezier",
                    "value": 0
                  },
                  {
                    "id": "5MNKDVNvWP",
                    "position": 2,
                    "connectedRight": true,
                    "handles": [0.515, 0.955, 0.455, 0.03],
                    "type": "bezier",
                    "value": -0.2
                  },
                  {
                    "id": "h_vCrfvuFs",
                    "position": 4,
                    "connectedRight": true,
                    "handles": [0.515, 0.955, 0.5, 0],
                    "type": "bezier",
                    "value": 0
                  }
                ]
              },
              "5yT_h05zwt": {
                "type": "BasicKeyframedTrack",
                "__debugName": "Box:[\"position\",\"z\"]",
                "keyframes": [
                  {
                    "id": "2FKQERGrJH",
                    "position": 0,
                    "connectedRight": true,
                    "handles": [0.5, 1, 0.5, 0],
                    "type": "bezier",
                    "value": 0
                  }
                ]
              }
            },
            "trackIdByPropPath": {
              "[\"position\",\"x\"]": "XpQldofCoc",
              "[\"position\",\"y\"]": "DIrxDuzcU2",
              "[\"position\",\"z\"]": "5yT_h05zwt"
            }
          }
        }
      }
    }
  },
  "definitionVersion": "0.4.0",
  "revisionHistory": [
    "qqJwziYf9rQuLpNb",
    "3WZqMkutbe2nKFJw",
    "H4q1oRw5vKb-x7io",
    "fFmuTDfiXVI1Yc10"
  ]
}

Auto Props

The <Sync> component automatically infers and synchronizes props of its parent component. Meanwhile the <Transform> component creates position and rotation props for its child components, and adds transform controls to the them.

Manual Props

Sometimes we want to control prop declaration manually for better control when implementing custom domain specific props. We can achieve this using manual prop declaration. Provide the props property to the component <SheetObject> for a manual property declaration.

<SheetObject props={{ x: 0 }}>
  {#snippet children({ values })}
    <T.Mesh position.x={values.x} />
  {/snippet}
</SheetObject>

You can also use the <Declare> prop slot component to colocate your manual declaration with other code.

Selection

The <SheetObject> component offers a slot prop based API for controlling selection in the Theatre.js studio. Simply declare the select and deselect methods and the selected variables to use it. You then need to use these in the mesh of your choice; see the example above for a demonstration.

Component Signature

Props

name
type
required
default

key
string
yes

detach
boolean
no
false

props
UnknownShorthandCompoundProps
no