react-three-game 0.0.108 → 0.0.110

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 (55) hide show
  1. package/README.md +9 -16
  2. package/dist/editor.d.ts +22 -0
  3. package/dist/editor.js +15 -0
  4. package/dist/plugins/crashcat/CrashcatPhysicsComponent.js +47 -9
  5. package/dist/plugins/crashcat/CrashcatRagdoll.d.ts +1 -1
  6. package/dist/plugins/crashcat/CrashcatRuntime.d.ts +1 -1
  7. package/dist/plugins/crashcat/CrashcatRuntime.js +1 -1
  8. package/dist/shared/ContactShadow.d.ts +1 -1
  9. package/dist/shared/GameCanvas.d.ts +1 -1
  10. package/dist/tools/assetviewer/page.d.ts +10 -10
  11. package/dist/tools/dragdrop/DragDropLoader.d.ts +2 -2
  12. package/dist/tools/prefabeditor/Dropdown.d.ts +1 -1
  13. package/dist/tools/prefabeditor/EditorContext.d.ts +36 -0
  14. package/dist/tools/prefabeditor/EditorContext.js +17 -0
  15. package/dist/tools/prefabeditor/EditorTree.d.ts +1 -1
  16. package/dist/tools/prefabeditor/EditorTree.js +1 -1
  17. package/dist/tools/prefabeditor/EditorTreeMenus.d.ts +2 -2
  18. package/dist/tools/prefabeditor/EditorTreeMenus.js +1 -1
  19. package/dist/tools/prefabeditor/EditorUI.d.ts +1 -1
  20. package/dist/tools/prefabeditor/EditorUI.js +1 -1
  21. package/dist/tools/prefabeditor/InstanceProvider.d.ts +1 -1
  22. package/dist/tools/prefabeditor/PrefabEditor.d.ts +4 -37
  23. package/dist/tools/prefabeditor/PrefabEditor.js +72 -71
  24. package/dist/tools/prefabeditor/PrefabRoot.d.ts +5 -29
  25. package/dist/tools/prefabeditor/PrefabRoot.js +72 -188
  26. package/dist/tools/prefabeditor/SceneContext.d.ts +28 -0
  27. package/dist/tools/prefabeditor/SceneContext.js +14 -0
  28. package/dist/tools/prefabeditor/SceneProvider.d.ts +14 -0
  29. package/dist/tools/prefabeditor/SceneProvider.js +68 -0
  30. package/dist/tools/prefabeditor/assetRuntime.d.ts +29 -2
  31. package/dist/tools/prefabeditor/assetRuntime.js +115 -1
  32. package/dist/tools/prefabeditor/components/ComponentRegistry.d.ts +1 -1
  33. package/dist/tools/prefabeditor/components/EnvironmentComponent.js +3 -3
  34. package/dist/tools/prefabeditor/components/Input.d.ts +19 -19
  35. package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +1 -1
  36. package/dist/tools/prefabeditor/components/MaterialComponent.js +13 -14
  37. package/dist/tools/prefabeditor/components/ModelComponent.js +3 -4
  38. package/dist/tools/prefabeditor/components/PrefabRefComponent.js +43 -19
  39. package/dist/tools/prefabeditor/components/SoundComponent.js +6 -2
  40. package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -5
  41. package/dist/tools/prefabeditor/components/TransformComponent.js +1 -1
  42. package/dist/tools/prefabeditor/components/index.d.ts +1 -0
  43. package/dist/tools/prefabeditor/components/index.js +8 -0
  44. package/dist/tools/prefabeditor/components/lightUtils.d.ts +2 -2
  45. package/dist/tools/prefabeditor/prefabStore.d.ts +2 -1
  46. package/dist/tools/prefabeditor/prefabStore.js +16 -1
  47. package/dist/tools/prefabeditor/runtimeUtils.d.ts +10 -0
  48. package/dist/tools/prefabeditor/runtimeUtils.js +30 -0
  49. package/dist/tools/prefabeditor/utils.d.ts +1 -9
  50. package/dist/tools/prefabeditor/utils.js +3 -28
  51. package/dist/viewer.d.ts +21 -0
  52. package/dist/viewer.js +12 -0
  53. package/package.json +18 -16
  54. package/dist/index.d.ts +0 -40
  55. package/dist/index.js +0 -32
@@ -1,11 +1,11 @@
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
- import { useAssetRuntime } from '../assetRuntime';
4
+ import { useAssetRevision } from '../assetRuntime';
5
5
  function EnvironmentView({ properties, children, }) {
6
- const { getAssetRevision } = useAssetRuntime();
6
+ const assetRevision = useAssetRevision();
7
7
  const { intensity = 1, resolution = 256 } = properties;
8
- const environmentRevision = `${getAssetRevision()}::${intensity}::${resolution}`;
8
+ const environmentRevision = `${assetRevision}::${intensity}::${resolution}`;
9
9
  return (_jsx(Environment, { background: true, environmentIntensity: intensity, resolution: resolution, frames: 1, children: children }, environmentRevision));
10
10
  }
