react-three-game 0.0.92 → 0.0.94

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 (39) hide show
  1. package/README.md +81 -88
  2. package/dist/helpers/index.d.ts +0 -3
  3. package/dist/helpers/index.js +1 -8
  4. package/dist/index.d.ts +10 -10
  5. package/dist/index.js +7 -6
  6. package/dist/tools/prefabeditor/EditorTree.js +10 -14
  7. package/dist/tools/prefabeditor/EditorUI.js +4 -4
  8. package/dist/tools/prefabeditor/GameEvents.d.ts +6 -12
  9. package/dist/tools/prefabeditor/GameEvents.js +0 -8
  10. package/dist/tools/prefabeditor/InstanceProvider.d.ts +6 -4
  11. package/dist/tools/prefabeditor/InstanceProvider.js +84 -199
  12. package/dist/tools/prefabeditor/PrefabEditor.d.ts +12 -21
  13. package/dist/tools/prefabeditor/PrefabEditor.js +138 -146
  14. package/dist/tools/prefabeditor/PrefabRoot.d.ts +30 -11
  15. package/dist/tools/prefabeditor/PrefabRoot.js +182 -139
  16. package/dist/tools/prefabeditor/assetRuntime.d.ts +9 -13
  17. package/dist/tools/prefabeditor/assetRuntime.js +13 -13
  18. package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +1 -1
  19. package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
  20. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +3 -3
  21. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
  22. package/dist/tools/prefabeditor/components/Input.js +5 -9
  23. package/dist/tools/prefabeditor/components/ModelComponent.js +4 -6
  24. package/dist/tools/prefabeditor/components/PointLightComponent.js +2 -2
  25. package/dist/tools/prefabeditor/components/SoundComponent.js +2 -2
  26. package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
  27. package/dist/tools/prefabeditor/components/index.js +0 -2
  28. package/dist/tools/prefabeditor/prefab.d.ts +1 -2
  29. package/dist/tools/prefabeditor/prefab.js +2 -3
  30. package/dist/tools/prefabeditor/prefabStore.d.ts +0 -6
  31. package/dist/tools/prefabeditor/prefabStore.js +1 -33
  32. package/dist/tools/prefabeditor/types.d.ts +1 -0
  33. package/dist/tools/prefabeditor/usePointerEvents.d.ts +3 -3
  34. package/dist/tools/prefabeditor/usePointerEvents.js +5 -5
  35. package/package.json +49 -51
  36. package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +0 -26
  37. package/dist/tools/prefabeditor/components/PhysicsComponent.js +0 -302
  38. package/dist/tools/prefabeditor/scene.d.ts +0 -70
  39. package/dist/tools/prefabeditor/scene.js +0 -237
@@ -10,11 +10,10 @@ 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, useHelper } from "@react-three/drei";
12
12
  import GameCanvas from "../../shared/GameCanvas";
