react-three-game 0.0.85 → 0.0.87

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 (38) hide show
  1. package/README.md +87 -35
  2. package/dist/index.d.ts +5 -7
  3. package/dist/index.js +2 -4
  4. package/dist/tools/prefabeditor/GameEvents.d.ts +36 -117
  5. package/dist/tools/prefabeditor/GameEvents.js +44 -96
  6. package/dist/tools/prefabeditor/InstanceProvider.d.ts +0 -4
  7. package/dist/tools/prefabeditor/InstanceProvider.js +13 -44
  8. package/dist/tools/prefabeditor/PrefabEditor.d.ts +7 -2
  9. package/dist/tools/prefabeditor/PrefabEditor.js +13 -24
  10. package/dist/tools/prefabeditor/PrefabRoot.js +93 -44
  11. package/dist/tools/prefabeditor/{runtime.d.ts → assetRuntime.d.ts} +0 -25
  12. package/dist/tools/prefabeditor/assetRuntime.js +37 -0
  13. package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +4 -2
  14. package/dist/tools/prefabeditor/components/CameraComponent.js +1 -1
  15. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +0 -3
  16. package/dist/tools/prefabeditor/components/DataComponent.d.ts +3 -0
  17. package/dist/tools/prefabeditor/components/DataComponent.js +87 -0
  18. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +1 -1
  19. package/dist/tools/prefabeditor/components/EnvironmentComponent.js +1 -1
  20. package/dist/tools/prefabeditor/components/GeometryComponent.js +4 -2
  21. package/dist/tools/prefabeditor/components/Input.d.ts +2 -13
  22. package/dist/tools/prefabeditor/components/Input.js +0 -55
  23. package/dist/tools/prefabeditor/components/MaterialComponent.js +1 -1
  24. package/dist/tools/prefabeditor/components/ModelComponent.js +3 -3
  25. package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +4 -0
  26. package/dist/tools/prefabeditor/components/PhysicsComponent.js +64 -130
  27. package/dist/tools/prefabeditor/components/PointLightComponent.js +1 -1
  28. package/dist/tools/prefabeditor/components/SoundComponent.js +18 -11
  29. package/dist/tools/prefabeditor/components/SpotLightComponent.js +1 -1
  30. package/dist/tools/prefabeditor/components/index.js +2 -2
  31. package/dist/tools/prefabeditor/types.d.ts +1 -0
  32. package/dist/tools/prefabeditor/types.js +18 -0
  33. package/dist/tools/prefabeditor/usePointerEvents.d.ts +27 -0
  34. package/dist/tools/prefabeditor/usePointerEvents.js +52 -0
  35. package/package.json +1 -1
  36. package/dist/tools/prefabeditor/components/ClickComponent.d.ts +0 -3
  37. package/dist/tools/prefabeditor/components/ClickComponent.js +0 -52
  38. package/dist/tools/prefabeditor/runtime.js +0 -184
@@ -15,8 +15,7 @@ import { Merged, useHelper } from '@react-three/drei';
15
15
  import { InstancedRigidBodies } from "@react-three/rapier";
16
16
  import { ActiveCollisionTypes } from "@dimforge/rapier3d-compat";
17
17
  import { Mesh, Matrix4, Vector3, Quaternion, Euler, BoxHelper } from "three";
18
- import { gameEvents, getEntityIdFromRigidBody } from "./GameEvents";
19
- import { useClickValid } from "./useClickValid";
18
+ import { usePointerEvents } from "./usePointerEvents";
20
19
  export const DEFAULT_REPEAT_AXES = [{ axis: 'x', count: 1, offset: 1 }];
