react-three-game 0.0.67 → 0.0.69

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.
Files changed (35) hide show
  1. package/README.md +109 -304
  2. package/dist/index.d.ts +15 -8
  3. package/dist/index.js +11 -8
  4. package/dist/shared/GameCanvas.d.ts +1 -2
  5. package/dist/tools/prefabeditor/EditorContext.d.ts +2 -2
  6. package/dist/tools/prefabeditor/EditorTree.d.ts +6 -6
  7. package/dist/tools/prefabeditor/EditorTree.js +92 -142
  8. package/dist/tools/prefabeditor/EditorTreeMenus.d.ts +4 -11
  9. package/dist/tools/prefabeditor/EditorTreeMenus.js +16 -25
  10. package/dist/tools/prefabeditor/EditorUI.d.ts +5 -5
  11. package/dist/tools/prefabeditor/EditorUI.js +14 -11
  12. package/dist/tools/prefabeditor/GameEvents.d.ts +0 -30
  13. package/dist/tools/prefabeditor/GameEvents.js +0 -7
  14. package/dist/tools/prefabeditor/PrefabEditor.d.ts +12 -13
  15. package/dist/tools/prefabeditor/PrefabEditor.js +168 -138
  16. package/dist/tools/prefabeditor/PrefabRoot.d.ts +8 -5
  17. package/dist/tools/prefabeditor/PrefabRoot.js +141 -123
  18. package/dist/tools/prefabeditor/components/AmbientLightComponent.js +3 -3
  19. package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
  20. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
  21. package/dist/tools/prefabeditor/components/ModelComponent.js +0 -1
  22. package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
  23. package/dist/tools/prefabeditor/components/TextComponent.js +2 -3
  24. package/dist/tools/prefabeditor/components/TransformComponent.js +9 -14
  25. package/dist/tools/prefabeditor/prefabStore.d.ts +42 -0
  26. package/dist/tools/prefabeditor/prefabStore.js +347 -0
  27. package/dist/tools/prefabeditor/sceneApi.d.ts +44 -0
  28. package/dist/tools/prefabeditor/sceneApi.js +161 -0
  29. package/dist/tools/prefabeditor/styles.d.ts +2 -1
  30. package/dist/tools/prefabeditor/styles.js +2 -12
  31. package/dist/tools/prefabeditor/utils.d.ts +15 -36
  32. package/dist/tools/prefabeditor/utils.js +36 -162
  33. package/package.json +4 -3
  34. package/dist/tools/prefabeditor/EventSystem.d.ts +0 -7
  35. package/dist/tools/prefabeditor/EventSystem.js +0 -23
@@ -10,14 +10,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { MapControls, TransformControls } from "@react-three/drei";
12
12
  import GameCanvas from "../../shared/GameCanvas";
13
- import { useState, useRef, useEffect, forwardRef, useImperativeHandle } from "react";
13
+ import { useCallback, useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle } from "react";
14
14
  import PrefabRoot from "./PrefabRoot";
15
15
  import { Physics } from "@react-three/rapier";
16
16
  import EditorUI from "./EditorUI";
17
17
  import { base, toolbar } from "./styles";
18
18
  import { EditorContext } from "./EditorContext";
19
- import { computeParentWorldMatrix, createImageNode, createModelNode, decompose, exportGLB as exportSceneGLB, exportGLBData, findNode, focusCameraOnObject, insertNode, updateNode } from "./utils";
19
+ import { createImageNode, createModelNode, computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, regenerateIds } from "./utils";
20
20
  import { loadFiles } from "../dragdrop";
21
+ import { createPrefabStore, PrefabStoreProvider, prefabStoreToPrefab } from "./prefabStore";
22
+ import { createScene } from "./sceneApi";
21
23
  const DEFAULT_PREFAB = {
22
24
  id: "prefab-default",
23
25
  name: "New Prefab",
@@ -31,36 +33,35 @@ const DEFAULT_PREFAB = {
31
33
  }
32
34
  }
33
35
  };
34
- const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPrefabChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
36
+ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
35
37
  const [editMode, setEditMode] = useState(true);
36
- const [loadedPrefab, setLoadedPrefab] = useState(initialPrefab !== null && initialPrefab !== void 0 ? initialPrefab : DEFAULT_PREFAB);
37
38
  const [selectedId, setSelectedId] = useState(null);
38
39
  const [transformMode, setTransformMode] = useState("translate");