13
- import { useCallback, useEffect, useLayoutEffect, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
13
+ import { useCallback, useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
14
14
  import { BoxHelper } from "three";
15
15
  import { findComponentEntry } from "./types";
16
- import PrefabRoot from "./PrefabRoot";
17
- import { Physics } from "@react-three/rapier";
16
+ import { PrefabEditorMode, PrefabRoot } from "./PrefabRoot";
18
17
  import EditorUI from "./EditorUI";
19
18
  import { base, toolbar } from "./styles";
20
19
  import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, regenerateIds } from "./utils";
@@ -38,12 +37,8 @@ function SelectionHelper({ object }) {
38
37
  useHelper(object ? objectRef : null, BoxHelper, "cyan");
39
38
  return null;
40
39
  }
41
- export var PrefabEditorMode;
42
- (function (PrefabEditorMode) {
43
- PrefabEditorMode["Edit"] = "edit";
44
- PrefabEditorMode["Play"] = "play";
45
- })(PrefabEditorMode || (PrefabEditorMode = {}));
46
40
  export const EditorContext = createContext(null);
41
+ export const EditorRefContext = createContext(null);
47
42
  export function useEditorContext() {
48
43
  const context = useContext(EditorContext);
49
44
  if (!context) {
@@ -51,6 +46,13 @@ export function useEditorContext() {
51
46
  }
52
47
  return context;
53
48
  }
49
+ export function useEditorRef() {
50
+ const editorRef = useContext(EditorRefContext);
51
+ if (!editorRef) {
52
+ throw new Error("useEditorRef must be used within PrefabEditor");
53
+ }
54
+ return editorRef;
55
+ }
54
56
  const MAX_HISTORY_LENGTH = 50;
55
57
  const HISTORY_DEBOUNCE_MS = 500;
56
58
  const DEFAULT_PREFAB = {
@@ -58,8 +60,7 @@ const DEFAULT_PREFAB = {
58
60
  name: "New Prefab",
59
61
  root: createNode('Root', {}, { id: 'root' })
60
62
  };
61
- const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
62
- var _a, _b;
63
+ const PrefabEditor = forwardRef(({ basePath, initialPrefab, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
63
64
  const [mode, setMode] = useState(initialMode);
64
65
  const [selectedId, setSelectedId] = useState(null);
65
66
  const [transformMode, setTransformMode] = useState("translate");
@@ -70,19 +71,68 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
70
71
  const [prefabStore] = useState(() => createPrefabStore(startingPrefab));
71
72
  const [history, setHistory] = useState([startingPrefab]);
72
73
  const [historyIndex, setHistoryIndex] = useState(0);
73
- const changeOriginRef = useRef(null);
74
74
  const historyIndexRef = useRef(0);
75
+ const historyTimeoutRef = useRef(null);
75
76
  const prefabRootRef = useRef(null);
76
77
  const canvasRef = useRef(null);
77
78
  const controlsRef = useRef(null);
78
79
  const transformControlsRef = useRef(null);
79
- const transformProxyRef = useRef(null);
80
80
  const onChangeRef = useRef(onChange);
81
81
  const isEditMode = mode === PrefabEditorMode.Edit;
82
82
  const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
83
- const getRootObject = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
83
+ const getNode = useCallback((nodeId) => { var _a; return (_a = prefabStore.getState().nodesById[nodeId]) !== null && _a !== void 0 ? _a : null; }, [prefabStore]);
84
+ const getRoot = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
84
85
  const getObject = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
85
- const getRigidBody = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getRigidBody(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
86
+ const getHandle = useCallback((nodeId, kind) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getHandle(nodeId, kind)) !== null && _b !== void 0 ? _b : null; }, []);
87
+ const scheduleHistory = useCallback((nextPrefab) => {
88
+ if (historyTimeoutRef.current) {
89
+ clearTimeout(historyTimeoutRef.current);
90
+ historyTimeoutRef.current = null;
91
+ }
92
+ historyTimeoutRef.current = setTimeout(() => {
93
+ const currentHistoryIndex = historyIndexRef.current;
94
+ setHistory(prev => {
95
+ const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
96
+ return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
97
+ });
98
+ const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
99
+ historyIndexRef.current = nextHistoryIndex;
100
+ setHistoryIndex(nextHistoryIndex);
101
+ historyTimeoutRef.current = null;
102
+ }, HISTORY_DEBOUNCE_MS);
103
+ }, []);
104
+ const mutate = useCallback((run, pushHistory = isEditMode) => {
105
+ var _a;
106
+ const before = prefabStore.getState();
107
+ const result = run(before);
108
+ const after = prefabStore.getState();
109
+ if (after === before)
110
+ return result;
111
+ const prefab = denormalizePrefab(after);
112
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, prefab);
113
+ if (pushHistory)
114
+ scheduleHistory(prefab);
115
+ return result;
116
+ }, [isEditMode, prefabStore, scheduleHistory]);
117
+ const update = useCallback((id, fn) => {
118
+ mutate(s => s.updateNode(id, fn));
119
+ }, [mutate]);
120
+ const remove = useCallback((id) => {
121
+ mutate(s => s.deleteNode(id));
122
+ }, [mutate]);
123
+ const duplicate = useCallback((id) => {
124
+ return mutate(s => s.duplicateNode(id));
125
+ }, [mutate]);
126
+ const move = useCallback((draggedId, targetId, position) => {
127
+ mutate(s => s.moveNode(draggedId, targetId, position));
128
+ }, [mutate]);
129
+ const add = useCallback((node, parentId) => {
130
+ mutate(s => s.addChild(parentId !== null && parentId !== void 0 ? parentId : s.rootId, node));
131
+ return node;
132
+ }, [mutate]);
133
+ const replace = useCallback((prefab) => {
134
+ mutate(s => s.replacePrefab(prefab), false);
135
+ }, [mutate]);
86
136
  onChangeRef.current = onChange;
87
137
  const setSelection = useCallback((nodeId) => {
88
138
  const nextNode = nodeId ? prefabStore.getState().nodesById[nodeId] : null;
@@ -108,10 +158,14 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
108
158
  updateMode(initialMode);
109
159
  }, [initialMode, updateMode]);
110
160
  const loadPrefab = useCallback((prefab, options) => {
111
- var _a;
112
- changeOriginRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? "replace-silent" : "replace";
161
+ var _a, _b;
113
162
  (_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
163
+ const before = prefabStore.getState();
114
164
  prefabStore.getState().replacePrefab(prefab);
165
+ const after = prefabStore.getState();
166
+ if (after !== before && (options === null || options === void 0 ? void 0 : options.notifyChange) !== false) {
167
+ (_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, prefab);
168
+ }
115
169
  if (options === null || options === void 0 ? void 0 : options.resetHistory) {
116
170
  setSelectedId(null);
117
171
  setHistory([prefab]);
@@ -127,46 +181,12 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
127
181
  loadPrefab(initialPrefab, { resetHistory: true, notifyChange: false });
128
182
  }, [initialPrefab, loadPrefab]);
129
183
  useEffect(() => {
130
- let historyTimeout = null;
131
- let lastRevision = prefabStore.getState().revision;
132
- const unsubscribe = prefabStore.subscribe((state) => {
133
- var _a;
134
- if (state.revision === lastRevision) {
135
- return;
136
- }
137
- lastRevision = state.revision;
138
- const nextPrefab = denormalizePrefab(state);
139
- const changeOrigin = changeOriginRef.current;
140
- if (changeOrigin !== "replace-silent") {
141
- (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, nextPrefab);
142
- }
143
- if (historyTimeout) {
144
- clearTimeout(historyTimeout);
145
- historyTimeout = null;
146
- }
147
- if (changeOrigin || !isEditMode) {
148
- changeOriginRef.current = null;
149
- return;
150
- }
151
- historyTimeout = setTimeout(() => {
152
- const currentHistoryIndex = historyIndexRef.current;
153
- setHistory(prev => {
154
- const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
155
- return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
156
- });
157
- const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
158
- historyIndexRef.current = nextHistoryIndex;
159
- setHistoryIndex(nextHistoryIndex);
160
- historyTimeout = null;
161
- }, HISTORY_DEBOUNCE_MS);
162
- });
163
184
  return () => {
164
- if (historyTimeout) {
165
- clearTimeout(historyTimeout);
185
+ if (historyTimeoutRef.current) {
186
+ clearTimeout(historyTimeoutRef.current);
166
187
  }
167
- unsubscribe();
168
188
  };
169
- }, [isEditMode, prefabStore]);
189
+ }, []);
170
190
  useEffect(() => {
171
191
  if (!selectedId)
172
192
  return;
@@ -177,54 +197,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
177
197
  });
178
198
  return () => unsubscribe();
179
199
  }, [prefabStore, selectedId]);
180
- const selectedNode = selectedId ? (_a = prefabStore.getState().nodesById[selectedId]) !== null && _a !== void 0 ? _a : null : null;
181
200
  const selectedObject = selectedId ? getObject(selectedId) : null;
182
- const selectedHasPhysics = Object.values((_b = selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.components) !== null && _b !== void 0 ? _b : {}).some(component => (component === null || component === void 0 ? void 0 : component.type) === "Physics");
183
- const transformObject = isEditMode && (selectedHasPhysics ? transformProxyRef.current : selectedObject)
184
- && isObjectAttachedToRoot(getRootObject(), selectedObject)
185
- ? (selectedHasPhysics ? transformProxyRef.current : selectedObject)
201
+ const transformObject = isEditMode && selectedObject
202
+ && isObjectAttachedToRoot(getRoot(), selectedObject)
203
+ ? selectedObject
186
204
  : null;
187
- useLayoutEffect(() => {
188
- if (!isEditMode || !selectedHasPhysics || !selectedObject || !transformProxyRef.current) {
189
- return;
190
- }
191
- selectedObject.updateMatrixWorld(true);
192
- transformProxyRef.current.matrixAutoUpdate = true;
193
- selectedObject.matrixWorld.decompose(transformProxyRef.current.position, transformProxyRef.current.quaternion, transformProxyRef.current.scale);
194
- transformProxyRef.current.updateMatrix();
195
- transformProxyRef.current.updateMatrixWorld(true);
196
- }, [isEditMode, selectedHasPhysics, selectedId, selectedObject]);
197
- const addNode = useCallback((node, options) => {
198
- var _a;
199
- const { addChild, rootId } = prefabStore.getState();
200
- addChild((_a = options === null || options === void 0 ? void 0 : options.parentId) !== null && _a !== void 0 ? _a : rootId, node);
201
- if ((options === null || options === void 0 ? void 0 : options.select) !== false) {
202
- setSelection(node.id);
203
- }
204
- return node;
205
- }, [prefabStore, setSelection]);
206
205
  const importPrefab = useCallback((prefab) => {
207
- addNode(regenerateIds(prefab.root), { select: false });
208
- }, [addNode]);
209
- const addModel = useCallback((path, model, options) => {
210
- var _a;
211
- const node = createModelNode(path, options === null || options === void 0 ? void 0 : options.name);
212
- addNode(node, options);
213
- (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model);
214
- return node;
215
- }, [addNode]);
216
- const addTexture = useCallback((path, texture, options) => {
217
- var _a;
218
- const node = createImageNode(path, options === null || options === void 0 ? void 0 : options.name);
219
- addNode(node, options);
220
- (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture);
221
- return node;
222
- }, [addNode]);
206
+ add(regenerateIds(prefab.root));
207
+ }, [add]);
223
208
  const applyHistory = (index) => {
224
- var _a;
225
- changeOriginRef.current = "history";
209
+ var _a, _b;
226
210
  (_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
227
211
  prefabStore.getState().replacePrefab(history[index]);
212
+ (_b = onChangeRef.current) === null || _b === void 0 ? void 0 : _b.call(onChangeRef, history[index]);
228
213
  historyIndexRef.current = index;
229
214
  setHistoryIndex(index);
230
215
  setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
@@ -272,18 +257,18 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
272
257
  }), [setSelection]);
