react-three-game 0.0.70 → 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 (36) hide show
  1. package/dist/index.d.ts +10 -5
  2. package/dist/index.js +7 -2
  3. package/dist/tools/prefabeditor/EditorTree.js +2 -12
  4. package/dist/tools/prefabeditor/EditorTreeMenus.js +1 -19
  5. package/dist/tools/prefabeditor/EditorUI.js +2 -1
  6. package/dist/tools/prefabeditor/PrefabEditor.d.ts +1 -1
  7. package/dist/tools/prefabeditor/PrefabEditor.js +12 -21
  8. package/dist/tools/prefabeditor/PrefabRoot.d.ts +25 -12
  9. package/dist/tools/prefabeditor/PrefabRoot.js +61 -28
  10. package/dist/tools/prefabeditor/RefBridge.d.ts +24 -0
  11. package/dist/tools/prefabeditor/RefBridge.js +44 -0
  12. package/dist/tools/prefabeditor/components/AmbientLightComponent.js +10 -7
  13. package/dist/tools/prefabeditor/components/CameraComponent.js +8 -14
  14. package/dist/tools/prefabeditor/components/ClickComponent.js +2 -0
  15. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +21 -1
  16. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +124 -52
  17. package/dist/tools/prefabeditor/components/EnvironmentComponent.js +5 -3
  18. package/dist/tools/prefabeditor/components/MaterialComponent.js +9 -6
  19. package/dist/tools/prefabeditor/components/ModelComponent.js +4 -2
  20. package/dist/tools/prefabeditor/components/PhysicsComponent.js +5 -3
  21. package/dist/tools/prefabeditor/components/PointLightComponent.d.ts +3 -0
  22. package/dist/tools/prefabeditor/components/PointLightComponent.js +55 -0
  23. package/dist/tools/prefabeditor/components/SoundComponent.js +20 -16
  24. package/dist/tools/prefabeditor/components/SpotLightComponent.js +48 -24
  25. package/dist/tools/prefabeditor/components/index.js +2 -0
  26. package/dist/tools/prefabeditor/components/lightUtils.d.ts +13 -0
  27. package/dist/tools/prefabeditor/components/lightUtils.js +64 -0
  28. package/dist/tools/prefabeditor/prefab.d.ts +37 -0
  29. package/dist/tools/prefabeditor/prefab.js +229 -0
  30. package/dist/tools/prefabeditor/prefabStore.d.ts +3 -16
  31. package/dist/tools/prefabeditor/prefabStore.js +29 -168
  32. package/dist/tools/prefabeditor/{sceneApi.js → scene.js} +3 -14
  33. package/dist/tools/prefabeditor/utils.d.ts +0 -4
  34. package/dist/tools/prefabeditor/utils.js +0 -37
  35. package/package.json +1 -1
  36. /package/dist/tools/prefabeditor/{sceneApi.d.ts → scene.d.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { PerspectiveCamera } from '@react-three/drei';
3
- import { useEffect, useMemo, useState } from 'react';
2
+ import { PerspectiveCamera, useHelper } from '@react-three/drei';
3
+ import { useRef } from 'react';
4
4
  import { CameraHelper } from 'three';
5
5
  import { useFrame } from '@react-three/fiber';
6
6
  import { FieldGroup, NumberField } from './Input';
@@ -20,21 +20,15 @@ function CameraComponentView({ properties, children, editMode, isSelected }) {
20
20
  const near = merged.near;
21
21
  const zoom = merged.zoom;
22
22
  const far = merged.far;
23
- const [camera, setCamera] = useState(null);
24
- const cameraHelper = useMemo(() => camera ? new CameraHelper(camera) : null, [camera]);
25
- useEffect(() => {
26
- return () => {
27
- cameraHelper === null || cameraHelper === void 0 ? void 0 : cameraHelper.dispose();
28
- };
29
- }, [cameraHelper]);
23
+ const cameraRef = useRef(null);
24
+ useHelper(editMode && isSelected ? cameraRef : null, CameraHelper);
30
25
  useFrame(() => {
31
- if (camera && cameraHelper && editMode && isSelected) {
32
- camera.updateProjectionMatrix();
33
- camera.updateMatrixWorld();
34
- cameraHelper.update();
26
+ if (cameraRef.current && editMode && isSelected) {
27
+ cameraRef.current.updateProjectionMatrix();
28
+ cameraRef.current.updateMatrixWorld();
35
29
  }
36
30
  });
37
- return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: (instance) => setCamera(instance), makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode && isSelected && cameraHelper && (_jsx("primitive", { object: cameraHelper })), editMode ? (_jsxs("group", { children: [_jsxs("mesh", { children: [_jsx("boxGeometry", { args: [0.3, 0.3, 0.5] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] }), _jsxs("mesh", { position: [0, 0, -0.25], rotation: [Math.PI / 2, 0, 0], children: [_jsx("coneGeometry", { args: [0.08, 0.16, 16] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] })] })) : null, children] }));
31
+ return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { ref: cameraRef, makeDefault: !editMode, fov: fov, near: near, zoom: zoom, far: far }), editMode ? (_jsxs("group", { children: [_jsxs("mesh", { children: [_jsx("boxGeometry", { args: [0.3, 0.3, 0.5] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] }), _jsxs("mesh", { position: [0, 0, -0.25], rotation: [Math.PI / 2, 0, 0], children: [_jsx("coneGeometry", { args: [0.08, 0.16, 16] }), _jsx("meshBasicMaterial", { color: '#22d3ee', wireframe: true })] })] })) : null, children] }));
38
32
  }
