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
@@ -19,6 +19,8 @@ declare class SoundManager {
19
19
  detune?: number;
20
20
  pitch?: number;
21
21
  }): void;
22
+ hasBuffer(path: string): boolean;
23
+ setBuffer(path: string, buffer: AudioBuffer): void;
22
24
  /** Load and play SFX - accepts file path directly */
23
25
  play(path: string, options?: {
24
26
  volume?: number;
@@ -68,6 +68,12 @@ class SoundManager {
68
68
  gain.connect(this.sfxGain);
69
69
  src.start();
70
70
  }
71
+ hasBuffer(path) {
72
+ return this.buffers.has(path);
73
+ }
74
+ setBuffer(path, buffer) {
75
+ this.buffers.set(path, buffer);
76
+ }
71
77
  /** Load and play SFX - accepts file path directly */
72
78
  play(path, options) {
73
79
  return __awaiter(this, void 0, void 0, function* () {
package/dist/index.d.ts CHANGED
@@ -4,26 +4,33 @@ export { ground } from './helpers';
4
4
  export type { GroundOptions, Vec3 } from './helpers';
5
5
  export { sound as soundManager } from './helpers/SoundManager';
6
6
  export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
7
+ export { PrefabEditorMode } from './tools/prefabeditor/PrefabEditor';
7
8
  export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
8
- export { useEditorContext } from './tools/prefabeditor/EditorContext';
9
- export type { EditorContextType } from './tools/prefabeditor/EditorContext';
10
- export { createPrefabStore, prefabStoreToPrefab } from './tools/prefabeditor/prefabStore';
9
+ export { useEditorContext } from './tools/prefabeditor/PrefabEditor';
10
+ export type { EditorContextType } from './tools/prefabeditor/PrefabEditor';
11
+ export { createPrefabStore, prefabStoreToPrefab, usePrefabStoreApi } from './tools/prefabeditor/prefabStore';
11
12
  export type { PrefabStoreApi, PrefabStoreState } from './tools/prefabeditor/prefabStore';
12
- export { createScene } from './tools/prefabeditor/sceneApi';
13
+ export { createScene } from './tools/prefabeditor/scene';
14
+ export { denormalizePrefab } from './tools/prefabeditor/prefab';
13
15
  export { registerComponent } from './tools/prefabeditor/components/ComponentRegistry';
14
- export { FieldRenderer, FieldGroup, Label, Vector3Input, Vector3Field, NumberField, ColorInput, ColorField, StringInput, StringField, BooleanInput, BooleanField, SelectInput, SelectField, } from './tools/prefabeditor/components/Input';
15
- export { loadJson, saveJson, exportGLB, exportGLBData, regenerateIds, computeParentWorldMatrix, createModelNode, createImageNode, } from './tools/prefabeditor/utils';
16
+ export { FieldRenderer, FieldGroup, ListEditor, Label, Vector3Input, Vector3Field, NumberField, ColorInput, ColorField, StringInput, StringField, BooleanInput, BooleanField, SelectInput, SelectField, } from './tools/prefabeditor/components/Input';
17
+ export { loadJson, saveJson, exportGLB, exportGLBData, regenerateIds, computeParentWorldMatrix, } from './tools/prefabeditor/utils';
16
18
  export type { ExportGLBOptions } from './tools/prefabeditor/utils';
19
+ export { createModelNode, createImageNode, } from './tools/prefabeditor/prefab';
17
20
  export type { PrefabEditorProps, PrefabEditorRef, } from './tools/prefabeditor/PrefabEditor';
18
- export type { SpawnOptions, Scene, Entity, EntityComponent, EntityData, EntityUpdate, PropertyPath, SceneUpdates, } from './tools/prefabeditor/sceneApi';
19
- export type { PrefabRootProps, PrefabRootRef } from './tools/prefabeditor/PrefabRoot';
20
- export type { Component } from './tools/prefabeditor/components/ComponentRegistry';
21
+ export type { SpawnOptions, Scene, Entity, EntityComponent, EntityData, EntityUpdate, PropertyPath, SceneUpdates, } from './tools/prefabeditor/scene';
22
+ export type { PrefabRootProps, PrefabRootRef, SceneRuntime } from './tools/prefabeditor/PrefabRoot';
23
+ export { useSceneRuntime } from './tools/prefabeditor/PrefabRoot';
24
+ export type { Component, ComponentViewProps } from './tools/prefabeditor/components/ComponentRegistry';
21
25
  export type { FieldDefinition, FieldType } from './tools/prefabeditor/components/Input';
22
- export type { Prefab, GameObject, ComponentData as ComponentDefinition } from './tools/prefabeditor/types';
26
+ export type { Prefab, GameObject, ComponentData } from './tools/prefabeditor/types';
27
+ export { findComponent, findComponentEntry, hasComponent } from './tools/prefabeditor/types';
23
28
  export { gameEvents, useGameEvent, getEntityIdFromRigidBody } from './tools/prefabeditor/GameEvents';
24
29
  export type { GameEventType, GameEventMap, GameEventPayload, PhysicsEventType, InteractionEventType, PhysicsEventPayload, ClickEventPayload } from './tools/prefabeditor/GameEvents';
30
+ export { createRefBridge } from './tools/prefabeditor/RefBridge';
31
+ export type { RefBridge } from './tools/prefabeditor/RefBridge';
25
32
  export { loadFiles } from './tools/dragdrop/DragDropLoader';
26
33
  export type { AssetLoadOptions } from './tools/dragdrop/DragDropLoader';
27
- export { loadModel, loadTexture } from './tools/dragdrop/modelLoader';
28
- export type { LoadedModel, LoadedTexture, LoadedModels, LoadedTextures, ModelLoadResult, ProgressCallback, TextureLoadResult } from './tools/dragdrop/modelLoader';
29
- export { TextureListViewer, ModelListViewer, SoundListViewer, TexturePicker, ModelPicker, SingleTextureViewer, SingleModelViewer, SingleSoundViewer, SharedCanvas, } from './tools/assetviewer/page';
34
+ export { loadModel, loadSound, loadTexture } from './tools/dragdrop/modelLoader';
35
+ export type { LoadedModel, LoadedModels, ModelLoadResult, LoadedSound, LoadedSounds, SoundLoadResult, LoadedTexture, LoadedTextures, TextureLoadResult, ProgressCallback, } from './tools/dragdrop/modelLoader';
36
+ export { ModelListViewer, SoundListViewer, ModelPicker, SoundPicker, TextureListViewer, TexturePicker, SingleModelViewer, SingleSoundViewer, SingleTextureViewer, SharedCanvas, } from './tools/assetviewer/page';
package/dist/index.js CHANGED
@@ -5,21 +5,28 @@ export { ground } from './helpers';
5
5
  export { sound as soundManager } from './helpers/SoundManager';
6
6
  // Prefab Editor
7
7
  export { default as PrefabEditor } from './tools/prefabeditor/PrefabEditor';
8
+ export { PrefabEditorMode } from './tools/prefabeditor/PrefabEditor';
8
9
  export { default as PrefabRoot } from './tools/prefabeditor/PrefabRoot';
9
- export { useEditorContext } from './tools/prefabeditor/EditorContext';
10
+ export { useEditorContext } from './tools/prefabeditor/PrefabEditor';
10
11
  // Prefab Editor - Store & Scene API
11
- export { createPrefabStore, prefabStoreToPrefab } from './tools/prefabeditor/prefabStore';
12
- export { createScene } from './tools/prefabeditor/sceneApi';
12
+ export { createPrefabStore, prefabStoreToPrefab, usePrefabStoreApi } from './tools/prefabeditor/prefabStore';
13
+ export { createScene } from './tools/prefabeditor/scene';
14
+ export { denormalizePrefab } from './tools/prefabeditor/prefab';
13
15
  // Prefab Editor - Component Registry
14
16
  export { registerComponent } from './tools/prefabeditor/components/ComponentRegistry';
15
17
  // Prefab Editor - Input Components
16
- export { FieldRenderer, FieldGroup, Label, Vector3Input, Vector3Field, NumberField, ColorInput, ColorField, StringInput, StringField, BooleanInput, BooleanField, SelectInput, SelectField, } from './tools/prefabeditor/components/Input';
18
+ export { FieldRenderer, FieldGroup, ListEditor, Label, Vector3Input, Vector3Field, NumberField, ColorInput, ColorField, StringInput, StringField, BooleanInput, BooleanField, SelectInput, SelectField, } from './tools/prefabeditor/components/Input';
17
19
  // Prefab Editor - Utils
18
- export { loadJson, saveJson, exportGLB, exportGLBData, regenerateIds, computeParentWorldMatrix, createModelNode, createImageNode, } from './tools/prefabeditor/utils';
20
+ export { loadJson, saveJson, exportGLB, exportGLBData, regenerateIds, computeParentWorldMatrix, } from './tools/prefabeditor/utils';
21
+ export { createModelNode, createImageNode, } from './tools/prefabeditor/prefab';
22
+ export { useSceneRuntime } from './tools/prefabeditor/PrefabRoot';
23
+ export { findComponent, findComponentEntry, hasComponent } from './tools/prefabeditor/types';
19
24
  // Game Events (physics + custom events)
20
25
  export { gameEvents, useGameEvent, getEntityIdFromRigidBody } from './tools/prefabeditor/GameEvents';
26
+ // RefBridge & Systems
27
+ export { createRefBridge } from './tools/prefabeditor/RefBridge';
21
28
  // Asset Loading
22
29
  export { loadFiles } from './tools/dragdrop/DragDropLoader';
23
- export { loadModel, loadTexture } from './tools/dragdrop/modelLoader';
30
+ export { loadModel, loadSound, loadTexture } from './tools/dragdrop/modelLoader';
24
31
  // Asset Viewer
25
- export { TextureListViewer, ModelListViewer, SoundListViewer, TexturePicker, ModelPicker, SingleTextureViewer, SingleModelViewer, SingleSoundViewer, SharedCanvas, } from './tools/assetviewer/page';
32
+ export { ModelListViewer, SoundListViewer, ModelPicker, SoundPicker, TextureListViewer, TexturePicker, SingleModelViewer, SingleSoundViewer, SingleTextureViewer, SharedCanvas, } from './tools/assetviewer/page';
@@ -23,8 +23,6 @@ import { Canvas, extend } from "@react-three/fiber";
23
23
  import { WebGPURenderer, MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial, PCFShadowMap } from "three/webgpu";
24
24
  import { Suspense, useState } from "react";
25
25
  import { Loader } from "@react-three/drei";
26
- // generic version
27
- // extend(THREE as any)
28
26
  extend({
29
27
  MeshBasicNodeMaterial: MeshBasicNodeMaterial,
30
28
  MeshStandardNodeMaterial: MeshStandardNodeMaterial,
@@ -30,6 +30,11 @@ export declare function ModelPicker({ value, onChange, basePath, pickerKey }: {
30
30
  basePath?: string;
31
31
  pickerKey?: string;
32
32
  }): import("react/jsx-runtime").JSX.Element;
33
+ export declare function SoundPicker({ value, onChange, basePath }: {
34
+ value: string | undefined;
35
+ onChange: (value: string | undefined) => void;
36
+ basePath?: string;
37
+ }): import("react/jsx-runtime").JSX.Element;
33
38
  export declare function SingleTextureViewer({ file, basePath }: {
34
39
  file?: string;
35
40
  basePath?: string;
@@ -209,6 +209,9 @@ export function TexturePicker({ value, onChange, basePath = "" }) {
209
209
  export function ModelPicker({ value, onChange, basePath = "", pickerKey }) {
210
210
  return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "models", rootStyle: { maxHeight: 160, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle: { width: '100%', padding: '6px 8px', backgroundColor: '#1f2937', color: 'inherit', fontSize: 10, cursor: 'pointer', border: '1px solid rgba(34, 211, 238, 0.3)' }, clearButtonStyle: { width: '100%', padding: '6px 8px', backgroundColor: '#1f2937', color: 'inherit', fontSize: 10, cursor: 'pointer', border: '1px solid rgba(34, 211, 238, 0.3)' }, popupStyle: { background: 'rgba(0,0,0,0.9)', border: '1px solid rgba(34, 211, 238, 0.3)' }, preview: _jsx("div", { style: { flex: '0 0 auto' }, children: _jsx(SingleModelViewer, { file: value ? `/${value}` : undefined, basePath: basePath }) }), renderList: ({ files, value: selectedValue, onSelect, basePath: currentBasePath }) => (_jsx(ModelListViewer, { files: files, selected: selectedValue ? `/${selectedValue}` : undefined, onSelect: (file) => onSelect(file.startsWith('/') ? file.slice(1) : file), basePath: currentBasePath }, pickerKey)) }));
211
211
  }
212
+ export function SoundPicker({ value, onChange, basePath = "" }) {
213
+ return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "sound", rootStyle: { maxHeight: 76, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle: { width: '100%', padding: '6px 8px', backgroundColor: '#1f2937', color: 'inherit', fontSize: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.12)', borderRadius: 3 }, clearButtonStyle: { width: '100%', padding: '6px 8px', backgroundColor: '#1f2937', color: 'inherit', fontSize: 10, cursor: 'pointer', border: '1px solid rgba(255,255,255,0.12)', borderRadius: 3 }, preview: _jsx("div", { style: { flex: '0 0 auto', minWidth: 84 }, children: value ? _jsx(SingleSoundViewer, { file: value, basePath: basePath }) : _jsx("div", { style: { width: 84, height: 60, backgroundColor: '#1f2937', border: '1px dashed rgba(255,255,255,0.12)', borderRadius: 4 } }) }), renderList: ({ files, value: selectedValue, onSelect, basePath: currentBasePath }) => (_jsx(SoundListViewer, { files: files, selected: selectedValue || undefined, onSelect: onSelect, basePath: currentBasePath })) }));
214
+ }
212
215
  // Single Asset Viewer Components - display only one selected asset
213
216
  export function SingleTextureViewer({ file, basePath = "" }) {
214
217
  if (!file)
@@ -1,8 +1,9 @@
1
1
  import type { HTMLAttributes, ReactNode } from "react";
2
- import type { LoadedModel, LoadedTexture } from "./modelLoader";
2
+ import type { LoadedModel, LoadedSound, LoadedTexture } from "./modelLoader";
3
3
  export interface AssetLoadOptions {
4
4
  onModelLoaded?: (model: LoadedModel, filename: string, file: File) => void | Promise<void>;
5
5
  onTextureLoaded?: (texture: LoadedTexture, filename: string, file: File) => void | Promise<void>;
6
+ onSoundLoaded?: (sound: LoadedSound, filename: string, file: File) => void | Promise<void>;
6
7
  onUnhandledFile?: (file: File) => void | Promise<void>;
7
8
  onFilesLoaded?: (files: File[]) => void | Promise<void>;
8
9
  onLoadError?: (error: unknown, filename: string, file: File) => void | Promise<void>;
@@ -16,7 +17,7 @@ export interface FilePickerProps extends AssetLoadOptions, DivProps {
16
17
  children?: ReactNode;
17
18
  multiple?: boolean;
18
19
  }
19
- export declare function loadFiles(files: File[], { onModelLoaded, onTextureLoaded, onUnhandledFile, onFilesLoaded, onLoadError }: AssetLoadOptions): Promise<void>;
20
+ export declare function loadFiles(files: File[], { onModelLoaded, onTextureLoaded, onSoundLoaded, onUnhandledFile, onFilesLoaded, onLoadError }: AssetLoadOptions): Promise<void>;
20
21
  export declare function DragDropLoader({ children, ...divProps }: DragDropLoaderProps): import("react/jsx-runtime").JSX.Element;
21
22
  export declare function FilePicker({ accept, children, multiple, ...divProps }: FilePickerProps): import("react/jsx-runtime").JSX.Element;
22
23
  export {};
@@ -20,16 +20,17 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  };
21
21
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
22
  import { useRef } from "react";
23
- import { canParseModelFile, canParseTextureFile, parseModelFromFile, parseTextureFromFile } from "./modelLoader";
24
- const DEFAULT_ACCEPT = ".glb,.gltf,.fbx,.png,.jpg,.jpeg,.webp,.gif,.bmp,.svg";
23
+ import { canParseModelFile, canParseSoundFile, canParseTextureFile, parseModelFromFile, parseSoundFromFile, parseTextureFromFile } from "./modelLoader";
24
+ const DEFAULT_ACCEPT = ".glb,.gltf,.fbx,.png,.jpg,.jpeg,.webp,.gif,.bmp,.svg,.mp3,.wav,.ogg,.m4a";
25
25
  function getFiles(fileList) {
26
26
  return fileList ? Array.from(fileList) : [];
27
27
  }
28
28
  export function loadFiles(files_1, _a) {
29
- return __awaiter(this, arguments, void 0, function* (files, { onModelLoaded, onTextureLoaded, onUnhandledFile, onFilesLoaded, onLoadError }) {
29
+ return __awaiter(this, arguments, void 0, function* (files, { onModelLoaded, onTextureLoaded, onSoundLoaded, onUnhandledFile, onFilesLoaded, onLoadError }) {
30
30
  yield Promise.all(files.map((file) => __awaiter(this, void 0, void 0, function* () {
31
31
  const shouldParseModel = canParseModelFile(file);
32
32
  const shouldParseTexture = canParseTextureFile(file);
33
+ const shouldParseSound = canParseSoundFile(file);
33
34
  if (shouldParseModel) {
34
35
  const result = yield parseModelFromFile(file);
35
36
  if (result.success && result.model) {
@@ -56,6 +57,19 @@ export function loadFiles(files_1, _a) {
56
57
  console.error("Texture parse error:", result.error);
57
58
  return;
58
59
  }
60
+ if (shouldParseSound) {
61
+ const result = yield parseSoundFromFile(file);
62
+ if (result.success && result.sound) {
63
+ yield (onSoundLoaded === null || onSoundLoaded === void 0 ? void 0 : onSoundLoaded(result.sound, file.name, file));
64
+ return;
65
+ }
66
+ if (onLoadError) {
67
+ yield onLoadError(result.error, file.name, file);
68
+ return;
69
+ }
70
+ console.error("Sound parse error:", result.error);
71
+ return;
72
+ }
59
73
  if (onUnhandledFile) {
60
74
  yield onUnhandledFile(file);
61
75
  }
@@ -70,6 +84,7 @@ function createLoadHandlers(options) {
70
84
  return {
71
85
  onFilesLoaded: options.onFilesLoaded,
72
86
  onModelLoaded: options.onModelLoaded,
87
+ onSoundLoaded: options.onSoundLoaded,
73
88
  onTextureLoaded: options.onTextureLoaded,
74
89
  onUnhandledFile: options.onUnhandledFile,
75
90
  onLoadError: options.onLoadError,
@@ -1,4 +1,4 @@
1
1
  export { DragDropLoader, FilePicker, loadFiles } from "./DragDropLoader";
2
2
  export type { AssetLoadOptions, DragDropLoaderProps, FilePickerProps } from "./DragDropLoader";
3
- export { loadModel, loadTexture, parseModelFromFile, parseTextureFromFile } from "./modelLoader";
4
- export type { LoadedModel, LoadedTexture, LoadedModels, LoadedTextures, ModelLoadResult, ProgressCallback, TextureLoadResult } from "./modelLoader";
3
+ export { loadModel, loadSound, loadTexture, parseModelFromFile, parseSoundFromFile, parseTextureFromFile } from "./modelLoader";
4
+ export type { LoadedModel, LoadedSound, LoadedTexture, LoadedModels, LoadedSounds, LoadedTextures, ModelLoadResult, ProgressCallback, SoundLoadResult, TextureLoadResult } from "./modelLoader";
@@ -1,2 +1,2 @@
1
1
  export { DragDropLoader, FilePicker, loadFiles } from "./DragDropLoader";
2
- export { loadModel, loadTexture, parseModelFromFile, parseTextureFromFile } from "./modelLoader";
2
+ export { loadModel, loadSound, loadTexture, parseModelFromFile, parseSoundFromFile, parseTextureFromFile } from "./modelLoader";
@@ -1,8 +1,10 @@
1
1
  import type { Object3D, Texture } from "three";
2
2
  export type LoadedModel = Object3D;
3
3
  export type LoadedTexture = Texture;
4
+ export type LoadedSound = AudioBuffer;
4
5
  export type LoadedModels = Record<string, LoadedModel>;
5
6
  export type LoadedTextures = Record<string, LoadedTexture>;
7
+ export type LoadedSounds = Record<string, LoadedSound>;
6
8
  export type ModelLoadResult = {
7
9
  success: boolean;
8
10
  model?: LoadedModel;
@@ -13,10 +15,18 @@ export type TextureLoadResult = {
13
15
  texture?: LoadedTexture;
14
16
  error?: unknown;
15
17
  };
18
+ export type SoundLoadResult = {
19
+ success: boolean;
20
+ sound?: LoadedSound;
21
+ error?: unknown;
22
+ };
16
23
  export type ProgressCallback = (filename: string, loaded: number, total: number) => void;
17
24
  export declare function canParseModelFile(file: File | string): boolean;
18
25
  export declare function canParseTextureFile(file: File | string): boolean;
26
+ export declare function canParseSoundFile(file: File | string): boolean;
19
27
  export declare function parseModelFromFile(file: File): Promise<ModelLoadResult>;
20
28
  export declare function parseTextureFromFile(file: File): Promise<TextureLoadResult>;
29
+ export declare function parseSoundFromFile(file: File): Promise<SoundLoadResult>;
21
30
  export declare function loadModel(filename: string, onProgress?: ProgressCallback): Promise<ModelLoadResult>;
22
31
  export declare function loadTexture(filename: string): Promise<TextureLoadResult>;
32
+ export declare function loadSound(filename: string): Promise<SoundLoadResult>;
@@ -16,6 +16,21 @@ gltfLoader.setDRACOLoader(dracoLoader);
16
16
  const fbxLoader = new FBXLoader();
17
17
  const textureLoader = new TextureLoader();
18
18
  const TEXTURE_FILE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".webp", ".gif", ".bmp", ".svg"];
19
+ const SOUND_FILE_EXTENSIONS = [".mp3", ".wav", ".ogg", ".m4a"];
20
+ let decodeAudioContext = null;
21
+ function getAudioContext() {
22
+ if (typeof window === 'undefined') {
23
+ throw new Error('Audio loading is only supported in the browser');
24
+ }
25
+ if (!decodeAudioContext) {
26
+ const AudioCtx = window.AudioContext || window.webkitAudioContext;
27
+ if (!AudioCtx) {
28
+ throw new Error('Web Audio API is not available in this browser');
29
+ }
30
+ decodeAudioContext = new AudioCtx();
31
+ }
32
+ return decodeAudioContext;
33
+ }
19
34
  function normalizeModelPath(name) {
20
35
  return name.split(/[?#]/, 1)[0].toLowerCase();
21
36
  }
@@ -38,6 +53,11 @@ export function canParseTextureFile(file) {
38
53
  const normalizedName = normalizeModelPath(filename);
39
54
  return TEXTURE_FILE_EXTENSIONS.some(extension => normalizedName.endsWith(extension));
40
55
  }
56
+ export function canParseSoundFile(file) {
57
+ const filename = typeof file === "string" ? file : file.name;
58
+ const normalizedName = normalizeModelPath(filename);
59
+ return SOUND_FILE_EXTENSIONS.some(extension => normalizedName.endsWith(extension));
60
+ }
41
61
  function parseModelBuffer(arrayBuffer, sourceName) {
42
62
  const modelFileKind = getModelFileKind(sourceName);
43
63
  if (modelFileKind === "gltf") {
@@ -89,6 +109,29 @@ export function parseTextureFromFile(file) {
89
109
  });
90
110
  });
91
111
  }
112
+ export function parseSoundFromFile(file) {
113
+ return new Promise(resolve => {
114
+ const reader = new FileReader();
115
+ reader.onload = (event) => __awaiter(this, void 0, void 0, function* () {
116
+ var _a;
117
+ const arrayBuffer = (_a = event.target) === null || _a === void 0 ? void 0 : _a.result;
118
+ if (!arrayBuffer) {
119
+ resolve({ success: false, error: new Error('Failed to read file') });
120
+ return;
121
+ }
122
+ try {
123
+ const context = getAudioContext();
124
+ const sound = yield context.decodeAudioData(arrayBuffer.slice(0));
125
+ resolve({ success: true, sound });
126
+ }
127
+ catch (error) {
128
+ resolve({ success: false, error });
129
+ }
130
+ });
131
+ reader.onerror = () => resolve({ success: false, error: reader.error });
132
+ reader.readAsArrayBuffer(file);
133
+ });
134
+ }
92
135
  export function loadModel(filename, onProgress) {
93
136
  return __awaiter(this, void 0, void 0, function* () {
94
137
  try {
@@ -141,3 +184,20 @@ export function loadTexture(filename) {
141
184
  }
142
185
  });
143
186
  }
187
+ export function loadSound(filename) {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ try {
190
+ if (!canParseSoundFile(filename)) {
191
+ return { success: false, error: new Error(`Unsupported file format: ${filename}`) };
192
+ }
193
+ const response = yield fetch(filename);
194
+ const arrayBuffer = yield response.arrayBuffer();
195
+ const context = getAudioContext();
196
+ const sound = yield context.decodeAudioData(arrayBuffer.slice(0));
197
+ return { success: true, sound };
198
+ }
199
+ catch (error) {
200
+ return { success: false, error };
201
+ }
202
+ });
203
+ }
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { memo, useCallback, useState } from 'react';
3
- import { getComponent } from './components/ComponentRegistry';
4
3
  import { base, colors, tree } from './styles';
5
- import { useEditorContext } from './EditorContext';
4
+ import { useEditorContext } from './PrefabEditor';
6
5
  import { Dropdown } from './Dropdown';
7
6
  import { FileMenu, TreeContextMenu, TreeNodeMenu } from './EditorTreeMenus';
7
+ import { createEmptyNode } from './prefab';
8
8
  import { usePrefabChildIds, usePrefabNode, usePrefabRootId, usePrefabStore, usePrefabStoreApi } from './prefabStore';
9
9
  export default function EditorTree({ selectedId, setSelectedId, getPrefab, onReplacePrefab, onImportPrefab, onUndo, onRedo, canUndo, canRedo }) {
10
10
  const { onFocusNode } = useEditorContext();
@@ -30,17 +30,7 @@ export default function EditorTree({ selectedId, setSelectedId, getPrefab, onRep
30
30
  });
31
31
  };
32
32
  const handleAddChild = (parentId) => {
33
- var _a;
34
- const newNode = {
35
- id: crypto.randomUUID(),
36
- name: "New Node",
37
- components: {
38
- transform: {
39
- type: "Transform",
40
- properties: Object.assign({}, (_a = getComponent('Transform')) === null || _a === void 0 ? void 0 : _a.defaultProperties)
41
- }
42
- }
43
- };
33
+ const newNode = createEmptyNode();
44
34
  addChild(parentId, newNode);
45
35
  setSelectedId(newNode.id);
46
36
  };
@@ -142,37 +132,13 @@ const TreeNode = memo(function TreeNode({ nodeId, depth, rootId, visibleIds, col
142
132
  marginRight: 4,
143
133
  cursor: 'pointer',
144
134
  visibility: hasChildren ? 'visible' : 'hidden'
145
- }, onClick: (e) => hasChildren && onToggleCollapse(e, nodeId), children: isCollapsed ? '▶' : '▼' }), !isRoot && _jsx("span", { style: { marginRight: 4, opacity: 0.4 }, children: "\u22EE\u22EE" }), _jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis' }, children: (_a = node.name) !== null && _a !== void 0 ? _a : node.id }), node.locked && _jsx("span", { style: { marginLeft: 6, opacity: 0.6 }, children: "\uD83D\uDD12" })] }), !isRoot && (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Dropdown, { placement: "bottom-end", trigger: ({ ref, toggle }) => (_jsx("button", { ref: ref, title: "Node Actions", style: {
146
- background: 'none',
147
- border: 'none',
148
- cursor: 'pointer',
149
- padding: '0 4px',
150
- fontSize: 14,
151
- opacity: 0.7,
152
- color: 'inherit',
153
- }, onClick: (e) => {
135
+ }, onClick: (e) => hasChildren && onToggleCollapse(e, nodeId), children: isCollapsed ? '▶' : '▼' }), !isRoot && _jsx("span", { style: { marginRight: 4, opacity: 0.4 }, children: "\u22EE\u22EE" }), _jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis' }, children: (_a = node.name) !== null && _a !== void 0 ? _a : node.id }), node.locked && _jsx("span", { style: { marginLeft: 6, opacity: 0.6 }, children: "\uD83D\uDD12" })] }), !isRoot && (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Dropdown, { placement: "bottom-end", trigger: ({ ref, toggle }) => (_jsx("button", { ref: ref, title: "Node Actions", style: tree.iconButton, onClick: (e) => {
154
136
  e.stopPropagation();
155
137
  toggle();
156
- }, children: "\u22EF" })), children: (close) => renderTreeNodeMenu(nodeId, false, close) }), _jsx("button", { style: {
157
- background: 'none',
158
- border: 'none',
159
- cursor: 'pointer',
160
- padding: '0 4px',
161
- fontSize: 14,
162
- opacity: node.disabled ? 0.5 : 0.7,
163
- color: 'inherit',
164
- }, onClick: (e) => {
138
+ }, children: "\u22EF" })), children: (close) => renderTreeNodeMenu(nodeId, false, close) }), _jsx("button", { style: Object.assign(Object.assign({}, tree.iconButton), { opacity: node.disabled ? 0.5 : 0.7 }), onClick: (e) => {
165
139
  e.stopPropagation();
166
140
  onToggleDisabled(nodeId);
167
- }, title: node.disabled ? 'Enable' : 'Disable', children: node.disabled ? '◎' : '◉' })] })), isRoot && (_jsx(Dropdown, { placement: "bottom-end", trigger: ({ ref, toggle }) => (_jsx("button", { ref: ref, title: "Scene Actions", style: {
168
- background: 'none',
169
- border: 'none',
170
- cursor: 'pointer',
171
- padding: '0 4px',
172
- fontSize: 14,
173
- opacity: 0.7,
174
- color: 'inherit',
175
- }, onClick: (e) => {
141
+ }, title: node.disabled ? 'Enable' : 'Disable', children: node.disabled ? '◎' : '◉' })] })), isRoot && (_jsx(Dropdown, { placement: "bottom-end", trigger: ({ ref, toggle }) => (_jsx("button", { ref: ref, title: "Scene Actions", style: tree.iconButton, onClick: (e) => {
176
142
  e.stopPropagation();
177
143
  toggle();
178
144
  }, children: "\u22EF" })), children: (close) => renderTreeNodeMenu(nodeId, true, close) }))] }), !isCollapsed && childIds.map(childId => (_jsx(TreeNode, { nodeId: childId, depth: depth + 1, rootId: rootId, visibleIds: visibleIds, collapsedIds: collapsedIds, dropTarget: dropTarget, selectedNodeId: selectedNodeId, onToggleCollapse: onToggleCollapse, onOpenContextMenu: onOpenContextMenu, onDragStart: onDragStart, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop, onDragEnd: onDragEnd, renderTreeNodeMenu: renderTreeNodeMenu, onToggleDisabled: onToggleDisabled, setSelectedId: setSelectedId }, childId)))] }));
