@theatre/core

getProject(id, config)

If you import and initialize Studio, you can call getProject() without an explicit state. In this case, the state of the project will be managed by Studio.


import { getProject } from '@theatre/core'
const config = {} // the config can be empty when starting a new project
const project = getProject('My Project', config)

In production, however, you'd pass a state object, which is exported from Studio in the config argument.


import { getProject } from '@theatre/core'
import state from './saved-state.json'
const config = { state } // here the config contains our saved state
const project = getProject('My Project', config)

Project

Project returned by getProject.

To read about Projects, check out the Projects Manual!

project.ready

Promise that resolves when Theatre.js is loaded. If @theatre/studio is used, this Promise would resolve when Studio has loaded the state of the project into memory. If @theatre/studio is not used, this Promise is already resolved.


project.ready.then(() => console.log('Project loaded!'))

project.isReady

Indicates whether the project is ready to be used. It is better to use Project.ready, which is a Promise that resolves when the project is ready.


if (project.isReady) {
console.log('Project loaded!')
} else {
console.log('Project not loaded yet.')
}

project.address

The Project's unique address in Theatre.js. It is a JS object that contains a single property projectId.


const { projectId } = project.address

project.sheet(name, instanceId?)

Creates or returns a Sheet under the Project. If a Sheet with the given name is in the Project's state then the existing Sheet is returned; otherwise, a new Sheet is created and returned. You can optionally give a second argument: a sheet instance id that allows you to create multiple instances of the same Sheet (this makes it possible to have multiple instances of the same animation). By default, the instance id is the same as the Sheet id.


import { getProject } from '@theatre/core'
const project = getProject('My Project')
const sheet = project.sheet('My Sheet', 'My optional Sheet instance id')

project.getAssetUrl(assetHandle)Since 0.6.0

Gets the url for the provided asset handle. You would normally get an asset handle by listening to changes of asset props, like the image prop.


const object = sheet.object('My Object', {
texture: types.image(undefined, {
label: 'Texture',
}),
})
object.onValuesChange(({ texture }) => {
setImageUrl(project.getAssetUrl(texture))
})

Sheet

Sheet returned by Project.sheet.

sheet.object(key, config, options?)

Creates or returns an Object with given props under this Sheet. If an Object with the given name is in the Project's state then the existing Object is returned; otherwise, a new Object is created and returned.


// Create an object with nested props
const myObject = sheet.object('My Object', { position: { x: 0, y: 0 } })
// {x: 0, y: 0}
console.log(myObject.value.position)

Objects can also be reconfigured on the fly. Learn more here.

sheet.detachObject(key)Since 0.5.1

Detaches a previously created child object from the sheet.

If you call sheet.object(key) again with the same key, the values of the object's props WILL NOT be reset to their initial values.

Note: Calling sheet.detachObject() does not unsubscribe the listeners you've attached to the object. For example, if you've called const unsubscribe = object.onValuesChange(...), you will have to manually call unsubscribe() either before or after calling sheet.detachObject().

sheet.sequence

The Sequence of this sheet. Sequences are JS objects that hold animation data such as Keyframes and current position.

sheet.project

The Project this Sheet belongs to.


import { getProject } from '@theatre/core'
const project = getProject('My Project')
const sheet = project.sheet('My Sheet')
// true
console.log(sheet.project === project)

sheet.address

The Sheet's unique address in Theatre.js. It is an object containing a projectId, sheetId, and sheetInstanceId.


import { getProject } from '@theatre/core'
const project = getProject('My Project')
const sheet = project.sheet('My Sheet')
const { projectId, sheetId, sheetInstanceId } = sheet.address

Sequence

A JS object that holds animation data such as Keyframes and current position.

sequence.play(opts?)

Starts playback of a sequence. Returns a Promise that either resolves to true when the playback completes or resolves to false if playback gets interrupted (for example by calling Sequence.pause)


// plays the sequence from the current position to sequence.length
sheet.sequence.play()
// plays the sequence at 2.4x speed
sheet.sequence.play({ rate: 2.4 })
// plays the sequence from second 1 to 4
sheet.sequence.play({ range: [1, 4] })
// plays the sequence 4 times
sheet.sequence.play({ iterationCount: 4 })
// plays the sequence in reverse
sheet.sequence.play({ direction: 'reverse' })
// plays the sequence back and forth forever (until interrupted)
sheet.sequence.play({ iterationCount: Infinity, direction: 'alternateReverse' })
// plays the sequence and logs "done" once playback is finished
sheet.sequence.play().then(() => console.log('done'))
// play the sequence using the given rafDriver (since version 0.6.0)
sheet.sequence.play({ rafDriver })

Hint: You can control how often sequence.play() progresses forward by optionally providing a rafDriver.

sequence.pause()

Pauses the currently playing animation.


sheet.sequence.play()
setTimeout(() => sheet.sequence.pause(), 1000) // pause after 1 second

sequence.position

The current position of the playhead. In a time-based sequence, this represents the current time in seconds.


