diff --git a/packages/playground/src/index.tsx b/packages/playground/src/index.tsx index 921d7a1..41a05e0 100644 --- a/packages/playground/src/index.tsx +++ b/packages/playground/src/index.tsx @@ -1 +1 @@ -import './r3f' +import './space-exploration' diff --git a/packages/plugin-r3f/src/Wrapper.tsx b/packages/plugin-r3f/src/Wrapper.tsx index df94b1b..13f8b61 100644 --- a/packages/plugin-r3f/src/Wrapper.tsx +++ b/packages/plugin-r3f/src/Wrapper.tsx @@ -15,7 +15,7 @@ const Wrapper: React.FC<{ `getSheet() in has returned an invalid value`, ) } - bindToCanvas({sheet})({gl, scene}) + bindToCanvas({sheet, gl, scene}) }, [scene, gl]) return <>{props.children} diff --git a/packages/plugin-r3f/src/components/EditableProxy.tsx b/packages/plugin-r3f/src/components/EditableProxy.tsx index fe2fec6..dea8c91 100644 --- a/packages/plugin-r3f/src/components/EditableProxy.tsx +++ b/packages/plugin-r3f/src/components/EditableProxy.tsx @@ -24,6 +24,7 @@ import type {IconType} from 'react-icons' import studio from '@theatre/studio' import {useSelected} from './useSelected' import {useVal} from '@theatre/dataverse-react' +import {getEditorSheetObject} from './editorStuff' export interface EditableProxyProps { editableName: string @@ -37,8 +38,9 @@ const EditableProxy: VFC = ({ editableType, object, }) => { - const [editorObject, setSnapshotProxyObject] = useEditorStore( - (state) => [state.editorObject, state.setSnapshotProxyObject], + const editorObject = getEditorSheetObject() + const setSnapshotProxyObject = useEditorStore( + (state) => state.setSnapshotProxyObject, shallow, ) diff --git a/packages/plugin-r3f/src/components/ProxyManager.tsx b/packages/plugin-r3f/src/components/ProxyManager.tsx index 330180e..ad26599 100644 --- a/packages/plugin-r3f/src/components/ProxyManager.tsx +++ b/packages/plugin-r3f/src/components/ProxyManager.tsx @@ -20,6 +20,7 @@ import type {$FixMe} from '../types' import {useSelected} from './useSelected' import {useVal} from '@theatre/dataverse-react' import useInvalidate from './useInvalidate' +import {getEditorSheetObject} from './editorStuff' export interface ProxyManagerProps { orbitControlsRef: React.MutableRefObject @@ -33,8 +34,9 @@ type IEditableProxy = { const ProxyManager: VFC = ({orbitControlsRef}) => { const isBeingEdited = useRef(false) - const [editorObject, sceneSnapshot, sheetObjects] = useEditorStore( - (state) => [state.editorObject, state.sceneSnapshot, state.sheetObjects], + const editorObject = getEditorSheetObject() + const [sceneSnapshot, sheetObjects] = useEditorStore( + (state) => [state.sceneSnapshot, state.sheetObjects], shallow, ) const transformControlsMode = diff --git a/packages/plugin-r3f/src/components/SnapshotEditor.tsx b/packages/plugin-r3f/src/components/SnapshotEditor.tsx index 4739c13..cf2decd 100644 --- a/packages/plugin-r3f/src/components/SnapshotEditor.tsx +++ b/packages/plugin-r3f/src/components/SnapshotEditor.tsx @@ -11,6 +11,7 @@ import styled, {createGlobalStyle, StyleSheetManager} from 'styled-components' import {IoCameraReverseOutline} from 'react-icons/all' import type {ISheet} from '@theatre/core' import useSnapshotEditorCamera from './useSnapshotEditorCamera' +import {getEditorSheet, getEditorSheetObject} from './editorStuff' const GlobalStyle = createGlobalStyle` :host { @@ -40,10 +41,9 @@ const EditorScene: React.FC<{snapshotEditorSheet: ISheet; paneId: string}> = ({ paneId, ) - const [editorObject, helpersRoot] = useEditorStore( - (state) => [state.editorObject, state.helpersRoot], - shallow, - ) + const editorObject = getEditorSheetObject() + + const helpersRoot = useEditorStore((state) => state.helpersRoot, shallow) const showGrid = useVal(editorObject?.props.viewport.showGrid) ?? true const showAxes = useVal(editorObject?.props.viewport.showAxes) ?? true @@ -95,16 +95,12 @@ const Tools = styled.div` ` const SnapshotEditor: React.FC<{paneId: string}> = (props) => { - const snapshotEditorSheet = studio.getStudioProject().sheet('Plugin-R3F') + const snapshotEditorSheet = getEditorSheet() const paneId = props.paneId + const editorObject = getEditorSheetObject() - const [editorObject, sceneSnapshot, createSnapshot, sheet] = useEditorStore( - (state) => [ - state.editorObject, - state.sceneSnapshot, - state.createSnapshot, - state.sheet, - ], + const [sceneSnapshot, createSnapshot, sheet] = useEditorStore( + (state) => [state.sceneSnapshot, state.createSnapshot, state.sheet], shallow, ) diff --git a/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx b/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx index f221fc0..c9db5eb 100644 --- a/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx +++ b/packages/plugin-r3f/src/components/Toolbar/Toolbar.tsx @@ -1,19 +1,15 @@ import type {VFC} from 'react' import React from 'react' -import {useEditorStore} from '../../store' -import shallow from 'zustand/shallow' import {IoCameraOutline} from 'react-icons/all' import studio, {ToolbarIconButton} from '@theatre/studio' import {useVal} from '@theatre/dataverse-react' import TransformControlsModeSelect from './TransformControlsModeSelect' import ViewportShadingSelect from './ViewportShadingSelect' import TransformControlsSpaceSelect from './TransformControlsSpaceSelect' +import {getEditorSheetObject} from '../editorStuff' const Toolbar: VFC = () => { - const [editorObject] = useEditorStore( - (state) => [state.editorObject], - shallow, - ) + const editorObject = getEditorSheetObject() const transformControlsMode = useVal(editorObject?.props.transformControls.mode) ?? 'translate' diff --git a/packages/plugin-r3f/src/components/editorStuff.ts b/packages/plugin-r3f/src/components/editorStuff.ts new file mode 100644 index 0000000..9104ff5 --- /dev/null +++ b/packages/plugin-r3f/src/components/editorStuff.ts @@ -0,0 +1,72 @@ +import type {ISheet, ISheetObject} from '@theatre/core' +import {types} from '@theatre/core' +import studio from '@theatre/studio' + +let sheet: ISheet | undefined = undefined +let sheetObject: ISheetObject | undefined = + undefined + +const editorSheetObjectConfig = types.compound({ + isOpen: types.boolean(false, {label: 'Editor Open'}), + viewport: types.compound( + { + showAxes: types.boolean(true, {label: 'Axes'}), + showGrid: types.boolean(true, {label: 'Grid'}), + showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}), + resolution: types.number(1440, { + label: 'Resolution', + range: [0, 1000], + }), + shading: types.stringLiteral( + 'rendered', + { + flat: 'Flat', + rendered: 'Rendered', + solid: 'Solid', + wireframe: 'Wireframe', + }, + {as: 'menu', label: 'Shading'}, + ), + }, + {label: 'Viewport Config'}, + ), + transformControls: types.compound( + { + mode: types.stringLiteral( + 'translate', + { + translate: 'Translate', + rotate: 'Rotate', + scale: 'Scale', + }, + {as: 'switch', label: 'Mode'}, + ), + space: types.stringLiteral( + 'world', + { + local: 'Local', + world: 'World', + }, + {as: 'switch', label: 'Space'}, + ), + }, + {label: 'Transform Controls'}, + ), +}) + +export function getEditorSheet(): ISheet { + if (!sheet) { + sheet = studio.getStudioProject().sheet('R3F UI') + } + return sheet +} + +export function getEditorSheetObject(): ISheetObject< + typeof editorSheetObjectConfig +> | null { + if (!sheetObject) { + sheetObject = + getEditorSheet().object('Editor', null, editorSheetObjectConfig) || null + } + return sheetObject +} diff --git a/packages/plugin-r3f/src/store.ts b/packages/plugin-r3f/src/store.ts index 8465ba2..64782ca 100644 --- a/packages/plugin-r3f/src/store.ts +++ b/packages/plugin-r3f/src/store.ts @@ -3,7 +3,7 @@ import create from 'zustand' import type {Object3D, Scene, WebGLRenderer} from 'three' import {Group} from 'three' import type {ISheet, ISheetObject} from '@theatre/core' -import {types, getProject} from '@theatre/core' +import {types} from '@theatre/core' export type EditableType = | 'group' @@ -129,7 +129,6 @@ export interface EditableState { export type EditorStore = { sheet: ISheet | null - editorObject: ISheetObject | null sheetObjects: {[uniqueName in string]?: BaseSheetObjectType} scene: Scene | null gl: WebGLRenderer | null @@ -146,7 +145,6 @@ export type EditorStore = { gl: WebGLRenderer, allowImplicitInstancing: boolean, sheet: ISheet, - editorObject: null | ISheetObject, ) => void addEditable: (type: T, uniqueName: string) => void @@ -174,13 +172,12 @@ const config: StateCreator = (set, get) => { editablesSnapshot: null, initialEditorCamera: {}, - init: (scene, gl, allowImplicitInstancing, sheet, editorObject) => { + init: (scene, gl, allowImplicitInstancing, sheet) => { set({ scene, gl, allowImplicitInstancing, sheet, - editorObject, }) }, @@ -264,70 +261,16 @@ export const useEditorStore = create(config) export type BindFunction = (options: { allowImplicitInstancing?: boolean sheet: ISheet -}) => (options: {gl: WebGLRenderer; scene: Scene}) => void - -const editorSheetObjectConfig = types.compound({ - isOpen: types.boolean(false, {label: 'Editor Open'}), - viewport: types.compound( - { - showAxes: types.boolean(true, {label: 'Axes'}), - showGrid: types.boolean(true, {label: 'Grid'}), - showOverlayIcons: types.boolean(false, {label: 'Overlay Icons'}), - resolution: types.number(1440, { - label: 'Resolution', - range: [0, 1000], - }), - shading: types.stringLiteral( - 'rendered', - { - flat: 'Flat', - rendered: 'Rendered', - solid: 'Solid', - wireframe: 'Wireframe', - }, - {as: 'menu', label: 'Shading'}, - ), - }, - {label: 'Viewport Config'}, - ), - transformControls: types.compound( - { - mode: types.stringLiteral( - 'translate', - { - translate: 'Translate', - rotate: 'Rotate', - scale: 'Scale', - }, - {as: 'switch', label: 'Mode'}, - ), - space: types.stringLiteral( - 'world', - { - local: 'Local', - world: 'World', - }, - {as: 'switch', label: 'Space'}, - ), - }, - {label: 'Transform Controls'}, - ), -}) + gl: WebGLRenderer + scene: Scene +}) => void export const bindToCanvas: BindFunction = ({ allowImplicitInstancing = false, sheet, + gl, + scene, }) => { - const uiSheet: null | ISheet = - process.env.NODE_ENV === 'development' - ? getProject('R3F Plugin').sheet('UI') - : null - - const editorSheetObject = - uiSheet?.object('Editor', null, editorSheetObjectConfig) || null - - return ({gl, scene}) => { - const init = useEditorStore.getState().init - init(scene, gl, allowImplicitInstancing, sheet, editorSheetObject) - } + const init = useEditorStore.getState().init + init(scene, gl, allowImplicitInstancing, sheet) }