21
20
  export function normalizeRepeatAxes(value) {
22
21
  if (!Array.isArray(value)) {
@@ -103,32 +102,9 @@ function hasPhysics(instance) {
103
102
  function getColliderType(physics) {
104
103
  return physics.colliders || (physics.type === 'fixed' ? 'trimesh' : 'hull');
105
104
  }
106
- function emitPhysicsEvent(sourceId, eventName, payload) {
107
- if (!eventName)
108
- return;
109
- gameEvents.emit(eventName, {
110
- sourceEntityId: sourceId,
111
- targetEntityId: getEntityIdFromRigidBody(payload.other.rigidBody),
112
- targetRigidBody: payload.other.rigidBody,
113
- });
114
- }
115
- function emitClick(sourceId, instanceId, eventName, event) {
116
- gameEvents.emit(eventName, {
117
- sourceEntityId: sourceId,
118
- instanceEntityId: instanceId && instanceId !== sourceId ? instanceId : undefined,
119
- point: [event.point.x, event.point.y, event.point.z],
120
- button: event.button,
121
- altKey: event.nativeEvent.altKey,
122
- ctrlKey: event.nativeEvent.ctrlKey,
123
- metaKey: event.nativeEvent.metaKey,
124
- shiftKey: event.nativeEvent.shiftKey,
125
- });
126
- }
127
105
  function instanceEquals(a, b) {
128
106
  return a.id === b.id &&
129
107
  a.sourceId === b.sourceId &&
130
- a.clickable === b.clickable &&
131
- a.clickEventName === b.clickEventName &&
132
108
  a.locked === b.locked &&
133
109
  a.meshPath === b.meshPath &&
134
110
  arrayEquals(a.position, b.position) &&
@@ -245,7 +221,7 @@ function InstancedRigidGroup({ group, modelKey, partCount, flatMeshes, onSelect,
245
221
  const rigidBodiesRef = useRef(null);
246
222
  const instances = useMemo(() => group.instances.filter(hasPhysics).map(inst => {
247
223
  const _a = inst.physics, { activeCollisionTypes: _activeCollisionTypes, colliders: _colliders, userData } = _a, rigidBodyProps = __rest(_a, ["activeCollisionTypes", "colliders", "userData"]);
248
- return Object.assign(Object.assign({ key: inst.id, position: inst.position, rotation: inst.rotation, scale: inst.scale }, rigidBodyProps), { colliders: getColliderType(inst.physics), userData: Object.assign(Object.assign({}, userData), { entityId: inst.sourceId }), onIntersectionEnter: (payload) => emitPhysicsEvent(inst.sourceId, inst.physics.sensorEnterEventName, payload), onIntersectionExit: (payload) => emitPhysicsEvent(inst.sourceId, inst.physics.sensorExitEventName, payload), onCollisionEnter: (payload) => emitPhysicsEvent(inst.sourceId, inst.physics.collisionEnterEventName, payload), onCollisionExit: (payload) => emitPhysicsEvent(inst.sourceId, inst.physics.collisionExitEventName, payload) });
224
+ return Object.assign(Object.assign({ key: inst.id, position: inst.position, rotation: inst.rotation, scale: inst.scale }, rigidBodyProps), { colliders: getColliderType(inst.physics), userData: Object.assign(Object.assign({}, userData), { entityId: inst.sourceId }) });
249
225
  }), [group.instances]);
250
226
  // Apply scale to visual meshes (InstancedRigidBodies only scales colliders, not visuals)
251
227
  useEffect(() => {
@@ -317,12 +293,8 @@ function InstancedRigidGroup({ group, modelKey, partCount, flatMeshes, onSelect,
317
293
  onSelect(instance.sourceId);
318
294
  return;
319
295
  }
320
- if (!instance.clickable)
321
- return;
322
- e.stopPropagation();
323
- emitClick(instance.sourceId, instance.id, instance.clickEventName || 'click', e);
324
296
  };
325
- const shouldHandleClick = editMode || group.instances.some(inst => inst.clickable);
297
+ const shouldHandleClick = editMode;
326
298
  // Add key to force remount when instance count changes significantly (helps with cleanup)
327
299
  const rigidBodyKey = `rb_${modelKey}_${group.instances.map(inst => `${inst.id}:${getPhysicsSignature(inst.physics)}`).join('|')}`;
328
300
  return (_jsx(InstancedRigidBodies, { ref: rigidBodiesRef, instances: instances, children: Array.from({ length: partCount }).map((_, i) => {
@@ -344,14 +316,15 @@ function InstanceGroupItem({ instance, InstanceComponents, onSelect, registerRef
344
316
  const isLocked = Boolean(instance.locked);
345
317
  const isSelected = selectedId === instance.id || selectedId === instance.sourceId;
346
318
  const canSelect = editMode && !isLocked;
347
- const canClick = !editMode && Boolean(instance.clickable);
348
- const pointerHandlers = useClickValid(canSelect || canClick, (e) => {
349
- if (editMode) {
350
- onSelect === null || onSelect === void 0 ? void 0 : onSelect(instance.sourceId);
351
- }
352
- else if (instance.clickable) {
353
- emitClick(instance.sourceId, instance.id, instance.clickEventName || 'click', e);
354
- }
319
+ const canClick = false;
320
+ const pointerHandlers = usePointerEvents({
321
+ enabled: canSelect || canClick,
322
+ entity: instance,
323
+ onClick: () => {
324
+ if (editMode) {
325
+ onSelect === null || onSelect === void 0 ? void 0 : onSelect(instance.sourceId);
326
+ }
327
+ },
355
328
  });
356
329
  // Use BoxHelper when object is selected in edit mode
357
330
  useHelper(editMode && isSelected ? groupRef : null, BoxHelper, 'cyan');
@@ -370,7 +343,7 @@ export function useInstanceCheck(id) {
370
343
  return (_a = ctx === null || ctx === void 0 ? void 0 : ctx.hasInstance(id)) !== null && _a !== void 0 ? _a : false;
371
344
  }
372
345
  // GameInstance component: registers an instance for batch rendering (renders nothing itself)
373
- export const GameInstance = React.forwardRef(({ id, sourceId, clickable = false, clickEventName, modelUrl, locked = false, position, rotation, scale, physics = undefined, }, ref) => {
346
+ export const GameInstance = React.forwardRef(({ id, sourceId, modelUrl, locked = false, position, rotation, scale, physics = undefined, }, ref) => {
374
347
  const ctx = useContext(GameInstanceContext);
375
348
  const addInstance = ctx === null || ctx === void 0 ? void 0 : ctx.addInstance;
376
349
  const removeInstance = ctx === null || ctx === void 0 ? void 0 : ctx.removeInstance;
@@ -381,8 +354,6 @@ export const GameInstance = React.forwardRef(({ id, sourceId, clickable = false,
381
354
  const instance = useMemo(() => ({
382
355
  id,
383
356
  sourceId: sourceId !== null && sourceId !== void 0 ? sourceId : id,
384
- clickable,
385
- clickEventName,
386
357
  locked,
387
358
  meshPath: modelUrl,
388
359
  position,
@@ -392,8 +363,6 @@ export const GameInstance = React.forwardRef(({ id, sourceId, clickable = false,
392
363
  }), [
393
364
  id,
394
365
  sourceId,
395
- clickable,
396
- clickEventName,
397
366
  locked,
398
367
  modelUrl,
399
368
  positionX,
@@ -2,18 +2,23 @@ import GameCanvas from "../../shared/GameCanvas";
2
2
  import { Object3D, Texture } from "three";
3
3
  import { GameObject, Prefab } from "./types";
4
4
  import type { ExportGLBOptions } from "./utils";
5
- import { type Scene, type SpawnOptions } from "./scene";
5
+ import { type PrefabStoreApi } from "./prefabStore";
6
+ import type { SpawnOptions } from "./scene";
6
7
  export interface PrefabEditorRef {
8
+ root: Object3D | null;
9
+ store: PrefabStoreApi;
10
+ getObject: (nodeId: string) => Object3D | null;
11
+ getRigidBody: (nodeId: string) => any;
7
12
  screenshot: () => void;
8
13
  exportGLB: (options?: ExportGLBOptions) => Promise<ArrayBuffer | undefined>;
9
14
  exportGLBData: () => Promise<ArrayBuffer | undefined>;
10
15
  clearSelection: () => Promise<void>;
11
16
  save: () => Prefab;
12
- scene: Scene;
13
17
  load: (prefab: Prefab, options?: {
14
18
  resetHistory?: boolean;
15
19
  notifyChange?: boolean;
16
20
  }) => void;
21
+ addNode: (node: GameObject, options?: SpawnOptions) => GameObject;
17
22
  addModel: (path: string, model: Object3D, options?: SpawnOptions) => GameObject;
18
23
  addTexture: (path: string, texture: Texture, options?: SpawnOptions) => GameObject;
19
24
  }
@@ -10,7 +10,7 @@ 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 { useCallback, useEffect, useMemo, useReducer, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
13
+ import { useCallback, useEffect, useReducer, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
14
14
  import { findComponentEntry } from "./types";
15
15
  import PrefabRoot from "./PrefabRoot";
16
16
  import { Physics } from "@react-three/rapier";
@@ -20,7 +20,6 @@ import { computeParentWorldMatrix, decompose, exportGLB as exportGLBFile, export
20
20
  import { loadFiles } from "../dragdrop";
21
21
  import { denormalizePrefab, createImageNode, createModelNode, createNode } from './prefab';
22
22
  import { createPrefabStore, PrefabStoreProvider } from "./prefabStore";
23
- import { createScene } from "./scene";
24
23
  function isObjectAttachedToRoot(root, object) {
25
24
  if (!root || !object)
26
25
  return false;
@@ -53,7 +52,6 @@ const DEFAULT_PREFAB = {
53
52
  root: createNode('Root', {}, { id: 'root' })
54
53
  };
55
54
  const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
56
- var _a, _b;
57
55
  const [mode, setMode] = useState(initialMode);
58
56
  const [selectedId, setSelectedId] = useState(null);
59
57
  const [transformMode, setTransformMode] = useState("translate");
@@ -73,6 +71,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
73
71
  const onChangeRef = useRef(onChange);
74
72
  const isEditMode = mode === PrefabEditorMode.Edit;
75
73
  const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
74
+ 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; }, []);
76
75
  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; }, []);
77
76
  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; }, []);
78
77
  const handleObjectRefChange = useCallback((nodeId) => {
@@ -173,7 +172,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
173
172
  return () => unsubscribe();
174
173
  }, [prefabStore, selectedId]);
175
174
  const selectedObject = selectedId ? getObject(selectedId) : null;
176
- const transformObject = isObjectAttachedToRoot((_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null, selectedObject)
175
+ const transformObject = isObjectAttachedToRoot(getRootObject(), selectedObject)
177
176
  ? selectedObject
178
177
  : null;
179
178
  const addNode = useCallback((node, options) => {
@@ -251,21 +250,19 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
251
250
  });
252
251
  }), [setSelection]);
253
252
  const handleExportGLB = useCallback((...args_1) => __awaiter(void 0, [...args_1], void 0, function* (options = {}) {
254
- var _a;
255
253
  yield clearSelection();
256
- const rootObject = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
254
+ const rootObject = getRootObject();
257
255
  if (!rootObject)
258
256
  return;
259
257
  return exportGLBFile(rootObject, Object.assign({ filename: `${prefabStore.getState().prefabName || 'prefab'}.glb` }, options));
260
- }), [clearSelection, prefabStore]);
258
+ }), [clearSelection, getRootObject, prefabStore]);
261
259
  const handleExportGLBData = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
262
- var _a;
263
260
  yield clearSelection();
264
- const rootObject = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root;
261
+ const rootObject = getRootObject();
265
262
  if (!rootObject)
266
263
  return;
267
264
  return exportGLBData(rootObject);
268
- }), [clearSelection]);
265
+ }), [clearSelection, getRootObject]);
269
266
  const handleFocusNode = useCallback((nodeId) => {
270
267
  const object = getObject(nodeId);
271
268
  const controls = controlsRef.current;
@@ -274,18 +271,6 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
274
271
  return;
275
272
  focusCameraOnObject(object, camera, controls.target, () => { var _a; return (_a = controls.update) === null || _a === void 0 ? void 0 : _a.call(controls); });
276
273
  }, [getObject]);
277
- const scene = useMemo(() => createScene({
278
- getRootId: () => prefabStore.getState().rootId,
279
- getNode: (id) => { var _a; return (_a = prefabStore.getState().nodesById[id]) !== null && _a !== void 0 ? _a : null; },
280
- getChildIds: (id) => { var _a; return (_a = prefabStore.getState().childIdsById[id]) !== null && _a !== void 0 ? _a : []; },
281
- getParentId: (id) => { var _a; return (_a = prefabStore.getState().parentIdById[id]) !== null && _a !== void 0 ? _a : null; },
282
- updateNode: (id, update) => prefabStore.getState().updateNode(id, update),
283
- updateNodes: (updates) => prefabStore.getState().updateNodes(Object.entries(updates).map(([id, update]) => ({ id, update }))),
284
- addNode: (node, options) => addNode(node, options).id,
285
- removeNode: (id) => prefabStore.getState().deleteNode(id),
286
- getObject,
287
- getRigidBody,
288
- }), [addNode, getObject, getRigidBody, prefabStore]);
289
274
  const handleTransformChange = () => {
290
275
  if (!selectedId)
291
276
  return;
@@ -342,16 +327,20 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
342
327
  };
343
328
  }, [addModel, addTexture, isEditMode, enableWindowDrop]);
344
329
  useImperativeHandle(ref, () => ({
330
+ root: getRootObject(),
331
+ store: prefabStore,
332
+ getObject,
333
+ getRigidBody,
345
334
  screenshot: handleScreenshot,
346
335
  exportGLB: handleExportGLB,
347
336
  exportGLBData: handleExportGLBData,
348
337
  clearSelection,
349
338
  save: getPrefab,
350
- scene,
351
339
  load: loadPrefab,
340
+ addNode,
352
341
  addModel,
353
342
  addTexture
354
- }), [addModel, addTexture, clearSelection, getPrefab, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, scene]);
343
+ }), [addModel, addNode, addTexture, clearSelection, getObject, getPrefab, getRigidBody, getRootObject, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, prefabStore]);
355
344
  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, onObjectRefChange: handleObjectRefChange, basePath: basePath }), children] }));
356
345
  const handleCanvasCreated = useCallback((state) => {
357
346
  var _a;
@@ -13,10 +13,9 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
13
13
  import { useHelper } from "@react-three/drei";
14
14
  import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
15
15
  import { BoxHelper, Euler, Matrix4, } from "three";
16
- import { useFrame } from "@react-three/fiber";
17
16
  import { useStore } from "zustand";
18
17
  import { useClickValid } from "./useClickValid";
19
- import { findComponent } from "./types";
18
+ import { findComponent, getNodeUserData } from "./types";
20
19
  import { getComponentDef, getComponentAssetRefs, registerComponent } from "./components/ComponentRegistry";
21
20
  import { builtinComponents } from "./components";
22
21
  import { loadModel, loadSound, loadTexture } from "../dragdrop";
@@ -24,7 +23,8 @@ import { GameInstance, GameInstanceProvider, getRepeatAxesFromModelProperties, u
24
23
  import { composeTransform, decompose } from "./utils";
25
24
  import { isPhysicsProps } from "./components/PhysicsComponent";
26
25
  import { createPrefabStore, PrefabStoreProvider, useOptionalPrefabStoreApi, usePrefabChildIds, usePrefabNode, usePrefabRootId } from "./prefabStore";
27
- import { AssetRuntimeContext, EntityRuntimeScope, createRuntimeEngine } from "./runtime";
26
+ import { AssetRuntimeContext, EntityRuntimeScope } from "./assetRuntime";
27
+ import { gameEvents } from "./GameEvents";
28
28
  import { sound as soundManager } from "../../helpers/SoundManager";
29
29
  builtinComponents.forEach(registerComponent);
30
30
  const IDENTITY = new Matrix4();
@@ -45,6 +45,30 @@ function isNodeReady(node, loadedModels) {
45
45
  return true;
46
46
  return Boolean(loadedModels[model.properties.filename]);
47
47
  }
48
+ function getNodeClickEventName(node) {
49
+ var _a;
50
+ const clickComponents = [
51
+ findComponent(node, 'BufferGeometry'),
52
+ findComponent(node, 'Geometry'),
53
+ ];
54
+ for (const component of clickComponents) {
55
+ if (!((_a = component === null || component === void 0 ? void 0 : component.properties) === null || _a === void 0 ? void 0 : _a.emitClickEvent))
56
+ continue;
57
+ const eventName = component.properties.clickEventName;
58
+ if (typeof eventName === 'string' && eventName.trim()) {
59
+ return eventName.trim();
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ function getNodeMetadataProps(node) {
65
+ var _a, _b;
66
+ const nodeName = (_b = (_a = node.name) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
67
+ return {
68
+ name: nodeName,
69
+ userData: Object.assign(Object.assign({ prefabNodeId: node.id }, (nodeName ? { prefabNodeName: nodeName } : {})), getNodeUserData(node)),
70
+ };
71
+ }
48
72
  export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick, onObjectRefChange, basePath = "" }, ref) => {
49
73
  var _a;
50
74
  const [models, setModels] = useState({});
@@ -94,29 +118,13 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
94
118
  setInjectedSounds(prev => (Object.assign(Object.assign({}, prev), { [path]: sound })));
95
119
  },
96
120
  }), [getObject]);
97
- const runtimeEngine = useMemo(() => createRuntimeEngine({
98
- store: resolvedStore,
99
- getObject,
100
- getRigidBody,
101
- }), [resolvedStore, getObject, getRigidBody]);
102
121
  const registerRef = useCallback((id, obj) => {
103
122
  objectRefs.current[id] = obj;
104
- runtimeEngine.invalidate();
105
123
  onObjectRefChange === null || onObjectRefChange === void 0 ? void 0 : onObjectRefChange(id, obj);
106
- }, [onObjectRefChange, runtimeEngine]);
124
+ }, [onObjectRefChange]);
107
125
  const registerRigidBodyRef = useCallback((id, rb) => {
108
126
  rigidBodyRefs.current.set(id, rb);
109
- runtimeEngine.invalidate();
110
- }, [runtimeEngine]);
111
- useEffect(() => {
112
- runtimeEngine.setActive(!editMode);
113
- }, [editMode, runtimeEngine]);
114
- useEffect(() => {
115
- return () => runtimeEngine.dispose();
116
- }, [runtimeEngine]);
117
- useFrame((_, dt) => {
118
- runtimeEngine.tick(dt);
119
- });
127
+ }, []);
120
128
  useEffect(() => {
121
129
  if (usesOwnedStore && data) {
122
130
  resolvedStore.getState().replacePrefab(data);
@@ -189,15 +197,36 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
189
197
  getAssetRevision: () => `${Object.keys(availableTextures).sort().join('|')}::${Object.keys(availableModels).sort().join('|')}`,
190
198
  }), [getObject, getRigidBody, registerRigidBodyRef, availableModels, availableTextures, availableSounds]);
191
199
  const content = (_jsx("group", { ref: rootRef, children: _jsx(GameInstanceProvider, { models: availableModels, selectedId: selectedId, editMode: editMode, onSelect: editMode ? onSelect : undefined, registerRef: registerRef, children: _jsx(StoreRootNode, { selectedId: selectedId, onSelect: editMode ? onSelect : undefined, onClick: onClick, registerRef: registerRef, loadedModels: availableModels, editMode: editMode, parentMatrix: IDENTITY }) }) }));
200
+ const runtimeContent = _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content });
192
201
  if (!shouldProvideStoreContext) {
193
- return _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content });
202
+ return runtimeContent;
194
203
  }