11
11
  const EnvironmentComponent = {
@@ -59,44 +59,44 @@ interface InputProps {
59
59
  style?: React.CSSProperties;
60
60
  label?: string;
61
61
  }
62
- export declare function NumberInput({ value, onChange, step, min, max, style }: InputProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function NumberInput({ value, onChange, step, min, max, style }: InputProps): React.JSX.Element;
63
63
  export declare function Label({ children }: {
64
64
  children: React.ReactNode;
65
- }): import("react/jsx-runtime").JSX.Element;
65
+ }): React.JSX.Element;
66
66
  export declare function FieldRow({ label, children, }: {
67
67
  label: string;
68
68
  children: React.ReactNode;
69
- }): import("react/jsx-runtime").JSX.Element;
69
+ }): React.JSX.Element;
70
70
  export declare function Vector3Input({ label, value, onChange, snap, labelExtra }: {
71
71
  label: string;
72
72
  value: [number, number, number];
73
73
  onChange: (v: [number, number, number]) => void;
74
74
  snap?: number;
75
75
  labelExtra?: React.ReactNode;
76
- }): import("react/jsx-runtime").JSX.Element;
76
+ }): React.JSX.Element;
77
77
  export declare function ColorInput({ label, value, onChange }: {
78
78
  label?: string;
79
79
  value: string;
80
80
  onChange: (value: string) => void;
81
- }): import("react/jsx-runtime").JSX.Element;
81
+ }): React.JSX.Element;
82
82
  export declare function StringInput({ label, value, onChange, placeholder }: {
83
83
  label?: string;
84
84
  value: string;
85
85
  onChange: (value: string) => void;
86
86
  placeholder?: string;
87
- }): import("react/jsx-runtime").JSX.Element;
87
+ }): React.JSX.Element;
88
88
  export declare function NodeInput({ label, value, onChange, placeholder, includeRoot, }: {
89
89
  label: string;
90
90
  value: string;
91
91
  onChange: (value: string) => void;
92
92
  placeholder?: string;
93
93
  includeRoot?: boolean;
94
- }): import("react/jsx-runtime").JSX.Element;
94
+ }): React.JSX.Element;
95
95
  export declare function BooleanInput({ label, value, onChange }: {
96
96
  label?: string;
97
97
  value: boolean;
98
98
  onChange: (value: boolean) => void;
99
- }): import("react/jsx-runtime").JSX.Element;
99
+ }): React.JSX.Element;
100
100
  export declare function SelectInput({ label, value, onChange, options }: {
101
101
  label?: string;
102
102
  value: string;
@@ -105,7 +105,7 @@ export declare function SelectInput({ label, value, onChange, options }: {
105
105
  value: string;
106
106
  label: string;
107
107
  }[];
108
- }): import("react/jsx-runtime").JSX.Element;
108
+ }): React.JSX.Element;
109
109
  interface BoundFieldProps {
110
110
  name: string;
111
111
  values: Record<string, any>;
@@ -148,7 +148,7 @@ interface BoundVector3FieldProps extends BoundFieldProps {
148
148
  }
149
149
  export declare function FieldGroup({ children }: {
150
150
  children: React.ReactNode;
151
- }): import("react/jsx-runtime").JSX.Element;
151
+ }): React.JSX.Element;
152
152
  interface ListEditorOption {
153
153
  value: string;
154
154
  label: string;
@@ -164,20 +164,20 @@ interface ListEditorProps<T> {
164
164
  addButtonTitle?: string;
165
165
  addDisabledTitle?: string;
166
166
  }
167
- export declare function ListEditor<T>({ label, items, renderItem, onAdd, addOptions, emptyMessage, canAdd, addButtonTitle, addDisabledTitle, }: ListEditorProps<T>): import("react/jsx-runtime").JSX.Element;
168
- export declare function NumberField({ name, label, values, onChange, fallback, step, min, max, style, }: BoundNumberFieldProps): import("react/jsx-runtime").JSX.Element;
169
- export declare function StringField({ name, label, values, onChange, fallback, placeholder, }: BoundStringFieldProps): import("react/jsx-runtime").JSX.Element;
170
- export declare function ColorField({ name, label, values, onChange, fallback, }: BoundColorFieldProps): import("react/jsx-runtime").JSX.Element;
171
- export declare function BooleanField({ name, label, values, onChange, fallback, }: BoundBooleanFieldProps): import("react/jsx-runtime").JSX.Element;
172
- export declare function SelectField({ name, label, values, onChange, fallback, options, }: BoundSelectFieldProps): import("react/jsx-runtime").JSX.Element;
167
+ export declare function ListEditor<T>({ label, items, renderItem, onAdd, addOptions, emptyMessage, canAdd, addButtonTitle, addDisabledTitle, }: ListEditorProps<T>): React.JSX.Element;
168
+ export declare function NumberField({ name, label, values, onChange, fallback, step, min, max, style, }: BoundNumberFieldProps): React.JSX.Element;
169
+ export declare function StringField({ name, label, values, onChange, fallback, placeholder, }: BoundStringFieldProps): React.JSX.Element;
170
+ export declare function ColorField({ name, label, values, onChange, fallback, }: BoundColorFieldProps): React.JSX.Element;
171
+ export declare function BooleanField({ name, label, values, onChange, fallback, }: BoundBooleanFieldProps): React.JSX.Element;
172
+ export declare function SelectField({ name, label, values, onChange, fallback, options, }: BoundSelectFieldProps): React.JSX.Element;
173
173
  export declare function NodeField({ name, label, values, onChange, fallback, }: BoundStringFieldProps & {
174
174
  fallback?: string;
175
- }): import("react/jsx-runtime").JSX.Element;
176
- export declare function Vector3Field({ name, label, values, onChange, fallback, snap, labelExtra, }: BoundVector3FieldProps): import("react/jsx-runtime").JSX.Element;
175
+ }): React.JSX.Element;
176
+ export declare function Vector3Field({ name, label, values, onChange, fallback, snap, labelExtra, }: BoundVector3FieldProps): React.JSX.Element;
177
177
  interface FieldRendererProps {
178
178
  fields: FieldDefinition[];
179
179
  values: Record<string, any>;
180
180
  onChange: (values: Record<string, any>) => void;
181
181
  }