273
258
  const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
274
259
  yield clearSelection();
275
- const rootObject = getRootObject();
260
+ const rootObject = getRoot();
276
261
  if (!rootObject)
277
262
  return;
278
263
  return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
279
- }), [clearSelection, getRootObject, prefabStore]);
264
+ }), [clearSelection, getRoot, prefabStore]);
280
265
  const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
281
266
  yield clearSelection();
282
- const rootObject = getRootObject();
267
+ const rootObject = getRoot();
283
268
  if (!rootObject)
284
269
  return;
285
270
  return exportGLBData(rootObject);
286
- }), [clearSelection, getRootObject]);
271
+ }), [clearSelection, getRoot]);
287
272
  const handleFocusNode = useCallback((nodeId) => {
288
273
  const object = getObject(nodeId);
289
274
  const controls = controlsRef.current;
@@ -295,13 +280,13 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
295
280
  const handleTransformChange = () => {
296
281
  if (!selectedId)
297
282
  return;
298
- const object = selectedHasPhysics ? transformProxyRef.current : getObject(selectedId);
283
+ const object = getObject(selectedId);
299
284
  if (!object)
300
285
  return;
301
286
  const parentWorld = computeParentWorldMatrix(prefabStore.getState(), selectedId);
302
287
  const local = parentWorld.clone().invert().multiply(object.matrixWorld);
303
288
  const { position, rotation, scale } = decompose(local);
304
- prefabStore.getState().updateNode(selectedId, node => {
289
+ update(selectedId, node => {
305
290
  var _a;
306
291
  const entry = findComponentEntry(node, "Transform");
307
292
  const key = (_a = entry === null || entry === void 0 ? void 0 : entry[0]) !== null && _a !== void 0 ? _a : "transform";
@@ -324,16 +309,17 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
324
309
  e.preventDefault();
325
310
  e.stopPropagation();
326
311
  const files = ((_a = e.dataTransfer) === null || _a === void 0 ? void 0 : _a.files) ? Array.from(e.dataTransfer.files) : [];
312
+ const scene = prefabRootRef.current;
327
313
  void loadFiles(files, {
328
314
  onModelLoaded: (model, filename) => {
329
- addModel(`models/${filename}`, model, {
330
- name: filename.replace(/\.[^.]+$/, '')
331
- });
315
+ const path = `models/${filename}`;
316
+ scene === null || scene === void 0 ? void 0 : scene.addModel(path, model);
317
+ add(createModelNode(path, filename.replace(/\.[^.]+$/, '')));
332
318
  },
333
319
  onTextureLoaded: (texture, filename) => {
334
- addTexture(`textures/${filename}`, texture, {
335
- name: filename.replace(/\.[^.]+$/, '')
336
- });
320
+ const path = `textures/${filename}`;
321
+ scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture);
322
+ add(createImageNode(path, filename.replace(/\.[^.]+$/, '')));
337
323
  },
338
324
  onLoadError: error => {
339
325
  console.error('Drop asset error:', error);
@@ -346,52 +332,58 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
346
332
  window.removeEventListener('dragover', handleDragOver);
347
333
  window.removeEventListener('drop', handleDrop);
348
334
  };
349
- }, [addModel, addTexture, isEditMode, enableWindowDrop]);
350
- useImperativeHandle(ref, () => ({
351
- root: getRootObject(),
352
- store: prefabStore,
335
+ }, [add, isEditMode, enableWindowDrop]);
336
+ const sceneValue = useMemo(() => ({
337
+ get root() {
338
+ return getRoot();
339
+ },
340
+ mode,
341
+ get: getNode,
353
342
  getObject,
354
- getRigidBody,
355
- screenshot: handleScreenshot,
356
- exportGLB: handleExportGLB,
357
- exportGLBData: handleExportGLBData,
358
- clearSelection,
359
- save: getPrefab,
360
- load: loadPrefab,
361
- addNode,
362
- addModel,
363
- addTexture
364
- }), [addModel, addNode, addTexture, clearSelection, getObject, getPrefab, getRigidBody, getRootObject, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, prefabStore]);
365
- const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection, basePath: basePath }), children] }));
343
+ getHandle,
344
+ add,
345
+ update,
346
+ remove,
347
+ duplicate,
348
+ move,
349
+ replace,
350
+ addModel: (path, model) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model); },
351
+ addTexture: (path, texture) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture); },
352
+ addSound: (path, sound) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addSound(path, sound); },
353
+ }), [add, duplicate, getHandle, getNode, getObject, getRoot, mode, move, remove, replace, update]);
354
+ const editorRefValue = useMemo(() => (Object.assign(Object.assign({}, sceneValue), { save: getPrefab, load: loadPrefab, undo,
355
+ redo, screenshot: handleScreenshot, exportGLB: handleExportGLB, exportGLBData: handleExportGLBData, clearSelection })), [clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, redo, sceneValue, undo]);
356
+ useImperativeHandle(ref, () => editorRefValue, [editorRefValue]);
357
+ const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection, basePath: basePath, children: children })] }));
366
358
  const handleCanvasCreated = useCallback((state) => {
367
359
  var _a;
368
360
  canvasRef.current = state.gl.domElement;
369
361
  (_a = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onCreated) === null || _a === void 0 ? void 0 : _a.call(canvasProps, state);
370
362
  }, [canvasProps]);