195
- return _jsx(PrefabStoreProvider, { store: resolvedStore, children: _jsx(AssetRuntimeContext.Provider, { value: assetRuntime, children: content }) });
204
+ return _jsx(PrefabStoreProvider, { store: resolvedStore, children: runtimeContent });
196
205
  });
197
206
  function StoreRootNode(props) {
198
207
  const rootId = usePrefabRootId();
199
208
  return _jsx(GameObjectRenderer, Object.assign({}, props, { nodeId: rootId }));
200
209
  }
210
+ function emitNodePointerEvent(eventName, event, nodeId, node, fallbackObject) {
211
+ var _a;
212
+ const trimmedEventName = eventName === null || eventName === void 0 ? void 0 : eventName.trim();
213
+ if (!trimmedEventName)
214
+ return;
215
+ gameEvents.emit(trimmedEventName, {
216
+ sourceEntityId: nodeId,
217
+ sourceNodeId: nodeId,
218
+ nodeId,
219
+ node,
220
+ object: (_a = event.object) !== null && _a !== void 0 ? _a : fallbackObject,
221
+ point: [event.point.x, event.point.y, event.point.z],
222
+ button: event.button,
223
+ altKey: event.nativeEvent.altKey,
224
+ ctrlKey: event.nativeEvent.ctrlKey,
225
+ metaKey: event.nativeEvent.metaKey,
226
+ shiftKey: event.nativeEvent.shiftKey,
227
+ r3fEvent: event,
228
+ });
229
+ }
201
230
  export function GameObjectRenderer(props) {
202
231
  var _a, _b;
203
232
  const node = usePrefabNode(props.nodeId);
@@ -221,20 +250,19 @@ export function GameObjectRenderer(props) {
221
250
  : _jsx(StandardNode, Object.assign({}, props), key);
222
251
  }
223
252
  function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef, onSelect, onClick }) {
224
- var _a, _b, _c;
253
+ var _a, _b;
225
254
  const gameObject = usePrefabNode(nodeId);
226
255
  if (!gameObject)
227
256
  return null;
228
257
  const localTransform = getNodeTransformProps(gameObject);
229
258
  const isLocked = Boolean(gameObject.locked);
230
- const clickComponent = findComponent(gameObject, "Click");
231
- const clickable = Boolean(clickComponent);
232
- const clickEventName = (_a = clickComponent === null || clickComponent === void 0 ? void 0 : clickComponent.properties) === null || _a === void 0 ? void 0 : _a.eventName;
259
+ const metadataProps = getNodeMetadataProps(gameObject);
260
+ const groupProps = Object.assign(Object.assign({}, metadataProps), { position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale });
233
261
  const physicsData = findComponent(gameObject, "Physics");
234
262
  const physicsProps = isPhysicsProps(physicsData === null || physicsData === void 0 ? void 0 : physicsData.properties)
235
263
  ? physicsData === null || physicsData === void 0 ? void 0 : physicsData.properties
236
264
  : undefined;
237
- const modelUrl = (_c = (_b = findComponent(gameObject, "Model")) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c.filename;
265
+ const modelUrl = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.filename;
238
266
  const instances = useMemo(() => buildRepeatedInstances(gameObject, parentMatrix, modelUrl, physicsProps), [gameObject, modelUrl, parentMatrix, physicsProps]);
239
267
  const groupRef = useRef(null);
240
268
  const handleGroupRef = useCallback((object) => {
@@ -243,22 +271,27 @@ function InstancedNode({ nodeId, parentMatrix = IDENTITY, editMode, registerRef,
243
271
  registerRef(nodeId, object);
244
272
  }
245
273
  }, [editMode, nodeId, registerRef]);
246
- const editClickHandlers = useClickValid(!!editMode && !isLocked, (e) => {
274
+ const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
247
275
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
248
- onClick === null || onClick === void 0 ? void 0 : onClick(e, gameObject);
276
+ onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
249
277
  });
278
+ 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, physics: instance.physics }, instance.id)));
250
279
  if (editMode) {
251
- return (_jsxs(_Fragment, { children: [_jsx("group", Object.assign({ ref: handleGroupRef, position: localTransform.position, rotation: localTransform.rotation, scale: localTransform.scale }, editClickHandlers, { children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) })), instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, clickEventName: clickEventName, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id)))] }));
280
+ 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] }));
252
281
  }
