@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 Object | Sheet Object Manual | Sheet 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.