diff --git a/packages/playground/src/shared/hello-world-extension-dataverse/App.tsx b/packages/playground/src/shared/hello-world-extension-dataverse/App.tsx
new file mode 100644
index 0000000..4d85034
--- /dev/null
+++ b/packages/playground/src/shared/hello-world-extension-dataverse/App.tsx
@@ -0,0 +1,37 @@
+import {editable as e, SheetProvider} from '@theatre/r3f'
+import {Stars, TorusKnot} from '@react-three/drei'
+import {getProject} from '@theatre/core'
+import React from 'react'
+import {Canvas} from '@react-three/fiber'
+
+function App() {
+ return (
+
{
+ // return setBgIndex((bgIndex) => (bgIndex + 1) % bgs.length)
+ }}
+ style={{
+ height: '100vh',
+ }}
+ >
+
+
+ )
+}
+
+export default App
diff --git a/packages/playground/src/shared/hello-world-extension-dataverse/index.tsx b/packages/playground/src/shared/hello-world-extension-dataverse/index.tsx
new file mode 100644
index 0000000..2ee1c43
--- /dev/null
+++ b/packages/playground/src/shared/hello-world-extension-dataverse/index.tsx
@@ -0,0 +1,70 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import App from './App'
+import type {ToolsetConfig} from '@theatre/studio'
+import studio from '@theatre/studio'
+import extension from '@theatre/r3f/dist/extension'
+import {Box, prism, Ticker, val} from '@theatre/dataverse'
+
+/**
+ * Let's take a look at how we can use `prism`, `Ticker`, and `val` from Theatre.js's Dataverse library
+ * to create a switch with state that is updated automatically,
+ * and is even stored in a Theatre.js object.
+ *
+ * Without going into the details of `prism`, `Ticker`, and `val`, note that by wrapping our `ToolsetConfig` in a prism, our
+ * ```ts
+ * ... .tapImmediate(Ticker.raf, (toolset) => {
+ * set(toolset)
+ * })
+ * ```
+ * code will be called whenever `val(obj.props.exampleProp)` changes (whenever the user clicks the switch and the `onChange` callback is called).
+ * This will ensure that our switch's value matches its state and is reflected in the UI via `set(toolset)`.
+ */
+
+studio.extend(extension)
+studio.extend({
+ id: '@theatre/hello-world-extension',
+ toolbars: {
+ global(set, studio) {
+ const exampleBox = new Box('mobile')
+
+ const untapFn = prism(() => [
+ {
+ type: 'Switch',
+ value: val(exampleBox.derivation),
+ onChange: (value) => exampleBox.set(value),
+ options: [
+ {
+ value: 'mobile',
+ label: 'view mobile version',
+ svgSource: '😀',
+ },
+ {
+ value: 'desktop',
+ label: 'view desktop version',
+ svgSource: '🪢',
+ },
+ ],
+ },
+ {
+ type: 'Icon',
+ title: 'Example Icon',
+ svgSource: '👁🗨',
+ onClick: () => {
+ console.log('hello')
+ },
+ },
+ ])
+ // listen to changes to this derivation using the requestAnimationFrame shared ticker
+ .tapImmediate(Ticker.raf, (value) => {
+ set(value)
+ })
+
+ return untapFn
+ },
+ },
+ panes: [],
+})
+studio.initialize()
+
+ReactDOM.render(, document.getElementById('root'))
diff --git a/packages/playground/src/shared/hello-world-extension-using-sheet-object/App.tsx b/packages/playground/src/shared/hello-world-extension-using-sheet-object/App.tsx
new file mode 100644
index 0000000..4d85034
--- /dev/null
+++ b/packages/playground/src/shared/hello-world-extension-using-sheet-object/App.tsx
@@ -0,0 +1,37 @@
+import {editable as e, SheetProvider} from '@theatre/r3f'
+import {Stars, TorusKnot} from '@react-three/drei'
+import {getProject} from '@theatre/core'
+import React from 'react'
+import {Canvas} from '@react-three/fiber'
+
+function App() {
+ return (
+ {
+ // return setBgIndex((bgIndex) => (bgIndex + 1) % bgs.length)
+ }}
+ style={{
+ height: '100vh',
+ }}
+ >
+
+
+ )
+}
+
+export default App
diff --git a/packages/playground/src/shared/hello-world-extension-using-sheet-object/index.tsx b/packages/playground/src/shared/hello-world-extension-using-sheet-object/index.tsx
new file mode 100644
index 0000000..d32c4b3
--- /dev/null
+++ b/packages/playground/src/shared/hello-world-extension-using-sheet-object/index.tsx
@@ -0,0 +1,63 @@
+import React from 'react'
+import ReactDOM from 'react-dom'
+import App from './App'
+import type {ISheetObject} from '@theatre/core';
+import { onChange, types, val} from '@theatre/core'
+import studio from '@theatre/studio'
+import extension from '@theatre/r3f/dist/extension'
+
+const dataConfig = {
+ exampleProp: types.stringLiteral('yes', {
+ no: 'no',
+ yes: 'yes',
+ }),
+}
+
+studio.extend(extension)
+studio.extend({
+ id: '@theatre/hello-world-extension',
+ toolbars: {
+ global(set, studio) {
+ // A sheet object used by this extension
+ const obj: ISheetObject = studio
+ .getStudioProject()
+ .sheet('example extension UI')
+ .object('editor', dataConfig)
+
+ const updateToolset = () =>
+ set([
+ {
+ type: 'Switch',
+ value: val(obj.props.exampleProp),
+ onChange: (value) =>
+ studio.transaction(({set}) => set(obj.props.exampleProp, value)),
+ options: [
+ {
+ value: 'no',
+ label: 'say no',
+ svgSource: '👎',
+ },
+ {
+ value: 'yes',
+ label: 'say yes',
+ svgSource: '👍',
+ },
+ ],
+ },
+ ])
+
+ const untapFn = onChange(obj.props.exampleProp, () => {
+ updateToolset()
+ })
+
+ // initial update
+ updateToolset()
+
+ return untapFn
+ },
+ },
+ panes: [],
+})
+studio.initialize()
+
+ReactDOM.render(, document.getElementById('root'))
diff --git a/packages/playground/src/shared/hello-world-extension/index.tsx b/packages/playground/src/shared/hello-world-extension/index.tsx
index 451d46d..ea029b8 100644
--- a/packages/playground/src/shared/hello-world-extension/index.tsx
+++ b/packages/playground/src/shared/hello-world-extension/index.tsx
@@ -1,46 +1,52 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
-import type {ToolsetConfig} from '@theatre/studio'
import studio from '@theatre/studio'
import extension from '@theatre/r3f/dist/extension'
-import {Box, prism, Ticker, val} from '@theatre/dataverse'
studio.extend(extension)
studio.extend({
id: '@theatre/hello-world-extension',
toolbars: {
global(set, studio) {
- const exampleBox = new Box('mobile')
- return prism(() => [
- {
- type: 'Switch',
- value: val(exampleBox.derivation),
- onChange: (value) => exampleBox.set(value),
- options: [
- {
- value: 'mobile',
- label: 'view mobile version',
- svgSource: '😀',
+ let switchValue = 'mobile'
+ const updateToolset = () =>
+ set([
+ {
+ type: 'Switch',
+ value: switchValue,
+ onChange: (value) => {
+ switchValue = value
+ updateToolset()
},
- {
- value: 'desktop',
- label: 'view desktop version',
- svgSource: '🪢',
- },
- ],
- },
- {
- type: 'Icon',
- title: 'Example Icon',
- svgSource: '👁🗨',
- onClick: () => {
- console.log('hello')
+ options: [
+ {
+ value: 'mobile',
+ label: 'view mobile version',
+ svgSource: '😀',
+ },
+ {
+ value: 'desktop',
+ label: 'view desktop version',
+ svgSource: '🪢',
+ },
+ ],
},
- },
- ]).tapImmediate(Ticker.raf, (value) => {
- set(value)
- })
+ {
+ type: 'Icon',
+ title: 'Example Icon',
+ svgSource: '👁🗨',
+ onClick: () => {
+ console.log('hello')
+ },
+ },
+ ])
+
+ updateToolset()
+
+ return () => {
+ // remove any listeners if necessary when the extension is unloaded
+ }
},
},
panes: [],