253
- return (_jsx(_Fragment, { children: instances.map(instance => (_jsx(GameInstance, { id: instance.id, sourceId: gameObject.id, clickable: clickable, clickEventName: clickEventName, modelUrl: instance.modelUrl, position: instance.position, rotation: instance.rotation, scale: instance.scale, locked: isLocked, physics: instance.physics }, instance.id))) }));
282
+ return _jsx(_Fragment, { children: renderedInstances });
254
283
  }
255
284
  function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, loadedModels, editMode, parentMatrix = IDENTITY, }) {
256
285
  var _a, _b;
257
286
  const gameObject = usePrefabNode(nodeId);
258
287
  const childIds = usePrefabChildIds(nodeId);
288
+ if (!gameObject)
289
+ return null;
259
290
  const isSelected = selectedId === nodeId;
260
- const isLocked = Boolean(gameObject === null || gameObject === void 0 ? void 0 : gameObject.locked);
291
+ const isLocked = Boolean(gameObject.locked);
261
292
  const stillInstanced = useInstanceCheck(nodeId);
293
+ const clickEventName = getNodeClickEventName(gameObject);
294
+ const metadataProps = getNodeMetadataProps(gameObject);
262
295
  const groupRef = useRef(null);
263
296
  const helperRef = useRef(null);
264
297
  const handleGroupRef = useCallback((object) => {
@@ -268,27 +301,43 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
268
301
  const handleHelperRef = useCallback((object) => {
269
302
  helperRef.current = object;
270
303
  }, []);
271
- const clickHandlers = useClickValid(!!editMode && !isLocked, (e) => {
304
+ const handleEditGroupRef = useCallback((object) => {
305
+ handleGroupRef(object);
306
+ handleHelperRef(object);
307
+ }, [handleGroupRef, handleHelperRef]);
308
+ const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
272
309
  onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
273
- if (gameObject)
274
- onClick === null || onClick === void 0 ? void 0 : onClick(e, gameObject);
310
+ onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
275
311
  });
312
+ const primaryClickHandlers = !editMode && (clickEventName || onClick)
313
+ ? {
314
+ onClick: (event) => {
315
+ event.stopPropagation();
316
+ emitNodePointerEvent(clickEventName, event, nodeId, gameObject, groupRef.current);
317
+ onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
318
+ },
319
+ }
320
+ : undefined;
276
321
  useHelper(editMode && isSelected ? helperRef : null, BoxHelper, "cyan");
277
- if (!gameObject)
278
- return null;
279
322
  const world = parentMatrix.clone().multiply(compose(gameObject));
280
323
  const physics = findComponent(gameObject, "Physics");
281
324
  const ready = isNodeReady(gameObject, loadedModels);
282
325
  const hasPhysics = physics && ready && !stillInstanced;
283
326
  const transform = getNodeTransformProps(gameObject);
327
+ const transformProps = {
328
+ position: transform.position,
329
+ rotation: transform.rotation,
330
+ scale: transform.scale,
331
+ };
332
+ const groupProps = Object.assign(Object.assign({}, metadataProps), transformProps);
284
333
  const physicsDef = hasPhysics ? getComponentDef(physics.type) : null;
285
334
  const isInstanced = (_b = (_a = findComponent(gameObject, "Model")) === null || _a === void 0 ? void 0 : _a.properties) === null || _b === void 0 ? void 0 : _b.instanced;
286
335
  const physicsKey = `physics_${nodeId}_${isInstanced ? 'instanced' : 'standard'}`;
287
336
  const renderCtx = { loadedModels, editMode, registerRef };
288
337
  const childNodes = _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode });
289
- const inner = (_jsx("group", Object.assign({}, clickHandlers, { children: renderCompositionNode(gameObject, renderCtx, childNodes) })));
338
+ const inner = renderCompositionNode(gameObject, renderCtx, primaryClickHandlers, childNodes);
290
339
  const physicsInner = editMode ? _jsx("group", { visible: false, children: inner }) : inner;
291
- return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: editMode ? (_jsxs(_Fragment, { children: [_jsx("group", { ref: handleGroupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: _jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }) }), _jsx("group", { ref: handleHelperRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: physicsInner }, physicsKey)) : null] })) : hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, { properties: physics.properties, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner }, physicsKey)) : (_jsx("group", { ref: handleGroupRef, position: transform.position, rotation: transform.rotation, scale: transform.scale, children: inner })) }));
340
+ return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: editMode ? (_jsxs(_Fragment, { children: [_jsxs("group", Object.assign({ ref: handleEditGroupRef }, groupProps, editClickHandlers, { children: [_jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) }), inner] })), hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, Object.assign({ properties: physics.properties }, transformProps, { children: physicsInner }), physicsKey)) : null] })) : hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, Object.assign({ properties: physics.properties }, transformProps, { children: _jsx("group", Object.assign({ ref: handleGroupRef }, metadataProps, { children: inner })) }), physicsKey)) : (_jsx("group", Object.assign({ ref: handleGroupRef }, groupProps, { children: inner }))) }));
292
341
  }