@@ -10,28 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { useEffect, useRef, useState } from 'react';
12
12
  import { createPortal } from 'react-dom';
13
+ import { createEmptyPrefab } from './prefab';
13
14
  import { menu } from './styles';
14
- import { useEditorContext } from './EditorContext';
15
- import { getComponent } from './components/ComponentRegistry';
15
+ import { useEditorContext } from './PrefabEditor';
16
16
  import { loadJson, saveJson } from './utils';
17
- function createEmptyPrefab() {
18
- var _a;
19
- return {
20
- id: crypto.randomUUID(),
21
- name: 'New Prefab',
22
- root: {
23
- id: crypto.randomUUID(),
24
- name: 'Root',
25
- components: {
26
- transform: {
27
- type: 'Transform',
28
- properties: Object.assign({}, (_a = getComponent('Transform')) === null || _a === void 0 ? void 0 : _a.defaultProperties)
29
- }
30
- },
31
- children: []
32
- }
33
- };
34
- }
35
17
  function MenuPanel({ children, style, }) {
36
18
  return (_jsx("div", { style: Object.assign(Object.assign(Object.assign({}, menu.container), { position: 'static' }), style), onClick: (e) => e.stopPropagation(), children: children }));
37
19
  }
@@ -11,8 +11,10 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
13
  import { useState } from 'react';