39
- const [snapResolution, setSnapResolution] = useState(0);
40
+ const [scaleSnap, setScaleSnap] = useState(0);
40
41
  const [positionSnap, setPositionSnap] = useState(0.5);
41
42
  const [rotationSnap, setRotationSnap] = useState(Math.PI / 4);
42
- const [history, setHistory] = useState([loadedPrefab]);
43
+ const startingPrefab = initialPrefab !== null && initialPrefab !== void 0 ? initialPrefab : DEFAULT_PREFAB;
44
+ const [prefabStore] = useState(() => createPrefabStore(startingPrefab));
45
+ const [history, setHistory] = useState([startingPrefab]);
43
46
  const [historyIndex, setHistoryIndex] = useState(0);
47
+ const changeOriginRef = useRef(null);
48
+ const historyIndexRef = useRef(0);
44
49
  const [selectedObject, setSelectedObject] = useState(null);
45
- const throttleRef = useRef(null);
46
- const lastDataRef = useRef(JSON.stringify(loadedPrefab));
47
50
  const prefabRootRef = useRef(null);
48
51
  const canvasRef = useRef(null);
49
52
  const controlsRef = useRef(null);
50
- const onPrefabChangeRef = useRef(onPrefabChange);
51
- const pendingPrefabChangeRef = useRef(null);
53
+ const onChangeRef = useRef(onChange);
52
54
  const [injectedModels, setInjectedModels] = useState({});
53
55
  const [injectedTextures, setInjectedTextures] = useState({});
