theatre-js

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Theatre.js Best Practices

Theatre.js 最佳实践

Motion design editor and animation library for the web. Provides a visual timeline editor (Studio) with programmatic control.
面向Web的动效设计编辑器与动画库,提供带有程序化控制功能的可视化时间轴编辑器(Studio)。

Installation

安装

bash
undefined
bash
undefined

Core + Studio (development)

核心库 + Studio(开发环境)

npm install @theatre/core@0.7 @theatre/studio@0.7
npm install @theatre/core@0.7 @theatre/studio@0.7

React Three Fiber integration

React Three Fiber 集成

npm install @theatre/r3f@0.7
npm install @theatre/r3f@0.7

React utilities

React 工具库

npm install @theatre/react
npm install @theatre/react

Theatric (simplified controls)

Theatric(简化版控件)

npm install theatric
undefined
npm install theatric
undefined

Quick Start

快速开始

tsx
import * as core from '@theatre/core'
import studio from '@theatre/studio'

// Initialize Studio (dev only)
if (import.meta.env.DEV) {
  studio.initialize()
}

// Create project → sheet → object
const project = core.getProject('My Project')
const sheet = project.sheet('Main')
const obj = sheet.object('Box', {
  position: { x: 0, y: 0 },
  opacity: 1
})

// Read values
console.log(obj.value.position.x)

// Listen to changes
obj.onValuesChange((values) => {
  element.style.opacity = values.opacity
  element.style.transform = `translate(${values.position.x}px, ${values.position.y}px)`
})

// Play animation
sheet.sequence.play({ iterationCount: Infinity })
tsx
import * as core from '@theatre/core'
import studio from '@theatre/studio'

// 初始化 Studio(仅开发环境)
if (import.meta.env.DEV) {
  studio.initialize()
}

// 创建项目 → 工作区 → 动画对象
const project = core.getProject('My Project')
const sheet = project.sheet('Main')
const obj = sheet.object('Box', {
  position: { x: 0, y: 0 },
  opacity: 1
})

// 读取数值
console.log(obj.value.position.x)

// 监听数值变化
obj.onValuesChange((values) => {
  element.style.opacity = values.opacity
  element.style.transform = `translate(${values.position.x}px, ${values.position.y}px)`
})

// 播放动画
sheet.sequence.play({ iterationCount: Infinity })

Core Concepts

核心概念

ConceptDescription
ProjectContainer for all animation data; maps to exported JSON state
SheetA scene or component; contains objects and one sequence
ObjectAnimatable entity with typed props
SequenceTimeline with keyframes; controls playback
PropsTyped values (number, compound, rgba, etc.)
概念描述
Project(项目)所有动画数据的容器;与导出的JSON状态映射
Sheet(工作区)一个场景或组件;包含动画对象与一个时间轴序列
Object(动画对象)带有类型化属性的可动画实体
Sequence(序列)带有关键帧的时间轴;控制动画播放
Props(属性)类型化数值(数字、复合值、RGBA颜色等)

Reference Index

参考索引

ReferenceUse When
references/01-core.md
Project setup, sheets, objects, sequences, playback control
references/02-prop-types.md
Defining props, custom types, compound props, constraints
references/03-studio.md
Studio UI, keyboard shortcuts, extensions, panels
references/04-react-integration.md
useVal, usePrism, @theatre/react hooks
references/05-r3f-integration.md
React Three Fiber, editable components, SheetProvider
references/06-production.md
Export state, assets, deployment, tree-shaking
参考文档使用场景
references/01-core.md
项目设置、工作区、动画对象、序列、播放控制
references/02-prop-types.md
属性定义、自定义类型、复合属性、约束条件
references/03-studio.md
Studio界面、键盘快捷键、扩展、面板
references/04-react-integration.md
useVal、usePrism、@theatre/react 钩子
references/05-r3f-integration.md
React Three Fiber、可编辑组件、SheetProvider
references/06-production.md
状态导出、资源管理、部署、Tree Shaking

Common Patterns

常见模式

Animate DOM Element

为DOM元素制作动画

tsx
const obj = sheet.object('Card', {
  x: 0,
  y: 0,
  rotation: 0,
  scale: 1,
  opacity: 1
})

obj.onValuesChange(({ x, y, rotation, scale, opacity }) => {
  element.style.transform = `translate(${x}px, ${y}px) rotate(${rotation}deg) scale(${scale})`
  element.style.opacity = opacity
})
tsx
const obj = sheet.object('Card', {
  x: 0,
  y: 0,
  rotation: 0,
  scale: 1,
  opacity: 1
})

obj.onValuesChange(({ x, y, rotation, scale, opacity }) => {
  element.style.transform = `translate(${x}px, ${y}px) rotate(${rotation}deg) scale(${scale})`
  element.style.opacity = opacity
})

Sequence Playback Control

序列播放控制

tsx
const seq = sheet.sequence

// Play once
seq.play()

// Play with options
seq.play({
  iterationCount: Infinity,  // loop forever
  range: [0, 2],             // play seconds 0-2
  rate: 1.5,                 // 1.5x speed
  direction: 'alternate'     // ping-pong
})

// Pause and seek
seq.pause()
seq.position = 1.5  // jump to 1.5s

// Await completion
await seq.play({ iterationCount: 1 })
console.log('Animation complete')
tsx
const seq = sheet.sequence

// 播放一次
seq.play()

// 带参数播放
seq.play({
  iterationCount: Infinity,  // 无限循环
  range: [0, 2],             // 播放0-2秒
  rate: 1.5,                 // 1.5倍速
  direction: 'alternate'     // 往返播放
})

// 暂停与定位
seq.pause()
seq.position = 1.5  // 跳转到1.5秒位置

// 等待动画完成
await seq.play({ iterationCount: 1 })
console.log('动画完成')

