react-three-game 0.0.69 → 0.0.71

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 (64) hide show
  1. package/dist/helpers/SoundManager.d.ts +2 -0
  2. package/dist/helpers/SoundManager.js +6 -0
  3. package/dist/index.d.ts +20 -13
  4. package/dist/index.js +14 -7
  5. package/dist/shared/GameCanvas.js +0 -2
  6. package/dist/tools/assetviewer/page.d.ts +5 -0
  7. package/dist/tools/assetviewer/page.js +3 -0
  8. package/dist/tools/dragdrop/DragDropLoader.d.ts +3 -2
  9. package/dist/tools/dragdrop/DragDropLoader.js +18 -3
  10. package/dist/tools/dragdrop/index.d.ts +2 -2
  11. package/dist/tools/dragdrop/index.js +1 -1
  12. package/dist/tools/dragdrop/modelLoader.d.ts +10 -0
  13. package/dist/tools/dragdrop/modelLoader.js +60 -0
  14. package/dist/tools/prefabeditor/EditorTree.js +6 -40
  15. package/dist/tools/prefabeditor/EditorTreeMenus.js +2 -20
  16. package/dist/tools/prefabeditor/EditorUI.js +8 -5
  17. package/dist/tools/prefabeditor/InstanceProvider.d.ts +2 -0
  18. package/dist/tools/prefabeditor/InstanceProvider.js +54 -52
  19. package/dist/tools/prefabeditor/PrefabEditor.d.ts +23 -1
  20. package/dist/tools/prefabeditor/PrefabEditor.js +79 -47
  21. package/dist/tools/prefabeditor/PrefabRoot.d.ts +26 -9
  22. package/dist/tools/prefabeditor/PrefabRoot.js +195 -159
  23. package/dist/tools/prefabeditor/RefBridge.d.ts +24 -0
  24. package/dist/tools/prefabeditor/RefBridge.js +44 -0
  25. package/dist/tools/prefabeditor/components/AmbientLightComponent.js +10 -7
  26. package/dist/tools/prefabeditor/components/CameraComponent.js +8 -14
  27. package/dist/tools/prefabeditor/components/ClickComponent.js +12 -7
  28. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +31 -5
  29. package/dist/tools/prefabeditor/components/ComponentRegistry.js +6 -6
  30. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +124 -52
  31. package/dist/tools/prefabeditor/components/EnvironmentComponent.js +5 -3
  32. package/dist/tools/prefabeditor/components/GeometryComponent.js +1 -1
  33. package/dist/tools/prefabeditor/components/Input.d.ts +16 -0
  34. package/dist/tools/prefabeditor/components/Input.js +33 -0
  35. package/dist/tools/prefabeditor/components/MaterialComponent.js +19 -8
  36. package/dist/tools/prefabeditor/components/ModelComponent.js +39 -45
  37. package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +10 -1
  38. package/dist/tools/prefabeditor/components/PhysicsComponent.js +127 -31
  39. package/dist/tools/prefabeditor/components/PointLightComponent.d.ts +3 -0
  40. package/dist/tools/prefabeditor/components/PointLightComponent.js +55 -0
  41. package/dist/tools/prefabeditor/components/SoundComponent.d.ts +3 -0
  42. package/dist/tools/prefabeditor/components/SoundComponent.js +244 -0
  43. package/dist/tools/prefabeditor/components/SpotLightComponent.js +53 -24
  44. package/dist/tools/prefabeditor/components/TransformComponent.js +2 -2
  45. package/dist/tools/prefabeditor/components/index.js +4 -0
  46. package/dist/tools/prefabeditor/components/lightUtils.d.ts +13 -0
  47. package/dist/tools/prefabeditor/components/lightUtils.js +64 -0
  48. package/dist/tools/prefabeditor/prefab.d.ts +37 -0
  49. package/dist/tools/prefabeditor/prefab.js +229 -0
  50. package/dist/tools/prefabeditor/prefabStore.d.ts +4 -16
  51. package/dist/tools/prefabeditor/prefabStore.js +32 -173
  52. package/dist/tools/prefabeditor/{sceneApi.d.ts → scene.d.ts} +15 -1
  53. package/dist/tools/prefabeditor/{sceneApi.js → scene.js} +66 -32
  54. package/dist/tools/prefabeditor/styles.d.ts +1 -0
  55. package/dist/tools/prefabeditor/styles.js +9 -0
  56. package/dist/tools/prefabeditor/types.d.ts +13 -0
  57. package/dist/tools/prefabeditor/types.js +28 -1
  58. package/dist/tools/prefabeditor/useClickValid.d.ts +13 -0
  59. package/dist/tools/prefabeditor/useClickValid.js +21 -0
  60. package/dist/tools/prefabeditor/utils.d.ts +2 -4
  61. package/dist/tools/prefabeditor/utils.js +8 -46
  62. package/package.json +1 -1
  63. package/dist/tools/prefabeditor/EditorContext.d.ts +0 -16
  64. package/dist/tools/prefabeditor/EditorContext.js +0 -9