39
33
  const CameraComponent = {
40
34
  name: 'Camera',
@@ -27,6 +27,8 @@ function ClickComponentView({ children, editMode, nodeId, properties }) {
27
27
  return (_jsx("group", { onPointerDown: (event) => {
28
28
  event.stopPropagation();
29
29
  clickValid.current = true;
30
+ }, onClick: (event) => {
31
+ event.stopPropagation();
30
32
  }, onPointerMove: () => {
31
33
  clickValid.current = false;
32
34
  }, onPointerUp: (event) => {
@@ -4,6 +4,25 @@ export type AssetRef = {
4
4
  type: "model" | "texture" | "sound";
5
5
  path: string;
6
6
  };
7
+ /** Props every component View receives from the renderer. */
8
+ export interface ComponentViewProps<P = Record<string, any>> {
9
+ /** This component's own data from the prefab JSON. */
10
+ properties: P;
11
+ /** Children to render (for wrapper / child-host components). */
12
+ children?: React.ReactNode;
13
+ /** The entity ID this component belongs to. */
14
+ nodeId?: string;
15
+ /** True when the editor is in edit mode. */
16
+ editMode?: boolean;
17
+ /** True when this entity is selected in the editor. */
18
+ isSelected?: boolean;
19
+ /** Entity local position (passed to wrapper components like Physics). */
20
+ position?: [number, number, number];
21
+ /** Entity local rotation in radians (passed to wrapper components like Physics). */
22
+ rotation?: [number, number, number];
23
+ /** Entity local scale (passed to wrapper components like Physics). */
24
+ scale?: [number, number, number];
25
+ }
7
26
  export interface Component {
8
27
  name: string;
9
28
  Editor: FC<{
@@ -13,9 +32,10 @@ export interface Component {
13
32
  basePath?: string;
14
33
  }>;
15
34
  defaultProperties: any;
16
- View?: FC<any>;
35
+ View?: FC<ComponentViewProps>;
17
36
  /** When true, this component wraps child entities (e.g. Physics wraps children in RigidBody). */
18
37
  isWrapper?: boolean;
38
+ /** Declare which asset paths this component references (for asset loading). */
19
39
  getAssetRefs?: (properties: Record<string, any>) => AssetRef[];
20
40
  }
21
41
  export declare function registerComponent(component: Component): void;
@@ -1,59 +1,114 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useRef, useEffect, useMemo, useState } from "react";
2
+ import { useHelper } from "@react-three/drei";
3
+ import { useRef, useEffect, useState } from "react";
3
4
  import { useFrame } from "@react-three/fiber";
4
5
  import { CameraHelper, Vector3 } from "three";
5
- import { FieldRenderer, NumberInput } from "./Input";
6
- const smallLabel = { display: 'block', fontSize: '8px', color: 'rgba(34, 211, 238, 0.5)', marginBottom: 2 };
6
+ import { BooleanField, ColorField, NumberField, NumberInput, Vector3Input } from "./Input";
7
+ import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
8
+ import { colors } from "../styles";
7
9
  const directionalLightDefaults = {
8
10
  color: '#ffffff',
9
11
  intensity: 1,
10
- castShadow: true,
11
- shadowMapSize: 1024,
12
- shadowCameraNear: 0.1,
13
- shadowCameraFar: 100,
14
- shadowCameraTop: 30,
15
- shadowCameraBottom: -30,
16
- shadowCameraLeft: -30,
17
- shadowCameraRight: 30,
12
+ castShadow: false,
13
+ shadowMapSize: 512,
14
+ shadowBias: 0,
15
+ shadowNormalBias: 0,
16
+ shadowAutoUpdate: true,
17
+ shadowCameraNear: 0.5,
18
+ shadowCameraFar: 500,
19
+ shadowCameraTop: 5,
20
+ shadowCameraBottom: -5,
21
+ shadowCameraLeft: -5,
22
+ shadowCameraRight: 5,
18
23
  targetOffset: [0, -5, 0],
19
24
  };
20
- const directionalLightFields = [
21
- { name: 'color', type: 'color', label: 'Color' },
22
- { name: 'intensity', type: 'number', label: 'Intensity', step: 0.1, min: 0 },
23
- { name: 'castShadow', type: 'boolean', label: 'Cast Shadow' },
24
- { name: 'shadowMapSize', type: 'number', label: 'Shadow Map Size', step: 256, min: 256 },
25
- {
26
- name: '_shadowCamera',
27
- type: 'custom',
28
- label: 'Shadow Camera',
29
- render: ({ values, onChangeMultiple }) => {
30
- var _a, _b, _c, _d, _e, _f;
31
- return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Near" }), _jsx(NumberInput, { step: 0.1, value: (_a = values.shadowCameraNear) !== null && _a !== void 0 ? _a : 0.1, onChange: v => onChangeMultiple({ shadowCameraNear: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Far" }), _jsx(NumberInput, { step: 1, value: (_b = values.shadowCameraFar) !== null && _b !== void 0 ? _b : 100, onChange: v => onChangeMultiple({ shadowCameraFar: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Top" }), _jsx(NumberInput, { step: 1, value: (_c = values.shadowCameraTop) !== null && _c !== void 0 ? _c : 30, onChange: v => onChangeMultiple({ shadowCameraTop: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Bottom" }), _jsx(NumberInput, { step: 1, value: (_d = values.shadowCameraBottom) !== null && _d !== void 0 ? _d : -30, onChange: v => onChangeMultiple({ shadowCameraBottom: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Left" }), _jsx(NumberInput, { step: 1, value: (_e = values.shadowCameraLeft) !== null && _e !== void 0 ? _e : -30, onChange: v => onChangeMultiple({ shadowCameraLeft: v }) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Right" }), _jsx(NumberInput, { step: 1, value: (_f = values.shadowCameraRight) !== null && _f !== void 0 ? _f : 30, onChange: v => onChangeMultiple({ shadowCameraRight: v }) })] })] }));
32
- },
33
- },
34
- {
35
- name: 'targetOffset',
36
- type: 'custom',
37
- label: 'Target Offset',
38
- render: ({ value, onChange }) => {
39
- const offset = value !== null && value !== void 0 ? value : [0, -5, 0];
40
- return (_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 4 }, children: [_jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "X" }), _jsx(NumberInput, { step: 0.5, value: offset[0], onChange: v => onChange([v, offset[1], offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Y" }), _jsx(NumberInput, { step: 0.5, value: offset[1], onChange: v => onChange([offset[0], v, offset[2]]) })] }), _jsxs("div", { children: [_jsx("label", { style: smallLabel, children: "Z" }), _jsx(NumberInput, { step: 0.5, value: offset[2], onChange: v => onChange([offset[0], offset[1], v]) })] })] }));
41
- },
42
- },
43
- ];
25
+ const frustumLabelStyle = {
26
+ fontSize: 10,
27
+ textTransform: 'uppercase',
28
+ letterSpacing: '0.06em',
29
+ color: colors.textMuted,
30
+ textAlign: 'center',
31
+ };
32
+ const frustumCellStyle = {
33
+ display: 'flex',
34
+ alignItems: 'center',
35
+ justifyContent: 'center',
36
+ };
37
+ const frustumInputStyle = {
38
+ width: 62,
39
+ minWidth: 62,
40
+ textAlign: 'center',
41
+ };
42
+ const centerLockButtonStyle = {
43
+ width: 34,
44
+ height: 34,
45
+ borderRadius: 999,
46
+ border: `1px solid ${colors.border}`,
47
+ background: colors.bgInput,
48
+ color: colors.textMuted,
49
+ cursor: 'pointer',
50
+ fontSize: 14,
51
+ lineHeight: 1,
52
+ padding: 0,
53
+ };
54
+ function areFrustumSidesLocked(values) {
55
+ const top = Math.abs(values.shadowCameraTop);
56
+ const bottom = Math.abs(values.shadowCameraBottom);
57
+ const left = Math.abs(values.shadowCameraLeft);
58
+ const right = Math.abs(values.shadowCameraRight);
59
+ return top === bottom && top === left && top === right;
60
+ }
61
+ function ShadowFrustumField({ values, onChange, }) {
62
+ const [locked, setLocked] = useState(() => areFrustumSidesLocked(values));
63
+ const updateSide = (side, nextValue) => {
64
+ if (!locked) {
65
+ onChange({ [side]: nextValue });
66
+ return;
67
+ }
68
+ const magnitude = Math.abs(nextValue);
69
+ onChange({
70
+ shadowCameraTop: magnitude,
71
+ shadowCameraBottom: -magnitude,
72
+ shadowCameraLeft: -magnitude,
73
+ shadowCameraRight: magnitude,
74
+ });
75
+ };
76
+ const toggleLocked = () => {
77
+ setLocked(current => {
78
+ const nextLocked = !current;
79
+ if (nextLocked) {
80
+ const magnitude = Math.max(Math.abs(values.shadowCameraTop), Math.abs(values.shadowCameraBottom), Math.abs(values.shadowCameraLeft), Math.abs(values.shadowCameraRight));
81
+ onChange({
82
+ shadowCameraTop: magnitude,
83
+ shadowCameraBottom: -magnitude,
84
+ shadowCameraLeft: -magnitude,
85
+ shadowCameraRight: magnitude,
86
+ });
87
+ }
88
+ return nextLocked;
89
+ });
90
+ };
91
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsx("div", { style: Object.assign(Object.assign({}, frustumLabelStyle), { textAlign: 'left' }), children: "Shadow Frustum" }), _jsxs("div", { style: {
92
+ display: 'grid',
93
+ gridTemplateColumns: '1fr auto 1fr',
94
+ gridTemplateRows: 'auto auto auto',
95
+ gap: 8,
96
+ alignItems: 'center',
97
+ }, children: [_jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Top" }), _jsx(NumberInput, { value: values.shadowCameraTop, onChange: nextValue => updateSide('shadowCameraTop', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Left" }), _jsx(NumberInput, { value: values.shadowCameraLeft, onChange: nextValue => updateSide('shadowCameraLeft', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", { style: frustumCellStyle, children: _jsx("button", { type: "button", onClick: toggleLocked, style: Object.assign(Object.assign({}, centerLockButtonStyle), { color: locked ? colors.accent : colors.textMuted, borderColor: locked ? colors.accentBorder : colors.border, background: locked ? colors.accentBg : colors.bgInput }), title: locked ? 'Frustum sides locked' : 'Frustum sides unlocked', children: locked ? '🔒' : '🔓' }) }), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Right" }), _jsx(NumberInput, { value: values.shadowCameraRight, onChange: nextValue => updateSide('shadowCameraRight', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {}), _jsx("div", { style: frustumCellStyle, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'center' }, children: [_jsx("div", { style: frustumLabelStyle, children: "Bottom" }), _jsx(NumberInput, { value: values.shadowCameraBottom, onChange: nextValue => updateSide('shadowCameraBottom', nextValue), step: 0.5, style: frustumInputStyle })] }) }), _jsx("div", {})] })] }));
98
+ }
44
99
  function DirectionalLightComponentEditor({ component, onUpdate }) {
45
- const values = Object.assign(Object.assign({}, directionalLightDefaults), component.properties);
46
- const fields = values.castShadow
47
- ? directionalLightFields
48
- : directionalLightFields.filter(field => field.name !== '_shadowCamera');
49
- return (_jsx(FieldRenderer, { fields: fields, values: values, onChange: onUpdate }));
100
+ const values = mergeWithDefaults(directionalLightDefaults, component.properties);
101
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(Vector3Input, { label: "Target Offset", value: values.targetOffset, onChange: targetOffset => onUpdate({ targetOffset }), snap: 0.5 })] }), _jsxs(LightSection, { title: "Shadow", children: [_jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: values, onChange: onUpdate, fallback: false }), values.castShadow ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "shadowAutoUpdate", label: "Auto Update", values: values, onChange: onUpdate, fallback: true }), _jsx(NumberField, { name: "shadowMapSize", label: "Map Size", values: values, onChange: onUpdate, min: 128, step: 128, fallback: 512 }), _jsx(ShadowBiasField, { name: "shadowBias", label: "Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(ShadowBiasField, { name: "shadowNormalBias", label: "Normal Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(NumberField, { name: "shadowCameraNear", label: "Near", values: values, onChange: onUpdate, min: 0.001, step: 0.1, fallback: 0.5 }), _jsx(NumberField, { name: "shadowCameraFar", label: "Far", values: values, onChange: onUpdate, min: 0.1, step: 1, fallback: 500 }), _jsx(ShadowFrustumField, { values: values, onChange: onUpdate })] })) : null] })] }));
50
102
  }