54
- onPrefabChangeRef.current = onPrefabChange;
55
- const setSelection = (nodeId) => {
56
- var _a, _b;
57
- const nextNode = nodeId ? findNode(loadedPrefab.root, nodeId) : null;
56
+ const getPrefab = useCallback(() => prefabStoreToPrefab(prefabStore.getState()), [prefabStore]);
57
+ onChangeRef.current = onChange;
58
+ const setSelection = useCallback((nodeId) => {
59
+ const nextNode = nodeId ? prefabStore.getState().nodesById[nodeId] : null;
58
60
  if (nextNode === null || nextNode === void 0 ? void 0 : nextNode.locked) {
59
61
  return;
60
62
  }
61
63
  setSelectedId(nodeId);
62
- setSelectedObject(nodeId ? (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null : null);
63
- };
64
+ }, [prefabStore]);
64
65
  const toggleEditMode = () => {
65
66
  setEditMode(prev => {
66
67
  const next = !prev;
@@ -71,75 +72,117 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
71
72
  return next;
72
73
  });
73
74
  };
74
- const setSelectedIdState = (value) => {
75
- setSelection(typeof value === 'function' ? value(selectedId) : value);
76
- };
77
- const replacePrefab = (prefab, options) => {
78
- if (throttleRef.current)
79
- clearTimeout(throttleRef.current);
80
- lastDataRef.current = JSON.stringify(prefab);
81
- pendingPrefabChangeRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? null : prefab;
82
- setSelection(null);
83
- setInjectedModels({});
84
- setInjectedTextures({});
85
- setHistory([prefab]);
86
- setHistoryIndex(0);
87
- setLoadedPrefab(prefab);
88
- };
89
- const setPrefab = (prefab) => {
90
- if (selectedId && !findNode(prefab.root, selectedId)) {
91
- setSelection(null);
75
+ const loadPrefab = useCallback((prefab, options) => {
76
+ changeOriginRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? "replace-silent" : "replace";
77
+ prefabStore.getState().replacePrefab(prefab);
78
+ setSelectedObject(null);
79
+ if (options === null || options === void 0 ? void 0 : options.resetHistory) {
80
+ setSelectedId(null);
81
+ setInjectedModels({});
82
+ setInjectedTextures({});
83
+ setHistory([prefab]);
84
+ historyIndexRef.current = 0;
85
+ setHistoryIndex(0);
92
86
  }
93
- updatePrefab(prefab);
94
- };
87
+ else {
88
+ setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
89
+ }
90
+ }, [prefabStore]);
95
91
  useEffect(() => {
96
92
  if (initialPrefab)
97
- replacePrefab(initialPrefab, { notifyChange: false });
98
- }, [initialPrefab]);
99
- const updatePrefab = (newPrefab) => {
100
- setLoadedPrefab(prev => {
101
- const resolved = typeof newPrefab === 'function' ? newPrefab(prev) : newPrefab;
102
- if (Object.is(resolved, prev)) {
103
- pendingPrefabChangeRef.current = null;
104
- return prev;
93
+ loadPrefab(initialPrefab, { resetHistory: true, notifyChange: false });
94
+ }, [initialPrefab, loadPrefab]);
95
+ useEffect(() => {
96
+ let historyTimeout = null;
97
+ let lastRevision = prefabStore.getState().revision;
98
+ const unsubscribe = prefabStore.subscribe((state) => {
99
+ var _a;
100
+ if (state.revision === lastRevision) {
101
+ return;
105
102
  }
106
- pendingPrefabChangeRef.current = resolved;
107
- return resolved;
103
+ lastRevision = state.revision;
104
+ const nextPrefab = prefabStoreToPrefab(state);
105
+ const changeOrigin = changeOriginRef.current;
106
+ if (changeOrigin !== "replace-silent") {
107
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, nextPrefab);
108
+ }
109
+ if (historyTimeout) {
110
+ clearTimeout(historyTimeout);
111
+ historyTimeout = null;
112
+ }
113
+ if (changeOrigin || !editMode) {
114
+ changeOriginRef.current = null;
115
+ return;
116
+ }
117
+ historyTimeout = setTimeout(() => {
118
+ const currentHistoryIndex = historyIndexRef.current;
119
+ setHistory(prev => {
120
+ const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
121
+ return nextHistory.length > 50 ? nextHistory.slice(1) : nextHistory;
122
+ });
123
+ const nextHistoryIndex = Math.min(currentHistoryIndex + 1, 49);
124
+ historyIndexRef.current = nextHistoryIndex;
125
+ setHistoryIndex(nextHistoryIndex);
126
+ historyTimeout = null;
127
+ }, 500);
108
128
  });
109
- };
129
+ return () => {
130
+ if (historyTimeout) {
131
+ clearTimeout(historyTimeout);
132
+ }
133
+ unsubscribe();
134
+ };
135
+ }, [editMode, prefabStore]);
110
136
  useEffect(() => {
111
- var _a;
112
- if (pendingPrefabChangeRef.current !== loadedPrefab)
137
+ if (!selectedId)
113
138
  return;
114
- (_a = onPrefabChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onPrefabChangeRef, loadedPrefab);
115
- pendingPrefabChangeRef.current = null;
116
- }, [loadedPrefab]);
117
- const insertPrefabNode = (node, options) => {
118
- updatePrefab(prev => {
119
- return Object.assign(Object.assign({}, prev), { root: insertNode(prev.root, node, options === null || options === void 0 ? void 0 : options.parentId) });
139
+ const unsubscribe = prefabStore.subscribe((state) => {
140
+ if (state.nodesById[selectedId])
141
+ return;
142
+ setSelectedId(null);
143
+ setSelectedObject(null);
120
144
  });
145
+ return () => unsubscribe();
146
+ }, [prefabStore, selectedId]);
147
+ useEffect(() => {
148
+ var _a, _b;
149
+ if (!selectedId) {
150
+ setSelectedObject(null);
151
+ return;
152
+ }
153
+ setSelectedObject((_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(selectedId)) !== null && _b !== void 0 ? _b : null);
154
+ }, [selectedId]);
155
+ const addNode = useCallback((node, options) => {
156
+ var _a;
157
+ const { addChild, rootId } = prefabStore.getState();
158
+ addChild((_a = options === null || options === void 0 ? void 0 : options.parentId) !== null && _a !== void 0 ? _a : rootId, node);
121
159
  if ((options === null || options === void 0 ? void 0 : options.select) !== false) {
122
160
  setSelection(node.id);
123
161
  }
124
162
  return node;
125
- };
126
- const addModel = (path, model, options) => {
163
+ }, [prefabStore, setSelection]);
164
+ const importPrefab = useCallback((prefab) => {
165
+ addNode(regenerateIds(prefab.root), { select: false });
166
+ }, [addNode]);
167
+ const addModel = useCallback((path, model, options) => {
127
168
  const node = createModelNode(path, options === null || options === void 0 ? void 0 : options.name);
128
- insertPrefabNode(node, options);
169
+ addNode(node, options);
129
170
  setInjectedModels(prev => (Object.assign(Object.assign({}, prev), { [path]: model })));
130
171
  return node;
131
- };
132
- const addTexture = (path, texture, options) => {
172
+ }, [addNode]);
173
+ const addTexture = useCallback((path, texture, options) => {
133
174
  const node = createImageNode(path, options === null || options === void 0 ? void 0 : options.name);
134
- insertPrefabNode(node, options);
175
+ addNode(node, options);
135
176
  setInjectedTextures(prev => (Object.assign(Object.assign({}, prev), { [path]: texture })));
136
177
  return node;
137
- };
178
+ }, [addNode]);
138
179
  const applyHistory = (index) => {
180
+ changeOriginRef.current = "history";
181
+ prefabStore.getState().replacePrefab(history[index]);
182
+ historyIndexRef.current = index;
139
183
  setHistoryIndex(index);
140
- lastDataRef.current = JSON.stringify(history[index]);
141
- pendingPrefabChangeRef.current = history[index];
142
- setLoadedPrefab(history[index]);
184
+ setSelectedObject(null);
185
+ setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
143
186
  };
144
187
  const undo = () => historyIndex > 0 && applyHistory(historyIndex - 1);
145
188
  const redo = () => historyIndex < history.length - 1 && applyHistory(historyIndex + 1);
@@ -161,24 +204,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
161
204
  window.addEventListener('keydown', handleKeyDown);
162
205
  return () => window.removeEventListener('keydown', handleKeyDown);
163
206
  }, [editMode, historyIndex, history]);