@@ -1,14 +1,23 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { findComponentEntry } from "./types";
13
+ import { createComponentData, createNode as createPrefabNode } from "./prefab";
1
14
  function missingNode(id) {
2
15
  throw new Error(`Scene node not found: ${id}`);
3
16
  }
4
17
  function normalizePath(path) {
5
- if (path === undefined) {
18
+ if (!path)
6
19
  return [];
7
- }
8
- if (Array.isArray(path)) {
9
- return path;
10
- }
11
- return path.split(".").filter(Boolean);
20
+ return Array.isArray(path) ? path : path.split(".").filter(Boolean);
12
21
  }
13
22
  function getValueAtPath(value, path) {
14
23
  const segments = normalizePath(path);
@@ -47,28 +56,12 @@ function setValueAtPath(value, path, nextValue) {
47
56
  };
48
57
  return cloneBranch(value, 0);
49
58
  }
50
- function findComponentEntry(node, name) {
51
- if (!node.components) {
52
- return null;
53
- }
54
- const direct = node.components[name];
55
- if (direct) {
56
- return [name, direct];
57
- }
58
- const normalizedName = name.toLowerCase();
59
- for (const [key, component] of Object.entries(node.components)) {
60
- if (!component) {
61
- continue;
62
- }
63
- if (key.toLowerCase() === normalizedName || component.type.toLowerCase() === normalizedName) {
64
- return [key, component];
65
- }
66
- }
67
- return null;
68
- }
69
59
  export function createScene(adapter) {
70
- const findNode = (id) => adapter.getNode(id) ? createNode(id) : null;
71
- const getNode = (id) => { var _a; return (_a = findNode(id)) !== null && _a !== void 0 ? _a : missingNode(id); };
60
+ const getNode = (id) => {
61
+ if (!adapter.getNode(id))
62
+ missingNode(id);
63
+ return createNode(id);
64
+ };
72
65
  function createComponent(entityId, componentKey, componentType) {
73
66
  return {
74
67
  key: componentKey,
@@ -111,6 +104,21 @@ export function createScene(adapter) {
111
104
  function createNode(id) {
112
105
  return {
113
106
  id,
107
+ get name() {
108
+ var _a;
109
+ return (_a = adapter.getNode(id)) === null || _a === void 0 ? void 0 : _a.name;
110
+ },
111
+ get enabled() {
112
+ var _a;
113
+ return !((_a = adapter.getNode(id)) === null || _a === void 0 ? void 0 : _a.disabled);
114
+ },
115
+ get parent() {
116
+ const parentId = adapter.getParentId(id);
117
+ return parentId ? createNode(parentId) : null;
118
+ },
119
+ get children() {
120
+ return adapter.getChildIds(id).map(createNode);
121
+ },
114
122
  set(data) {
115
123
  adapter.updateNode(id, () => data);
116
124
  },
@@ -119,16 +127,33 @@ export function createScene(adapter) {
119
127
  },
120
128
  getComponent(name) {
121
129
  const node = adapter.getNode(id);
122
- if (!node) {
130
+ if (!node)
123
131
  return null;
124
- }
125
132
  const entry = findComponentEntry(node, name);
126
- if (!entry) {
133
+ if (!entry)
127
134
  return null;
128
- }
129
135
  const [componentKey, component] = entry;
130
136
  return createComponent(id, componentKey, component.type);
131
137
  },
138
+ addComponent(type, properties) {
139
+ const key = type.toLowerCase();
140
+ adapter.updateNode(id, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { [key]: createComponentData(type, properties) }) })));
141
+ return createComponent(id, key, type);
142
+ },
143
+ removeComponent(name) {
144
+ adapter.updateNode(id, node => {
145
+ var _a;
146
+ const entry = findComponentEntry(node, name);
147
+ if (!entry)
148
+ return node;
149
+ const [key] = entry;
150
+ const _b = (_a = node.components) !== null && _a !== void 0 ? _a : {}, _c = key, _ = _b[_c], rest = __rest(_b, [typeof _c === "symbol" ? _c : _c + ""]);
151
+ return Object.assign(Object.assign({}, node), { components: rest });
152
+ });
153
+ },
154
+ destroy() {
155
+ adapter.removeNode(id);
156
+ },
132
157
  };
133
158
  }