182
- export declare function FieldRenderer({ fields, values, onChange }: FieldRendererProps): import("react/jsx-runtime").JSX.Element;
182
+ export declare function FieldRenderer({ fields, values, onChange }: FieldRendererProps): React.JSX.Element;
183
183
  export { styles };
@@ -41,6 +41,6 @@ export declare function useMaterialOverrides(): MaterialOverrides;
41
41
  export declare function MaterialOverridesProvider({ overrides, children, }: {
42
42
  overrides: MaterialOverrides;
43
43
  children: ReactNode;
44
- }): import("react/jsx-runtime").JSX.Element;
44
+ }): import("react").JSX.Element;
45
45
  declare const MaterialComponent: Component;
46
46
  export default MaterialComponent;
@@ -15,7 +15,7 @@ import { extend } from '@react-three/fiber';
15
15
  import { useFrame } from '@react-three/fiber';
16
16
  import { assetRef, assetRefs } from './ComponentRegistry';
17
17
  import { FieldRenderer, Label, NumberInput } from './Input';
18
- import { useAssetRuntime } from '../assetRuntime';
18
+ import { useTextureAsset } from '../assetRuntime';
19
19
  import { MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial } from 'three/webgpu';
20
20
  import { TexturePicker } from '../../assetviewer/page';
21
21
  import { RepeatWrapping, ClampToEdgeWrapping, NoColorSpace, SRGBColorSpace, NearestFilter, LinearFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter, FrontSide, BackSide, DoubleSide, } from 'three';
@@ -219,8 +219,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "", }) {
219
219
  }
220
220
  // View for Material component
