react-three-game 0.0.69 → 0.0.70

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 (52) 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 +10 -8
  4. package/dist/index.js +7 -5
  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 -30
  15. package/dist/tools/prefabeditor/EditorTreeMenus.js +3 -3
  16. package/dist/tools/prefabeditor/EditorUI.js +6 -4
  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 +22 -0
  20. package/dist/tools/prefabeditor/PrefabEditor.js +68 -27
  21. package/dist/tools/prefabeditor/PrefabRoot.d.ts +5 -1
  22. package/dist/tools/prefabeditor/PrefabRoot.js +148 -145
  23. package/dist/tools/prefabeditor/components/ClickComponent.js +10 -7
  24. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +10 -4
  25. package/dist/tools/prefabeditor/components/ComponentRegistry.js +6 -6
  26. package/dist/tools/prefabeditor/components/GeometryComponent.js +1 -1
  27. package/dist/tools/prefabeditor/components/Input.d.ts +16 -0
  28. package/dist/tools/prefabeditor/components/Input.js +33 -0
  29. package/dist/tools/prefabeditor/components/MaterialComponent.js +10 -2
  30. package/dist/tools/prefabeditor/components/ModelComponent.js +35 -43
  31. package/dist/tools/prefabeditor/components/PhysicsComponent.d.ts +10 -1
  32. package/dist/tools/prefabeditor/components/PhysicsComponent.js +122 -28
  33. package/dist/tools/prefabeditor/components/SoundComponent.d.ts +3 -0
  34. package/dist/tools/prefabeditor/components/SoundComponent.js +240 -0
  35. package/dist/tools/prefabeditor/components/SpotLightComponent.js +6 -1
  36. package/dist/tools/prefabeditor/components/TransformComponent.js +2 -2
  37. package/dist/tools/prefabeditor/components/index.js +2 -0
  38. package/dist/tools/prefabeditor/prefabStore.d.ts +1 -0
  39. package/dist/tools/prefabeditor/prefabStore.js +11 -13
  40. package/dist/tools/prefabeditor/sceneApi.d.ts +15 -1
  41. package/dist/tools/prefabeditor/sceneApi.js +77 -32
  42. package/dist/tools/prefabeditor/styles.d.ts +1 -0
  43. package/dist/tools/prefabeditor/styles.js +9 -0
  44. package/dist/tools/prefabeditor/types.d.ts +13 -0
  45. package/dist/tools/prefabeditor/types.js +28 -1
  46. package/dist/tools/prefabeditor/useClickValid.d.ts +13 -0
  47. package/dist/tools/prefabeditor/useClickValid.js +21 -0
  48. package/dist/tools/prefabeditor/utils.d.ts +2 -0
  49. package/dist/tools/prefabeditor/utils.js +34 -35
  50. package/package.json +1 -1
  51. package/dist/tools/prefabeditor/EditorContext.d.ts +0 -16
  52. package/dist/tools/prefabeditor/EditorContext.js +0 -9
@@ -51,6 +51,11 @@ const SpotLightComponent = {
51
51
  name: 'SpotLight',
52
52
  Editor: SpotLightComponentEditor,
53
53
  View: SpotLightView,
54
- defaultProperties: spotLightDefaults
54
+ defaultProperties: spotLightDefaults,
55
+ getAssetRefs: (properties) => {
56
+ if (properties.map)
57
+ return [{ type: 'texture', path: properties.map }];
58
+ return [];
59
+ },
55
60
  };
56
61
  export default SpotLightComponent;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Label, Vector3Input } from "./Input";
3
- import { useEditorContext } from "../EditorContext";
3
+ import { useEditorContext } from "../PrefabEditor";
4
4
  import { colors } from "../styles";