293
342
  function isRendererHandledComponent(componentType) {
294
343
  return componentType === "Transform"
@@ -383,11 +432,11 @@ function getNodeTransformProps(node) {
383
432
  scale: (_d = t === null || t === void 0 ? void 0 : t.scale) !== null && _d !== void 0 ? _d : [1, 1, 1],
384
433
  };
385
434
  }
386
- function renderCompositionNode(gameObject, ctx, childNodes) {
387
- const primaryContent = renderNodePrimaryContent(gameObject, ctx);
435
+ function renderCompositionNode(gameObject, ctx, primaryClickHandlers, childNodes) {
436
+ const primaryContent = renderNodePrimaryContent(gameObject, ctx, primaryClickHandlers);
388
437
  return applyNodeComposition(gameObject, _jsxs(_Fragment, { children: [primaryContent, childNodes] }));
389
438
  }
390
- function renderNodePrimaryContent(gameObject, ctx) {
439
+ function renderNodePrimaryContent(gameObject, ctx, primaryClickHandlers) {
391
440
  var _a, _b, _c;
392
441
  const geometry = (_a = findComponent(gameObject, "BufferGeometry")) !== null && _a !== void 0 ? _a : findComponent(gameObject, "Geometry");
393
442
  const material = findComponent(gameObject, "Material");
@@ -400,7 +449,7 @@ function renderNodePrimaryContent(gameObject, ctx) {
400
449
  const meshCastShadow = meshVisible && geometryProperties.castShadow !== false;
401
450
  const meshReceiveShadow = meshVisible && geometryProperties.receiveShadow !== false;
402
451
  if ((geometry === null || geometry === void 0 ? void 0 : geometry.type) && (geometryDef === null || geometryDef === void 0 ? void 0 : geometryDef.View)) {
403
- return (_jsxs("mesh", { visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow, children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] }));
452
+ return (_jsxs("mesh", Object.assign({ visible: meshVisible, castShadow: meshCastShadow, receiveShadow: meshReceiveShadow }, primaryClickHandlers, { children: [_jsx(geometryDef.View, { properties: geometry.properties }), material && (materialDef === null || materialDef === void 0 ? void 0 : materialDef.View) && (_jsx(materialDef.View, { properties: material.properties }, "material"))] })));
404
453
  }
405
454
  if ((model === null || model === void 0 ? void 0 : model.type) && (modelDef === null || modelDef === void 0 ? void 0 : modelDef.View) && !((_c = model.properties) === null || _c === void 0 ? void 0 : _c.instanced) && isNodeReady(gameObject, ctx.loadedModels)) {
406
455
  return _jsx(modelDef.View, { properties: model.properties });
@@ -1,7 +1,5 @@
1
1
  import { type ReactNode } from "react";
2
2
  import type { Object3D, Texture } from "three";
3
- import type { PrefabStoreApi } from "./prefabStore";
4
- import { type EntityComponent, type Scene } from "./scene";
5
3
  export interface AssetRuntime {
6
4
  registerRigidBodyRef: (id: string, rb: any) => void;
7
5
  getModel: (path: string) => Object3D | null;
@@ -36,26 +34,3 @@ export declare function EntityRuntimeScope({ nodeId, editMode, isSelected, child
36
34
  isSelected?: boolean;
37
35
  children: ReactNode;
38
36
  }): import("react/jsx-runtime").JSX.Element;
39
- /** Runtime behaviour produced by `Component.create(ctx)`. All methods optional. */
40
- export interface ComponentInstance {
41
- start?(): void;
42
- update?(dt: number): void;
43
- destroy?(): void;
44
- }
45
- export interface ComponentRuntimeContext<TProperties = Record<string, any>> {
46
- scene: Scene;
47
- component: EntityComponent<TProperties>;
48
- object: Object3D;
49
- rigidBody: any;
50
- }
51
- export interface RuntimeEngine {
52
- tick: (dt: number) => void;
53
- setActive: (active: boolean) => void;
54
- invalidate: () => void;
55
- dispose: () => void;
56
- }
57
- export declare function createRuntimeEngine({ store, getObject, getRigidBody, }: {
58
- store: PrefabStoreApi;
59
- getObject: (id: string) => Object3D | null;
60
- getRigidBody: (id: string) => any;
61
- }): RuntimeEngine;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo } from "react";
3
+ export const AssetRuntimeContext = createContext(null);
4
+ const EntityRuntimeContext = createContext(null);
5
+ export function useAssetRuntime() {
6
+ const ctx = useContext(AssetRuntimeContext);
7
+ if (!ctx)
8
+ throw new Error("useAssetRuntime must be used inside <PrefabRoot>");
9
+ return ctx;
10
+ }
11
+ export function useEntityRuntime() {
12
+ const ctx = useContext(EntityRuntimeContext);
13
+ if (!ctx)
14
+ throw new Error("useEntityRuntime must be used inside a component View rendered by <PrefabRoot>");
15
+ return ctx;
16
+ }
17
+ export function useEntityObjectRef() {
18
+ const { getObject } = useEntityRuntime();
19
+ return useMemo(() => ({ get current() { return getObject(); } }), [getObject]);
20
+ }
21
+ export function useEntityRigidBodyRef() {
22
+ const { getRigidBody } = useEntityRuntime();
23
+ return useMemo(() => ({ get current() { return getRigidBody(); } }), [getRigidBody]);
24
+ }
25
+ export function EntityRuntimeScope({ nodeId, editMode, isSelected, children, }) {
26
+ const asset = useContext(AssetRuntimeContext);
27
+ if (!asset)
28
+ throw new Error("EntityRuntimeScope must be used inside <PrefabRoot>");
29
+ const value = useMemo(() => ({
30
+ nodeId,
31
+ editMode,
32
+ isSelected,
33
+ getObject: () => asset.getObject(nodeId),
34
+ getRigidBody: () => asset.getRigidBody(nodeId),
35
+ }), [asset, editMode, isSelected, nodeId]);
36
+ return _jsx(EntityRuntimeContext.Provider, { value: value, children: children });
37
+ }
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { BooleanField, FieldGroup } from "./Input";
2
+ import { BooleanField, FieldGroup, StringField } from "./Input";
3
3
  const DEFAULT_TRIANGLE_POSITIONS = [
4
4
  0, 0, 0,
5
5
  1, 0, 0,
@@ -63,7 +63,7 @@ function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
63
63
  function BufferGeometryComponentEditor({ component, onUpdate, }) {
64
64
  var _a;
65
65
  const properties = (_a = component.properties) !== null && _a !== void 0 ? _a : {};
66
- 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 })] }));
66
+ 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: "entity:click" })) : null] }));
67
67
  }