164
- useEffect(() => {
165
- const currentStr = JSON.stringify(loadedPrefab);
166
- if (currentStr === lastDataRef.current)
167
- return;
168
- if (throttleRef.current)
169
- clearTimeout(throttleRef.current);
170
- throttleRef.current = setTimeout(() => {
171
- lastDataRef.current = currentStr;
172
- setHistory(prev => {
173
- const newHistory = [...prev.slice(0, historyIndex + 1), loadedPrefab];
174
- return newHistory.length > 50 ? newHistory.slice(1) : newHistory;
175
- });
176
- setHistoryIndex(prev => Math.min(prev + 1, 49));
177
- }, 500);
178
- return () => { if (throttleRef.current)
179
- clearTimeout(throttleRef.current); };
180
- }, [loadedPrefab]);
181
- const handleScreenshot = () => {
207
+ const handleScreenshot = useCallback(() => {
182
208
  const canvas = canvasRef.current;
183
209
  if (!canvas)
184
210
  return;
@@ -188,38 +214,34 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
188
214
  const url = URL.createObjectURL(blob);
189
215
  const a = document.createElement('a');
190
216
  a.href = url;
191
- a.download = `${loadedPrefab.name || 'screenshot'}.png`;
217
+ a.download = `${prefabStore.getState().prefabName || 'screenshot'}.png`;
192
218
  a.click();
193
219
  URL.revokeObjectURL(url);
194
220
  });
195
- };
196
- const clearSelection = () => __awaiter(void 0, void 0, void 0, function* () {
197
- if (!selectedId)
198
- return;
221
+ }, [prefabStore]);
222
+ const clearSelection = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
199
223
  setSelection(null);
200
224
  yield new Promise(resolve => {
201
- requestAnimationFrame(() => {
202
- requestAnimationFrame(() => resolve());
203
- });
225
+ requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
204
226
  });
205
- });
206
- const handleExportGLB = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
227
+ }), [setSelection]);
228
+ const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
207
229
  var _a;
208
230
  yield clearSelection();
209
- const sceneRoot = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
210
- if (!sceneRoot)
231
+ const rootObject = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
232
+ if (!rootObject)
211
233
  return;
212
- return exportSceneGLB(sceneRoot, Object.assign({ filename: `${loadedPrefab.name || 'scene'}.glb` }, options));
213
- });
214
- const handleExportGLBData = () => __awaiter(void 0, void 0, void 0, function* () {
234
+ return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
235
+ }), [clearSelection, prefabStore]);
236
+ const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
215
237
  var _a;
216
238
  yield clearSelection();
217
- const sceneRoot = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
218
- if (!sceneRoot)
239
+ const rootObject = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
240
+ if (!rootObject)
219
241
  return;