5
5
  const buttonStyle = {
6
6
  padding: '4px 8px',
@@ -48,7 +48,7 @@ function TransformComponentEditor({ component, onUpdate }) {
48
48
  const TransformComponent = {
49
49
  name: 'Transform',
50
50
  Editor: TransformComponentEditor,
51
- nonComposable: true,
51
+ isWrapper: true,
52
52
  defaultProperties: {
53
53
  position: [0, 0, 0],
54
54
  rotation: [0, 0, 0],
@@ -10,6 +10,7 @@ import TextComponent from './TextComponent';
10
10
  import EnvironmentComponent from './EnvironmentComponent';
11
11
  import CameraComponent from './CameraComponent';
12
12
  import ClickComponent from './ClickComponent';
13
+ import SoundComponent from './SoundComponent';
13
14
  export default [
14
15
  GeometryComponent,
15
16
  TransformComponent,
@@ -23,4 +24,5 @@ export default [
23
24
  EnvironmentComponent,
24
25
  CameraComponent,
25
26
  ClickComponent,
27
+ SoundComponent,
26
28
  ];
@@ -33,6 +33,7 @@ export declare function PrefabStoreProvider({ store, children, }: {
33
33
  children: ReactNode;
34
34
  }): import("react").FunctionComponentElement<import("react").ProviderProps<PrefabStoreApi | null>>;
35
35
  export declare function usePrefabStoreApi(): PrefabStoreApi;
36
+ export declare function useOptionalPrefabStoreApi(): PrefabStoreApi | null;
36
37
  export declare function usePrefabStore<T>(selector: (state: PrefabStoreState) => T): T;
37
38
  export declare function usePrefabRootId(): string;
38
39
  export declare function usePrefabNode(nodeId: string | null | undefined): PrefabNodeRecord | null;
@@ -13,6 +13,7 @@ import { createContext, createElement, useContext } from "react";
13
13
  import { subscribeWithSelector } from "zustand/middleware";
14
14
  import { useStore } from "zustand";
15
15
  import { createStore } from "zustand/vanilla";
16
+ import { getComponentAssetRefs } from "./components/ComponentRegistry";
16
17
  const PrefabStoreContext = createContext(null);
17
18
  const EMPTY_CHILD_IDS = [];
18
19
  export function PrefabStoreProvider({ store, children, }) {
@@ -25,6 +26,9 @@ export function usePrefabStoreApi() {
25
26
  }
26
27
  return store;
27
28
  }
29
+ export function useOptionalPrefabStoreApi() {
30
+ return useContext(PrefabStoreContext);
31
+ }
28
32
  export function usePrefabStore(selector) {
29
33
  return useStore(usePrefabStoreApi(), selector);
30
34
  }
@@ -296,26 +300,20 @@ function collectSubtreeAssetRefs(node) {
296
300
  return refs;
297
301
  }
298
302
  function collectAssetRefsForIds(ids, nodesById) {
299
- return ids.flatMap(id => getAssetRefs(nodesById[id]));
303
+ return ids.reduce((refs, id) => {
304
+ refs.push(...getAssetRefs(nodesById[id]));
305
+ return refs;
306
+ }, []);
300
307
  }
301
308
  function getAssetRefs(node) {
302
309
  var _a;
303
310
  const refs = [];
304
311
  Object.values((_a = node === null || node === void 0 ? void 0 : node.components) !== null && _a !== void 0 ? _a : {}).forEach(component => {
305
- var _a, _b, _c, _d;
312
+ var _a;
306
313
  if (!(component === null || component === void 0 ? void 0 : component.type))
307
314
  return;
308
- if (component.type === "Model" && ((_a = component.properties) === null || _a === void 0 ? void 0 : _a.filename)) {
309
- refs.push(`model:${component.properties.filename}`);
310
- }
311
- if (component.type === "Material") {
312
- if ((_b = component.properties) === null || _b === void 0 ? void 0 : _b.texture)
313
- refs.push(`texture:${component.properties.texture}`);
314
- if ((_c = component.properties) === null || _c === void 0 ? void 0 : _c.normalMapTexture)
315
- refs.push(`texture:${component.properties.normalMapTexture}`);
316
- }
317
- if (component.type === "SpotLight" && ((_d = component.properties) === null || _d === void 0 ? void 0 : _d.map)) {
318
- refs.push(`texture:${component.properties.map}`);
315
+ for (const ref of getComponentAssetRefs(component.type, (_a = component.properties) !== null && _a !== void 0 ? _a : {})) {
316
+ refs.push(`${ref.type}:${ref.path}`);
319
317
  }
320
318
  });
321
319
  return refs.sort();
@@ -15,16 +15,27 @@ export interface EntityComponent<TProperties = Record<string, any>> {
15
15
  }
16
16
  export interface Entity {
17
17
  readonly id: string;
18
+ readonly name: string | undefined;
19
+ readonly enabled: boolean;
20
+ readonly parent: Entity | null;
21
+ readonly children: Entity[];
18
22
  set: (data: EntityData) => void;
19
23
  update: (update: (node: EntityData) => EntityData) => void;
20
24
  getComponent: <TProperties = Record<string, any>>(name: string) => EntityComponent<TProperties> | null;
25
+ addComponent: (type: string, properties?: Record<string, any>) => EntityComponent | null;
26
+ removeComponent: (name: string) => void;
27
+ destroy: () => void;
21
28
  }
22
29
  export type EntityUpdate = (node: EntityData) => EntityData;
23
30
  export type SceneUpdates = Record<string, EntityUpdate>;
24
31
  export interface Scene {
25
32
  readonly rootId: string;
26
- find: (id: string) => Entity | null;
33
+ find: (nameOrId: string) => Entity | null;
27
34
  get: (id: string) => Entity;
35
+ create: (name: string, components?: Record<string, {
36
+ type: string;
37
+ properties?: Record<string, any>;
38
+ }>, options?: SpawnOptions) => Entity;
28
39
  update: {
29
40
  (id: string, update: EntityUpdate): void;
30
41
  (updates: SceneUpdates): void;
@@ -35,6 +46,9 @@ export interface Scene {
35
46
  interface SceneAdapter {
36
47
  getRootId: () => string;
37
48
  getNode: (id: string) => EntityData | null;
49
+ getChildIds: (id: string) => string[];
50
+ getParentId: (id: string) => string | null;
51
+ findByName: (name: string) => string | null;
38
52
  updateNode: (id: string, update: (node: EntityData) => EntityData) => void;
39
53
  updateNodes: (updates: Record<string, (node: EntityData) => EntityData>) => void;
40
54
  addNode: (node: GameObject, options?: SpawnOptions) => string;
@@ -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 { getComponentDef } from "./components/ComponentRegistry";
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,36 @@ 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
+ var _a;
140
+ const def = getComponentDef(type);
141
+ const key = type.toLowerCase();
142
+ const props = (_a = properties !== null && properties !== void 0 ? properties : def === null || def === void 0 ? void 0 : def.defaultProperties) !== null && _a !== void 0 ? _a : {};
143
+ adapter.updateNode(id, node => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node.components), { [key]: { type, properties: props } }) })));
144
+ return createComponent(id, key, type);
145
+ },
146
+ removeComponent(name) {
147
+ adapter.updateNode(id, node => {
148
+ var _a;
149
+ const entry = findComponentEntry(node, name);
150
+ if (!entry)
151
+ return node;
152
+ const [key] = entry;
153
+ const _b = (_a = node.components) !== null && _a !== void 0 ? _a : {}, _c = key, _ = _b[_c], rest = __rest(_b, [typeof _c === "symbol" ? _c : _c + ""]);
154
+ return Object.assign(Object.assign({}, node), { components: rest });
155
+ });
156
+ },
157
+ destroy() {
158
+ adapter.removeNode(id);
159
+ },
132
160
  };
133
161
  }
134
162
  function update(idOrUpdates, mutate) {
@@ -148,8 +176,25 @@ export function createScene(adapter) {
148
176
  get rootId() {
149
177
  return adapter.getRootId();
150
178
  },
151
- find: findNode,
179
+ find(nameOrId) {
180
+ // Try by ID first, then by name
181
+ if (adapter.getNode(nameOrId))
182
+ return createNode(nameOrId);
183
+ const foundId = adapter.findByName(nameOrId);
184
+ return foundId ? createNode(foundId) : null;
185
+ },
152
186
  get: getNode,
187
+ create(name, components, options) {
188
+ const node = {
189
+ id: crypto.randomUUID(),
190
+ name,
191
+ components: Object.assign({ transform: {
192
+ type: "Transform",
193
+ properties: { position: [0, 0, 0], rotation: [0, 0, 0], scale: [1, 1, 1] },
194
+ } }, components),
195
+ };
196
+ return createNode(adapter.addNode(node, options));
197
+ },
153
198
  update,
154
199
  add(node, options) {
155
200
  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, {
@@ -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,40 @@ 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) {
158
+ function createNode(path, name, extraComponents) {
155
159
  return {
156
160
  id: crypto.randomUUID(),
157
- name: name !== null && name !== void 0 ? name : filename.replace(/^.*[\/]/, '').replace(/\.[^.]+$/, ''),
158
- components: {
159
- transform: {
161
+ name: name !== null && name !== void 0 ? name : path.replace(/^.*[\/]/, '').replace(/\.[^.]+$/, ''),
162
+ components: Object.assign({ transform: {
160
163
  type: 'Transform',
161
164
  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
- }
165
+ } }, extraComponents)
166
+ };
167
+ }
168
+ /** Create a GameObject node for a 3D model file */
169
+ export function createModelNode(filename, name) {
170
+ return createNode(filename, name, {
171
+ model: {
172
+ type: 'Model',
173
+ properties: {
174
+ filename,
175
+ instanced: false,
176
+ repeat: false,
177
+ repeatAxes: [{ axis: 'x', count: 1, offset: 1 }]
171
178
  }
172
179
  }
173
- };
180
+ });
174
181
  }
175
182
  /** Create a GameObject node for an image as a textured plane */
176
183
  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
- }
184
+ return createNode(texturePath, name, {
185
+ geometry: {
186
+ type: 'Geometry',
187
+ properties: { geometryType: 'plane', args: [1, 1] }
188
+ },
189
+ material: {
190
+ type: 'Material',
191
+ properties: { color: '#ffffff', texture: texturePath }
193
192
  }
194
- };
193
+ });
195
194
  }
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.70",
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
- }