react-three-game 0.0.92 → 0.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -33
- package/dist/helpers/index.d.ts +0 -3
- package/dist/helpers/index.js +1 -8
- package/dist/index.d.ts +5 -8
- package/dist/index.js +3 -4
- package/dist/tools/prefabeditor/EditorTree.js +2 -2
- package/dist/tools/prefabeditor/GameEvents.d.ts +6 -12
- package/dist/tools/prefabeditor/GameEvents.js +0 -8
- package/dist/tools/prefabeditor/InstanceProvider.d.ts +6 -4
- package/dist/tools/prefabeditor/InstanceProvider.js +84 -199
- package/dist/tools/prefabeditor/PrefabEditor.d.ts +18 -6
- package/dist/tools/prefabeditor/PrefabEditor.js +55 -39
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +15 -8
- package/dist/tools/prefabeditor/PrefabRoot.js +141 -117
- package/dist/tools/prefabeditor/assetRuntime.d.ts +13 -11
- package/dist/tools/prefabeditor/assetRuntime.js +15 -15
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +1 -1
- package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
- package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +3 -3
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/ModelComponent.js +1 -1
- package/dist/tools/prefabeditor/components/PointLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SoundComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
- package/dist/tools/prefabeditor/components/index.js +0 -2
- package/dist/tools/prefabeditor/types.d.ts +1 -0
- package/dist/tools/prefabeditor/usePointerEvents.d.ts +3 -3
- package/dist/tools/prefabeditor/usePointerEvents.js +5 -5
- package/package.json +1 -3
- package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +0 -26
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +0 -302
- package/dist/tools/prefabeditor/scene.d.ts +0 -70
- package/dist/tools/prefabeditor/scene.js +0 -237
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type ForwardRefExoticComponent, type RefAttributes } from "react";
|
|
2
|
+
import { Matrix4, Object3D, Texture } from "three";
|
|
2
3
|
import { ThreeEvent } from "@react-three/fiber";
|
|
3
4
|
import { GameObject as GameObjectType, Prefab } from "./types";
|
|
4
5
|
import { LoadedModels } from "../dragdrop";
|
|
5
6
|
import { PrefabStoreApi } from "./prefabStore";
|
|
6
7
|
export interface PrefabRootRef {
|
|
7
|
-
root:
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
root: Object3D | null;
|
|
9
|
+
getNodeObject: (nodeId: string) => Object3D | null;
|
|
10
|
+
getNodeHandle: <T = unknown>(nodeId: string, kind: string) => T | null;
|
|
10
11
|
addModel: (path: string, model: Object3D) => void;
|
|
11
12
|
addTexture: (path: string, texture: Texture) => void;
|
|
12
13
|
addSound: (path: string, sound: AudioBuffer) => void;
|
|
@@ -14,22 +15,28 @@ export interface PrefabRootRef {
|
|
|
14
15
|
export interface PrefabRootProps {
|
|
15
16
|
editMode?: boolean;
|
|
16
17
|
data?: Prefab;
|
|
17
|
-
store?: PrefabStoreApi;
|
|
18
18
|
selectedId?: string | null;
|
|
19
19
|
onSelect?: (id: string | null) => void;
|
|
20
|
-
onClick?: (event: ThreeEvent<PointerEvent>,
|
|
20
|
+
onClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
21
|
+
onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
21
22
|
basePath?: string;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
interface PrefabRootInternalProps extends PrefabRootProps {
|
|
25
|
+
store?: PrefabStoreApi;
|
|
26
|
+
}
|
|
27
|
+
export declare const PrefabRootInternal: ForwardRefExoticComponent<PrefabRootInternalProps & RefAttributes<PrefabRootRef>>;
|
|
28
|
+
export declare const PrefabRoot: ForwardRefExoticComponent<PrefabRootProps & RefAttributes<PrefabRootRef>>;
|
|
24
29
|
export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
|
|
25
30
|
interface RendererProps {
|
|
26
31
|
nodeId: string;
|
|
27
32
|
selectedId?: string | null;
|
|
28
33
|
onSelect?: (id: string) => void;
|
|
29
|
-
onClick?: (event: ThreeEvent<PointerEvent>,
|
|
34
|
+
onClick?: (event: ThreeEvent<PointerEvent>, nodeId: string, object: Object3D | null) => void;
|
|
35
|
+
onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
|
|
30
36
|
registerRef: (id: string, obj: Object3D | null) => void;
|
|
31
37
|
loadedModels: LoadedModels;
|
|
32
38
|
editMode?: boolean;
|
|
33
39
|
parentMatrix?: Matrix4;
|
|
40
|
+
isVisible?: boolean;
|
|
34
41
|
}
|
|
35
42
|
export default PrefabRoot;
|
|
@@ -20,9 +20,8 @@ import { builtinComponents } from "./components";
|
|
|
20
20
|
import { loadModel, loadSound, loadTexture } from "../dragdrop";
|
|
21
21
|
import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, useInstanceCheck } from "./InstanceProvider";
|
|
22
22
|
import { composeTransform, decompose } from "./utils";
|
|
23
|
-
import { isPhysicsProps } from "./components/PhysicsComponent";
|
|
24
23
|
import { createPrefabStore, PrefabStoreProvider, useOptionalPrefabStoreApi, usePrefabChildIds, usePrefabNode, usePrefabRootId } from "./prefabStore";
|
|
25
|
-
import { AssetRuntimeContext,
|
|
24
|
+
import { AssetRuntimeContext, CurrentNodeScope } from "./assetRuntime";
|
|
26
25
|
import { gameEvents } from "./GameEvents";
|
|
27
26
|
import { sound as soundManager } from "../../helpers/SoundManager";
|
|
28
27
|
builtinComponents.forEach(registerComponent);
|
|
@@ -36,30 +35,13 @@ function resolveAssetPath(basePath, file) {
|
|
|
36
35
|
return file;
|
|
37
36
|
return file.startsWith("/") ? `${basePath}${file}` : `${basePath}/${file}`;
|
|
38
37
|
}
|
|
39
|
-
/** Check if
|
|
40
|
-
function isNodeReady(
|
|
38
|
+
/** Check if a model component's assets are loaded. */
|
|
39
|
+
function isNodeReady(model, loadedModels) {
|
|
41
40
|
var _a;
|
|
42
|
-
const model = findComponent(node, "Model");
|
|
43
41
|
if (!((_a = model === null || model === void 0 ? void 0 : model.properties) === null || _a === void 0 ? void 0 : _a.filename))
|
|
44
42
|
return true;
|
|
45
43
|
return Boolean(loadedModels[model.properties.filename]);
|
|
46
44
|
}
|
|
47
|
-
function getNodeClickEventName(node) {
|
|
48
|
-
var _a;
|
|
49
|
-
const clickComponents = [
|
|
50
|
-
findComponent(node, 'BufferGeometry'),
|
|
51
|
-
findComponent(node, 'Geometry'),
|
|
52
|
-
];
|
|
53
|
-
for (const component of clickComponents) {
|
|
54
|
-
if (!((_a = component === null || component === void 0 ? void 0 : component.properties) === null || _a === void 0 ? void 0 : _a.emitClickEvent))
|
|
55
|
-
continue;
|
|
56
|
-
const eventName = component.properties.clickEventName;
|
|
57
|
-
if (typeof eventName === 'string' && eventName.trim()) {
|
|
58
|
-
return eventName.trim();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
45
|
function getNodeMetadataProps(node) {
|
|
64
46
|
var _a, _b;
|
|
65
47
|
const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
|
|
@@ -68,7 +50,7 @@ function getNodeMetadataProps(node) {
|
|
|
68
50
|
userData: Object.assign(Object.assign({ prefabNodeId: node.id }, (nodeName ? { prefabNodeName: nodeName } : {})), getNodeUserData(node)),
|
|
69
51
|
};
|
|
70
52
|
}
|
|
71
|
-
export const
|
|
53
|
+
export const PrefabRootInternal = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick, onEditNodeClick, basePath = "" }, ref) => {
|
|
72
54
|
var _a;
|
|
73
55
|
const [models, setModels] = useState({});
|
|
74
56
|
const [textures, setTextures] = useState({});
|
|
@@ -81,8 +63,7 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
81
63
|
const failedTextures = useRef(new Set());
|
|
82
64
|
const failedSounds = useRef(new Set());
|
|
83
65
|
const objectRefs = useRef({});
|
|
84
|
-
const
|
|
85
|
-
const rootRef = useRef(null);
|
|
66
|
+
const nodeHandles = useRef(new Map());
|
|
86
67
|
const parentStore = useOptionalPrefabStoreApi();
|
|
87
68
|
const [ownedStore] = useState(() => {
|
|
88
69
|
if (data)
|
|
@@ -94,35 +75,53 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
94
75
|
const resolvedStore = (_a = store !== null && store !== void 0 ? store : parentStore) !== null && _a !== void 0 ? _a : ownedStore;
|
|
95
76
|
const usesOwnedStore = resolvedStore === ownedStore;
|
|
96
77
|
const shouldProvideStoreContext = !parentStore || parentStore !== resolvedStore;
|
|
78
|
+
const rootId = useStore(resolvedStore, state => state.rootId);
|
|
97
79
|
const assetManifestKey = useStore(resolvedStore, state => state.assetManifestKey);
|
|
98
80
|
const availableModels = useMemo(() => (Object.assign(Object.assign({}, models), injectedModels)), [models, injectedModels]);
|
|
99
81
|
const availableTextures = useMemo(() => (Object.assign(Object.assign({}, textures), injectedTextures)), [textures, injectedTextures]);
|
|
100
82
|
const availableSounds = useMemo(() => (Object.assign(Object.assign({}, sounds), injectedSounds)), [sounds, injectedSounds]);
|
|
101
|
-
const
|
|
83
|
+
const getNodeObject = useCallback((id) => {
|
|
102
84
|
var _a;
|
|
103
85
|
return (_a = objectRefs.current[id]) !== null && _a !== void 0 ? _a : null;
|
|
104
86
|
}, []);
|
|
105
|
-
const
|
|
106
|
-
var _a;
|
|
107
|
-
return (_a =
|
|
87
|
+
const getNodeHandle = useCallback((id, kind) => {
|
|
88
|
+
var _a, _b;
|
|
89
|
+
return (_b = (_a = nodeHandles.current.get(id)) === null || _a === void 0 ? void 0 : _a.get(kind)) !== null && _b !== void 0 ? _b : null;
|
|
90
|
+
}, []);
|
|
91
|
+
const registerNodeHandle = useCallback((id, kind, handle) => {
|
|
92
|
+
const current = nodeHandles.current.get(id);
|
|
93
|
+
if (handle == null) {
|
|
94
|
+
if (!current)
|
|
95
|
+
return;
|
|
96
|
+
current.delete(kind);
|
|
97
|
+
if (current.size === 0) {
|
|
98
|
+
nodeHandles.current.delete(id);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (current) {
|
|
103
|
+
current.set(kind, handle);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
nodeHandles.current.set(id, new Map([[kind, handle]]));
|
|
108
107
|
}, []);
|
|
109
108
|
useImperativeHandle(ref, () => ({
|
|
110
|
-
root
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
get root() {
|
|
110
|
+
var _a;
|
|
111
|
+
return (_a = objectRefs.current[rootId]) !== null && _a !== void 0 ? _a : null;
|
|
112
|
+
},
|
|
113
|
+
getNodeObject,
|
|
114
|
+
getNodeHandle,
|
|
113
115
|
addModel: (path, model) => setInjectedModels(prev => (Object.assign(Object.assign({}, prev), { [path]: model }))),
|
|
114
116
|
addTexture: (path, texture) => setInjectedTextures(prev => (Object.assign(Object.assign({}, prev), { [path]: texture }))),
|
|
115
117
|
addSound: (path, sound) => {
|
|
116
118
|
soundManager.setBuffer(path, sound);
|
|
117
119
|
setInjectedSounds(prev => (Object.assign(Object.assign({}, prev), { [path]: sound })));
|
|
118
120
|
},
|
|
119
|
-
}), [
|
|
121
|
+
}), [getNodeHandle, getNodeObject, rootId]);
|
|
120
122
|
const registerRef = useCallback((id, obj) => {
|
|
121
123
|
objectRefs.current[id] = obj;
|
|
122
124
|
}, []);
|
|
123
|
-
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
124
|
-
rigidBodyRefs.current.set(id, rb);
|
|
125
|
-
}, []);
|
|
126
125
|
useEffect(() => {
|
|
127
126
|
if (usesOwnedStore && data) {
|
|
128
127
|
resolvedStore.getState().replacePrefab(data);
|
|
@@ -186,25 +185,87 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
186
185
|
syncAssets();
|
|
187
186
|
}, [resolvedStore, assetManifestKey, basePath, injectedModels, injectedSounds, injectedTextures, models, sounds, textures]);
|
|
188
187
|
const assetRuntime = useMemo(() => ({
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
registerNodeHandle,
|
|
189
|
+
getNodeHandle,
|
|
190
|
+
getNodeObject,
|
|
192
191
|
getModel: (path) => { var _a; return (_a = availableModels[path]) !== null && _a !== void 0 ? _a : null; },
|
|
193
192
|
getTexture: (path) => { var _a; return (_a = availableTextures[path]) !== null && _a !== void 0 ? _a : null; },
|
|
194
193
|
getSound: (path) => { var _a; return (_a = availableSounds[path]) !== null && _a !== void 0 ? _a : null; },
|
|
195
194
|
getAssetRevision: () => `${Object.keys(availableTextures).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`,
|
|
196
|
-
}), [
|
|
197
|
-
const
|
|
195
|
+
}), [registerNodeHandle, getNodeHandle, getNodeObject, availableModels, availableTextures, availableSounds]);
|
|
196
|
+
const handleNodeClick = useCallback((event, nodeId, fallbackObject) => {
|
|
197
|
+
const node = resolvedStore.getState().nodesById[nodeId];
|
|
198
|
+
if (!node)
|
|
199
|
+
return;
|
|
200
|
+
const { clickEventName } = analyzeNodeComponents(node);
|
|
201
|
+
emitNodePointerEvent(clickEventName, event, nodeId, node, fallbackObject);
|
|
202
|
+
onClick === null || onClick === void 0 ? void 0 : onClick(event, node);
|
|
203
|
+
}, [onClick, resolvedStore]);
|
|
204
|
+
const content = (_jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, onClick: editMode ? undefined : handleNodeClick, registerRef: registerRef, children: _jsx(StoreRootNode, { selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: editMode ? undefined : handleNodeClick, onEditNodeClick: editMode ? onEditNodeClick : undefined, registerRef: registerRef, loadedModels: availableModels, editMode: editMode, parentMatrix: IDENTITY }) }));
|
|
198
205
|
const runtimeContent = _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content });
|
|
199
206
|
if (!shouldProvideStoreContext) {
|
|
200
207
|
return runtimeContent;
|
|
201
208
|
}
|
|
202
209
|
return _jsx(PrefabStoreProvider, { store: resolvedStore, children: runtimeContent });
|
|
203
210
|
});
|
|
211
|
+
export const PrefabRoot = PrefabRootInternal;
|
|
204
212
|
function StoreRootNode(props) {
|
|
205
213
|
const rootId = usePrefabRootId();
|
|
206
214
|
return _jsx(GameObjectRenderer, Object.assign({}, props, { nodeId: rootId }));
|
|
207
215
|
}
|
|
216
|
+
function getClickEventName(component) {
|
|
217
|
+
var _a;
|
|
218
|
+
if (!((_a = component === null || component === void 0 ? void 0 : component.properties) === null || _a === void 0 ? void 0 : _a.emitClickEvent))
|
|
219
|
+
return null;
|
|
220
|
+
const eventName = component.properties.clickEventName;
|
|
221
|
+
return typeof eventName === 'string' && eventName.trim() ? eventName.trim() : null;
|
|
222
|
+
}
|
|
223
|
+
function analyzeNodeComponents(node) {
|
|
224
|
+
var _a, _b, _c;
|
|
225
|
+
let bufferGeometry;
|
|
226
|
+
let geometry;
|
|
227
|
+
let material;
|
|
228
|
+
let model;
|
|
229
|
+
const composition = [];
|
|
230
|
+
for (const [key, component] of Object.entries((_a = node.components) !== null && _a !== void 0 ? _a : {})) {
|
|
231
|
+
if (!(component === null || component === void 0 ? void 0 : component.type))
|
|
232
|
+
continue;
|
|
233
|
+
switch (component.type) {
|
|
234
|
+
case "Transform":
|
|
235
|
+
break;
|
|
236
|
+
case "BufferGeometry":
|
|
237
|
+
bufferGeometry = component;
|
|
238
|
+
break;
|
|
239
|
+
case "Geometry":
|
|
240
|
+
geometry = component;
|
|
241
|
+
break;
|
|
242
|
+
case "Material":
|
|
243
|
+
material = component;
|
|
244
|
+
break;
|
|
245
|
+
case "Model":
|
|
246
|
+
model = component;
|
|
247
|
+
break;
|
|
248
|
+
default: {
|
|
249
|
+
const def = getComponentDef(component.type);
|
|
250
|
+
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
251
|
+
break;
|
|
252
|
+
composition.push({
|
|
253
|
+
key,
|
|
254
|
+
View: def.View,
|
|
255
|
+
properties: component.properties,
|
|
256
|
+
});
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
geometry: bufferGeometry !== null && bufferGeometry !== void 0 ? bufferGeometry : geometry,
|
|
263
|
+
material,
|
|
264
|
+
model,
|
|
265
|
+
clickEventName: (_c = (_b = getClickEventName(bufferGeometry)) !== null && _b !== void 0 ? _b : getClickEventName(geometry)) !== null && _c !== void 0 ? _c : getClickEventName(model),
|
|
266
|
+
composition,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
208
269
|
function emitNodePointerEvent(eventName, event, nodeId, node, fallbackObject) {
|
|
209
270
|
var _a;
|
|
210
271
|
const trimmedEventName = eventName === null || eventName === void 0 ? void 0 : eventName.trim();
|
|
@@ -247,21 +308,19 @@ export function GameObjectRenderer(props) {
|
|
|
247
308
|
? _jsx(InstancedNode, Object.assign({}, props), key)
|
|
248
309
|
: _jsx(StandardNode, Object.assign({}, props), key);
|
|
249
310
|
}
|
|
250
|
-
function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef, onSelect, onClick }) {
|
|
311
|
+
function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef, onSelect, onEditNodeClick, onClick, isVisible = true }) {
|
|
251
312
|
var _a, _b;
|
|
252
313
|
const gameObject = usePrefabNode(nodeId);
|
|
253
314
|
if (!gameObject)
|
|
254
315
|
return null;
|
|
316
|
+
const analyzedComponents = useMemo(() => analyzeNodeComponents(gameObject), [gameObject]);
|
|
255
317
|
const localTransform = getNodeTransformProps(gameObject);
|
|
256
318
|
const isLocked = Boolean(gameObject.locked);
|
|
319
|
+
const nodeVisible = isVisible && !gameObject.hidden;
|
|
257
320
|
const metadataProps = getNodeMetadataProps(gameObject);
|
|
258
|
-
const groupProps = Object.assign(Object.assign({}, metadataProps), { position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale });
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
? physicsData === null || physicsData === void 0 ? void 0 : physicsData.properties
|
|
262
|
-
: undefined;
|
|
263
|
-
const modelUrl = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.filename;
|
|
264
|
-
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physicsProps), [gameObject, modelUrl, parentMatrix, physicsProps]);
|
|
321
|
+
const groupProps = Object.assign(Object.assign({}, metadataProps), { visible: nodeVisible, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale });
|
|
322
|
+
const modelUrl = (_b = (_a = analyzedComponents.model) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.filename;
|
|
323
|
+
const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl), [gameObject, modelUrl, parentMatrix]);
|
|
265
324
|
const groupRef = useRef(null);
|
|
266
325
|
const handleGroupRef = useCallback((object) => {
|
|
267
326
|
groupRef.current = object;
|
|
@@ -271,24 +330,24 @@ function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef,
|
|
|
271
330
|
}, [editMode, nodeId, registerRef]);
|
|
272
331
|
const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
|
|
273
332
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
|
|
274
|
-
|
|
333
|
+
onEditNodeClick === null || onEditNodeClick === void 0 ? void 0 : onEditNodeClick(event, gameObject);
|
|
275
334
|
});
|
|
276
|
-
const renderedInstances = instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked,
|
|
335
|
+
const renderedInstances = instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, visible: nodeVisible, locked: isLocked, onClick: onClick }, instance.id)));
|
|
277
336
|
if (editMode) {
|
|
278
337
|
return (_jsxs(_Fragment, { children: [_jsx("group", Object.assign({ ref: handleGroupRef }, groupProps, editClickHandlers, { children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) })), renderedInstances] }));
|
|
279
338
|
}
|
|
280
339
|
return _jsx(_Fragment, { children: renderedInstances });
|
|
281
340
|
}
|
|
282
|
-
function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, loadedModels, editMode, parentMatrix = IDENTITY, }) {
|
|
283
|
-
var _a, _b;
|
|
341
|
+
function StandardNode({ nodeId, selectedId, onSelect, onClick, onEditNodeClick, registerRef, loadedModels, editMode, parentMatrix = IDENTITY, isVisible = true, }) {
|
|
284
342
|
const gameObject = usePrefabNode(nodeId);
|
|
285
343
|
const childIds = usePrefabChildIds(nodeId);
|
|
286
344
|
if (!gameObject)
|
|
287
345
|
return null;
|
|
346
|
+
const analyzedComponents = useMemo(() => analyzeNodeComponents(gameObject), [gameObject]);
|
|
288
347
|
const isSelected = selectedId === nodeId;
|
|
289
348
|
const isLocked = Boolean(gameObject.locked);
|
|
349
|
+
const nodeVisible = isVisible && !gameObject.hidden;
|
|
290
350
|
const stillInstanced = useInstanceCheck(nodeId);
|
|
291
|
-
const clickEventName = getNodeClickEventName(gameObject);
|
|
292
351
|
const metadataProps = getNodeMetadataProps(gameObject);
|
|
293
352
|
const groupRef = useRef(null);
|
|
294
353
|
const handleGroupRef = useCallback((object) => {
|
|
@@ -297,21 +356,18 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
297
356
|
}, [nodeId, registerRef]);
|
|
298
357
|
const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
|
|
299
358
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
|
|
300
|
-
|
|
359
|
+
onEditNodeClick === null || onEditNodeClick === void 0 ? void 0 : onEditNodeClick(event, gameObject);
|
|
301
360
|
});
|
|
302
|
-
const primaryClickHandlers = !editMode &&
|
|
361
|
+
const primaryClickHandlers = !editMode && onClick
|
|
303
362
|
? {
|
|
304
363
|
onClick: (event) => {
|
|
305
364
|
event.stopPropagation();
|
|
306
|
-
|
|
307
|
-
onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
|
|
365
|
+
onClick(event, nodeId, groupRef.current);
|
|
308
366
|
},
|
|
309
367
|
}
|
|
310
368
|
: undefined;
|
|
311
369
|
const world = parentMatrix.clone().multiply(compose(gameObject));
|
|
312
|
-
const
|
|
313
|
-
const ready = isNodeReady(gameObject, loadedModels);
|
|
314
|
-
const hasPhysics = physics && ready && !stillInstanced;
|
|
370
|
+
const ready = isNodeReady(analyzedComponents.model, loadedModels);
|
|
315
371
|
const transform = getNodeTransformProps(gameObject);
|
|
316
372
|
const transformProps = {
|
|
317
373
|
position: transform.position,
|
|
@@ -319,40 +375,11 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
319
375
|
scale: transform.scale,
|
|
320
376
|
};
|
|
321
377
|
const groupProps = Object.assign(Object.assign({}, metadataProps), transformProps);
|
|
322
|
-
const
|
|
323
|
-
const
|
|
324
|
-
const physicsKey = `physics_${nodeId}_${isInstanced ? 'instanced' : 'standard'}`;
|
|
325
|
-
const renderCtx = { loadedModels, editMode, registerRef };
|
|
326
|
-
const childNodes = _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode });
|
|
327
|
-
const inner = renderCompositionNode(gameObject, renderCtx, primaryClickHandlers, childNodes);
|
|
378
|
+
const childNodes = _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, onEditNodeClick: onEditNodeClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode, isVisible: nodeVisible });
|
|
379
|
+
const inner = renderNodeContent(analyzedComponents, loadedModels, primaryClickHandlers, childNodes);
|
|
328
380
|
const editAnchor = editMode ? (_jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) })) : null;
|
|
329
|
-
const standardNode = (_jsxs("group", Object.assign({ ref: handleGroupRef }, groupProps, (editMode ? editClickHandlers : undefined), { children: [editAnchor, inner] })));
|
|
330
|
-
|
|
331
|
-
return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: physicsNode !== null && physicsNode !== void 0 ? physicsNode : standardNode }));
|
|
332
|
-
}
|
|
333
|
-
function isRendererHandledComponent(componentType) {
|
|
334
|
-
return componentType === "Transform"
|
|
335
|
-
|| componentType === "BufferGeometry"
|
|
336
|
-
|| componentType === "Geometry"
|
|
337
|
-
|| componentType === "Material"
|
|
338
|
-
|| componentType === "Physics"
|
|
339
|
-
|| componentType === "Model";
|
|
340
|
-
}
|
|
341
|
-
function getCompositionComponents(gameObject) {
|
|
342
|
-
var _a;
|
|
343
|
-
return Object.entries((_a = gameObject.components) !== null && _a !== void 0 ? _a : {}).reduce((result, [key, comp]) => {
|
|
344
|
-
if (!(comp === null || comp === void 0 ? void 0 : comp.type) || isRendererHandledComponent(comp.type))
|
|
345
|
-
return result;
|
|
346
|
-
const def = getComponentDef(comp.type);
|
|
347
|
-
if (!(def === null || def === void 0 ? void 0 : def.View))
|
|
348
|
-
return result;
|
|
349
|
-
result.push({
|
|
350
|
-
key,
|
|
351
|
-
View: def.View,
|
|
352
|
-
properties: comp.properties,
|
|
353
|
-
});
|
|
354
|
-
return result;
|
|
355
|
-
}, []);
|
|
381
|
+
const standardNode = (_jsxs("group", Object.assign({ ref: handleGroupRef }, groupProps, { visible: nodeVisible }, (editMode ? editClickHandlers : undefined), { children: [editAnchor, inner] })));
|
|
382
|
+
return (_jsx(CurrentNodeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: standardNode }));
|
|
356
383
|
}
|
|
357
384
|
function ChildNodes(_a) {
|
|
358
385
|
var { childIds, parentMatrix } = _a, props = __rest(_a, ["childIds", "parentMatrix"]);
|
|
@@ -370,7 +397,7 @@ function getModelRepeatSettings(node) {
|
|
|
370
397
|
repeatAxes: getRepeatAxesFromModelProperties(properties),
|
|
371
398
|
};
|
|
372
399
|
}
|
|
373
|
-
function buildRepeatedInstances(gameObject, parentMatrix, modelUrl
|
|
400
|
+
function buildRepeatedInstances(gameObject, parentMatrix, modelUrl) {
|
|
374
401
|
if (!modelUrl)
|
|
375
402
|
return [];
|
|
376
403
|
const transform = getNodeTransformProps(gameObject);
|
|
@@ -407,7 +434,6 @@ function buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physics) {
|
|
|
407
434
|
position,
|
|
408
435
|
rotation,
|
|
409
436
|
scale,
|
|
410
|
-
physics,
|
|
411
437
|
});
|
|
412
438
|
}
|
|
413
439
|
}
|
|
@@ -423,32 +449,30 @@ function getNodeTransformProps(node) {
|
|
|
423
449
|
scale: (_d = t === null || t === void 0 ? void 0 : t.scale) !== null && _d !== void 0 ? _d : [1, 1, 1],
|
|
424
450
|
};
|
|
425
451
|
}
|
|
426
|
-
function
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
const
|
|
433
|
-
const material = findComponent(gameObject, "Material");
|
|
434
|
-
const model = findComponent(gameObject, "Model");
|
|
435
|
-
const geometryDef = geometry && getComponentDef(geometry.type);
|
|
436
|
-
const materialDef = material && getComponentDef(material.type);
|
|
437
|
-
const modelDef = model && getComponentDef(model.type);
|
|
438
|
-
const geometryProperties = (_b = geometry === null || geometry === void 0 ? void 0 : geometry.properties) !== null && _b !== void 0 ? _b : {};
|
|
452
|
+
function renderNodeContent(analyzedComponents, loadedModels, primaryClickHandlers, childNodes) {
|
|
453
|
+
var _a, _b, _c, _d;
|
|
454
|
+
const geometry = analyzedComponents.geometry;
|
|
455
|
+
const geometryDef = analyzedComponents.geometry && getComponentDef(analyzedComponents.geometry.type);
|
|
456
|
+
const materialDef = analyzedComponents.material && getComponentDef(analyzedComponents.material.type);
|
|
457
|
+
const modelDef = analyzedComponents.model && getComponentDef(analyzedComponents.model.type);
|
|
458
|
+
const geometryProperties = (_a = geometry === null || geometry === void 0 ? void 0 : geometry.properties) !== null && _a !== void 0 ? _a : {};
|
|
439
459
|
const meshVisible = geometryProperties.visible !== false;
|
|
440
460
|
const meshCastShadow = meshVisible && geometryProperties.castShadow !== false;
|
|
441
461
|
const meshReceiveShadow = meshVisible && geometryProperties.receiveShadow !== false;
|
|
442
|
-
|
|
443
|
-
|
|
462
|
+
let primaryContent = null;
|
|
463
|
+
if (((_b = analyzedComponents.geometry) === null || _b === void 0 ? void 0 : _b.type) && (geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View)) {
|
|
464
|
+
primaryContent = (_jsxs("mesh", Object.assign({ visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow }, primaryClickHandlers, { children: [_jsx(geometryDef.View, { properties: analyzedComponents.geometry.properties }), analyzedComponents.material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: analyzedComponents.material.properties }, "material"))] })));
|
|
444
465
|
}
|
|
445
|
-
if ((
|
|
446
|
-
|
|
466
|
+
else if (((_c = analyzedComponents.model) === null || _c === void 0 ? void 0 : _c.type)
|
|
467
|
+
&& (modelDef === null || modelDef === void 0 ? void 0 : modelDef.View)
|
|
468
|
+
&& !((_d = analyzedComponents.model.properties) === null || _d === void 0 ? void 0 : _d.instanced)
|
|
469
|
+
&& isNodeReady(analyzedComponents.model, loadedModels)) {
|
|
470
|
+
primaryContent = primaryClickHandlers ? (_jsx("group", Object.assign({}, primaryClickHandlers, { children: _jsx(modelDef.View, { properties: analyzedComponents.model.properties }) }))) : (_jsx(modelDef.View, { properties: analyzedComponents.model.properties }));
|
|
447
471
|
}
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
return
|
|
472
|
+
let content = _jsxs(_Fragment, { children: [primaryContent, childNodes] });
|
|
473
|
+
for (const { key, View, properties } of analyzedComponents.composition) {
|
|
474
|
+
content = (_jsx(View, { properties: properties, children: content }, key));
|
|
475
|
+
}
|
|
476
|
+
return content;
|
|
453
477
|
}
|
|
454
478
|
export default PrefabRoot;
|
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { Object3D, Texture } from "three";
|
|
3
3
|
export interface AssetRuntime {
|
|
4
|
-
|
|
4
|
+
registerNodeHandle: (id: string, kind: string, handle: unknown) => void;
|
|
5
|
+
getNodeHandle: <T = unknown>(id: string, kind: string) => T | null;
|
|
5
6
|
getModel: (path: string) => Object3D | null;
|
|
6
7
|
getTexture: (path: string) => Texture | null;
|
|
7
8
|
getSound: (path: string) => AudioBuffer | null;
|
|
8
9
|
getAssetRevision: () => string;
|
|
9
|
-
|
|
10
|
-
getRigidBody: (id: string) => any;
|
|
10
|
+
getNodeObject: (id: string) => Object3D | null;
|
|
11
11
|
}
|
|
12
12
|
export interface AssetRuntimeContextValue extends AssetRuntime {
|
|
13
13
|
}
|
|
14
|
-
export interface
|
|
14
|
+
export interface CurrentNodeRuntime {
|
|
15
15
|
nodeId: string;
|
|
16
16
|
editMode?: boolean;
|
|
17
17
|
isSelected?: boolean;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
getCurrentNodeObject: <T extends Object3D = Object3D>() => T | null;
|
|
19
|
+
getCurrentNodeHandle: <T = unknown>(kind: string) => T | null;
|
|
20
20
|
}
|
|
21
21
|
export interface LiveRef<T> {
|
|
22
22
|
readonly current: T | null;
|
|
23
23
|
}
|
|
24
24
|
export type LiveObjectRef<T extends Object3D = Object3D> = LiveRef<T>;
|
|
25
|
-
export type
|
|
25
|
+
export type LiveHandleRef<T = unknown> = LiveRef<T>;
|
|
26
|
+
export type CurrentNodeObjectRef<T extends Object3D = Object3D> = LiveObjectRef<T>;
|
|
27
|
+
export type CurrentNodeHandleRef<T = unknown> = LiveHandleRef<T>;
|
|
26
28
|
export declare const AssetRuntimeContext: import("react").Context<AssetRuntimeContextValue | null>;
|
|
27
29
|
export declare function useAssetRuntime(): AssetRuntime;
|
|
28
|
-
export declare function
|
|
29
|
-
export declare function
|
|
30
|
-
export declare function
|
|
31
|
-
export declare function
|
|
30
|
+
export declare function useCurrentNode(): CurrentNodeRuntime;
|
|
31
|
+
export declare function useCurrentNodeObject<T extends Object3D = Object3D>(): LiveRef<T>;
|
|
32
|
+
export declare function useCurrentNodeHandle<T = unknown>(kind: string): LiveRef<T>;
|
|
33
|
+
export declare function CurrentNodeScope({ nodeId, editMode, isSelected, children, }: {
|
|
32
34
|
nodeId: string;
|
|
33
35
|
editMode?: boolean;
|
|
34
36
|
isSelected?: boolean;
|
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useMemo } from "react";
|
|
3
3
|
export const AssetRuntimeContext = createContext(null);
|
|
4
|
-
const
|
|
4
|
+
const CurrentNodeRuntimeContext = createContext(null);
|
|
5
5
|
export function useAssetRuntime() {
|
|
6
6
|
const ctx = useContext(AssetRuntimeContext);
|
|
7
7
|
if (!ctx)
|
|
8
8
|
throw new Error("useAssetRuntime must be used inside <PrefabRoot>");
|
|
9
9
|
return ctx;
|
|
10
10
|
}
|
|
11
|
-
export function
|
|
12
|
-
const ctx = useContext(
|
|
11
|
+
export function useCurrentNode() {
|
|
12
|
+
const ctx = useContext(CurrentNodeRuntimeContext);
|
|
13
13
|
if (!ctx)
|
|
14
|
-
throw new Error("
|
|
14
|
+
throw new Error("useCurrentNode must be used inside a component View rendered by <PrefabRoot>");
|
|
15
15
|
return ctx;
|
|
16
16
|
}
|
|
17
|
-
export function
|
|
18
|
-
const {
|
|
19
|
-
return useMemo(() => ({ get current() { return
|
|
17
|
+
export function useCurrentNodeObject() {
|
|
18
|
+
const { getCurrentNodeObject } = useCurrentNode();
|
|
19
|
+
return useMemo(() => ({ get current() { return getCurrentNodeObject(); } }), [getCurrentNodeObject]);
|
|
20
20
|
}
|
|
21
|
-
export function
|
|
22
|
-
const {
|
|
23
|
-
return useMemo(() => ({ get current() { return
|
|
21
|
+
export function useCurrentNodeHandle(kind) {
|
|
22
|
+
const { getCurrentNodeHandle } = useCurrentNode();
|
|
23
|
+
return useMemo(() => ({ get current() { return getCurrentNodeHandle(kind); } }), [getCurrentNodeHandle, kind]);
|
|
24
24
|
}
|
|
25
|
-
export function
|
|
25
|
+
export function CurrentNodeScope({ nodeId, editMode, isSelected, children, }) {
|
|
26
26
|
const asset = useContext(AssetRuntimeContext);
|
|
27
27
|
if (!asset)
|
|
28
|
-
throw new Error("
|
|
28
|
+
throw new Error("CurrentNodeScope must be used inside <PrefabRoot>");
|
|
29
29
|
const value = useMemo(() => ({
|
|
30
30
|
nodeId,
|
|
31
31
|
editMode,
|
|
32
32
|
isSelected,
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
getCurrentNodeObject: () => asset.getNodeObject(nodeId),
|
|
34
|
+
getCurrentNodeHandle: (kind) => asset.getNodeHandle(nodeId, kind),
|
|
35
35
|
}), [asset, editMode, isSelected, nodeId]);
|
|
36
|
-
return _jsx(
|
|
36
|
+
return _jsx(CurrentNodeRuntimeContext.Provider, { value: value, children: children });
|
|
37
37
|
}
|
|
@@ -52,7 +52,7 @@ function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
|
|
|
52
52
|
function BufferGeometryComponentEditor({ component, onUpdate, }) {
|
|
53
53
|
var _a;
|
|
54
54
|
const properties = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
|
|
55
|
-
return (_jsxs(FieldGroup, { children: [_jsx(BufferArrayField, { label: "Positions", value: properties.positions, fallback: DEFAULT_TRIANGLE_POSITIONS, rows: 5, onChange: (positions) => onUpdate({ positions }) }), _jsx(BufferArrayField, { label: "Indices", value: properties.indices, fallback: DEFAULT_TRIANGLE_INDICES, onChange: (indices) => onUpdate({ indices }) }), _jsx(BufferArrayField, { label: "Normals", value: properties.normals, fallback: [], onChange: (normals) => onUpdate({ normals }) }), _jsx(BufferArrayField, { label: "UVs", value: properties.uvs, fallback: DEFAULT_TRIANGLE_UVS, onChange: (uvs) => onUpdate({ uvs }) }), _jsx(BooleanField, { name: "computeVertexNormals", label: "Compute Normals", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "visible", label: "Visible", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "receiveShadow", label: "Receive Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: properties, onChange: onUpdate, fallback: false }), properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: properties, onChange: onUpdate, placeholder: "
|
|
55
|
+
return (_jsxs(FieldGroup, { children: [_jsx(BufferArrayField, { label: "Positions", value: properties.positions, fallback: DEFAULT_TRIANGLE_POSITIONS, rows: 5, onChange: (positions) => onUpdate({ positions }) }), _jsx(BufferArrayField, { label: "Indices", value: properties.indices, fallback: DEFAULT_TRIANGLE_INDICES, onChange: (indices) => onUpdate({ indices }) }), _jsx(BufferArrayField, { label: "Normals", value: properties.normals, fallback: [], onChange: (normals) => onUpdate({ normals }) }), _jsx(BufferArrayField, { label: "UVs", value: properties.uvs, fallback: DEFAULT_TRIANGLE_UVS, onChange: (uvs) => onUpdate({ uvs }) }), _jsx(BooleanField, { name: "computeVertexNormals", label: "Compute Normals", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "visible", label: "Visible", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "receiveShadow", label: "Receive Shadow", values: properties, onChange: onUpdate, fallback: true }), _jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: properties, onChange: onUpdate, fallback: false }), properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: properties, onChange: onUpdate, placeholder: "node:click" })) : null] }));
|
|
56
56
|
}
|
|
57
57
|
function BufferGeometryComponentView({ properties }) {
|
|
58
58
|
const positions = normalizeNumberArray(properties.positions, DEFAULT_TRIANGLE_POSITIONS);
|
|
@@ -3,7 +3,7 @@ import { OrthographicCamera, PerspectiveCamera, useHelper } from '@react-three/d
|
|
|
3
3
|
import { useRef } from 'react';
|
|
4
4
|
import { CameraHelper } from 'three';
|
|
5
5
|
import { useFrame, useThree } from '@react-three/fiber';
|
|
6
|
-
import {
|
|
6
|
+
import { useCurrentNode } from '../assetRuntime';
|
|
7
7
|
import { FieldGroup, NumberField, SelectField } from './Input';
|
|
8
8
|
const CAMERA_PROJECTION_OPTIONS = [
|
|
9
9
|
{ value: 'perspective', label: 'Perspective' },
|
|
@@ -25,7 +25,7 @@ function CameraComponentEditor({ component, onUpdate }) {
|
|
|
25
25
|
}
|
|
26
26
|
function CameraComponentView({ properties, children }) {
|
|
27
27
|
var _a;
|
|
28
|
-
const { editMode, isSelected } =
|
|
28
|
+
const { editMode, isSelected } = useCurrentNode();
|
|
29
29
|
const { size } = useThree();
|
|
30
30
|
const merged = Object.assign(Object.assign({}, cameraDefaults), properties);
|
|
31
31
|
const projection = (_a = merged.projection) !== null && _a !== void 0 ? _a : cameraDefaults.projection;
|
|
@@ -10,11 +10,11 @@ export interface ComponentViewProps<P = Record<string, any>> {
|
|
|
10
10
|
properties: P;
|
|
11
11
|
/** Children to render for components that wrap the current subtree. */
|
|
12
12
|
children?: React.ReactNode;
|
|
13
|
-
/**
|
|
13
|
+
/** Current node local position for wrapper components. */
|
|
14
14
|
position?: [number, number, number];
|
|
15
|
-
/**
|
|
15
|
+
/** Current node local rotation in radians for wrapper components. */
|
|
16
16
|
rotation?: [number, number, number];
|
|
17
|
-
/**
|
|
17
|
+
/** Current node local scale for wrapper components. */
|
|
18
18
|
scale?: [number, number, number];
|
|
19
19
|
}
|
|
20
20
|
export interface Component {
|