Loading...
Loading...
Compare original and translation side by side
undefinedundefinedundefinedundefinedimport * 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 })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 })| Concept | Description |
|---|---|
| Project | Container for all animation data; maps to exported JSON state |
| Sheet | A scene or component; contains objects and one sequence |
| Object | Animatable entity with typed props |
| Sequence | Timeline with keyframes; controls playback |
| Props | Typed values (number, compound, rgba, etc.) |
| 概念 | 描述 |
|---|---|
| Project(项目) | 所有动画数据的容器;与导出的JSON状态映射 |
| Sheet(工作区) | 一个场景或组件;包含动画对象与一个时间轴序列 |
| Object(动画对象) | 带有类型化属性的可动画实体 |
| Sequence(序列) | 带有关键帧的时间轴;控制动画播放 |
| Props(属性) | 类型化数值(数字、复合值、RGBA颜色等) |
| Reference | Use When |
|---|---|
| Project setup, sheets, objects, sequences, playback control |
| Defining props, custom types, compound props, constraints |
| Studio UI, keyboard shortcuts, extensions, panels |
| useVal, usePrism, @theatre/react hooks |
| React Three Fiber, editable components, SheetProvider |
| Export state, assets, deployment, tree-shaking |
| 参考文档 | 使用场景 |
|---|---|
| 项目设置、工作区、动画对象、序列、播放控制 |
| 属性定义、自定义类型、复合属性、约束条件 |
| Studio界面、键盘快捷键、扩展、面板 |
| useVal、usePrism、@theatre/react 钩子 |
| React Three Fiber、可编辑组件、SheetProvider |
| 状态导出、资源管理、部署、Tree Shaking |
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
})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
})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')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('动画完成')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>
)
}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>
)
}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]} />
}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]} />
}// ❌ Includes studio in bundle
import studio from '@theatre/studio'
studio.initialize()
// ✅ Dev-only initialization
if (import.meta.env.DEV) {
studio.initialize()
}// ❌ 会将Studio打包进生产代码
import studio from '@theatre/studio'
studio.initialize()
// ✅ 仅在开发环境初始化
if (import.meta.env.DEV) {
studio.initialize()
}// ❌ 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 })// ❌ 没有状态则无法播放动画
const project = core.getProject('My Project')
// ✅ 加载导出的状态
import state from './state.json'
const project = core.getProject('My Project', { state })// ❌ 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 })// ❌ 相同键名会指向同一个对象(共享状态)
sheet.object('Box', { x: 0 })
sheet.object('Box', { y: 0 }) // 会覆盖之前的对象!
// ✅ 每个对象使用唯一键名
sheet.object('Box1', { x: 0 })
sheet.object('Box2', { y: 0 })// ❌ No 3D controls in Studio
studio.initialize()
// ✅ Extend with R3F extension
import extension from '@theatre/r3f/dist/extension'
studio.initialize()
studio.extend(extension)// ❌ Studio中无法控制3D元素
studio.initialize()
// ✅ 扩展R3F功能
import extension from '@theatre/r3f/dist/extension'
studio.initialize()
studio.extend(extension)// ❌ Not editable
<e.mesh>
// ✅ Requires theatreKey
<e.mesh theatreKey="MyCube">// ❌ 无法编辑
<e.mesh>
// ✅ 必须添加theatreKey
<e.mesh theatreKey="MyCube">| Task | Solution |
|---|---|
| Create project | |
| Create sheet | |
| Create object | |
| Listen to values | |
| Read value | |
| Play animation | |
| Pause animation | |
| Seek position | |
| R3F editable | |
| React value hook | |
| Export state | Studio → Project → Export (JSON) |
| 任务 | 解决方案 |
|---|---|
| 创建项目 | |
| 创建工作区 | |
| 创建动画对象 | |
| 监听数值变化 | |
| 读取数值 | |
| 播放动画 | |
| 暂停动画 | |
| 定位到指定时间点 | |
| R3F可编辑元素 | |
| React数值钩子 | |
| 导出状态 | Studio → 项目 → 导出(JSON格式) |