// if the animation is past the 1 second mark
if (sheet.sequence.position > 1) {
// do something
}


// set the animation position to 1 second
sheet.sequence.position = 1

sequence.pointer

A Pointer to the Sequence's inner state.

As with any Pointer, you can use this with onChange() to listen to its value changes or with val() to read its current value.


import { onChange, val } from '@theatre/core'
// ...
onChange(sequence.pointer.length, (len) => {
console.log('Length of the sequence changed to:', len)
})
onChange(sequence.pointer.position, (position) => {
console.log('Position of the sequence changed to:', position)
})
onChange(sequence.pointer.playing, (playing) => {
console.log(playing ? 'playing' : 'paused')
})
// we can also read the current value of the pointer
console.log('current length is', val(sequence.pointer.length))

sequence.attachAudio(opts)

Attaches an audio source to the sequence. Playing the sequence automatically plays the audio source and the audio and animation times are kept in sync.

Returns a Promise that resolves once the audio source is loaded and decoded.

Learn more from the Using Audio manual.


// Loads and decodes audio from the URL and then attaches it to the sequence
await sheet.sequence.attachAudio({source: "http://localhost:3000/audio.mp3"})
sheet.sequence.play()
// Providing your own AudioAPI Context, destination, etc
const audioContext: AudioContext = {...} // create an AudioContext using the Audio API
const audioBuffer: AudioBuffer = {...} // create an AudioBuffer
const destinationNode = audioContext.destination
await sheet.sequence.attachAudio({source: audioBuffer, audioContext, destinationNode})

Note: It's better to provide the audioContext rather than allow Theatre.js to create it. That's because some browsers suspend the audioContext unless it's initiated by a user gesture, like a click. If that happens, Theatre.js will wait for a user gesture to resume the audioContext. But that's probably not an optimal user experience. It is better to provide a button or some other UI element to communicate to the user that they have to initiate the animation.


// html: <button id="#start">start</button>
const button = document.getElementById('start')
button.addEventListener('click', async () => {
const audioContext = somehowCreateAudioContext()
await sheet.sequence.attachAudio({ audioContext, source: '...' })
sheet.sequence.play()
})

To read about Audio, check out the Using Audio Manual!

sequence.__experimental_getKeyframes(pointer)Since 0.6.1

Returns the keyframes of a given prop of an object.


const obj = sheet.object('My Object', { position: { x: 0, y: 0 } })
// (assuming the user has sequenced the x prop)
const keyframes = sequence.__experimental_getKeyframes(obj.props.position.x) // an array of keyframes

Object

A Sheet Object returned by sheet.object with some given props.


const obj = sheet.object('My Object', { x: 0 })

To read about Objects, check out the Objects Manual.

To read about the props of Objects, check out the Prop Types Manual or the Prop types API docs below!

object.value

The current values of the props of the Object.


const obj = sheet.object('obj', { x: 0 })
console.log(obj.value.x) // prints 0 or the current numeric value

object.props

A Pointer to the props of the Object.


onChange(obj.props.x, (x) => {
console.log(x)
})
// we can also read the current value of the pointer
console.log('current x is', val(obj.props.x))

object.sheet

The instance of Sheet that the Object belongs to.


const sheet = project.sheet('My Sheet')
const obj = sheet.object('obj', { x: 0 })
// true
console.log(obj.sheet === sheet)

object.project

The Project this object belongs to.


const project = getProject('My Project')
const sheet = project.sheet('My Sheet')
const obj = sheet.object('My Object', { x: 0 })
// true
console.log(obj.project === project)

object.address

An Object address is a JS object representing the unique address of the Object in Theatre.js. It contains a projectId, sheetId, sheetInstanceId , and objectKey.


const { projectId, sheetId, sheetInstanceId, objectKey } = obj.address

object.initialValue

Sets the initial value of the Object. This value overrides the default values defined in the Object's prop types. And, it can then be overridden if the user overrides it in the Studio UI with a static or sequenced value.


const obj = sheet.object('obj', { position: { x: 0, y: 0 } })
obj.value // {position: {x: 0, y: 0}}
// here, we only override position.x
obj.initialValue = { position: { x: 2 } }
obj.value // {position: {x: 2, y: 0}}

object.onValuesChange(callback)

Calls a given callback every time any of the Object's prop values change.

Returns an unsubscribe function that can be called to stop listening.


const obj = sheet.object('Box', { position: { x: 0, y: 0 } })
const div = document.getElementById('box')
const unsubscribe = obj.onValuesChange((newValues) => {
div.style.left = newValues.position.x + 'px'
div.style.top = newValues.position.y + 'px'
})
// you can call unsubscribe() to stop listening to changes

Prop types

You can define the types of props when creating an Object through sheet.object using the types object.


import { types } from '@theatre/core'

Many prop types allow you to omit the type, and the type is inferred from the initial prop values you provide. For example, in the following code snippet, the "My Object" Object has a single prop x with an inferred prop type types.number.


// A simple number prop
const obj = sheet.object('My Object', { x: 0 })

