react-three-game 0.0.108 → 0.0.110

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 (55) hide show
  1. package/README.md +9 -16
  2. package/dist/editor.d.ts +22 -0
  3. package/dist/editor.js +15 -0
  4. package/dist/plugins/crashcat/CrashcatPhysicsComponent.js +47 -9
  5. package/dist/plugins/crashcat/CrashcatRagdoll.d.ts +1 -1
  6. package/dist/plugins/crashcat/CrashcatRuntime.d.ts +1 -1
  7. package/dist/plugins/crashcat/CrashcatRuntime.js +1 -1
  8. package/dist/shared/ContactShadow.d.ts +1 -1
  9. package/dist/shared/GameCanvas.d.ts +1 -1
  10. package/dist/tools/assetviewer/page.d.ts +10 -10
  11. package/dist/tools/dragdrop/DragDropLoader.d.ts +2 -2
  12. package/dist/tools/prefabeditor/Dropdown.d.ts +1 -1
  13. package/dist/tools/prefabeditor/EditorContext.d.ts +36 -0
  14. package/dist/tools/prefabeditor/EditorContext.js +17 -0
  15. package/dist/tools/prefabeditor/EditorTree.d.ts +1 -1
  16. package/dist/tools/prefabeditor/EditorTree.js +1 -1
  17. package/dist/tools/prefabeditor/EditorTreeMenus.d.ts +2 -2
  18. package/dist/tools/prefabeditor/EditorTreeMenus.js +1 -1
  19. package/dist/tools/prefabeditor/EditorUI.d.ts +1 -1
  20. package/dist/tools/prefabeditor/EditorUI.js +1 -1
  21. package/dist/tools/prefabeditor/InstanceProvider.d.ts +1 -1
  22. package/dist/tools/prefabeditor/PrefabEditor.d.ts +4 -37
  23. package/dist/tools/prefabeditor/PrefabEditor.js +72 -71
  24. package/dist/tools/prefabeditor/PrefabRoot.d.ts +5 -29
  25. package/dist/tools/prefabeditor/PrefabRoot.js +72 -188
  26. package/dist/tools/prefabeditor/SceneContext.d.ts +28 -0
  27. package/dist/tools/prefabeditor/SceneContext.js +14 -0
  28. package/dist/tools/prefabeditor/SceneProvider.d.ts +14 -0
  29. package/dist/tools/prefabeditor/SceneProvider.js +68 -0
  30. package/dist/tools/prefabeditor/assetRuntime.d.ts +29 -2
  31. package/dist/tools/prefabeditor/assetRuntime.js +115 -1
  32. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +1 -1
  33. package/dist/tools/prefabeditor/components/EnvironmentComponent.js +3 -3
  34. package/dist/tools/prefabeditor/components/Input.d.ts +19 -19
  35. package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +1 -1
  36. package/dist/tools/prefabeditor/components/MaterialComponent.js +13 -14
  37. package/dist/tools/prefabeditor/components/ModelComponent.js +3 -4
  38. package/dist/tools/prefabeditor/components/PrefabRefComponent.js +43 -19
  39. package/dist/tools/prefabeditor/components/SoundComponent.js +6 -2
  40. package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -5
  41. package/dist/tools/prefabeditor/components/TransformComponent.js +1 -1
  42. package/dist/tools/prefabeditor/components/index.d.ts +1 -0
  43. package/dist/tools/prefabeditor/components/index.js +8 -0
  44. package/dist/tools/prefabeditor/components/lightUtils.d.ts +2 -2
  45. package/dist/tools/prefabeditor/prefabStore.d.ts +2 -1
  46. package/dist/tools/prefabeditor/prefabStore.js +16 -1
  47. package/dist/tools/prefabeditor/runtimeUtils.d.ts +10 -0
  48. package/dist/tools/prefabeditor/runtimeUtils.js +30 -0
  49. package/dist/tools/prefabeditor/utils.d.ts +1 -9
  50. package/dist/tools/prefabeditor/utils.js +3 -28
  51. package/dist/viewer.d.ts +21 -0
  52. package/dist/viewer.js +12 -0
  53. package/package.json +18 -16
  54. package/dist/index.d.ts +0 -40
  55. package/dist/index.js +0 -32