220
- return exportGLBData(sceneRoot);
221
- });
222
- const handleFocusNode = (nodeId) => {
242
+ return exportGLBData(rootObject);
243
+ }), [clearSelection]);
244
+ const handleFocusNode = useCallback((nodeId) => {
223
245
  var _a;
224
246
  const object = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId);
225
247
  const controls = controlsRef.current;
@@ -227,7 +249,15 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
227
249
  if (!object || !controls || !camera)
228
250
  return;
229
251
  focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
230
- };
252
+ }, []);
253
+ const scene = useMemo(() => createScene({
254
+ getRootId: () => prefabStore.getState().rootId,
255
+ getNode: (id) => { var _a; return (_a = prefabStore.getState().nodesById[id]) !== null && _a !== void 0 ? _a : null; },
256
+ updateNode: (id, update) => prefabStore.getState().updateNode(id, update),
257
+ updateNodes: (updates) => prefabStore.getState().updateNodes(Object.entries(updates).map(([id, update]) => ({ id, update }))),
258
+ addNode: (node, options) => addNode(node, options).id,
259
+ removeNode: (id) => prefabStore.getState().deleteNode(id),
260
+ }), [addNode, prefabStore]);
231
261
  const handleTransformChange = () => {
232
262
  var _a;
233
263
  if (!selectedId)
@@ -235,13 +265,13 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
235
265
  const object = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(selectedId);
236
266
  if (!object)
237
267
  return;
238
- const parentWorld = computeParentWorldMatrix(loadedPrefab.root, selectedId);
268
+ const parentWorld = computeParentWorldMatrix(prefabStore.getState(), selectedId);
239
269
  const local = parentWorld.clone().invert().multiply(object.matrixWorld);
240
270
  const { position, rotation, scale } = decompose(local);
241
- updatePrefab(prev => (Object.assign(Object.assign({}, prev), { root: updateNode(prev.root, selectedId, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { transform: {
242
- type: "Transform",
243
- properties: { position, rotation, scale },
244
- } }) }))) })));
271
+ prefabStore.getState().updateNode(selectedId, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { transform: {
272
+ type: "Transform",
273
+ properties: { position, rotation, scale },
274
+ } }) })));
245
275
  };
246
276
  // --- Drag & drop files to add nodes ---
