@threlte/theatre
useSequence
The useSequence
hook allows you to access a sequence’s playback controls using a store API.
Usage
The hook can be used within the <Sheet>
context or withing the <Sequence>
context:
<!-- child of a <Sheet> or <Sequence> -->
<script lang="ts">
import { useSequence } from '@threlte/theatre'
const { position, playing, length, play, pause, config } = useSequence()
</script>
Example
This example uses the useSequence
hook to allow you to control the feather’s animation using the feather itself. Hover will pause the animation and clicking and dragging the feather up and down allow you to wind back and forth in time.
<script lang="ts">
import { Canvas } from '@threlte/core'
import { Project, Sheet } from '@threlte/theatre'
import Scene from './Scene.svelte'
import state from './state.json'
</script>
<div>
<Canvas>
<Project config={{ state }}>
<Sheet>
<Scene />
</Sheet>
</Project>
</Canvas>
</div>
<style>
div {
height: 100%;
}
</style>
<script lang="ts">
import { T } from '@threlte/core'
import { GLTF, interactivity } from '@threlte/extras'
import { SheetObject, useSequence } from '@threlte/theatre'
interactivity()
const { play, pause, position, length } = useSequence()
let baseline: number | undefined = undefined
</script>
<T.Group
onpointerenter={pause}
onpointerleave={() => {
play()
baseline = undefined
}}
onpointerdown={(event) => {
baseline = event.intersections[0].point.y
}}
onpointermove={(event) => {
if (baseline) {
const current = event.intersections[0].point.y
const progress = (baseline - current) / 2
$position = $position + progress * $length
baseline = current
}
}}
onpointerup={() => (baseline = undefined)}
>
<SheetObject key="Feather">
{#snippet children({ Transform })}
<Transform>
<GLTF url="/models/feather.glb" />
</Transform>
{/snippet}
</SheetObject>
</T.Group>
<script lang="ts">
import { T } from '@threlte/core'
import { Environment, Text, interactivity } from '@threlte/extras'
import { useSequence } from '@threlte/theatre'
import Feather from './Feather.svelte'
interactivity()
const { position, config, play } = useSequence()
// adjust playback settings
config({ iterationCount: Infinity, rate: 0.3 })
const format = (num: number) =>
num.toLocaleString('en-US', {
minimumFractionDigits: 1,
maximumFractionDigits: 1
})
$: time = format($position)
play()
</script>
<Feather />
<Text
position.x={1}
text={time}
/>
<T.PerspectiveCamera
position.z={2}
makeDefault
/>
<T.AmbientLight intensity={0.2} />
<Environment
path="/hdr/"
files="industrial_sunset_puresky_1k.hdr"
isBackground={true}
format="hdr"
/>
{
"sheetsById": {
"default": {
"staticOverrides": {
"byObject": {
"Mesh / Transforms": {
"Position": {
"x": 0,
"y": 0.3570440680404296,
"z": -1.0408340855860843e-17
}
},
"Lights / Main": {
"Position": {
"x": 1.4581874883286385,
"y": 2,
"z": 1
}
},
"Box / Mesh": {
"Position": {
"y": 0
}
},
"Hourglass": {
"Position": {
"x": 2.443734229380632,
"y": 0,
"z": 2.835536858006085
},
"Scale": {
"x": 0.05,
"y": 0.05,
"z": 0.05
}
},
"Cat": {
"Scale": {
"x": 0.05,
"y": 0.05,
"z": 0.05
},
"Position": {
"x": -2.809109334778998,
"y": 0,
"z": -4.164744872672715
}
},
"button": {
"y": 0,
"w": false,
"bold": true
}
}
},
"sequence": {
"subUnitsPerUnit": 30,
"length": 3,
"type": "PositionalSequence",
"tracksByObject": {
"Box / Mesh": {
"trackData": {
"b_3bpv4hlh": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Position\",\"y\"]",
"keyframes": [
{
"id": "CpaIOcSb26",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "IM4gcoDPhQ",
"position": 0.5,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 3
},
{
"id": "eNqDQ7mfVb",
"position": 1,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
}
]
},
"Es26qfLqOq": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Scale\",\"y\"]",
"keyframes": [
{
"id": "h4weN9vKxi",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 1
},
{
"id": "PiPY6s5HQj",
"position": 0.233,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 1.5
},
{
"id": "XuOoDZU4gN",
"position": 0.5,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 1
},
{
"id": "foewgZ636r",
"position": 1,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 1
}
]
},
"DIdMVZg5_1": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Rotation\",\"x\"]",
"keyframes": [
{
"id": "KWyDKX5oLa",
"position": 0.4,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "-LIQQzk5Y6",
"position": 0.633,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 90
}
]
},
"2jtXEh_wSh": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Rotation\",\"y\"]",
"keyframes": [
{
"id": "lHxxYY2-SZ",
"position": 0.4,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "NbRDJ244kN",
"position": 0.633,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 90
}
]
},
"--pnqicX6P": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Rotation\",\"z\"]",
"keyframes": [
{
"id": "SDdqaxukkj",
"position": 0.4,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "Inin2CTeg0",
"position": 0.633,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
}
]
},
"xcEIo-kPmX": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Scale\",\"x\"]",
"keyframes": []
},
"_HEyQtrmLa": {
"type": "BasicKeyframedTrack",
"__debugName": "Box / Mesh:[\"Scale\",\"z\"]",
"keyframes": []
}
},
"trackIdByPropPath": {
"[\"Position\",\"y\"]": "b_3bpv4hlh",
"[\"Scale\",\"y\"]": "Es26qfLqOq",
"[\"Rotation\",\"x\"]": "DIdMVZg5_1",
"[\"Rotation\",\"y\"]": "2jtXEh_wSh",
"[\"Rotation\",\"z\"]": "--pnqicX6P",
"[\"Scale\",\"x\"]": "xcEIo-kPmX",
"[\"Scale\",\"z\"]": "_HEyQtrmLa"
}
},
"button": {
"trackData": {
"zcBh-D8Uq_": {
"type": "BasicKeyframedTrack",
"__debugName": "button:[\"x\"]",
"keyframes": [
{
"id": "B2xSbyvYpP",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "xrp-bpABsN",
"position": 0.2,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": -200
},
{
"id": "BsbFH-RJli",
"position": 0.6,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 200
},
{
"id": "hZhY9rtW2l",
"position": 0.8,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
}
]
},
"odyviKqKB4": {
"type": "BasicKeyframedTrack",
"__debugName": "button:[\"y\"]",
"keyframes": [
{
"id": "EZc_TOnB8l",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
},
{
"id": "k4d5KSMm3S",
"position": 0.1,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": -50
},
{
"id": "xQWcr8pHxG",
"position": 0.3,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 50
},
{
"id": "g7zdL4auIV",
"position": 0.5,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": -50
},
{
"id": "62GD2tlQvM",
"position": 0.7,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 50
},
{
"id": "yCTiQlHoj1",
"position": 0.9,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": 0
}
]
},
"6P6ha6na9e": {
"type": "BasicKeyframedTrack",
"__debugName": "button:[\"bold\"]",
"keyframes": [
{
"id": "kl7MVNMl-Y",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": false
},
{
"id": "GlgZf6996q",
"position": 0.9,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": true
},
{
"id": "xaWNVuJc3B",
"position": 1,
"connectedRight": true,
"handles": [0.5, 1, 0.5, 0],
"type": "bezier",
"value": true
}
]
}
},
"trackIdByPropPath": {
"[\"x\"]": "zcBh-D8Uq_",
"[\"y\"]": "odyviKqKB4",
"[\"bold\"]": "6P6ha6na9e"
}
},
"Feather": {
"trackData": {
"XFWRBWGCYD": {
"type": "BasicKeyframedTrack",
"__debugName": "Feather:[\"position\",\"x\"]",
"keyframes": []
},
"3i48L_UXaD": {
"type": "BasicKeyframedTrack",
"__debugName": "Feather:[\"position\",\"y\"]",
"keyframes": [
{
"id": "1fcUkLkxf3",
"position": 0,
"connectedRight": true,
"handles": [0.5, 1, 0.12825278810408913, 0.12136219682258331],
"type": "bezier",
"value": 2
},
{
"id": "nXzSEOZ5rG",
"position": 3,
"connectedRight": true,
"handles": [0.7973977695167287, 0.7989938615125962, 0.5, 0],
"type": "bezier",
"value": -2
}
]
},
"xoXXb0Gj6w": {
"type": "BasicKeyframedTrack",
"__debugName": "Feather:[\"position\",\"z\"]",
"keyframes": []
}
},
"trackIdByPropPath": {
"[\"position\",\"x\"]": "XFWRBWGCYD",
"[\"position\",\"y\"]": "3i48L_UXaD",
"[\"position\",\"z\"]": "xoXXb0Gj6w"
}
}
}
}
}
},
"definitionVersion": "0.4.0",
"revisionHistory": [
"9oKH4i0sbUCjnC12",
"jn9FHXpLtlURzWOs",
"qpo86xX0z9LVRsoV",
"62cBnS0EMiw9EDzl",
"WdqDOLSNW-TCSoDz",
"ZxoPi9jfsYCHwP__"
]
}
Output
The following values are returned by the hook:
store | type | description |
---|---|---|
length | number | The length of the sequence, which is set within the studio |
position | Writable<number> | The sequence playhead position |
playing | Writable<boolean> | The sequence state (playing or paused) |
play | (opts?: SequenceOptions) => Promise<boolean> | Method for playing the sequence |
pause | () => void | Method for pausing the sequence |
config | (opts: SequenceOptions) => void | Method for updating the sequence’s options |