React Three Fiber Scene

React Three Fiber 场景

tsx
import { Canvas } from '@react-three/fiber'
import { editable as e, SheetProvider } from '@theatre/r3f'
import { getProject } from '@theatre/core'
import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension'

// Dev setup
if (import.meta.env.DEV) {
  studio.initialize()
  studio.extend(extension)
}

const sheet = getProject('R3F Demo').sheet('Scene')

function App() {
  return (
    <Canvas>
      <SheetProvider sheet={sheet}>
        <e.mesh theatreKey="Cube">
          <boxGeometry />
          <meshStandardMaterial color="orange" />
        </e.mesh>
        <e.pointLight theatreKey="Light" position={[10, 10, 10]} />
      </SheetProvider>
    </Canvas>
  )
}
tsx
import { Canvas } from '@react-three/fiber'
import { editable as e, SheetProvider } from '@theatre/r3f'
import { getProject } from '@theatre/core'
import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension'

// 开发环境设置
if (import.meta.env.DEV) {
  studio.initialize()
  studio.extend(extension)
}

const sheet = getProject('R3F Demo').sheet('Scene')

function App() {
  return (
    <Canvas>
      <SheetProvider sheet={sheet}>
        <e.mesh theatreKey="Cube">
          <boxGeometry />
          <meshStandardMaterial color="orange" />
        </e.mesh>
        <e.pointLight theatreKey="Light" position={[10, 10, 10]} />
      </SheetProvider>
    </Canvas>
  )
}

Theatric Controls (Simple)

Theatric 简化控件

tsx
import { useControls, types } from 'theatric'

function Component() {
  const { color, intensity, position } = useControls({
    color: '#ff0000',
    intensity: types.number(1, { range: [0, 2] }),
    position: { x: 0, y: 0, z: 0 }
  })

  return <mesh position={[position.x, position.y, position.z]} />
}
tsx
import { useControls, types } from 'theatric'

function Component() {
  const { color, intensity, position } = useControls({
    color: '#ff0000',
    intensity: types.number(1, { range: [0, 2] }),
    position: { x: 0, y: 0, z: 0 }
  })

  return <mesh position={[position.x, position.y, position.z]} />
}

Critical Mistakes to Avoid

需避免的常见错误

1. Studio in Production

1. 生产环境中包含Studio

tsx
// ❌ Includes studio in bundle
import studio from '@theatre/studio'
studio.initialize()

// ✅ Dev-only initialization
if (import.meta.env.DEV) {
  studio.initialize()
}
tsx
// ❌ 会将Studio打包进生产代码
import studio from '@theatre/studio'
studio.initialize()

// ✅ 仅在开发环境初始化
if (import.meta.env.DEV) {
  studio.initialize()
}

2. Missing State in Production

2. 生产环境缺少动画状态

tsx
// ❌ No animations without state
const project = core.getProject('My Project')

// ✅ Load exported state
import state from './state.json'
const project = core.getProject('My Project', { state })
tsx
// ❌ 没有状态则无法播放动画
const project = core.getProject('My Project')

// ✅ 加载导出的状态
import state from './state.json'
const project = core.getProject('My Project', { state })

3. Object Key Collisions

3. 动画对象键名冲突

tsx
// ❌ Same key = same object (shared state)
sheet.object('Box', { x: 0 })
sheet.object('Box', { y: 0 })  // Overwrites!

// ✅ Unique keys per object
sheet.object('Box1', { x: 0 })
sheet.object('Box2', { y: 0 })
tsx
// ❌ 相同键名会指向同一个对象(共享状态)
sheet.object('Box', { x: 0 })
sheet.object('Box', { y: 0 })  // 会覆盖之前的对象!

// ✅ 每个对象使用唯一键名
sheet.object('Box1', { x: 0 })
sheet.object('Box2', { y: 0 })

4. Missing R3F Extension

4. 缺少R3F扩展

tsx
// ❌ No 3D controls in Studio
studio.initialize()

// ✅ Extend with R3F extension
import extension from '@theatre/r3f/dist/extension'
studio.initialize()
studio.extend(extension)
tsx
// ❌ Studio中无法控制3D元素
studio.initialize()

// ✅ 扩展R3F功能
import extension from '@theatre/r3f/dist/extension'
studio.initialize()
studio.extend(extension)

5. Forgetting theatreKey

5. 遗漏theatreKey

tsx
// ❌ Not editable
<e.mesh>

// ✅ Requires theatreKey
<e.mesh theatreKey="MyCube">
tsx
// ❌ 无法编辑
<e.mesh>

// ✅ 必须添加theatreKey
<e.mesh theatreKey="MyCube">

Quick Reference

快速参考

TaskSolution
Create project
getProject('Name', { state? })
Create sheet
project.sheet('Name')
Create object
sheet.object('Key', { props })
Listen to values
obj.onValuesChange(cb)
Read value
obj.value.propName
Play animation
sheet.sequence.play(opts?)
Pause animation
sheet.sequence.pause()
Seek position
sheet.sequence.position = 1.5
R3F editable
<e.mesh theatreKey="Key">
React value hook
useVal(obj.props.x)
Export stateStudio → Project → Export (JSON)
任务解决方案
创建项目
getProject('Name', { state? })
创建工作区
project.sheet('Name')
创建动画对象
sheet.object('Key', { props })
监听数值变化
obj.onValuesChange(cb)
读取数值
obj.value.propName
播放动画
sheet.sequence.play(opts?)
暂停动画
sheet.sequence.pause()
定位到指定时间点
sheet.sequence.position = 1.5
R3F可编辑元素
<e.mesh theatreKey="Key">
React数值钩子
useVal(obj.props.x)
导出状态Studio → 项目 → 导出(JSON格式)