134
159
  function update(idOrUpdates, mutate) {
@@ -148,8 +173,17 @@ export function createScene(adapter) {
148
173
  get rootId() {
149
174
  return adapter.getRootId();
150
175
  },
151
- find: findNode,
176
+ find(nameOrId) {
177
+ if (adapter.getNode(nameOrId))
178
+ return createNode(nameOrId);
179
+ const foundId = adapter.findByName(nameOrId);
180
+ return foundId ? createNode(foundId) : null;
181
+ },
152
182
  get: getNode,
183
+ create(name, components, options) {
184
+ const node = createPrefabNode(name, components);
185
+ return createNode(adapter.addNode(node, options));
186
+ },
153
187
  update,
154
188
  add(node, options) {
155
189
  return createNode(adapter.addNode(node, options));
@@ -1771,6 +1771,7 @@ export declare const tree: {
1771
1771
  background: string;
1772
1772
  borderBottomColor: string;
1773
1773
  };
1774
+ iconButton: React.CSSProperties;
1774
1775
  };
1775
1776
  export declare const menu: {
1776
1777
  container: {
@@ -129,6 +129,15 @@ export const tree = {
129
129
  background: colors.accentBg,
130
130
  borderBottomColor: colors.accentBorder,
131
131
  },
132
+ iconButton: {
133
+ background: 'none',
134
+ border: 'none',
135
+ cursor: 'pointer',
136
+ padding: '0 4px',
137
+ fontSize: 14,
138
+ opacity: 0.7,
139
+ color: 'inherit',
140
+ },
132
141
  };
133
142
  export const menu = {
134
143
  container: {
@@ -17,3 +17,16 @@ export interface ComponentData {
17
17
  type: string;
18
18
  properties: Record<string, any>;
19
19
  }
20
+ type ComponentHost = {
21
+ components?: Record<string, {
22
+ type?: string;
23
+ properties?: Record<string, any>;
24
+ } | undefined>;
25
+ };
26
+ /** Find a component on a node by type name or key (e.g. "Model", "transform"). */
27
+ export declare function findComponent(node: ComponentHost | null | undefined, name: string): ComponentData | undefined;
28
+ /** Find a component entry [key, data] by type name or key — use when you need the key for mutations. */
29
+ export declare function findComponentEntry(node: ComponentHost | null | undefined, name: string): [string, ComponentData] | undefined;
30
+ /** Check if a node has a component of the given type. */
31
+ export declare function hasComponent(node: ComponentHost | null | undefined, typeName: string): boolean;
32
+ export {};
@@ -1 +1,28 @@
1
- export {};
1
+ /** Find a component on a node by type name or key (e.g. "Model", "transform"). */
2
+ export function findComponent(node, name) {
3
+ var _a;
4
+ return (_a = findComponentEntry(node, name)) === null || _a === void 0 ? void 0 : _a[1];
5
+ }
6
+ /** Find a component entry [key, data] by type name or key — use when you need the key for mutations. */
7
+ export function findComponentEntry(node, name) {
8
+ if (!(node === null || node === void 0 ? void 0 : node.components))
9
+ return undefined;
10
+ // Direct key match
11
+ const direct = node.components[name];
12
+ if (direct === null || direct === void 0 ? void 0 : direct.type)
13
+ return [name, direct];
14
+ // Case-insensitive key + type scan
15
+ const normalized = name.toLowerCase();
16
+ for (const [key, comp] of Object.entries(node.components)) {
17
+ if (!(comp === null || comp === void 0 ? void 0 : comp.type))
18
+ continue;
19
+ if (key.toLowerCase() === normalized || comp.type.toLowerCase() === normalized) {
20
+ return [key, comp];
21
+ }
22
+ }
23
+ return undefined;
24
+ }
25
+ /** Check if a node has a component of the given type. */
26
+ export function hasComponent(node, typeName) {
27
+ return findComponentEntry(node, typeName) !== undefined;
28
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Shared click-valid pattern: tracks pointer down → move → up
3
+ * to distinguish clicks from drags. Returns handlers to spread onto a group.
4
+ */
5
+ export declare function useClickValid(enabled: boolean, onValidClick: (e: any) => void): {
6
+ onPointerDown: undefined;
7
+ onPointerMove: undefined;
8
+ onPointerUp: undefined;
9
+ } | {
10
+ onPointerDown: (e: any) => void;
11
+ onPointerMove: () => void;
12
+ onPointerUp: (e: any) => void;
13
+ };
@@ -0,0 +1,21 @@
1
+ import { useRef } from "react";
2
+ /**
3
+ * Shared click-valid pattern: tracks pointer down → move → up
4
+ * to distinguish clicks from drags. Returns handlers to spread onto a group.
5
+ */
6
+ export function useClickValid(enabled, onValidClick) {
7
+ const clickValid = useRef(false);
8
+ if (!enabled)
9
+ return { onPointerDown: undefined, onPointerMove: undefined, onPointerUp: undefined };
10
+ return {
11
+ onPointerDown: (e) => { e.stopPropagation(); clickValid.current = true; },
12
+ onPointerMove: () => { clickValid.current = false; },
13
+ onPointerUp: (e) => {
14
+ if (clickValid.current) {
15
+ e.stopPropagation();
16
+ onValidClick(e);
17
+ }
18
+ clickValid.current = false;
19
+ }
20
+ };
21
+ }
@@ -21,6 +21,8 @@ export declare function decompose(m: Matrix4): {
21
21
  rotation: [number, number, number];
22
22
  scale: [number, number, number];
23
23
  };
24
+ /** Build a local Matrix4 from position/rotation/scale arrays. */
25
+ export declare function composeTransform(position?: [number, number, number], rotation?: [number, number, number], scale?: [number, number, number]): Matrix4;
24
26
  /** Compute the parent world matrix for a node using the normalized store data */
25
27
  export declare function computeParentWorldMatrix(state: {
26
28
  nodesById: Record<string, {
@@ -32,7 +34,3 @@ export declare function computeParentWorldMatrix(state: {
32
34
  }, targetId: string): Matrix4;
33
35
  /** Recursively update all IDs in a node tree */
34
36
  export declare function regenerateIds(node: GameObject): GameObject;
35
- /** Create a GameObject node for a 3D model file */
36
- export declare function createModelNode(filename: string, name?: string): GameObject;
37
- /** Create a GameObject node for an image as a textured plane */
38
- export declare function createImageNode(texturePath: string, name?: string): GameObject;
@@ -7,6 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ import { findComponent } from "./types";
10
11
  import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
11
12
  import { Box3, Euler, Matrix4, PerspectiveCamera, Quaternion, Vector3 } from 'three';
12
13
  /** Save scene JSON, showing a Save As dialog when supported */
@@ -129,9 +130,13 @@ export function decompose(m) {
129
130
  scale: [s.x, s.y, s.z],
130
131
  };
131
132
  }
133
+ /** Build a local Matrix4 from position/rotation/scale arrays. */
134
+ export function composeTransform(position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1]) {
135
+ return new Matrix4().compose(new Vector3(...position), new Quaternion().setFromEuler(new Euler(...rotation)), new Vector3(...scale));
136
+ }
132
137
  /** Compute the parent world matrix for a node using the normalized store data */
133
138
  export function computeParentWorldMatrix(state, targetId) {
134
- var _a, _b, _c, _d, _e, _f;
139
+ var _a;
135
140
  const parentWorld = new Matrix4();
136
141
  const chain = [];
137
142
  let currentId = state.parentIdById[targetId];
@@ -140,8 +145,8 @@ export function computeParentWorldMatrix(state, targetId) {
140
145
  currentId = state.parentIdById[currentId];
141
146
  }
142
147
  for (const nodeId of chain) {
143
- const transform = (_c = (_b = (_a = state.nodesById[nodeId]) === null || _a === void 0 ? void 0 : _a.components) === null || _b === void 0 ? void 0 : _b.transform) === null || _c === void 0 ? void 0 : _c.properties;
144
- parentWorld.multiply(new Matrix4().compose(new Vector3(...((_d = transform === null || transform === void 0 ? void 0 : transform.position) !== null && _d !== void 0 ? _d : [0, 0, 0])), new Quaternion().setFromEuler(new Euler(...((_e = transform === null || transform === void 0 ? void 0 : transform.rotation) !== null && _e !== void 0 ? _e : [0, 0, 0]))), new Vector3(...((_f = transform === null || transform === void 0 ? void 0 : transform.scale) !== null && _f !== void 0 ? _f : [1, 1, 1]))));
148
+ const transform = (_a = findComponent(state.nodesById[nodeId], "Transform")) === null || _a === void 0 ? void 0 : _a.properties;
149
+ parentWorld.multiply(composeTransform(transform === null || transform === void 0 ? void 0 : transform.position, transform === null || transform === void 0 ? void 0 : transform.rotation, transform === null || transform === void 0 ? void 0 : transform.scale));
145
150
  }
146
151
  return parentWorld;
147
152
  }
@@ -150,46 +155,3 @@ export function regenerateIds(node) {
150
155
  var _a;
151
156
  return Object.assign(Object.assign({}, node), { id: crypto.randomUUID(), children: (_a = node.children) === null || _a === void 0 ? void 0 : _a.map(regenerateIds) });
152
157
  }
153
- /** Create a GameObject node for a 3D model file */
154
- export function createModelNode(filename, name) {
155
- return {
156
- id: crypto.randomUUID(),
157
- name: name !== null && name !== void 0 ? name : filename.replace(/^.*[\/]/, '').replace(/\.[^.]+$/, ''),
158
- components: {
159
- transform: {
160
- type: 'Transform',
161
- properties: { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] }
162
- },
163
- model: {
164
- type: 'Model',
165
- properties: {
166
- filename,
167
- instanced: false,
168
- repeat: false,
169
- repeatAxes: [{ axis: 'x', count: 1, offset: 1 }]
170
- }
171
- }
172
- }
173
- };
174
- }
175
- /** Create a GameObject node for an image as a textured plane */
176
- export function createImageNode(texturePath, name) {
177
- return {
178
- id: crypto.randomUUID(),
179
- name: name !== null && name !== void 0 ? name : texturePath.replace(/^.*[\/]/, '').replace(/\.[^.]+$/, ''),
180
- components: {
181
- transform: {
182
- type: 'Transform',
183
- properties: { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] }
184
- },
185
- geometry: {
186
- type: 'Geometry',
187
- properties: { geometryType: 'plane', args: [1, 1] }
188
- },
189
- material: {
190
- type: 'Material',
191
- properties: { color: '#ffffff', texture: texturePath }
192
- }
193
- }
194
- };
195
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-three-game",
3
- "version": "0.0.69",
3
+ "version": "0.0.71",
4
4
  "description": "high performance 3D game engine built in React",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -1,16 +0,0 @@
1
- export interface EditorContextType {
2
- editMode: boolean;
3
- transformMode: "translate" | "rotate" | "scale";
4
- setTransformMode: (mode: "translate" | "rotate" | "scale") => void;
5
- scaleSnap: number;
6
- setScaleSnap: (resolution: number) => void;
7
- positionSnap: number;
8
- setPositionSnap: (resolution: number) => void;
9
- rotationSnap: number;
10
- setRotationSnap: (resolution: number) => void;
11
- onFocusNode?: (nodeId: string) => void;
12
- onScreenshot?: () => void;
13
- onExportGLB?: () => void;
14
- }
15
- export declare const EditorContext: import("react").Context<EditorContextType | null>;
16
- export declare function useEditorContext(): EditorContextType;
@@ -1,9 +0,0 @@
1
- import { createContext, useContext } from "react";
2
- export const EditorContext = createContext(null);
3
- export function useEditorContext() {
4
- const context = useContext(EditorContext);
5
- if (!context) {
6
- throw new Error("useEditorContext must be used within EditorContext.Provider");
7
- }
8
- return context;
9
- }