51
103
  function DirectionalLightView({ properties, children, editMode, isSelected }) {
52
- const merged = Object.assign(Object.assign({}, directionalLightDefaults), properties);
104
+ const merged = mergeWithDefaults(directionalLightDefaults, properties);
53
105
  const color = merged.color;
54
106
  const intensity = merged.intensity;
55
107
  const castShadow = merged.castShadow;
56
108
  const shadowMapSize = merged.shadowMapSize;
109
+ const shadowBias = merged.shadowBias;
110
+ const shadowNormalBias = merged.shadowNormalBias;
111
+ const shadowAutoUpdate = merged.shadowAutoUpdate;
57
112
  const shadowCameraNear = merged.shadowCameraNear;
58
113
  const shadowCameraFar = merged.shadowCameraFar;
59
114
  const shadowCameraTop = merged.shadowCameraTop;
@@ -63,31 +118,48 @@ function DirectionalLightView({ properties, children, editMode, isSelected }) {
63
118
  const targetOffset = merged.targetOffset;
64
119
  const directionalLightRef = useRef(null);
65
120
  const targetRef = useRef(null);
121
+ const shadowCameraRef = useRef(null);
66
122
  const [shadowCamera, setShadowCamera] = useState(null);
67
- const shadowCameraHelper = useMemo(() => shadowCamera ? new CameraHelper(shadowCamera) : null, [shadowCamera]);
68
- useEffect(() => {
69
- return () => {
70
- shadowCameraHelper === null || shadowCameraHelper === void 0 ? void 0 : shadowCameraHelper.dispose();
71
- };
72
- }, [shadowCameraHelper]);
123
+ useHelper(editMode && isSelected && castShadow ? shadowCameraRef : null, CameraHelper);
73
124
  // Use a local target object so node transforms rotate the light direction naturally.
74
125
  useEffect(() => {
75
126
  if (directionalLightRef.current && targetRef.current) {
76
127
  directionalLightRef.current.target = targetRef.current;
77
- setShadowCamera(directionalLightRef.current.shadow.camera);
128
+ const nextShadowCamera = directionalLightRef.current.shadow.camera;
129
+ shadowCameraRef.current = nextShadowCamera;
130
+ setShadowCamera(nextShadowCamera);
78
131
  }
79
132
  }, []);
133
+ useEffect(() => {
134
+ var _a;
135
+ const shadow = (_a = directionalLightRef.current) === null || _a === void 0 ? void 0 : _a.shadow;
136
+ if (!shadow)
137
+ return;
138
+ shadow.needsUpdate = true;
139
+ shadow.camera.updateProjectionMatrix();
140
+ }, [
141
+ castShadow,
142
+ shadowMapSize,
143
+ shadowBias,
144
+ shadowNormalBias,
145
+ shadowAutoUpdate,
146
+ shadowCameraNear,
147
+ shadowCameraFar,
148
+ shadowCameraTop,
149
+ shadowCameraBottom,
150
+ shadowCameraLeft,
151
+ shadowCameraRight,
152
+ ]);
80
153
  useFrame(() => {
81
154
  if (!directionalLightRef.current || !targetRef.current)
82
155
  return;
83
156
  directionalLightRef.current.target.updateMatrixWorld();
84
- if (shadowCamera && shadowCameraHelper && castShadow) {
157
+ if (shadowCamera && castShadow) {
85
158
  shadowCamera.updateProjectionMatrix();
86
159
  shadowCamera.updateMatrixWorld();
87
- shadowCameraHelper.update();
88
160
  }
89
161
  });
90
- return (_jsxs(_Fragment, { children: [_jsx("directionalLight", { ref: directionalLightRef, color: color, intensity: intensity, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar, "shadow-camera-top": shadowCameraTop, "shadow-camera-bottom": shadowCameraBottom, "shadow-camera-left": shadowCameraLeft, "shadow-camera-right": shadowCameraRight, "shadow-bias": -0.001, "shadow-normalBias": 0.02 }), _jsx("object3D", { ref: targetRef, position: targetOffset }), editMode && isSelected && castShadow && shadowCameraHelper && (_jsx("primitive", { object: shadowCameraHelper })), editMode && isSelected && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.3, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] }), _jsxs("mesh", { position: targetOffset, children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true, opacity: 0.5, transparent: true })] }), _jsxs("line", { children: [_jsx("bufferGeometry", { onUpdate: (geo) => {
162
+ return (_jsxs(_Fragment, { children: [_jsx("directionalLight", { ref: directionalLightRef, color: color, intensity: intensity, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar, "shadow-camera-top": shadowCameraTop, "shadow-camera-bottom": shadowCameraBottom, "shadow-camera-left": shadowCameraLeft, "shadow-camera-right": shadowCameraRight, "shadow-bias": shadowBias, "shadow-normalBias": shadowNormalBias, "shadow-autoUpdate": shadowAutoUpdate }), _jsx("object3D", { ref: targetRef, position: targetOffset }), editMode && isSelected && (_jsxs(_Fragment, { children: [_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.3, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] }), _jsxs("mesh", { position: targetOffset, children: [_jsx("sphereGeometry", { args: [0.2, 8, 6] }), _jsx("meshBasicMaterial", { color: color, wireframe: true, opacity: 0.5, transparent: true })] }), _jsxs("line", { children: [_jsx("bufferGeometry", { onUpdate: (geo) => {
91
163
  const points = [
92
164
  new Vector3(0, 0, 0),
93
165
  new Vector3(targetOffset[0], targetOffset[1], targetOffset[2])
@@ -99,6 +171,6 @@ const DirectionalLightComponent = {
99
171
  name: 'DirectionalLight',
100
172
  Editor: DirectionalLightComponentEditor,
101
173
  View: DirectionalLightView,
102
- defaultProperties: directionalLightDefaults
174
+ defaultProperties: {}
103
175
  };
104
176
  export default DirectionalLightComponent;
@@ -1,10 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Environment } from '@react-three/drei';
3
3
  import { FieldGroup, NumberField } from './Input';
4
- function EnvironmentView({ properties, children, editMode, loadedTextures, loadedModels, }) {
4
+ import { useSceneRuntime } from '../PrefabRoot';
5
+ function EnvironmentView({ properties, children, }) {
6
+ const { getAssetRevision } = useSceneRuntime();
5
7
  const { intensity = 1, resolution = 256 } = properties;
6
- const assetRevision = `${Object.keys(loadedTextures !== null && loadedTextures !== void 0 ? loadedTextures : {}).sort().join('|')}::${Object.keys(loadedModels !== null && loadedModels !== void 0 ? loadedModels : {}).sort().join('|')}`;
7
- return (_jsx(Environment, { background: true, environmentIntensity: intensity, resolution: resolution, frames: editMode ? undefined : 1, children: children }, assetRevision));
8
+ const environmentRevision = `${getAssetRevision()}::${intensity}::${resolution}`;
9
+ return (_jsx(Environment, { background: true, environmentIntensity: intensity, resolution: resolution, frames: 1, children: children }, environmentRevision));
8
10
  }
9
11
  const EnvironmentComponent = {
10
12
  name: 'Environment',
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import { extend } from '@react-three/fiber';
14
14
  import { FieldRenderer, Label, NumberInput } from './Input';
15
+ import { useSceneRuntime } from '../PrefabRoot';
15
16
  import { useMemo } from 'react';
16
17
  import { MeshBasicNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
17
18
  import { TexturePicker } from '../../assetviewer/page';
@@ -119,8 +120,10 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
119
120
  return (_jsx(FieldRenderer, { fields: fields, values: component.properties, onChange: onUpdate }));
120
121
  }
121
122
  // View for Material component
122
- function MaterialComponentView({ properties, loadedTextures }) {
123
- var _a, _b, _c;
123
+ function MaterialComponentView({ properties: rawProps }) {
124
+ var _a, _b, _c, _d, _e;
125
+ const { getTexture } = useSceneRuntime();
126
+ const properties = rawProps;
124
127
  const materialType = (_a = properties === null || properties === void 0 ? void 0 : properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
125
128
  const textureName = properties === null || properties === void 0 ? void 0 : properties.texture;
126
129
  const repeat = properties === null || properties === void 0 ? void 0 : properties.repeat;
@@ -128,15 +131,15 @@ function MaterialComponentView({ properties, loadedTextures }) {
128
131
  const generateMipmaps = (properties === null || properties === void 0 ? void 0 : properties.generateMipmaps) !== false;
129
132
  const minFilter = (properties === null || properties === void 0 ? void 0 : properties.minFilter) || 'LinearMipmapLinearFilter';
130
133
  const magFilter = (properties === null || properties === void 0 ? void 0 : properties.magFilter) || 'LinearFilter';
131
- const texture = textureName && loadedTextures ? loadedTextures[textureName] : undefined;
134
+ const texture = textureName ? (_b = getTexture(textureName)) !== null && _b !== void 0 ? _b : undefined : undefined;
132
135
  const normalMapTextureName = properties === null || properties === void 0 ? void 0 : properties.normalMapTexture;
133
136
  const normalScaleProp = properties === null || properties === void 0 ? void 0 : properties.normalScale;
134
- const normalMapTexture = normalMapTextureName && loadedTextures ? loadedTextures[normalMapTextureName] : undefined;
137
+ const normalMapTexture = normalMapTextureName ? (_c = getTexture(normalMapTextureName)) !== null && _c !== void 0 ? _c : undefined : undefined;
135
138
  const materialSource = properties !== null && properties !== void 0 ? properties : {};
136
139
  // Destructure all material props and separate custom texture handling props
137
140
  const { texture: _texture, repeat: _repeat, repeatCount: _repeatCount, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "repeat", "repeatCount", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
138
141
  const sideMap = { FrontSide, BackSide, DoubleSide };
139
- const resolvedSide = sideProp ? ((_b = sideMap[sideProp]) !== null && _b !== void 0 ? _b : FrontSide) : FrontSide;
142
+ const resolvedSide = sideProp ? ((_d = sideMap[sideProp]) !== null && _d !== void 0 ? _d : FrontSide) : FrontSide;
140
143
  const minFilterMap = {
141
144
  NearestFilter,
142
145
  LinearFilter,
@@ -187,7 +190,7 @@ function MaterialComponentView({ properties, loadedTextures }) {
187
190
  if (!properties) {
188
191
  return _jsx("meshStandardNodeMaterial", { color: "red", wireframe: true });
189
192
  }
190
- const materialKey = `${(_c = finalTexture === null || finalTexture === void 0 ? void 0 : finalTexture.uuid) !== null && _c !== void 0 ? _c : 'no-texture'}:${materialProps.transparent ? 'transparent' : 'opaque'}`;
193
+ const materialKey = `${(_e = finalTexture === null || finalTexture === void 0 ? void 0 : finalTexture.uuid) !== null && _e !== void 0 ? _e : 'no-texture'}:${materialProps.transparent ? 'transparent' : 'opaque'}`;
191
194
  const sharedProps = Object.assign({ map: finalTexture, side: resolvedSide }, materialProps);
192
195
  if (materialType === 'basic') {
193
196
  return _jsx("meshBasicNodeMaterial", Object.assign({}, sharedProps), materialKey);
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { ModelPicker } from '../../assetviewer/page';
3
3
  import { useContext, useMemo } from 'react';
4
4
  import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput } from './Input';
5
+ import { useSceneRuntime } from '../PrefabRoot';
5
6
  import { EditorContext } from '../PrefabEditor';
6
7
  import { DEFAULT_REPEAT_AXES, getRepeatAxesFromModelProperties, normalizeRepeatAxes } from '../InstanceProvider';
7
8
  import { colors } from '../styles';
@@ -63,11 +64,12 @@ function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
63
64
  return (_jsxs(FieldGroup, { children: [_jsx(ModelPicker, { value: component.properties.filename, onChange: (filename) => onUpdate({ filename }), basePath: basePath, pickerKey: node === null || node === void 0 ? void 0 : node.id }), _jsx(BooleanField, { name: "instanced", label: "Instanced", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.instanced && (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "repeat", label: "Repeat", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.repeat && (_jsx(RepeatAxisEditor, { axes: repeatAxes, onChange: (nextAxes) => onUpdate({ repeatAxes: nextAxes }), positionSnap: positionSnap }))] }))] }));
64
65
  }
65
66
  // View for Model component
66
- function ModelComponentView({ properties, loadedModels, children }) {
67
+ function ModelComponentView({ properties, children }) {
68
+ const { getModel } = useSceneRuntime();
67
69
  // Instanced models are handled elsewhere (GameInstance), so only render non-instanced here
68
70
  if (!properties.filename || properties.instanced)
69
71
  return _jsx(_Fragment, { children: children });
70
- const sourceModel = loadedModels === null || loadedModels === void 0 ? void 0 : loadedModels[properties.filename];
72
+ const sourceModel = getModel(properties.filename);
71
73
  // Clone model once and set up shadows - memoized to avoid cloning on every render
72
74
  const clonedModel = useMemo(() => {
73
75
  if (!sourceModel)
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
13
  import { CapsuleCollider, RigidBody, useRapier } from "@react-three/rapier";
14
14
  import { useRef, useEffect, useCallback } from 'react';
15
+ import { useSceneRuntime } from "../PrefabRoot";
15
16
  import { BooleanField, FieldGroup, ListEditor, NumberField, SelectField, SelectInput, StringInput, Vector3Field } from "./Input";
16
17
  import { gameEvents, getEntityIdFromRigidBody } from "../GameEvents";
17
18
  import { colors } from "../styles";
@@ -162,7 +163,8 @@ function PhysicsComponentEditor({ component, onUpdate }) {
162
163
  { value: 'all', label: 'All (includes kinematic & fixed)' },
163
164
  ] })] }));
164
165
  }
165
- function PhysicsComponentView({ properties, children, position, rotation, scale, editMode, nodeId, registerRigidBodyRef }) {
166
+ function PhysicsComponentView({ properties, children, position, rotation, scale, editMode, nodeId }) {
167
+ const { registerRigidBodyRef } = useSceneRuntime();
166
168
  const { type, colliders, sensor, activeCollisionTypes, linearVelocity = [0, 0, 0], angularVelocity = [0, 0, 0], capsuleRadius = capsuleRadiusFallback, capsuleHalfHeight = capsuleHalfHeightFallback, sensorEnterEventName, sensorExitEventName, collisionEnterEventName, collisionExitEventName, enabledTranslations = enabledAxesFallback, enabledRotations = enabledAxesFallback } = properties, otherProps = __rest(properties, ["type", "colliders", "sensor", "activeCollisionTypes", "linearVelocity", "angularVelocity", "capsuleRadius", "capsuleHalfHeight", "sensorEnterEventName", "sensorExitEventName", "collisionEnterEventName", "collisionExitEventName", "enabledTranslations", "enabledRotations"]);
167
169
  const colliderType = colliders || (type === 'fixed' ? 'trimesh' : 'hull');
168
170
  const usesManualCapsuleCollider = colliderType === 'capsule';
@@ -183,11 +185,11 @@ function PhysicsComponentView({ properties, children, position, rotation, scale,
183
185
  }
184
186
  // Register RigidBody ref when it's available
185
187
  useEffect(() => {
186
- if (nodeId && registerRigidBodyRef && rigidBodyRef.current) {
188
+ if (nodeId && rigidBodyRef.current) {
187
189
  registerRigidBodyRef(nodeId, rigidBodyRef.current);
188
190
  }
189
191
  return () => {
190
- if (nodeId && registerRigidBodyRef) {
192
+ if (nodeId) {
191
193
  registerRigidBodyRef(nodeId, null);
192
194
  }
193
195
  };
@@ -0,0 +1,3 @@
1
+ import { Component } from './ComponentRegistry';
2
+ declare const PointLightComponent: Component;
3
+ export default PointLightComponent;
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { useHelper } from '@react-three/drei';
4
+ import { PointLightHelper } from 'three';
5
+ import { BooleanField, ColorField, NumberField } from './Input';
6
+ import { LightSection, ShadowBiasField, mergeWithDefaults } from './lightUtils';
7
+ const pointLightDefaults = {
8
+ color: '#ffffff',
9
+ intensity: 1,
10
+ distance: 0,
11
+ decay: 2,
12
+ castShadow: false,
13
+ shadowMapSize: 512,
14
+ shadowBias: 0,
15
+ shadowNormalBias: 0,
16
+ shadowAutoUpdate: true,
17
+ shadowCameraNear: 0.5,
18
+ shadowCameraFar: 500,
19
+ };
20
+ function PointLightComponentEditor({ component, onUpdate }) {
21
+ const values = mergeWithDefaults(pointLightDefaults, component.properties);
22
+ return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs(LightSection, { title: "Light", children: [_jsx(ColorField, { name: "color", label: "Color", values: values, onChange: onUpdate }), _jsx(NumberField, { name: "intensity", label: "Intensity", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 1 }), _jsx(NumberField, { name: "distance", label: "Distance", values: values, onChange: onUpdate, min: 0, step: 1, fallback: 0 }), _jsx(NumberField, { name: "decay", label: "Decay", values: values, onChange: onUpdate, min: 0, step: 0.1, fallback: 2 })] }), _jsxs(LightSection, { title: "Shadow", children: [_jsx(BooleanField, { name: "castShadow", label: "Cast Shadow", values: values, onChange: onUpdate, fallback: false }), values.castShadow ? (_jsxs(_Fragment, { children: [_jsx(BooleanField, { name: "shadowAutoUpdate", label: "Auto Update", values: values, onChange: onUpdate, fallback: true }), _jsx(NumberField, { name: "shadowMapSize", label: "Map Size", values: values, onChange: onUpdate, min: 128, step: 128, fallback: 512 }), _jsx(ShadowBiasField, { name: "shadowBias", label: "Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(ShadowBiasField, { name: "shadowNormalBias", label: "Normal Bias", values: values, onChange: onUpdate, fallback: 0 }), _jsx(NumberField, { name: "shadowCameraNear", label: "Near", values: values, onChange: onUpdate, min: 0.001, step: 0.1, fallback: 0.5 }), _jsx(NumberField, { name: "shadowCameraFar", label: "Far", values: values, onChange: onUpdate, min: 0.1, step: 1, fallback: 500 })] })) : null] })] }));
23
+ }
24
+ function PointLightView({ properties, children, editMode, isSelected }) {
25
+ const merged = mergeWithDefaults(pointLightDefaults, properties);
26
+ const color = merged.color;
27
+ const intensity = merged.intensity;
28
+ const distance = merged.distance;
29
+ const decay = merged.decay;
30
+ const castShadow = merged.castShadow;
31
+ const shadowMapSize = merged.shadowMapSize;
32
+ const shadowBias = merged.shadowBias;
33
+ const shadowNormalBias = merged.shadowNormalBias;
34
+ const shadowAutoUpdate = merged.shadowAutoUpdate;
35
+ const shadowCameraNear = merged.shadowCameraNear;
36
+ const shadowCameraFar = merged.shadowCameraFar;
37
+ const lightRef = useRef(null);
38
+ useHelper(editMode && isSelected ? lightRef : null, PointLightHelper, 0.5, color);
39
+ useEffect(() => {
40
+ var _a;
41
+ const shadow = (_a = lightRef.current) === null || _a === void 0 ? void 0 : _a.shadow;
42
+ if (!shadow)
43
+ return;
44
+ shadow.needsUpdate = true;
45
+ shadow.camera.updateProjectionMatrix();
46
+ }, [castShadow, shadowMapSize, shadowBias, shadowNormalBias, shadowAutoUpdate, shadowCameraNear, shadowCameraFar]);
47
+ return (_jsxs(_Fragment, { children: [_jsx("pointLight", { ref: lightRef, color: color, intensity: intensity, distance: distance, decay: decay, castShadow: castShadow, "shadow-mapSize-width": shadowMapSize, "shadow-mapSize-height": shadowMapSize, "shadow-bias": shadowBias, "shadow-normalBias": shadowNormalBias, "shadow-autoUpdate": shadowAutoUpdate, "shadow-camera-near": shadowCameraNear, "shadow-camera-far": shadowCameraFar }), editMode && isSelected ? (_jsxs("mesh", { children: [_jsx("sphereGeometry", { args: [0.2, 10, 8] }), _jsx("meshBasicMaterial", { color: color, wireframe: true })] })) : null, children] }));
48
+ }
49
+ const PointLightComponent = {
50
+ name: 'PointLight',
51
+ Editor: PointLightComponentEditor,
52
+ View: PointLightView,
53
+ defaultProperties: {},
54
+ };
55
+ export default PointLightComponent;
@@ -4,6 +4,7 @@ import { useThree } from '@react-three/fiber';
4
4
  import { SoundPicker } from '../../assetviewer/page';
5
5
  import { sound as soundManager } from '../../../helpers/SoundManager';
6
6
  import { gameEvents } from '../GameEvents';
7
+ import { useSceneRuntime } from '../PrefabRoot';
7
8
  import { BooleanField, FieldGroup, FieldRenderer, ListEditor, NumberField, SelectField, StringField } from './Input';
8
9
  import { colors } from '../styles';
9
10
  import { AudioListener } from 'three';
@@ -44,12 +45,12 @@ function getVolumeValue(properties) {
44
45
  }
45
46
  return Number.isFinite(properties.volume) ? Number(properties.volume) : 1;
46
47
  }
47
- function resolveClipPaths({ path, clips, clipMode }) {
48
+ function resolveClipPaths({ clips, clipMode }) {
48
49
  const normalizedClips = normalizeClips(clips);
49
50
  if (normalizedClips.length > 0) {
50
51
  return { paths: normalizedClips, mode: clipMode !== null && clipMode !== void 0 ? clipMode : 'random' };
51
52
  }
52
- return path ? { paths: [path], mode: 'single' } : { paths: [], mode: 'single' };
53
+ return { paths: [], mode: 'single' };
53
54
  }
54
55
  function pickClip(paths, mode, sequenceIndexRef) {
55
56
  if (paths.length <= 1 || mode === 'single') {
@@ -63,22 +64,27 @@ function pickClip(paths, mode, sequenceIndexRef) {
63
64
  return paths[Math.floor(Math.random() * paths.length)];
64
65
  }
65
66
  function SoundComponentEditor({ component, onUpdate, basePath = '' }) {
66
- const clips = normalizeClips(component.properties.clips);
67
+ const clips = Array.isArray(component.properties.clips)
68
+ ? component.properties.clips.map((clip) => typeof clip === 'string' ? clip : '')
69
+ : [];
67
70
  const randomizePitch = Boolean(component.properties.randomizePitch);
68
71
  const randomizeVolume = Boolean(component.properties.randomizeVolume);
69
72
  const positional = Boolean(component.properties.positional);
73
+ const setClips = (nextClips) => {
74
+ onUpdate({ clips: nextClips });
75
+ };
70
76
  const addClip = () => {
71
- onUpdate({ clips: [...clips, ''] });
77
+ setClips([...clips, '']);
72
78
  };
73
79
  const updateClip = (index, nextPath) => {
74
- onUpdate({
75
- clips: clips.map((clip, clipIndex) => clipIndex === index ? nextPath : clip),
76
- });
80
+ const nextClips = [...clips];
81
+ nextClips[index] = nextPath;
82
+ setClips(nextClips);
77
83
  };
78
84
  const removeClip = (index) => {
79
- onUpdate({ clips: clips.filter((_, clipIndex) => clipIndex !== index) });
85
+ setClips(clips.filter((_, clipIndex) => clipIndex !== index));
80
86
  };
81
- return (_jsxs(FieldGroup, { children: [_jsx(SoundPicker, { value: component.properties.path, onChange: (path) => onUpdate({ path: path !== null && path !== void 0 ? path : '' }), basePath: basePath }), _jsx(StringField, { name: "eventName", label: "Listen Event", values: component.properties, onChange: onUpdate, placeholder: "click" }), _jsx(FieldRenderer, { fields: [
87
+ return (_jsxs(FieldGroup, { children: [_jsx(StringField, { name: "eventName", label: "Listen Event", values: component.properties, onChange: onUpdate, placeholder: "click" }), _jsx(FieldRenderer, { fields: [
82
88
  {
83
89
  name: 'clipMode',
84
90
  label: 'Clip Mode',
@@ -117,7 +123,8 @@ function payloadMatchesNode(nodeId, payload) {
117
123
  const hasEntityIds = ids.some(id => typeof id === 'string');
118
124
  return hasEntityIds ? ids.includes(nodeId) : true;
119
125
  }
120
- function SoundComponentView({ properties, editMode, nodeId, children, loadedSounds }) {
126
+ function SoundComponentView({ properties, editMode, nodeId, children }) {
127
+ const { getSound } = useSceneRuntime();
121
128
  const { camera } = useThree();
122
129
  const { eventName, positional = false, refDistance = 1, maxDistance = 24, rolloffFactor = 1, distanceModel = 'inverse' } = properties;
123
130
  const sequenceIndexRef = useRef(0);
@@ -170,7 +177,7 @@ function SoundComponentView({ properties, editMode, nodeId, children, loadedSoun
170
177
  const pitch = getPitchValue(properties);
171
178
  const volume = getVolumeValue(properties);
172
179
  if (!positional) {
173
- const loadedBuffer = loadedSounds === null || loadedSounds === void 0 ? void 0 : loadedSounds[clip];
180
+ const loadedBuffer = getSound(clip);
174
181
  if (loadedBuffer && !soundManager.hasBuffer(clip)) {
175
182
  soundManager.setBuffer(clip, loadedBuffer);
176
183
  }
@@ -183,7 +190,7 @@ function SoundComponentView({ properties, editMode, nodeId, children, loadedSoun
183
190
  }
184
191
  const audio = positionalAudioRef.current;
185
192
  const listener = listenerRef.current;
186
- const buffer = loadedSounds === null || loadedSounds === void 0 ? void 0 : loadedSounds[clip];
193
+ const buffer = getSound(clip);
187
194
  if (!audio || !listener || !buffer) {
188
195
  return;
189
196
  }
@@ -197,7 +204,7 @@ function SoundComponentView({ properties, editMode, nodeId, children, loadedSoun
197
204
  audio.setVolume(volume);
198
205
  audio.play();
199
206
  });
200
- }, [editMode, eventName, loadedSounds, mode, nodeId, paths, positional, properties]);
207
+ }, [editMode, eventName, getSound, mode, nodeId, paths, positional, properties]);
201
208
  return (_jsxs(_Fragment, { children: [positional && listenerRef.current ? _jsx("positionalAudio", { ref: positionalAudioRef, args: [listenerRef.current] }) : null, children] }));
202
209
  }
203
210
  const SoundComponent = {
@@ -205,7 +212,6 @@ const SoundComponent = {
205
212
  Editor: SoundComponentEditor,
206
213
  View: SoundComponentView,
207
214
  defaultProperties: {
208
- path: '',
209
215
  eventName: '',
210
216
  clips: [],
211
217
  clipMode: 'single',
@@ -225,8 +231,6 @@ const SoundComponent = {
225
231
  },
226
232
  getAssetRefs: (properties) => {
227
233
  const refs = [];
228
- if (properties.path)
229
- refs.push({ type: 'sound', path: properties.path });
230
234
  if (Array.isArray(properties.clips)) {
231
235
  properties.clips.forEach((clip) => {
232
236
  if (typeof clip === 'string' && clip.trim().length > 0) {