221
221
  function MaterialComponentView({ properties: rawProps }) {
222
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
223
- const { getTexture } = useAssetRuntime();
222
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
224
223
  const properties = rawProps;
225
224
  const materialSource = properties !== null && properties !== void 0 ? properties : {};
226
225
  const materialType = (_a = materialSource.materialType) !== null && _a !== void 0 ? _a : 'standard';
@@ -234,15 +233,15 @@ function MaterialComponentView({ properties: rawProps }) {
234
233
  const generateMipmaps = materialSource.generateMipmaps !== false;
235
234
  const minFilter = (_b = materialSource.minFilter) !== null && _b !== void 0 ? _b : 'LinearMipmapLinearFilter';
236
235
  const magFilter = (_c = materialSource.magFilter) !== null && _c !== void 0 ? _c : 'LinearFilter';
237
- const texture = textureName ? getTexture(textureName) : undefined;
236
+ const texture = (_d = useTextureAsset(textureName)) !== null && _d !== void 0 ? _d : undefined;
238
237
  const normalScaleProp = materialSource.normalScale;
239
- const normalMapTexture = normalMapTextureName ? getTexture(normalMapTextureName) : undefined;
238
+ const normalMapTexture = (_e = useTextureAsset(normalMapTextureName)) !== null && _e !== void 0 ? _e : undefined;
240
239
  // Destructure all material props and separate custom texture handling props
241
240
  const { texture: _texture, offset: _offset, repeat: _repeat, repeatCount: _repeatCount, animateOffset: _animateOffset, offsetSpeed: _offsetSpeed, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, attach, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, rotation, sizeAttenuation, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "offset", "repeat", "repeatCount", "animateOffset", "offsetSpeed", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "attach", "normalMapTexture", "normalScale", "normalMap", "rotation", "sizeAttenuation", "side"]);
242
- const resolvedSide = sideProp ? (_d = SIDE_MAP[sideProp]) !== null && _d !== void 0 ? _d : FrontSide : FrontSide;
243
- const resolvedMinFilter = (_e = MIN_FILTER_MAP[minFilter]) !== null && _e !== void 0 ? _e : LinearMipmapLinearFilter;
244
- const resolvedMagFilter = (_f = MAG_FILTER_MAP[magFilter]) !== null && _f !== void 0 ? _f : LinearFilter;
245
- const animatedOffsetRef = useRef([(_g = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _g !== void 0 ? _g : 0, (_h = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _h !== void 0 ? _h : 0]);
241
+ const resolvedSide = sideProp ? (_f = SIDE_MAP[sideProp]) !== null && _f !== void 0 ? _f : FrontSide : FrontSide;
242
+ const resolvedMinFilter = (_g = MIN_FILTER_MAP[minFilter]) !== null && _g !== void 0 ? _g : LinearMipmapLinearFilter;
243
+ const resolvedMagFilter = (_h = MAG_FILTER_MAP[magFilter]) !== null && _h !== void 0 ? _h : LinearFilter;
244
+ const animatedOffsetRef = useRef([(_j = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _j !== void 0 ? _j : 0, (_k = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _k !== void 0 ? _k : 0]);
246
245
  const textureConfig = {
247
246
  repeat,
248
247
  repeatCount,
@@ -253,7 +252,7 @@ function MaterialComponentView({ properties: rawProps }) {
253
252
  };
254
253
  const finalTexture = useConfiguredTexture(texture, Object.assign(Object.assign({}, textureConfig), { colorSpace: SRGBColorSpace }));
255
254
  const finalNormalMap = useConfiguredTexture(normalMapTexture, Object.assign(Object.assign({}, textureConfig), { colorSpace: NoColorSpace }));
256
- animatedOffsetRef.current = [(_j = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _j !== void 0 ? _j : 0, (_k = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _k !== void 0 ? _k : 0];
255
+ animatedOffsetRef.current = [(_l = offset === null || offset === void 0 ? void 0 : offset[0]) !== null && _l !== void 0 ? _l : 0, (_m = offset === null || offset === void 0 ? void 0 : offset[1]) !== null && _m !== void 0 ? _m : 0];
257
256
  useFrame((_, delta) => {
258
257
  var _a, _b;
259
258
  if ((!finalTexture && !finalNormalMap) || !animateOffset)
@@ -276,8 +275,8 @@ function MaterialComponentView({ properties: rawProps }) {
276
275
  textureName !== null && textureName !== void 0 ? textureName : 'no-texture',
277
276
  normalMapTextureName !== null && normalMapTextureName !== void 0 ? normalMapTextureName : 'no-normal',
278
277
  repeat ? 'repeat' : 'clamp',
279
- (_l = repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0]) !== null && _l !== void 0 ? _l : 1,
280
- (_m = repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1]) !== null && _m !== void 0 ? _m : 1,
278
+ (_o = repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[0]) !== null && _o !== void 0 ? _o : 1,
279
+ (_p = repeatCount === null || repeatCount === void 0 ? void 0 : repeatCount[1]) !== null && _p !== void 0 ? _p : 1,
281
280
  generateMipmaps ? 'mips' : 'no-mips',
282
281
  minFilter,
283
282
  magFilter,
@@ -287,11 +286,11 @@ function MaterialComponentView({ properties: rawProps }) {
287
286
  }
288
287
  if (materialType === 'sprite') {
289
288
  const spriteTransparent = materialSource.transparent !== false;
290
- return (_jsx("spriteNodeMaterial", Object.assign({ attach: attach !== null && attach !== void 0 ? attach : 'material', map: finalTexture !== null && finalTexture !== void 0 ? finalTexture : null, color: (_o = materialSource.color) !== null && _o !== void 0 ? _o : '#ffffff', opacity: (_p = materialSource.opacity) !== null && _p !== void 0 ? _p : 1, transparent: spriteTransparent, alphaTest: (_q = materialSource.alphaTest) !== null && _q !== void 0 ? _q : 0, depthTest: (_r = materialSource.depthTest) !== null && _r !== void 0 ? _r : false, depthWrite: (_s = materialSource.depthWrite) !== null && _s !== void 0 ? _s : false, toneMapped: (_t = materialSource.toneMapped) !== null && _t !== void 0 ? _t : true, onUpdate: material => {
289
+ return (_jsx("spriteNodeMaterial", Object.assign({ attach: attach !== null && attach !== void 0 ? attach : 'material', map: finalTexture !== null && finalTexture !== void 0 ? finalTexture : null, color: (_q = materialSource.color) !== null && _q !== void 0 ? _q : '#ffffff', opacity: (_r = materialSource.opacity) !== null && _r !== void 0 ? _r : 1, transparent: spriteTransparent, alphaTest: (_s = materialSource.alphaTest) !== null && _s !== void 0 ? _s : 0, depthTest: (_t = materialSource.depthTest) !== null && _t !== void 0 ? _t : false, depthWrite: (_u = materialSource.depthWrite) !== null && _u !== void 0 ? _u : false, toneMapped: (_v = materialSource.toneMapped) !== null && _v !== void 0 ? _v : true, onUpdate: material => {
291
290
  material.needsUpdate = true;
292
291
  } }, overrides, { rotation: rotation !== null && rotation !== void 0 ? rotation : 0, sizeAttenuation: sizeAttenuation !== null && sizeAttenuation !== void 0 ? sizeAttenuation : true }), materialKey));
293
292
  }
294
- return (_jsx("meshStandardNodeMaterial", Object.assign({ attach: attach !== null && attach !== void 0 ? attach : 'material' }, sharedProps, { normalMap: finalNormalMap !== null && finalNormalMap !== void 0 ? finalNormalMap : null, normalScale: finalNormalMap ? [(_u = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _u !== void 0 ? _u : 1, (_v = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _v !== void 0 ? _v : 1] : undefined }), materialKey));
293
+ return (_jsx("meshStandardNodeMaterial", Object.assign({ attach: attach !== null && attach !== void 0 ? attach : 'material' }, sharedProps, { normalMap: finalNormalMap !== null && finalNormalMap !== void 0 ? finalNormalMap : null, normalScale: finalNormalMap ? [(_w = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _w !== void 0 ? _w : 1, (_x = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _x !== void 0 ? _x : 1] : undefined }), materialKey));
295
294
  }
296
295
  const MaterialComponent = {
297
296
  name: 'Material',
@@ -4,8 +4,8 @@ import { useMemo } from 'react';
4
4
  import { Mesh } from 'three';
5
5
  import { assetRef, assetRefs } from './ComponentRegistry';
6
6
  import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput, StringField } from './Input';
7
- import { useAssetRuntime } from '../assetRuntime';
8
- import { useEditorContext, useEditorRef } from '../PrefabEditor';
7
+ import { useModelAsset } from '../assetRuntime';
8
+ import { useEditorContext, useEditorRef } from '../EditorContext';
9
9
  import { getRepeatAxesFromModelProperties, normalizeRepeatAxes } from '../InstanceProvider';
10
10
  import { base, colors, ui } from '../styles';
11
11
  import { decomposeModelToPrefabNodes } from '../modelPrefab';
@@ -89,8 +89,7 @@ function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
89
89
  }
90
90
  // View for Model component
91
91
  function ModelComponentView({ properties, children }) {
92
- const { getModel } = useAssetRuntime();
93
- const sourceModel = properties.filename ? getModel(properties.filename) : null;
92
+ const sourceModel = useModelAsset(properties.filename);
94
93
  // Clone model once and set up shadows - memoized to avoid cloning on every render
95
94
  const clonedModel = useMemo(() => {
96
95
  if (!sourceModel || !properties.filename || properties.instanced)
@@ -8,29 +8,43 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
11
- import { useEffect, useState } from 'react';
12
- import PrefabRoot from '../PrefabRoot';
13
- import { useEditorRef } from '../PrefabEditor';
11
+ import { lazy, Suspense, useEffect, useState } from 'react';
12
+ import { useEditorRef } from '../EditorContext';
14
13
  import { withBasePath } from '../utils';
15
14
  import { base, colors } from '../styles';
16
15
  import { FieldGroup, Label } from './Input';
16
+ const PrefabRoot = lazy(() => import('../PrefabRoot'));
17
+ function fetchJson(url) {
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ const response = yield fetch(url);
20
+ if (!response.ok) {
21
+ throw new Error(`Request failed (${response.status}) for ${url}`);
22
+ }
23
+ return response.json();
24
+ });
25
+ }
17
26
  function PrefabRefView({ properties, children, basePath = '' }) {
18
- var _a;
19
27
  const [loadedPrefab, setLoadedPrefab] = useState(null);
20
- const url = (_a = properties.url) !== null && _a !== void 0 ? _a : '';
21
- const resolvedUrl = url ? withBasePath(basePath, url) : '';
28
+ const resolvedUrl = properties.url ? withBasePath(basePath, properties.url) : '';
22
29
  useEffect(() => {
23
- if (!resolvedUrl)
30
+ if (!resolvedUrl) {
31
+ setLoadedPrefab(null);
24
32
  return;
33
+ }
25
34
  let cancelled = false;
26
- fetch(resolvedUrl)
27
- .then(r => r.json())
28
- .then(data => { if (!cancelled)
29
- setLoadedPrefab(data); })
30
- .catch(err => console.warn('[PrefabRef] Failed to load:', resolvedUrl, err));
35
+ void fetchJson(resolvedUrl)
36
+ .then((data) => {
37
+ if (!cancelled)
38
+ setLoadedPrefab(data);
39
+ })
40
+ .catch((err) => {
41
+ if (!cancelled)
42
+ setLoadedPrefab(null);
43
+ console.warn('[PrefabRef] Failed to load:', resolvedUrl, err);
44
+ });
31
45
  return () => { cancelled = true; };
32
46
  }, [resolvedUrl]);
33
- return (_jsxs(_Fragment, { children: [loadedPrefab && _jsx(PrefabRoot, { data: loadedPrefab, editMode: false, basePath: basePath }), children] }));
47
+ return (_jsxs(_Fragment, { children: [loadedPrefab && (_jsx(Suspense, { fallback: null, children: _jsx(PrefabRoot, { data: loadedPrefab, editMode: false, basePath: basePath }) })), children] }));
34
48
  }
35
49
  function PrefabRefEditor({ node, component, onUpdate, basePath = '', }) {
36
50
  var _a, _b;
@@ -39,17 +53,27 @@ function PrefabRefEditor({ node, component, onUpdate, basePath = '', }) {
39
53
  const [unpacking, setUnpacking] = useState(false);
40
54
  const editor = useEditorRef();
41
55
  useEffect(() => {
42
- fetch(withBasePath(basePath, '/prefabs/manifest.json'))
43
- .then(r => r.json())
44
- .then(data => setManifest(data))
45
- .catch(() => setManifest([]));
46
- }, []);
56
+ let cancelled = false;
57
+ void fetchJson(withBasePath(basePath, '/prefabs/manifest.json'))
58
+ .then((data) => {
59
+ if (cancelled)
60
+ return;
61
+ setManifest(Array.isArray(data) ? data.filter((entry) => typeof entry === 'string') : []);
62
+ })
63
+ .catch(() => {
64
+ if (!cancelled)
65
+ setManifest([]);
66
+ });
67
+ return () => {
68
+ cancelled = true;
69
+ };
70
+ }, [basePath]);
47
71
  const handleUnpack = () => __awaiter(this, void 0, void 0, function* () {
48
72
  if (!node || !url)
49
73
  return;
50
74
  setUnpacking(true);
51
75
  try {
52
- const prefab = yield fetch(withBasePath(basePath, url)).then(r => r.json());
76
+ const prefab = yield fetchJson(withBasePath(basePath, url));
53
77
  editor.replaceNode(node.id, prefab.root);
54
78
  }
55
79
  catch (err) {
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useEffect, useRef } from 'react';
3
3
  import { useThree } from '@react-three/fiber';
4
4
  import { SoundPicker } from '../../assetviewer/page';
5
- import { useAssetRuntime, useNode } from '../assetRuntime';
5
+ import { useAssetRevision, useAssetRuntime, useNode } from '../assetRuntime';
6
6
  import { gameEvents } from '../GameEvents';
7
7
  import { BooleanField, FieldGroup, FieldRenderer, ListEditor, NumberField, SelectField, StringField } from './Input';
8
8
  import { colors, ui } from '../styles';
@@ -124,6 +124,7 @@ function SoundComponentEditor({ component, onUpdate, basePath = '' }) {
124
124
  }
125
125
  function SoundComponentView({ properties, children }) {
126
126
  const { getSound } = useAssetRuntime();
127
+ const assetRevision = useAssetRevision();
127
128
  const { editMode, nodeId } = useNode();
128
129
  const { camera } = useThree();
129
130
  const { eventName, autoplay = false, positional = false, refDistance = 1, maxDistance = 24, rolloffFactor = 1, distanceModel = 'inverse' } = properties;
@@ -180,6 +181,9 @@ function SoundComponentView({ properties, children }) {
180
181
  });
181
182
  }, [editMode, eventName, getSound, mode, nodeId, paths, properties]);
182
183
  useEffect(() => {
184
+ // Re-run when assets load so autoplay can start once the buffer is ready
185
+ // (the asset runtime context is now stable and no longer re-renders on load).
186
+ void assetRevision;
183
187
  if (editMode || !autoplay || paths.length === 0) {
184
188
  return;
185
189
  }
@@ -198,7 +202,7 @@ function SoundComponentView({ properties, children }) {
198
202
  audio.stop();
199
203
  }
200
204
  };
201
- }, [autoplay, editMode, getSound, mode, paths, properties]);
205
+ }, [autoplay, editMode, getSound, mode, paths, properties, assetRevision]);
202
206
  return (_jsxs(_Fragment, { children: [listenerRef.current ? _jsx("positionalAudio", { ref: positionalAudioRef, args: [listenerRef.current] }) : null, children] }));
203
207
  }
204
208
  const SoundComponent = {
@@ -4,7 +4,7 @@ import { useHelper } from "@react-three/drei";
4
4
  import { useRef } from "react";
5
5
  import { BooleanField, ColorField, Label, NumberField, Vector3Input } from "./Input";
6
6
  import { SpotLightHelper } from "three";
7
- import { useAssetRuntime, useNode } from "../assetRuntime";
7
+ import { useTextureAsset, useNode } from "../assetRuntime";
8
8
  import { TexturePicker } from "../../assetviewer/page";
9
9
  import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
10
10
  const spotLightDefaults = {
@@ -30,12 +30,9 @@ function SpotLightComponentEditor({ component, onUpdate, basePath = "" }) {
30
30
  }
31
31
  function SpotLightView({ properties, children }) {
32
32
  var _a, _b;
33
- const { getTexture } = useAssetRuntime();
34
33
  const { editMode, isSelected } = useNode();
35
34
  const merged = mergeWithDefaults(spotLightDefaults, properties);
36
- const textureMap = merged.map
37
- ? (_a = getTexture(merged.map)) !== null && _a !== void 0 ? _a : undefined
38
- : undefined;
35
+ const textureMap = (_a = useTextureAsset(merged.map)) !== null && _a !== void 0 ? _a : undefined;
39
36
  const lightProps = {
40
37
  color: merged.color,
41
38
  intensity: merged.intensity,
@@ -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 "../PrefabEditor";
3
+ import { useEditorContext } from "../EditorContext";
4
4
  import { colors } from "../styles";
5
5
  const buttonStyle = {
6
6
  padding: '2px 6px',
@@ -1 +1,2 @@
1
1
  export declare const builtinComponents: import("./ComponentRegistry").Component[];
2
+ export declare function registerBuiltinComponents(): void;
@@ -15,6 +15,7 @@ import EnvironmentComponent from "./EnvironmentComponent";
15
15
  import CameraComponent from "./CameraComponent";
16
16
  import SoundComponent from "./SoundComponent";
17
17
  import DataComponent from "./DataComponent";
18
+ import { registerComponent } from "./ComponentRegistry";
18
19
  // this controls the order of components in the editor, and also which components are available to add
19
20
  export const builtinComponents = [
20
21
  TransformComponent,
@@ -38,3 +39,10 @@ export const builtinComponents = [
38
39
  DataComponent,
39
40
  PrefabRefComponent,
40
41
  ];
42
+ let didRegisterBuiltinComponents = false;
43
+ export function registerBuiltinComponents() {
44
+ if (didRegisterBuiltinComponents)
45
+ return;
46
+ builtinComponents.forEach(registerComponent);
47
+ didRegisterBuiltinComponents = true;
48
+ }
@@ -3,11 +3,11 @@ export declare function mergeWithDefaults<T extends Record<string, any>>(default
3
3
  export declare function LightSection({ title, children }: {
4
4
  title: string;
5
5
  children: ReactNode;
6
- }): import("react/jsx-runtime").JSX.Element;
6
+ }): import("react").JSX.Element;
7
7
  export declare function ShadowBiasField({ name, label, values, onChange, fallback, }: {
8
8
  name: string;
9
9
  label: string;
10
10
  values: Record<string, any>;
11
11
  onChange: (values: Record<string, any>) => void;
12
12
  fallback?: number;
13
- }): import("react/jsx-runtime").JSX.Element;
13
+ }): import("react").JSX.Element;
@@ -4,6 +4,7 @@ import { GameObject, Prefab } from "./types";
4
4
  import { denormalizePrefab, PrefabState, PrefabNodeRecord } from "./prefab";
5
5
  export interface PrefabStoreState extends PrefabState {
6
6
  replacePrefab: (prefab: Prefab) => void;
7
+ restoreState: (snapshot: PrefabState) => void;
7
8
  updateNode: (id: string, update: (node: PrefabNodeRecord) => PrefabNodeRecord) => void;
8
9
  replaceNode: (id: string, node: GameObject) => void;
9
10
  addChild: (parentId: string, node: GameObject) => void;
@@ -15,7 +16,7 @@ export type PrefabStoreApi = StoreApi<PrefabStoreState>;
15
16
  export declare function PrefabStoreProvider({ store, children, }: {
16
17
  store: PrefabStoreApi;
17
18
  children: ReactNode;
18
- }): import("react").FunctionComponentElement<import("react").ProviderProps<PrefabStoreApi | null>>;
19
+ }): import("react").FunctionComponentElement<import("react").FragmentProps> | import("react").FunctionComponentElement<import("react").ProviderProps<PrefabStoreApi | null>>;
19
20
  export declare function usePrefabStoreApi(): PrefabStoreApi;
20
21
  export declare function usePrefabStore<T>(selector: (state: PrefabStoreState) => T): T;
21
22
  export declare function usePrefabRootId(): string;
@@ -1,4 +1,4 @@
1
- import { createContext, createElement, useContext } from "react";
1
+ import { Fragment, createContext, createElement, useContext } from "react";
2
2
  import { subscribeWithSelector } from "zustand/middleware";
3
3
  import { useStore } from "zustand";
4
4
  import { createStore } from "zustand/vanilla";
@@ -45,6 +45,10 @@ function insertSubtreeIntoGraph(node, parentId, next) {
45
45
  addAssetRefs(next.assetRefCounts, collectSubtreeAssetRefs(node));
46
46
  }
47
47
  export function PrefabStoreProvider({ store, children, }) {
48
+ const parentStore = useContext(PrefabStoreContext);
49
+ if (parentStore === store) {
50
+ return createElement(Fragment, null, children);
51
+ }
48
52
  return createElement(PrefabStoreContext.Provider, { value: store }, children);
49
53
  }
50
54
  export function usePrefabStoreApi() {
@@ -69,6 +73,17 @@ export function usePrefabChildIds(nodeId) {
69
73
  export function createPrefabStore(prefab) {
70
74
  return createStore()(subscribeWithSelector((set, get) => (Object.assign(Object.assign({}, normalizePrefab(prefab)), { replacePrefab: (nextPrefab) => {
71
75
  set(normalizePrefab(nextPrefab));
76
+ }, restoreState: (snapshot) => {
77
+ set({
78
+ prefabId: snapshot.prefabId,
79
+ prefabName: snapshot.prefabName,
80
+ rootId: snapshot.rootId,
81
+ nodesById: snapshot.nodesById,
82
+ childIdsById: snapshot.childIdsById,
83
+ parentIdById: snapshot.parentIdById,
84
+ assetManifestKey: snapshot.assetManifestKey,
85
+ assetRefCounts: snapshot.assetRefCounts,
86
+ });
72
87
  }, updateNode: (id, update) => {
73
88
  const state = get();
74
89
  const node = state.nodesById[id];
@@ -0,0 +1,10 @@
1
+ import { Matrix4 } from "three";
2
+ export declare function isExternalPath(path: string): boolean;
3
+ export declare function withBasePath(basePath: string | undefined, path: string): string;
4
+ export declare function decompose(m: Matrix4): {
5
+ position: [number, number, number];
6
+ rotation: [number, number, number];
7
+ scale: [number, number, number];
8
+ };
9
+ /** Build a local Matrix4 from position/rotation/scale arrays. */
10
+ export declare function composeTransform(position?: [number, number, number], rotation?: [number, number, number], scale?: [number, number, number]): Matrix4;
@@ -0,0 +1,30 @@
1
+ import { Euler, Matrix4, Quaternion, Vector3 } from "three";
2
+ export function isExternalPath(path) {
3
+ return (path.startsWith("data:") ||
4
+ path.startsWith("http://") ||
5
+ path.startsWith("https://"));
6
+ }
7
+ export function withBasePath(basePath, path) {
8
+ if (!path)
9
+ return (basePath !== null && basePath !== void 0 ? basePath : "").replace(/\/$/, "");
10
+ if (isExternalPath(path))
11
+ return path;
12
+ const normalizedBasePath = (basePath !== null && basePath !== void 0 ? basePath : "").replace(/\/$/, "");
13
+ return path.startsWith("/") ? `${normalizedBasePath}${path}` : `${normalizedBasePath}/${path}`;
14
+ }
15
+ export function decompose(m) {
16
+ const p = new Vector3();
17
+ const q = new Quaternion();
18
+ const s = new Vector3();
19
+ m.decompose(p, q, s);
20
+ const e = new Euler().setFromQuaternion(q);
21
+ return {
22
+ position: [p.x, p.y, p.z],
23
+ rotation: [e.x, e.y, e.z],
24
+ scale: [s.x, s.y, s.z],
25
+ };
26
+ }
27
+ /** Build a local Matrix4 from position/rotation/scale arrays. */
28
+ export function composeTransform(position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1]) {
29
+ return new Matrix4().compose(new Vector3(...position), new Quaternion().setFromEuler(new Euler(...rotation)), new Vector3(...scale));
30
+ }
@@ -1,7 +1,6 @@
1
1
  import { GameObject, Prefab } from "./types";
2
2
  import { Matrix4, Object3D, Vector3 } from "three";
3
- export declare function isExternalPath(path: string): boolean;
4
- export declare function withBasePath(basePath: string | undefined, path: string): string;
3
+ export { composeTransform, decompose, isExternalPath, withBasePath } from "./runtimeUtils";
5
4
  export interface ExportGLBOptions {
6
5
  filename?: string;
7
6
  }
@@ -23,13 +22,6 @@ export declare function exportGLBData(sceneRoot: Object3D): Promise<ArrayBuffer>
23
22
  */
24
23
  export declare function exportGLB(sceneRoot: Object3D, options?: ExportGLBOptions): Promise<ArrayBuffer>;
25
24
  export declare function focusCameraOnObject(object: Object3D, camera: Object3D, target: Vector3, update?: () => void): void;
26
- export declare function decompose(m: Matrix4): {
27
- position: [number, number, number];
28
- rotation: [number, number, number];
29
- scale: [number, number, number];
30
- };
31
- /** Build a local Matrix4 from position/rotation/scale arrays. */
32
- export declare function composeTransform(position?: [number, number, number], rotation?: [number, number, number], scale?: [number, number, number]): Matrix4;
33
25
  /** Compute the parent world matrix for a node using the normalized store data */
34
26
  export declare function computeParentWorldMatrix(state: {
35
27
  nodesById: Record<string, {
@@ -8,21 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { findComponent } from "./types";
11
+ import { composeTransform } from "./runtimeUtils";
11
12
  import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter.js";
12
- import { Box3, Euler, Matrix4, PerspectiveCamera, Quaternion, Vector3, } from "three";
13
- export function isExternalPath(path) {
14
- return (path.startsWith("data:") ||
15
- path.startsWith("http://") ||
16
- path.startsWith("https://"));
17
- }
18
- export function withBasePath(basePath, path) {
19
- if (!path)
20
- return (basePath !== null && basePath !== void 0 ? basePath : "").replace(/\/$/, "");
21
- if (isExternalPath(path))
22
- return path;
23
- const normalizedBasePath = (basePath !== null && basePath !== void 0 ? basePath : "").replace(/\/$/, "");
24
- return path.startsWith("/") ? `${normalizedBasePath}${path}` : `${normalizedBasePath}/${path}`;
25
- }
13
+ import { Box3, Matrix4, PerspectiveCamera, Quaternion, Vector3, } from "three";
14
+ export { composeTransform, decompose, isExternalPath, withBasePath } from "./runtimeUtils";
26
15
  /** Save scene JSON, showing a Save As dialog when supported */
27
16
  export function saveJson(data, filename) {
28
17
  return __awaiter(this, void 0, void 0, function* () {
@@ -172,20 +161,6 @@ export function focusCameraOnObject(object, camera, target, update) {
172
161
  target.copy(center);
173
162
  update === null || update === void 0 ? void 0 : update();
174
163
  }
175
- export function decompose(m) {
176
- const p = new Vector3(), q = new Quaternion(), s = new Vector3();
177
- m.decompose(p, q, s);
178
- const e = new Euler().setFromQuaternion(q);
179
- return {
180
- position: [p.x, p.y, p.z],
181
- rotation: [e.x, e.y, e.z],
182
- scale: [s.x, s.y, s.z],
183
- };
184
- }
185
- /** Build a local Matrix4 from position/rotation/scale arrays. */
186
- export function composeTransform(position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1]) {
187
- return new Matrix4().compose(new Vector3(...position), new Quaternion().setFromEuler(new Euler(...rotation)), new Vector3(...scale));
188
- }
189
164
  /** Compute the parent world matrix for a node using the normalized store data */
190
165
  export function computeParentWorldMatrix(state, targetId) {
191
166
  var _a;
@@ -0,0 +1,21 @@
1
+ export { default as GameCanvas } from "./shared/GameCanvas";
2
+ export type { GameCanvasProps } from "./shared/GameCanvas";
3
+ export { ground } from "./helpers";
4
+ export type { GroundOptions, Vec3 } from "./helpers";
5
+ export { sound as soundManager } from "./helpers/SoundManager";
6
+ export { default as PrefabRoot } from "./tools/prefabeditor/PrefabRoot";
7
+ export type { PrefabRootProps } from "./tools/prefabeditor/PrefabRoot";
8
+ export { PrefabEditorMode, SceneContext, useScene, } from "./tools/prefabeditor/SceneContext";
9
+ export type { PrefabNode, Scene } from "./tools/prefabeditor/SceneContext";
10
+ export { SceneProvider } from "./tools/prefabeditor/SceneProvider";
11
+ export type { AssetRuntime, NodeApi, LiveRef, } from "./tools/prefabeditor/assetRuntime";
12
+ export { useAssetRuntime, useNode, useNodeHandle, useNodeObject, AssetRuntimeProvider, } from "./tools/prefabeditor/assetRuntime";
13
+ export { gameEvents, useClickEvent, useGameEvent, } from "./tools/prefabeditor/GameEvents";
14
+ export type { ClickEventPayload, ContactEventPayload, GameEventHandler, GameEventMap, } from "./tools/prefabeditor/GameEvents";
15
+ export { registerComponent } from "./tools/prefabeditor/components/ComponentRegistry";
16
+ export type { Component, ComponentViewProps, } from "./tools/prefabeditor/components/ComponentRegistry";
17
+ export { denormalizePrefab, createModelNode, createImageNode, } from "./tools/prefabeditor/prefab";
18
+ export type { Prefab, GameObject, ComponentData, } from "./tools/prefabeditor/types";
19
+ export { findComponent, findComponentEntry, hasComponent, } from "./tools/prefabeditor/types";
20
+ export { loadModel, loadSound, loadTexture, } from "./tools/dragdrop/modelLoader";
21
+ export type { LoadedModel, LoadedModels, ModelLoadResult, LoadedSound, LoadedSounds, SoundLoadResult, LoadedTexture, LoadedTextures, TextureLoadResult, ProgressCallback, } from "./tools/dragdrop/modelLoader";