247
277
  useEffect(() => {
@@ -278,43 +308,43 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, onPr
278
308
  window.removeEventListener('dragover', handleDragOver);
279
309
  window.removeEventListener('drop', handleDrop);
280
310
  };
281
- }, [editMode, enableWindowDrop]);
311
+ }, [addModel, addTexture, editMode, enableWindowDrop]);
282
312
  useImperativeHandle(ref, () => ({
283
313
  screenshot: handleScreenshot,
284
314
  exportGLB: handleExportGLB,
285
315
  exportGLBData: handleExportGLBData,
286
316
  clearSelection,
287
- prefab: loadedPrefab,
288
- setPrefab,
289
- replacePrefab,
317
+ save: getPrefab,
318
+ scene,
319
+ load: loadPrefab,
290
320
  addModel,
291
321
  addTexture,
292
- rootRef: prefabRootRef
293
- }));
294
- const content = (_jsxs(_Fragment, { children: [_jsx("ambientLight", { intensity: 1.5 }), _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }), _jsx(PrefabRoot, { ref: prefabRootRef, data: loadedPrefab, editMode: editMode, selectedId: selectedId, onSelect: setSelection, onSelectedObjectChange: editMode ? setSelectedObject : undefined, onFocusNode: editMode ? handleFocusNode : undefined, basePath: basePath, injectedModels: injectedModels, injectedTextures: injectedTextures }), children] }));
295
- return _jsxs(EditorContext.Provider, { value: {
296
- editMode,
297
- transformMode,
298
- setTransformMode,
299
- snapResolution,
300
- setSnapResolution,
301
- positionSnap,
302
- setPositionSnap,
303
- rotationSnap,
304
- setRotationSnap,
305
- onFocusNode: editMode ? handleFocusNode : undefined,
306
- onScreenshot: handleScreenshot,
307
- onExportGLB: handleExportGLB
308
- }, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] }, canvasRef: canvasRef }, canvasProps, { onPointerMissed: editMode
309
- ? (event) => {
310
- var _a, _b, _c, _d;
311
- const button = (_c = (_a = event.button) !== null && _a !== void 0 ? _a : (_b = event.sourceEvent) === null || _b === void 0 ? void 0 : _b.button) !== null && _c !== void 0 ? _c : 0;
312
- if (button === 0 && selectedId) {
313
- setSelection(null);
322
+ viewRef: prefabRootRef
323
+ }), [addModel, addTexture, clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, scene]);
324
+ const content = (_jsxs(_Fragment, { children: [_jsx("ambientLight", { intensity: 1.5 }), _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }), _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: editMode, selectedId: selectedId, onSelect: setSelection, onSelectedObjectChange: editMode ? setSelectedObject : undefined, onFocusNode: editMode ? handleFocusNode : undefined, basePath: basePath, injectedModels: injectedModels, injectedTextures: injectedTextures }), children] }));
325
+ return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsxs(EditorContext.Provider, { value: {
326
+ editMode,
327
+ transformMode,
328
+ setTransformMode,
329
+ scaleSnap,
330
+ setScaleSnap,
331
+ positionSnap,
332
+ setPositionSnap,
333
+ rotationSnap,
334
+ setRotationSnap,
335
+ onFocusNode: editMode ? handleFocusNode : undefined,
336
+ onScreenshot: handleScreenshot,
337
+ onExportGLB: handleExportGLB
338
+ }, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] }, canvasRef: canvasRef }, canvasProps, { onPointerMissed: editMode
339
+ ? (event) => {
340
+ var _a, _b, _c, _d;
341
+ const button = (_c = (_a = event.button) !== null && _a !== void 0 ? _a : (_b = event.sourceEvent) === null || _b === void 0 ? void 0 : _b.button) !== null && _c !== void 0 ? _c : 0;
342
+ if (button === 0 && selectedId) {
343
+ setSelection(null);
344
+ }
345
+ (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
314
346
  }
315
- (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
316
- }
317
- : canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { debug: editMode, paused: editMode, children: content })) : content, editMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, makeDefault: true }), selectedObject && (_jsx(TransformControls, { object: selectedObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: snapResolution > 0 ? snapResolution : undefined }, `transform-${transformMode}-${positionSnap}-${rotationSnap}-${snapResolution}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleEditMode, children: editMode ? "▶" : "⏸" }), uiPlugins] }), editMode && (_jsx(EditorUI, { prefabData: loadedPrefab, setPrefabData: updatePrefab, selectedId: selectedId, setSelectedId: setSelectedIdState, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] });
347
+ : canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { debug: editMode, paused: editMode, children: content })) : content, editMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, makeDefault: true }), selectedObject && (_jsx(TransformControls, { object: selectedObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleEditMode, children: editMode ? "▶" : "⏸" }), uiPlugins] }), editMode && (_jsx(EditorUI, { selectedId: selectedId, setSelectedId: setSelection, getPrefab: getPrefab, onReplacePrefab: (prefab) => loadPrefab(prefab, { resetHistory: true }), onImportPrefab: importPrefab, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] }) });
318
348
  });
319
349
  PrefabEditor.displayName = "PrefabEditor";
320
350
  export default PrefabEditor;
@@ -1,16 +1,18 @@
1
1
  import { Group, Matrix4, Object3D } from "three";
2
2
  import { ThreeEvent } from "@react-three/fiber";
3
- import { Prefab, GameObject as GameObjectType } from "./types";
3
+ import { GameObject as GameObjectType, Prefab } from "./types";
4
4
  import { LoadedModels, LoadedTextures } from "../dragdrop";
5
+ import { PrefabStoreApi } from "./prefabStore";
5
6
  export interface PrefabRootRef {
6
7
  root: Group | null;
7
8
  rigidBodyRefs: Map<string, any>;
8
9
  getObject: (nodeId: string) => Object3D | null;
9
10
  focusNode: (nodeId: string) => void;
10
11
  }
11
- export declare const PrefabRoot: import("react").ForwardRefExoticComponent<{
12
+ export interface PrefabRootProps {
12
13
  editMode?: boolean;
13
- data: Prefab;
14
+ data?: Prefab;
15
+ store?: PrefabStoreApi;
14
16
  selectedId?: string | null;
15
17
  onSelect?: (id: string | null) => void;
16
18
  onClick?: (event: ThreeEvent<PointerEvent>, entity: GameObjectType) => void;
@@ -19,10 +21,11 @@ export declare const PrefabRoot: import("react").ForwardRefExoticComponent<{
19
21
  basePath?: string;
20
22
  injectedModels?: LoadedModels;
21
23
  injectedTextures?: LoadedTextures;
22
- } & import("react").RefAttributes<PrefabRootRef>>;
24
+ }
25
+ export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<PrefabRootRef>>;
23
26
  export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
24
27
  interface RendererProps {
25
- gameObject: GameObjectType;
28
+ nodeId: string;
26
29
  selectedId?: string | null;
27
30
  onSelect?: (id: string) => void;
28
31
  onClick?: (event: ThreeEvent<PointerEvent>, entity: GameObjectType) => void;