14
+ import { hasComponent } from "./types";
14
15
  import EditorTree from './EditorTree';
15
- import { getAllComponents } from './components/ComponentRegistry';
16
+ import { getAllComponentDefs } from './components/ComponentRegistry';
17
+ import { createComponentData } from './prefab';
16
18
  import { base, colors, inspector, componentCard } from './styles';
17
19
  import { usePrefabStore } from './prefabStore';
18
20
  function EditorUI({ selectedId, setSelectedId, getPrefab, onReplacePrefab, onImportPrefab, basePath, onUndo, onRedo, canUndo, canRedo }) {
@@ -36,9 +38,9 @@ function EditorUI({ selectedId, setSelectedId, getPrefab, onReplacePrefab, onImp
36
38
  }
37
39
  function NodeInspector({ node, updateNode, deleteNode, basePath }) {
38
40
  var _a;
39
- const ALL_COMPONENTS = getAllComponents();
41
+ const ALL_COMPONENTS = getAllComponentDefs();
40
42
  const allKeys = Object.keys(ALL_COMPONENTS);
41
- const available = allKeys.filter(k => { var _a; return !((_a = node.components) === null || _a === void 0 ? void 0 : _a[k.toLowerCase()]); });
43
+ const available = allKeys.filter(k => !hasComponent(node, k));
42
44
  const [preferredAddType, setAddType] = useState(available[0] || "");
43
45
  const addType = available.includes(preferredAddType) ? preferredAddType : (available[0] || "");
44
46
  return _jsxs("div", { style: inspector.content, children: [_jsxs("div", { style: base.section, children: [_jsxs("div", { style: { display: "flex", marginBottom: 8, alignItems: 'center', gap: 8 }, children: [_jsx("div", { style: { fontSize: 10, color: colors.textDim, wordBreak: 'break-all', border: `1px solid ${colors.border}`, padding: '2px 6px', borderRadius: 3, flex: 1, fontFamily: 'monospace' }, children: node.id }), _jsx("button", { style: Object.assign(Object.assign({}, base.btn), base.btnDanger), title: "Delete Node", onClick: deleteNode, children: "\u274C" })] }), _jsx("input", { style: base.input, value: (_a = node.name) !== null && _a !== void 0 ? _a : "", placeholder: 'Node name', onChange: e => updateNode(n => (Object.assign(Object.assign({}, n), { name: e.target.value }))) })] }), _jsxs("div", { style: base.section, children: [_jsx("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }, children: _jsx("div", { style: base.label, children: "Components" }) }), node.components && Object.entries(node.components).map(([key, comp]) => {
@@ -48,7 +50,8 @@ function NodeInspector({ node, updateNode, deleteNode, basePath }) {
48
50
  if (!def)
49
51
  return _jsxs("div", { style: { color: colors.danger, fontSize: 11 }, children: ["Unknown: ", comp.type] }, key);
50
52
  return (_jsxs("div", { style: componentCard.container, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }, children: [_jsx("div", { style: { fontSize: 11, fontWeight: 500 }, children: key }), _jsx("button", { style: Object.assign(Object.assign({}, base.btn), { padding: '2px 6px' }), title: "Remove Component", onClick: () => updateNode(n => {
51
- const _a = n.components || {}, _b = key, _ = _a[_b], rest = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
53
+ var _a;
54
+ const _b = (_a = n.components) !== null && _a !== void 0 ? _a : {}, _c = key, _ = _b[_c], rest = __rest(_b, [typeof _c === "symbol" ? _c : _c + ""]);
52
55
  return Object.assign(Object.assign({}, n), { components: rest });
53
56
  }), children: "\u2715" })] }), def.Editor && (_jsx(def.Editor, { component: comp, node: node, onUpdate: (newProps) => updateNode(n => (Object.assign(Object.assign({}, n), { components: Object.assign(Object.assign({}, n.components), { [key]: Object.assign(Object.assign({}, comp), { properties: Object.assign(Object.assign({}, comp.properties), newProps) }) }) }))), basePath: basePath }))] }, key));
54
57
  })] }), available.length > 0 && (_jsx("div", { children: _jsxs("div", { style: base.row, children: [_jsx("select", { style: Object.assign(Object.assign({}, base.input), { flex: 1 }), value: addType, onChange: e => setAddType(e.target.value), children: available.map(k => _jsx("option", { value: k, children: k }, k)) }), _jsx("button", { style: base.btn, disabled: !addType, onClick: () => {
@@ -56,7 +59,7 @@ function NodeInspector({ node, updateNode, deleteNode, basePath }) {
56
59
  return;
57
60
  const def = ALL_COMPONENTS[addType];
58
61
  if (def) {
59
- updateNode(n => (Object.assign(Object.assign({}, n), { components: Object.assign(Object.assign({}, n.components), { [addType.toLowerCase()]: { type: def.name, properties: def.defaultProperties } }) })));
62
+ updateNode(n => (Object.assign(Object.assign({}, n), { components: Object.assign(Object.assign({}, n.components), { [addType.toLowerCase()]: createComponentData(def.name) }) })));
60
63
  }
61
64
  }, title: "Add Component", children: "+" })] }) }))] });
62
65
  }
@@ -13,6 +13,7 @@ export type InstanceData = {
13
13
  id: string;
14
14
  sourceId: string;
15
15
  clickable?: boolean;
16
+ clickEventName?: string;
16
17
  locked?: boolean;
17
18
  position: [number, number, number];
18
19
  rotation: [number, number, number];
@@ -35,6 +36,7 @@ export declare const GameInstance: React.ForwardRefExoticComponent<{
35
36
  id: string;
36
37
  sourceId?: string;
37
38
  clickable?: boolean;
39
+ clickEventName?: string;
38
40
  modelUrl: string;
39
41
  locked?: boolean;
40
42
  position: [number, number, number];