@@ -9,18 +9,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
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
- import GameCanvas from "../../shared/GameCanvas";
13
- import { useCallback, useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
12
+ import { useCallback, useEffect, useMemo, useRef, useState, forwardRef, useImperativeHandle } from "react";
14
13
  import { BoxHelper } from "three";
15
14
  import { findComponentEntry } from "./types";
16
- import { PrefabEditorMode, PrefabRoot } from "./PrefabRoot";
15
+ import { GameCanvas, PrefabRoot, PrefabEditorMode, SceneContext, AssetRuntimeProvider, createImageNode, createModelNode, denormalizePrefab } from "../../viewer";
17
16
  import EditorUI from "./EditorUI";
18
17
  import { base, toolbar } from "./styles";
19
18
  import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, exportGLBData, focusCameraOnObject, isExternalPath, regenerateIds, withBasePath } from "./utils";
20
19
  import { loadDroppedAssets } from "../dragdrop";
21
- import { denormalizePrefab, createImageNode, createModelNode, createNode } from './prefab';
20
+ import { createNode } from './prefab';
22
21
  import { createPrefabStore, PrefabStoreProvider } from "./prefabStore";
23
22
  import { decomposeModelToPrefabNodes, hasCollisionMeshConventions } from "./modelPrefab";
23
+ import { EditorContext, EditorRefContext } from "./EditorContext";
24
24
  function isObjectAttachedToRoot(root, object) {
25
25
  if (!root || !object)
26
26
  return false;
@@ -48,22 +48,7 @@ function SelectionHelper({ object }) {
48
48
  useHelper(helperTarget, BoxHelper, "cyan");
49
49
  return null;
50
50
  }
51
- export const EditorContext = createContext(null);
52
- export const EditorRefContext = createContext(null);
53
- export function useEditorContext() {
54
- const context = useContext(EditorContext);
55
- if (!context) {
56
- throw new Error("useEditorContext must be used within EditorContext.Provider");
57
- }
58
- return context;
59
- }
60
- export function useEditorRef() {
61
- const editorRef = useContext(EditorRefContext);
62
- if (!editorRef) {
63
- throw new Error("useEditorRef must be used within PrefabEditor");
64
- }
65
- return editorRef;
66
- }
51
+ export { EditorContext, EditorRefContext, useEditorContext, useEditorRef } from "./EditorContext";
67
52
  const MAX_HISTORY_LENGTH = 50;
68
53
  const HISTORY_DEBOUNCE_MS = 500;
69
54
  const DEFAULT_PREFAB = {
@@ -80,11 +65,12 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
80
65
  const [rotationSnap, setRotationSnap] = useState(Math.PI / 4);
81
66
  const startingPrefab = initialPrefab !== null && initialPrefab !== void 0 ? initialPrefab : DEFAULT_PREFAB;
82
67
  const [prefabStore] = useState(() => createPrefabStore(startingPrefab));
83
- const [history, setHistory] = useState([startingPrefab]);
68
+ const [history, setHistory] = useState(() => [prefabStore.getState()]);
84
69
  const [historyIndex, setHistoryIndex] = useState(0);
85
70
  const historyIndexRef = useRef(0);
86
71
  const historyTimeoutRef = useRef(null);
87
- const prefabRootRef = useRef(null);
72
+ const notifyRafRef = useRef(null);
73
+ const runtimeRef = useRef(null);
88
74
  const canvasRef = useRef(null);
89
75
  const controlsRef = useRef(null);
90
76
  const transformControlsRef = useRef(null);
@@ -96,11 +82,14 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
96
82
  }, []);
97
83
  const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
98
84
  const getNode = useCallback((nodeId) => { var _a; return (_a = prefabStore.getState().nodesById[nodeId]) !== null && _a !== void 0 ? _a : null; }, [prefabStore]);