371
- return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsxs(EditorContext.Provider, { value: {
372
- mode,
373
- setMode: updateMode,
374
- transformMode,
375
- setTransformMode,
376
- scaleSnap,
377
- setScaleSnap,
378
- positionSnap,
379
- setPositionSnap,
380
- rotationSnap,
381
- setRotationSnap,
382
- onFocusNode: isEditMode ? handleFocusNode : undefined,
383
- onScreenshot: handleScreenshot,
384
- onExportGLB: handleExportGLB
385
- }, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] } }, canvasProps, { onCreated: handleCanvasCreated, onPointerMissed: isEditMode
386
- ? (event) => {
387
- var _a, _b, _c, _d;
388
- 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;
389
- if (button === 0 && selectedId) {
390
- setSelection(null);
363
+ return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsx(EditorRefContext.Provider, { value: editorRefValue, children: _jsxs(EditorContext.Provider, { value: {
364
+ mode,
365
+ setMode: updateMode,
366
+ transformMode,
367
+ setTransformMode,
368
+ scaleSnap,
369
+ setScaleSnap,
370
+ positionSnap,
371
+ setPositionSnap,
372
+ rotationSnap,
373
+ setRotationSnap,
374
+ onFocusNode: isEditMode ? handleFocusNode : undefined,
375
+ onScreenshot: handleScreenshot,
376
+ onExportGLB: handleExportGLB
377
+ }, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] } }, canvasProps, { onCreated: handleCanvasCreated, onPointerMissed: isEditMode
378
+ ? (event) => {
379
+ var _a, _b, _c, _d;
380
+ 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;
381
+ if (button === 0 && selectedId) {
382
+ setSelection(null);
383
+ }
384
+ (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
391
385
  }
392
- (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
393
- }
394
- : canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { colliders: false, debug: isEditMode, paused: isEditMode, children: content })) : content, _jsx("group", { ref: transformProxyRef, visible: false }), isEditMode ? _jsx(SelectionHelper, { object: transformObject }) : null, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { ref: transformControlsRef, object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_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 }))] }))] }) });
386
+ : canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [content, isEditMode ? _jsx(SelectionHelper, { object: transformObject }) : null, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { ref: transformControlsRef, object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_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 }))] }))] }) }) });
395
387
  });