In cases where you want more control over your Object's props, you can specify the type explicitly. Prop types accept options that alter the way the prop behaves when sequenced or displayed in the Studio UI.


// A number prop with custom UI
const obj = sheet.object('My Object', {
x: types.number(0, {
// limited to 0 and 10
range: [0, 10],
}),
})

For stringLiteral, string, and boolean types, we can define a custom interpolator as an option, see the code below for an example.


/**
* A string interpolator for a "typewriter effect" when `left` is an empty
* string or `right` starts with `left`.
*/
const typeWriterInterpolate = (left: string, right: string, progression: number) => {
if (!left || right.startsWith(left)) {
const length = Math.floor(Math.max(0, (right.length - left.length) * progression))
return left + right.slice(left.length, left.length + length)
}
return left
}
const obj = sheet.object('My Object', {
title: types.string('', { interpolate: typeWriterInterpolate }),
})

To read about Prop types, check out the Prop Types Manual!

types.compound(props, opts?)

Compound props are analogous to JavaScript objects in that they enable the nesting of props. In the example below, position has an inferred prop type of types.compound.


const obj = sheet.object('My Object', {
position: {
x: 0,
y: 0,
},
})
assert(obj.value.position.x === 0)

You can pass additional options when specifying compound types explicitly.


const obj = sheet.object('My Object', {
position: types.compound(
{ x: 0, y: 0 },
// a custom label for the prop:
{ label: 'Position' },
),
})

types.number(default, opts?)

A number prop type.


const x = types.number(0, {
// The range allowed in the UI (just a visual guide, not a validation rule)
range: [0, 10],
// Factor influencing the mouse-sensitivity when scrubbing the input
nudgeMultiplier: 0.1,
})
// Number prop with a custom nudging function
const y = types.number({
nudgeFn: (
// The mouse movement (in pixels)
deltaX: number,
// The movement as a fraction of the width of the number editor's input
deltaFraction: number,
// A multiplier that's usually 1, but might be another number if user wants to nudge slower/faster
magnitude: number,
// The configuration of the number
config: { nudgeMultiplier?: number; range?: [number, number] },
): number => {
return deltaX * magnitude
},
})

types.rgba(default?)

An RGBA prop type. All color channels are normalized between 0 and 1.


// red
const color = types.rgba({ r: 1, g: 0, b: 0, a: 1 })

types.boolean(default)

A boolean prop type. This prop type may take a custom interpolator as an option.


const isOn = types.boolean(true)

types.string(default, opts?)

A string prop type. This prop type may take a custom interpolator as an option.


const message = types.string('Animation Loading')

types.stringLiteral(default, choices, opts?)

A stringLiteral prop type, useful for building menus or radio buttons. This prop type may take a custom interpolator as an option.

String literals can be presented as radio buttons.


const light = types.stringLiteral('r', { r: 'Red', g: 'Green' }, { as: 'switch', label: 'Street Light' })

Or as menus.


const light = types.stringLiteral('r', { r: 'Red', g: 'Green' }, { as: 'menu', label: 'Street Light' })

types.image(default, opts?)Since 0.6.0

An image prop type. This prop type may take a custom interpolator as an option.

Image props are asset props, meaning their values are asset handles that can be used to retrieve a URL for that asset.

The default value for image props is the id of the default asset. If you don't know the id, an empty string or undefined represents the lack of an assigned asset.


const texture = types.image('', {
label: 'Texture',
})

types.file(default, opts?)Since 0.7.0

An file prop type. This prop type may take a custom interpolator as an option.

File props are asset props, meaning their values are asset handles that can be used to retrieve a URL for that asset.

The default value for file props is the id of the default asset. If you don't know the id, an empty string or undefined represents the lack of an assigned asset.


const model = types.file('', {
label: '3D Model (GLTF)',
})

Pointers

Pointers basically point to values that you can read, observe, and in some cases change.

onChange(pointer, callback, rafDriver?)

Takes a Pointer as the first argument and a callback as the second argument. Calls the callback every time the value pointed to by pointer changes.

Returns an unsubscribe function.


import { getProject, onChange } from '@theatre/core'
const obj = getProject('A project')
.sheet('Scene')
.object('Box', { position: { x: 0 } })
const usubscribe = onChange(obj.props.position.x, (x) => {
console.log('position.x changed to:', x)
})
setTimeout(usubscribe, 10000) // stop listening to changes after 10 seconds

Hint: You can control how often onChange() calls the callback by optoinally providing a rafDriver.

val(pointer)

Takes a Pointer and returns the value it points to.


import { val, getProject } from '@theatre/core'
const obj = getProject('A project')
.sheet('Scene')
.object('Box', { position: { x: 0 } })
console.log(val(obj.props.position.x)) // logs the value of obj.props.x


Was this article helpful to you?

Last edited on October 06, 2023.
Edit this page

Theatre.js
Theatre.js is a design tool in the making. We aim to blur the line between designer/developer, author/consumer, and artist/scientist.
© 2022 Theatre.js Oy – Helsinki.