99
- 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; }, []);
100
- 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; }, []);
101
- 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; }, []);
102
- const getModel = useCallback((path) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getModel(path)) !== null && _b !== void 0 ? _b : null; }, []);
103
- const scheduleHistory = useCallback((nextPrefab) => {
85
+ const getRoot = useCallback(() => { var _a, _b; return (_b = (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.getObject(prefabStore.getState().rootId)) !== null && _b !== void 0 ? _b : null; }, [prefabStore]);
86
+ const getObject = useCallback((nodeId) => { var _a, _b; return (_b = (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
87
+ const getHandle = useCallback((nodeId, kind) => { var _a, _b; return (_b = (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.getHandle(nodeId, kind)) !== null && _b !== void 0 ? _b : null; }, []);
88
+ const getModel = useCallback((path) => { var _a, _b; return (_b = (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.getModel(path)) !== null && _b !== void 0 ? _b : null; }, []);
89
+ // History stores normalized state snapshots. Because store mutations use
90
+ // structural sharing (unchanged nodes keep their references), capturing a
91
+ // snapshot is O(1) instead of deep-cloning the whole prefab tree.
92
+ const scheduleHistory = useCallback((snapshot) => {
104
93
  if (historyTimeoutRef.current) {
105
94
  clearTimeout(historyTimeoutRef.current);
106
95
  historyTimeoutRef.current = null;
@@ -108,7 +97,7 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
108
97
  historyTimeoutRef.current = setTimeout(() => {
109
98
  const currentHistoryIndex = historyIndexRef.current;
110
99
  setHistory(prev => {
111
- const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), nextPrefab];
100
+ const nextHistory = [...prev.slice(0, currentHistoryIndex + 1), snapshot];
112
101
  return nextHistory.length > MAX_HISTORY_LENGTH ? nextHistory.slice(1) : nextHistory;
113
102
  });
114
103
  const nextHistoryIndex = Math.min(currentHistoryIndex + 1, MAX_HISTORY_LENGTH - 1);
@@ -117,19 +106,29 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
117
106
  historyTimeoutRef.current = null;
118
107
  }, HISTORY_DEBOUNCE_MS);
119
108
  }, []);
109
+ // Coalesce onChange notifications to once per frame. denormalizePrefab walks
110
+ // the entire tree, so calling it on every mutation (e.g. per-frame gizmo
111
+ // drags) does not scale. We only pay that cost once, with the latest state.
112
+ const scheduleChange = useCallback(() => {
113
+ if (!onChangeRef.current || notifyRafRef.current != null)
114
+ return;
115
+ notifyRafRef.current = requestAnimationFrame(() => {
116
+ var _a;
117
+ notifyRafRef.current = null;
118
+ (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, denormalizePrefab(prefabStore.getState()));
119
+ });
120
+ }, [prefabStore]);
120
121
  const mutate = useCallback((run, pushHistory = isEditMode) => {
121
- var _a;
122
122
  const before = prefabStore.getState();
123
123
  const result = run(before);
124
124
  const after = prefabStore.getState();
125
125
  if (after === before)
126
126
  return result;
127
- const prefab = denormalizePrefab(after);
128
- (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, prefab);
127
+ scheduleChange();
129
128
  if (pushHistory)
130
- scheduleHistory(prefab);
129
+ scheduleHistory(after);
131
130
  return result;
132
- }, [isEditMode, prefabStore, scheduleHistory]);
131
+ }, [isEditMode, prefabStore, scheduleChange, scheduleHistory]);
133
132
  const update = useCallback((id, fn) => {
134
133
  mutate(s => s.updateNode(id, fn));
135
134
  }, [mutate]);
@@ -187,7 +186,7 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
187
186
  }
188
187
  if (options === null || options === void 0 ? void 0 : options.resetHistory) {
189
188
  setSelectedId(null);
190
- setHistory([prefab]);
189
+ setHistory([prefabStore.getState()]);
191
190
  historyIndexRef.current = 0;
192
191
  setHistoryIndex(0);
193
192
  }
@@ -204,6 +203,9 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
204
203
  if (historyTimeoutRef.current) {
205
204
  clearTimeout(historyTimeoutRef.current);
206
205
  }
206
+ if (notifyRafRef.current != null) {
207
+ cancelAnimationFrame(notifyRafRef.current);
208
+ }
207
209
  };
208
210
  }, []);
209
211
  useEffect(() => {
@@ -225,14 +227,13 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
225
227
  add(regenerateIds(prefab.root));
226
228
  }, [add]);
227
229
  const applyHistory = useCallback((index) => {
228
- var _a;
229
230
  detachTransformControls();
230
- prefabStore.getState().replacePrefab(history[index]);
231
- (_a = onChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onChangeRef, history[index]);
231
+ prefabStore.getState().restoreState(history[index]);
232
+ scheduleChange();
232
233
  historyIndexRef.current = index;
233
234
  setHistoryIndex(index);
234
235
  setSelectedId(prev => prev && prefabStore.getState().nodesById[prev] ? prev : null);
235
- }, [detachTransformControls, history, prefabStore]);
236
+ }, [detachTransformControls, history, prefabStore, scheduleChange]);
236
237
  const undo = useCallback(() => {
237
238
  if (historyIndex > 0) {
238
239
  applyHistory(historyIndex - 1);
@@ -334,11 +335,11 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
334
335
  function handleDrop(e) {
335
336
  e.preventDefault();
336
337
  e.stopPropagation();
337
- const scene = prefabRootRef.current;
338
+ const runtime = runtimeRef.current;
338
339
  void loadDroppedAssets(e.dataTransfer, {
339
340
  onModelLoaded: (model, filename, file) => {
340
341
  const path = getPrefabAssetRef(filename, 'models');
341
- scene === null || scene === void 0 ? void 0 : scene.addModel(path, model);
342
+ runtime === null || runtime === void 0 ? void 0 : runtime.registerModel(path, model);
342
343
  const modelName = file.name.replace(/\.[^.]+$/, '');
343
344
  const modelIdPrefix = modelName.replace(/[^\w-]+/g, '-') || 'model';
344
345
  if (hasCollisionMeshConventions(model)) {
@@ -351,7 +352,7 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
351
352
  return key;
352
353
  },
353
354
  });
354
- textureRefs.forEach((texture, path) => scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture));
355
+ textureRefs.forEach((texture, path) => { runtime === null || runtime === void 0 ? void 0 : runtime.registerTexture(path, texture); });
355
356
  add(Object.assign(Object.assign({}, decomposed), { name: modelName || decomposed.name }));
356
357
  return;
357
358
  }
@@ -359,7 +360,7 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
359
360
  },
360
361
  onTextureLoaded: (texture, filename, file) => {
361
362
  const path = getPrefabAssetRef(filename, 'textures');
362
- scene === null || scene === void 0 ? void 0 : scene.addTexture(path, texture);
363
+ runtime === null || runtime === void 0 ? void 0 : runtime.registerTexture(path, texture);
363
364
  add(createImageNode(path, file.name.replace(/\.[^.]+$/, '')));
364
365
  },
365
366
  onLoadError: error => {
@@ -391,44 +392,44 @@ const PrefabEditor = forwardRef(({ basePath = "", initialPrefab, mode: initialMo
391
392
  duplicate,
392
393
  move,
393
394
  replace,
394
- addModel: (path, model) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addModel(path, model); },
395
- addTexture: (path, texture) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addTexture(path, texture); },
396
- addSound: (path, sound) => { var _a; return (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.addSound(path, sound); },
395
+ addModel: (path, model) => { var _a; return (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.registerModel(path, model); },
396
+ addTexture: (path, texture) => { var _a; return (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.registerTexture(path, texture); },
397
+ addSound: (path, sound) => { var _a; return (_a = runtimeRef.current) === null || _a === void 0 ? void 0 : _a.registerSound(path, sound); },
397
398
  }), [add, basePath, duplicate, getHandle, getModel, getNode, getObject, getRoot, mode, move, remove, replace, replaceNode, update]);
398
399
  const editorRefValue = useMemo(() => (Object.assign(Object.assign({}, sceneValue), { save: getPrefab, load: loadPrefab, undo,
399
400
  redo, screenshot: handleScreenshot, exportGLB: handleExportGLB, exportGLBData: handleExportGLBData, clearSelection })), [clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, redo, sceneValue, undo]);
400
401
  useImperativeHandle(ref, () => editorRefValue, [editorRefValue]);
401
- 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 })] }));
402
+ const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection, basePath: basePath, children: children })] }));
402
403
  const handleCanvasCreated = useCallback((state) => {
403
404
  var _a;
404
405
  canvasRef.current = state.gl.domElement;
405
406
  (_a = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onCreated) === null || _a === void 0 ? void 0 : _a.call(canvasProps, state);
406
407
  }, [canvasProps]);