68
68
  function BufferGeometryComponentView({ properties }) {
69
69
  const positions = normalizeNumberArray(properties.positions, DEFAULT_TRIANGLE_POSITIONS);
@@ -91,6 +91,8 @@ const BufferGeometryComponent = {
91
91
  normals: [],
92
92
  uvs: DEFAULT_TRIANGLE_UVS,
93
93
  computeVertexNormals: true,
94
+ emitClickEvent: false,
95
+ clickEventName: '',
94
96
  },
95
97
  };
96
98
  export default BufferGeometryComponent;
@@ -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 { useEntityRuntime } from '../runtime';
6
+ import { useEntityRuntime } from '../assetRuntime';
7
7
  import { FieldGroup, NumberField, SelectField } from './Input';
8
8
  const CAMERA_PROJECTION_OPTIONS = [
9
9
  { value: 'perspective', label: 'Perspective' },
@@ -1,6 +1,5 @@
1
1
  import { FC } from "react";
2
2
  import { ComponentData, GameObject } from "../types";
3
- import type { ComponentInstance, ComponentRuntimeContext } from "../runtime";
4
3
  export type AssetRef = {
5
4
  type: "model" | "texture" | "sound";
6
5
  path: string;
@@ -28,8 +27,6 @@ export interface Component {
28
27
  }>;
29
28
  defaultProperties: any;
30
29
  View?: FC<ComponentViewProps>;
31
- /** Optional runtime factory for the non-React game loop. */
32
- create?: (ctx: ComponentRuntimeContext) => ComponentInstance | void;
33
30
  /** Declare which asset paths this component references (for asset loading). */
34
31
  getAssetRefs?: (properties: Record<string, any>) => AssetRef[];
35
32
  }