396
388
  PrefabEditor.displayName = "PrefabEditor";
397
389
  export default PrefabEditor;
@@ -1,35 +1,54 @@
1
- import { Group, Matrix4, Object3D, Texture } from "three";
1
+ import { Matrix4, Object3D, Texture } from "three";
2
2
  import { ThreeEvent } from "@react-three/fiber";
3
3
  import { GameObject as GameObjectType, Prefab } from "./types";
4
4
  import { LoadedModels } from "../dragdrop";
5
5
  import { PrefabStoreApi } from "./prefabStore";
6
- export interface PrefabRootRef {
7
- root: Group | null;
8
- getObject: (nodeId: string) => Object3D | null;
9
- getRigidBody: (nodeId: string) => any;
10
- addModel: (path: string, model: Object3D) => void;
11
- addTexture: (path: string, texture: Texture) => void;
12
- addSound: (path: string, sound: AudioBuffer) => void;
6
+ export declare enum PrefabEditorMode {
7
+ Edit = "edit",
8
+ Play = "play"
13
9
  }
10
+ export type PrefabNode = Omit<GameObjectType, "children">;
11
+ export interface Scene {
12
+ root: Object3D | null;
13
+ mode: PrefabEditorMode;
14
+ get(id: string): GameObjectType | null;
15
+ getObject(id: string): Object3D | null;
16
+ getHandle<T = unknown>(id: string, kind: string): T | null;
17
+ add(node: GameObjectType, parentId?: string): GameObjectType;
18
+ update(id: string, fn: (node: PrefabNode) => PrefabNode): void;
19
+ remove(id: string): void;
20
+ duplicate(id: string): string | null;
21
+ move(draggedId: string, targetId: string, position: "before" | "inside"): void;
22
+ replace(prefab: Prefab): void;
23
+ addModel(path: string, model: Object3D): void;
24
+ addTexture(path: string, texture: Texture): void;
25
+ addSound(path: string, sound: AudioBuffer): void;
26
+ }
27
+ export declare const SceneContext: import("react").Context<Scene | null>;
28
+ export declare function useScene(): Scene;
14
29
  export interface PrefabRootProps {
15
30
  editMode?: boolean;
16
31
  data?: Prefab;
17
32
  store?: PrefabStoreApi;
18
33
  selectedId?: string | null;
19
34
  onSelect?: (id: string | null) => void;
20
- onClick?: (event: ThreeEvent<PointerEvent>, entity: GameObjectType) => void;
35
+ onClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
36
+ onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
21
37
  basePath?: string;
38
+ children?: React.ReactNode;
22
39
  }
23
- export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<PrefabRootRef>>;
40
+ export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<Scene>>;
24
41
  export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
25
42
  interface RendererProps {
26
43
  nodeId: string;
27
44
  selectedId?: string | null;
28
45
  onSelect?: (id: string) => void;
29
- onClick?: (event: ThreeEvent<PointerEvent>, entity: GameObjectType) => void;
46
+ onClick?: (event: ThreeEvent<PointerEvent>, nodeId: string, object: Object3D | null) => void;
47
+ onEditNodeClick?: (event: ThreeEvent<PointerEvent>, node: GameObjectType) => void;
30
48
  registerRef: (id: string, obj: Object3D | null) => void;
31
49
  loadedModels: LoadedModels;
32
50
  editMode?: boolean;
33
51
  parentMatrix?: Matrix4;
52
+ isVisible?: boolean;
34
53
  }
35
54
  export default PrefabRoot;