407
- return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsx(EditorRefContext.Provider, { value: editorRefValue, children: _jsxs(EditorContext.Provider, { value: {
408
- mode,
409
- basePath,
410
- setMode: updateMode,
411
- transformMode,
412
- setTransformMode,
413
- scaleSnap,
414
- setScaleSnap,
415
- positionSnap,
416
- setPositionSnap,
417
- rotationSnap,
418
- setRotationSnap,
419
- onFocusNode: isEditMode ? handleFocusNode : undefined,
420
- onScreenshot: handleScreenshot,
421
- onExportGLB: handleExportGLB
422
- }, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] } }, canvasProps, { onCreated: handleCanvasCreated, onPointerMissed: isEditMode
423
- ? (event) => {
424
- var _a, _b, _c, _d;
425
- 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;
426
- if (button === 0 && selectedId) {
427
- setSelection(null);
428
- }
429
- (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
430
- }
431
- : 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: transformMode === "translate" ? "world" : "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", { type: "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 }))] }))] }) }) });
408
+ return _jsx(PrefabStoreProvider, { store: prefabStore, children: _jsx(AssetRuntimeProvider, { runtimeRef: runtimeRef, children: _jsx(EditorRefContext.Provider, { value: editorRefValue, children: _jsx(EditorContext.Provider, { value: {
409
+ mode,
410
+ basePath,
411
+ setMode: updateMode,
412
+ transformMode,
413
+ setTransformMode,
414
+ scaleSnap,
415
+ setScaleSnap,
416
+ positionSnap,
417
+ setPositionSnap,
418
+ rotationSnap,
419
+ setRotationSnap,
420
+ onFocusNode: isEditMode ? handleFocusNode : undefined,
421
+ onScreenshot: handleScreenshot,
422
+ onExportGLB: handleExportGLB
423
+ }, children: _jsxs(SceneContext.Provider, { value: sceneValue, children: [_jsxs(GameCanvas, Object.assign({ camera: { position: [0, 5, 15] } }, canvasProps, { onCreated: handleCanvasCreated, onPointerMissed: isEditMode
424
+ ? (event) => {
425
+ var _a, _b, _c, _d;
426
+ 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;
427
+ if (button === 0 && selectedId) {
428
+ setSelection(null);
429
+ }
430
+ (_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
431
+ }
432
+ : 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: transformMode === "translate" ? "world" : "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", { type: "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 }))] }))] }) }) }) }) });
432
433
  });
433
434
  PrefabEditor.displayName = "PrefabEditor";
434
435
  export default PrefabEditor;
@@ -1,35 +1,11 @@
1
1
  import { Matrix4 } from "three";
2
- import type { Object3D, Texture } from "three";
3
- import { type ThreeEvent } from "@react-three/fiber";
2
+ import type { Object3D } from "three";
3
+ import type { ThreeEvent } from "@react-three/fiber";
4
4
  import type { GameObject as GameObjectType, Prefab } from "./types";
5
5
  import type { LoadedModels } from "../dragdrop";
6
6
  import type { PrefabStoreApi } from "./prefabStore";
7
- export declare enum PrefabEditorMode {
8
- Edit = "edit",
9
- Play = "play"
10
- }
11
- export type PrefabNode = Omit<GameObjectType, "children">;
12
- export interface Scene {
13
- root: Object3D | null;
14
- mode: PrefabEditorMode;
15
- basePath: string;
16
- get(id: string): GameObjectType | null;
17
- getObject(id: string): Object3D | null;
18
- getHandle<T = unknown>(id: string, kind: string): T | null;
19
- getModel(path: string): Object3D | null;
20
- add(node: GameObjectType, parentId?: string): GameObjectType;
21
- update(id: string, fn: (node: PrefabNode) => PrefabNode): void;
22
- replaceNode(id: string, node: GameObjectType): void;
23
- remove(id: string): void;
24
- duplicate(id: string): string | null;
25
- move(draggedId: string, targetId: string, position: "before" | "inside"): void;
26
- replace(prefab: Prefab): void;
27
- addModel(path: string, model: Object3D): void;
28
- addTexture(path: string, texture: Texture): void;
29
- addSound(path: string, sound: AudioBuffer): void;
30
- }
31
- export declare const SceneContext: import("react").Context<Scene | null>;
32
- export declare function useScene(): Scene;
7
+ import { type Scene } from "./SceneContext";
8
+ export type { Scene };
33
9
  export interface PrefabRootProps {
34
10
  editMode?: boolean;
35
11
  data?: Prefab;
@@ -42,7 +18,7 @@ export interface PrefabRootProps {
42
18
  children?: React.ReactNode;
43
19
  }
44
20
  export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<Scene>>;
45
- export declare function GameObjectRenderer(props: RendererProps): import("react/jsx-runtime").JSX.Element | null;
21
+ export declare function GameObjectRenderer(props: RendererProps): import("react").JSX.Element | null;
46
22
  interface RendererProps {
47
23
  nodeId: string;
48
24
  selectedId?: string | null;