react-three-game 0.0.93 → 0.0.95

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 (28) hide show
  1. package/README.md +35 -77
  2. package/dist/index.d.ts +9 -6
  3. package/dist/index.js +5 -3
  4. package/dist/tools/prefabeditor/EditorTree.js +8 -12
  5. package/dist/tools/prefabeditor/EditorUI.js +4 -4
  6. package/dist/tools/prefabeditor/PrefabEditor.d.ts +12 -33
  7. package/dist/tools/prefabeditor/PrefabEditor.js +137 -161
  8. package/dist/tools/prefabeditor/PrefabRoot.d.ts +24 -12
  9. package/dist/tools/prefabeditor/PrefabRoot.js +117 -59
  10. package/dist/tools/prefabeditor/assetRuntime.d.ts +11 -17
  11. package/dist/tools/prefabeditor/assetRuntime.js +15 -15
  12. package/dist/tools/prefabeditor/components/CameraComponent.js +2 -2
  13. package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +2 -2
  14. package/dist/tools/prefabeditor/components/Input.js +5 -9
  15. package/dist/tools/prefabeditor/components/MaterialComponent.d.ts +5 -2
  16. package/dist/tools/prefabeditor/components/MaterialComponent.js +40 -24
  17. package/dist/tools/prefabeditor/components/ModelComponent.js +3 -5
  18. package/dist/tools/prefabeditor/components/PointLightComponent.js +2 -2
  19. package/dist/tools/prefabeditor/components/SoundComponent.js +2 -2
  20. package/dist/tools/prefabeditor/components/SpotLightComponent.js +2 -2
  21. package/dist/tools/prefabeditor/components/SpriteComponent.d.ts +8 -0
  22. package/dist/tools/prefabeditor/components/SpriteComponent.js +27 -0
  23. package/dist/tools/prefabeditor/components/index.js +22 -14
  24. package/dist/tools/prefabeditor/prefab.d.ts +1 -2
  25. package/dist/tools/prefabeditor/prefab.js +2 -3
  26. package/dist/tools/prefabeditor/prefabStore.d.ts +0 -6
  27. package/dist/tools/prefabeditor/prefabStore.js +1 -33
  28. package/package.json +49 -49
@@ -15,7 +15,7 @@ import { extend } from '@react-three/fiber';
15
15
  import { useFrame } from '@react-three/fiber';
16
16
  import { FieldRenderer, Label, NumberInput } from './Input';
17
17
  import { useAssetRuntime } from '../assetRuntime';
18
- import { MeshBasicNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
18
+ import { MeshBasicNodeMaterial, MeshStandardNodeMaterial, SpriteNodeMaterial } from 'three/webgpu';
19
19
  import { TexturePicker } from '../../assetviewer/page';
20
20
  import { RepeatWrapping, ClampToEdgeWrapping, SRGBColorSpace, LinearSRGBColorSpace, NearestFilter, LinearFilter, NearestMipmapNearestFilter, NearestMipmapLinearFilter, LinearMipmapNearestFilter, LinearMipmapLinearFilter, FrontSide, BackSide, DoubleSide, } from 'three';
21
21
  function Vector2Editor({ label, value, onChange, min, max, step, }) {
@@ -35,6 +35,7 @@ export function MaterialOverridesProvider({ overrides, children, }) {
35
35
  extend({
36
36
  MeshBasicNodeMaterial,
37
37
  MeshStandardNodeMaterial,
38
+ SpriteNodeMaterial,
38
39
  });
39
40
  function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
40
41
  var _a;
@@ -43,6 +44,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
43
44
  const hasRepeat = component.properties.repeat;
44
45
  const animateOffset = component.properties.animateOffset;
45
46
  const isStandardMaterial = materialType === 'standard';
47
+ const isSpriteMaterial = materialType === 'sprite';
46
48
  const fields = [
47
49
  {
48
50
  name: 'materialType',
@@ -51,13 +53,22 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
51
53
  options: [
52
54
  { value: 'standard', label: 'Standard' },
53
55
  { value: 'basic', label: 'Basic' },
56
+ { value: 'sprite', label: 'Sprite' },
54
57
  ],
55
58
  },
56
59
  { name: 'color', type: 'color', label: 'Color' },
57
60
  { name: 'toneMapped', type: 'boolean', label: 'Tone Mapped' },
58
- { name: 'wireframe', type: 'boolean', label: 'Wireframe' },
61
+ ...(!isSpriteMaterial ? [
62
+ { name: 'wireframe', type: 'boolean', label: 'Wireframe' },
63
+ ] : []),
59
64
  { name: 'transparent', type: 'boolean', label: 'Transparent' },
60
65
  { name: 'opacity', type: 'number', label: 'Opacity', min: 0, max: 1, step: 0.01 },
66
+ ...(isSpriteMaterial ? [
67
+ { name: 'rotation', type: 'number', label: 'Rotation', step: 0.01 },
68
+ { name: 'sizeAttenuation', type: 'boolean', label: 'Size Attenuation' },
69
+ { name: 'depthTest', type: 'boolean', label: 'Depth Test' },
70
+ { name: 'depthWrite', type: 'boolean', label: 'Depth Write' },
71
+ ] : []),
61
72
  ...(isStandardMaterial ? [
62
73
  { name: 'metalness', type: 'number', label: 'Metalness', min: 0, max: 1, step: 0.01 },
63
74
  { name: 'roughness', type: 'number', label: 'Roughness', min: 0, max: 1, step: 0.01 },
@@ -65,16 +76,16 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
65
76
  { name: 'thickness', type: 'number', label: 'Thickness', min: 0, step: 0.1 },
66
77
  { name: 'ior', type: 'number', label: 'IOR (Index of Refraction)', min: 1, max: 2.333, step: 0.01 },
67
78
  ] : []),
68
- {
69
- name: 'side',
70
- type: 'select',
71
- label: 'Side',
72
- options: [
73
- { value: 'FrontSide', label: 'Front' },
74
- { value: 'BackSide', label: 'Back' },
75
- { value: 'DoubleSide', label: 'Double' },
76
- ],
77
- },
79
+ ...(!isSpriteMaterial ? [{
80
+ name: 'side',
81
+ type: 'select',
82
+ label: 'Side',
83
+ options: [
84
+ { value: 'FrontSide', label: 'Front' },
85
+ { value: 'BackSide', label: 'Back' },
86
+ { value: 'DoubleSide', label: 'Double' },
87
+ ],
88
+ }] : []),
78
89
  {
79
90
  name: 'texture',
80
91
  type: 'custom',
@@ -103,13 +114,13 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
103
114
  label: 'Speed (X, Y)',
104
115
  render: ({ value, onChange }) => (_jsx(Vector2Editor, { label: "Speed", value: value, onChange: onChange, step: 0.01 })),
105
116
  }] : []),
106
- {
107
- name: 'normalMapTexture',
108
- type: 'custom',
109
- label: 'Normal Map',
110
- render: ({ value, onChange }) => (_jsx(TexturePicker, { value: value, onChange: onChange, basePath: basePath })),
111
- },
112
- ...(component.properties.normalMapTexture ? [{
117
+ ...(!isSpriteMaterial ? [{
118
+ name: 'normalMapTexture',
119
+ type: 'custom',
120
+ label: 'Normal Map',
121
+ render: ({ value, onChange }) => (_jsx(TexturePicker, { value: value, onChange: onChange, basePath: basePath })),
122
+ }] : []),
123
+ ...(!isSpriteMaterial && component.properties.normalMapTexture ? [{
113
124
  name: 'normalScale',
114
125
  type: 'custom',
115
126
  label: 'Normal Scale (X, Y)',
@@ -144,7 +155,7 @@ function MaterialComponentEditor({ component, onUpdate, basePath = "" }) {
144
155
  }
145
156
  // View for Material component
146
157
  function MaterialComponentView({ properties: rawProps }) {
147
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
158
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
148
159
  const { getTexture } = useAssetRuntime();
149
160
  const properties = rawProps;
150
161
  const materialType = (_a = properties === null || properties === void 0 ? void 0 : properties.materialType) !== null && _a !== void 0 ? _a : 'standard';
@@ -163,7 +174,7 @@ function MaterialComponentView({ properties: rawProps }) {
163
174
  const normalMapTexture = normalMapTextureName ? (_c = getTexture(normalMapTextureName)) !== null && _c !== void 0 ? _c : undefined : undefined;
164
175
  const materialSource = properties !== null && properties !== void 0 ? properties : {};
165
176
  // Destructure all material props and separate custom texture handling props
166
- const { texture: _texture, offset: _offset, repeat: _repeat, repeatCount: _repeatCount, animateOffset: _animateOffset, offsetSpeed: _offsetSpeed, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, normalMapTexture: _normalMapTexture, normalScale: _normalScale, normalMap: _normalMap, side: sideProp } = materialSource, materialProps = __rest(materialSource, ["texture", "offset", "repeat", "repeatCount", "animateOffset", "offsetSpeed", "generateMipmaps", "minFilter", "magFilter", "map", "materialType", "normalMapTexture", "normalScale", "normalMap", "side"]);
177
+ const { texture: _texture, offset: _offset, repeat: _repeat, repeatCount: _repeatCount, animateOffset: _animateOffset, offsetSpeed: _offsetSpeed, generateMipmaps: _generateMipmaps, minFilter: _minFilter, magFilter: _magFilter, map: _map, materialType: _materialType, 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", "normalMapTexture", "normalScale", "normalMap", "rotation", "sizeAttenuation", "side"]);
167
178
  const sideMap = { FrontSide, BackSide, DoubleSide };
168
179
  const resolvedSide = sideProp ? ((_d = sideMap[sideProp]) !== null && _d !== void 0 ? _d : FrontSide) : FrontSide;
169
180
  const minFilterMap = {
@@ -220,14 +231,18 @@ function MaterialComponentView({ properties: rawProps }) {
220
231
  return t;
221
232
  }, [normalMapTexture]);
222
233
  if (!properties) {
223
- return _jsx("meshStandardNodeMaterial", { color: "red", wireframe: true });
234
+ return _jsx("meshStandardNodeMaterial", { attach: "material", color: "red", wireframe: true });
224
235
  }
225
236
  const overrides = useMaterialOverrides();
226
237
  const sharedProps = Object.assign(Object.assign({ map: finalTexture, side: resolvedSide }, materialProps), overrides);
227
238
  if (materialType === 'basic') {
228
- return _jsx("meshBasicNodeMaterial", Object.assign({}, sharedProps));
239
+ return _jsx("meshBasicNodeMaterial", Object.assign({ attach: "material" }, sharedProps));
240
+ }
241
+ if (materialType === 'sprite') {
242
+ const spriteTransparent = properties.transparent !== false;
243
+ return (_jsx("spriteNodeMaterial", Object.assign({ attach: "material", map: finalTexture, color: (_j = properties.color) !== null && _j !== void 0 ? _j : '#ffffff', opacity: (_k = properties.opacity) !== null && _k !== void 0 ? _k : 1, transparent: spriteTransparent, alphaTest: (_l = properties.alphaTest) !== null && _l !== void 0 ? _l : 0, depthTest: (_m = properties.depthTest) !== null && _m !== void 0 ? _m : false, depthWrite: (_o = properties.depthWrite) !== null && _o !== void 0 ? _o : false, toneMapped: (_p = properties.toneMapped) !== null && _p !== void 0 ? _p : true }, overrides, { rotation: rotation !== null && rotation !== void 0 ? rotation : 0, sizeAttenuation: sizeAttenuation !== null && sizeAttenuation !== void 0 ? sizeAttenuation : true })));
229
244
  }
230
- return (_jsx("meshStandardNodeMaterial", Object.assign({}, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(_j = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _j !== void 0 ? _j : 1, (_k = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _k !== void 0 ? _k : 1] : undefined })));
245
+ return (_jsx("meshStandardNodeMaterial", Object.assign({ attach: "material" }, sharedProps, { normalMap: finalNormalMap, normalScale: finalNormalMap ? [(_q = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[0]) !== null && _q !== void 0 ? _q : 1, (_r = normalScaleProp === null || normalScaleProp === void 0 ? void 0 : normalScaleProp[1]) !== null && _r !== void 0 ? _r : 1] : undefined })));
231
246
  }
232
247
  const MaterialComponent = {
233
248
  name: 'Material',
@@ -240,6 +255,7 @@ const MaterialComponent = {
240
255
  wireframe: false,
241
256
  transparent: false,
242
257
  opacity: 1,
258
+ sizeAttenuation: true,
243
259
  offset: [0, 0],
244
260
  animateOffset: false,
245
261
  offsetSpeed: [0, 0],
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { ModelPicker } from '../../assetviewer/page';
3
- import { useContext, useMemo } from 'react';
3
+ import { useMemo } from 'react';
4
4
  import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput, StringField } from './Input';
5
5
  import { useAssetRuntime } from '../assetRuntime';
6
- import { EditorContext } from '../PrefabEditor';
6
+ import { useEditorContext } from '../PrefabEditor';
7
7
  import { getRepeatAxesFromModelProperties, normalizeRepeatAxes } from '../InstanceProvider';
8
8
  import { colors, ui } from '../styles';
9
9
  const AXIS_OPTIONS = [
@@ -39,9 +39,7 @@ function RepeatAxisEditor({ axes, onChange, positionSnap, }) {
39
39
  } }));
40
40
  }
41
41
  function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
42
- var _a;
43
- const editorContext = useContext(EditorContext);
44
- const positionSnap = (_a = editorContext === null || editorContext === void 0 ? void 0 : editorContext.positionSnap) !== null && _a !== void 0 ? _a : 0.5;
42
+ const { positionSnap } = useEditorContext();
45
43
  const repeatAxes = getRepeatAxesFromModelProperties(component.properties);
46
44
  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: "emitClickEvent", label: "Emit Click Event", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: component.properties, onChange: onUpdate, placeholder: "node:click" })) : null] })) : null, 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 }))] }))] }));
47
45
  }
@@ -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 { useHelper } from '@react-three/drei';
4
4
  import { PointLightHelper } from 'three';
5
- import { useCurrentNode } from '../assetRuntime';
5
+ import { useNode } from '../assetRuntime';
6
6
  import { BooleanField, ColorField, NumberField } from './Input';
7
7
  import { LightSection, ShadowBiasField, mergeWithDefaults } from './lightUtils';
8
8
  const pointLightDefaults = {
@@ -23,7 +23,7 @@ function PointLightComponentEditor({ component, onUpdate }) {
23
23
  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] })] }));
24
24
  }
25
25
  function PointLightView({ properties, children }) {
26
- const { editMode, isSelected } = useCurrentNode();
26
+ const { editMode, isSelected } = useNode();
27
27
  const merged = mergeWithDefaults(pointLightDefaults, properties);
28
28
  const color = merged.color;
29
29
  const intensity = merged.intensity;
@@ -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, useCurrentNode } from '../assetRuntime';
5
+ import { 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,7 +124,7 @@ function SoundComponentEditor({ component, onUpdate, basePath = '' }) {
124
124
  }
125
125
  function SoundComponentView({ properties, children }) {
126
126
  const { getSound } = useAssetRuntime();
127
- const { editMode, nodeId } = useCurrentNode();
127
+ const { editMode, nodeId } = useNode();
128
128
  const { camera } = useThree();
129
129
  const { eventName, autoplay = false, positional = false, refDistance = 1, maxDistance = 24, rolloffFactor = 1, distanceModel = 'inverse' } = properties;
130
130
  const sequenceIndexRef = useRef(0);
@@ -3,7 +3,7 @@ import { useHelper } from "@react-three/drei";
3
3
  import { useRef, useEffect } from "react";
4
4
  import { BooleanField, ColorField, Label, NumberField, Vector3Input } from "./Input";
5
5
  import { SpotLightHelper } from "three";
6
- import { useAssetRuntime, useCurrentNode } from "../assetRuntime";
6
+ import { useAssetRuntime, useNode } from "../assetRuntime";
7
7
  import { useFrame } from "@react-three/fiber";
8
8
  import { TexturePicker } from "../../assetviewer/page";
9
9
  import { LightSection, ShadowBiasField, mergeWithDefaults } from "./lightUtils";
@@ -31,7 +31,7 @@ function SpotLightComponentEditor({ component, onUpdate, basePath = "" }) {
31
31
  function SpotLightView({ properties, children }) {
32
32
  var _a;
33
33
  const { getTexture } = useAssetRuntime();
34
- const { editMode, isSelected } = useCurrentNode();
34
+ const { editMode, isSelected } = useNode();
35
35
  const merged = mergeWithDefaults(spotLightDefaults, properties);
36
36
  const color = merged.color;
37
37
  const intensity = merged.intensity;
@@ -0,0 +1,8 @@
1
+ import type { Component } from './ComponentRegistry';
2
+ export interface SpriteProps {
3
+ center?: [number, number];
4
+ emitClickEvent?: boolean;
5
+ clickEventName?: string;
6
+ }
7
+ declare const SpriteComponent: Component;
8
+ export default SpriteComponent;
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { BooleanField, FieldRenderer, NumberInput, StringField } from './Input';
3
+ function Vector2Editor({ value, onChange, min, max, step, }) {
4
+ var _a, _b;
5
+ return (_jsxs("div", { style: { display: 'flex', gap: 2 }, children: [_jsx(NumberInput, { value: (_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, onChange: x => { var _a; return onChange([x, (_a = value === null || value === void 0 ? void 0 : value[1]) !== null && _a !== void 0 ? _a : 0]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } }), _jsx(NumberInput, { value: (_b = value === null || value === void 0 ? void 0 : value[1]) !== null && _b !== void 0 ? _b : 0, onChange: y => { var _a; return onChange([(_a = value === null || value === void 0 ? void 0 : value[0]) !== null && _a !== void 0 ? _a : 0, y]); }, min: min, max: max, step: step, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }));
6
+ }
7
+ function SpriteComponentEditor({ component, onUpdate, }) {
8
+ const fields = [
9
+ {
10
+ name: 'center',
11
+ type: 'custom',
12
+ label: 'Center',
13
+ render: ({ value, onChange }) => (_jsx(Vector2Editor, { value: value, onChange: onChange, min: 0, max: 1, step: 0.01 })),
14
+ },
15
+ ];
16
+ return (_jsxs(_Fragment, { children: [_jsx(FieldRenderer, { fields: fields, values: component.properties, onChange: onUpdate }), _jsxs("div", { style: { marginTop: 8 }, children: [_jsx(BooleanField, { name: "emitClickEvent", label: "Emit Click Event", values: component.properties, onChange: onUpdate, fallback: false }), component.properties.emitClickEvent ? (_jsx(StringField, { name: "clickEventName", label: "Click Event Name", values: component.properties, onChange: onUpdate, fallback: "node:click" })) : null] })] }));
17
+ }
18
+ const SpriteComponent = {
19
+ name: 'Sprite',
20
+ Editor: SpriteComponentEditor,
21
+ defaultProperties: {
22
+ center: [0.5, 0.5],
23
+ emitClickEvent: false,
24
+ clickEventName: 'node:click',
25
+ },
26
+ };
27
+ export default SpriteComponent;
@@ -1,28 +1,36 @@
1
- import TransformComponent from './TransformComponent';
2
- import GeometryComponent from './GeometryComponent';
3
- import BufferGeometryComponent from './BufferGeometryComponent';
4
- import ModelComponent from './ModelComponent';
5
- import TextComponent from './TextComponent';
6
- import MaterialComponent from './MaterialComponent';
7
- import SpotLightComponent from './SpotLightComponent';
8
- import PointLightComponent from './PointLightComponent';
9
- import DirectionalLightComponent from './DirectionalLightComponent';
10
- import AmbientLightComponent from './AmbientLightComponent';
11
- import EnvironmentComponent from './EnvironmentComponent';
12
- import CameraComponent from './CameraComponent';
13
- import SoundComponent from './SoundComponent';
14
- import DataComponent from './DataComponent';
1
+ // biome-ignore assist/source/organizeImports: <in order of display in the editor>
2
+ import TransformComponent from "./TransformComponent";
3
+ import GeometryComponent from "./GeometryComponent";
4
+ import BufferGeometryComponent from "./BufferGeometryComponent";
5
+ import ModelComponent from "./ModelComponent";
6
+ import SpriteComponent from "./SpriteComponent";
7
+ import TextComponent from "./TextComponent";
8
+ import MaterialComponent from "./MaterialComponent";
9
+ import SpotLightComponent from "./SpotLightComponent";
10
+ import PointLightComponent from "./PointLightComponent";
11
+ import DirectionalLightComponent from "./DirectionalLightComponent";
12
+ import AmbientLightComponent from "./AmbientLightComponent";
13
+ import EnvironmentComponent from "./EnvironmentComponent";
14
+ import CameraComponent from "./CameraComponent";
15
+ import SoundComponent from "./SoundComponent";
16
+ import DataComponent from "./DataComponent";
17
+ // this controls the order of components in the editor, and also which components are available to add
15
18
  export const builtinComponents = [
16
19
  TransformComponent,
20
+ // geometry components
17
21
  GeometryComponent,
18
22
  BufferGeometryComponent,
19
23
  ModelComponent,
24
+ SpriteComponent,
20
25
  TextComponent,
26
+ // material components
21
27
  MaterialComponent,
28
+ // light components
22
29
  SpotLightComponent,
23
30
  PointLightComponent,
24
31
  DirectionalLightComponent,
25
32
  AmbientLightComponent,
33
+ // other components
26
34
  EnvironmentComponent,
27
35
  CameraComponent,
28
36
  SoundComponent,
@@ -8,7 +8,6 @@ export interface PrefabState {
8
8
  nodesById: Record<string, PrefabNodeRecord>;
9
9
  childIdsById: Record<string, string[]>;
10
10
  parentIdById: Record<string, string | null>;
11
- revision: number;
12
11
  assetManifestKey: string;
13
12
  assetRefCounts: PrefabAssetRefCounts;
14
13
  }
@@ -25,7 +24,7 @@ export declare function createEmptyNode(name?: string): GameObject;
25
24
  export declare function createEmptyPrefab(): Prefab;
26
25
  export declare function createModelNode(filename: string, name?: string): GameObject;
27
26
  export declare function createImageNode(texturePath: string, name?: string): GameObject;
28
- export declare function normalizePrefab(prefab: Prefab, revision?: number): PrefabState;
27
+ export declare function normalizePrefab(prefab: Prefab): PrefabState;
29
28
  export declare function createPrefabPatch(state: PrefabState, patch: Partial<PrefabState>, nextAssetRefCounts?: PrefabAssetRefCounts): Partial<PrefabState>;
30
29
  export declare function denormalizePrefab(state: Pick<PrefabState, 'prefabId' | 'prefabName' | 'rootId' | 'nodesById' | 'childIdsById'>): Prefab;
31
30
  export declare function collectSubtreeIds(id: string, childIdsById: Record<string, string[]>): string[];
@@ -132,7 +132,7 @@ export function createImageNode(texturePath, name) {
132
132
  },
133
133
  });
134
134
  }
135
- export function normalizePrefab(prefab, revision = 0) {
135
+ export function normalizePrefab(prefab) {
136
136
  const nodesById = {};
137
137
  const childIdsById = {};
138
138
  const parentIdById = {};
@@ -145,14 +145,13 @@ export function normalizePrefab(prefab, revision = 0) {
145
145
  nodesById,
146
146
  childIdsById,
147
147
  parentIdById,
148
- revision,
149
148
  assetManifestKey: getAssetManifestKey(assetRefCounts),
150
149
  assetRefCounts,
151
150
  };
152
151
  }
153
152
  export function createPrefabPatch(state, patch, nextAssetRefCounts = state.assetRefCounts) {
154
153
  const assetRefsChanged = nextAssetRefCounts !== state.assetRefCounts;
155
- return Object.assign(Object.assign(Object.assign({}, patch), { revision: state.revision + 1 }), (assetRefsChanged ? {
154
+ return Object.assign(Object.assign({}, patch), (assetRefsChanged ? {
156
155
  assetRefCounts: nextAssetRefCounts,
157
156
  assetManifestKey: getAssetManifestKey(nextAssetRefCounts),
158
157
  } : null));
@@ -5,14 +5,9 @@ import { denormalizePrefab, PrefabState, PrefabNodeRecord } from "./prefab";
5
5
  export interface PrefabStoreState extends PrefabState {
6
6
  replacePrefab: (prefab: Prefab) => void;
7
7
  updateNode: (id: string, update: (node: PrefabNodeRecord) => PrefabNodeRecord) => void;
8
- updateNodes: (updates: Array<{
9
- id: string;
10
- update: (node: PrefabNodeRecord) => PrefabNodeRecord;
11
- }>) => void;
12
8
  addChild: (parentId: string, node: GameObject) => void;
13
9
  deleteNode: (id: string) => void;
14
10
  duplicateNode: (id: string) => string | null;
15
- toggleNodeFlag: (id: string, key: "disabled" | "locked") => void;
16
11
  moveNode: (draggedId: string, targetId: string, position: "before" | "inside") => void;
17
12
  }
18
13
  export type PrefabStoreApi = StoreApi<PrefabStoreState>;
@@ -21,7 +16,6 @@ export declare function PrefabStoreProvider({ store, children, }: {
21
16
  children: ReactNode;
22
17
  }): import("react").FunctionComponentElement<import("react").ProviderProps<PrefabStoreApi | null>>;
23
18
  export declare function usePrefabStoreApi(): PrefabStoreApi;
24
- export declare function useOptionalPrefabStoreApi(): PrefabStoreApi | null;
25
19
  export declare function usePrefabStore<T>(selector: (state: PrefabStoreState) => T): T;
26
20
  export declare function usePrefabRootId(): string;
27
21
  export declare function usePrefabNode(nodeId: string | null | undefined): PrefabNodeRecord | null;
@@ -15,9 +15,6 @@ export function usePrefabStoreApi() {
15
15
  }
16
16
  return store;
17
17
  }
18
- export function useOptionalPrefabStoreApi() {
19
- return useContext(PrefabStoreContext);
20
- }
21
18
  export function usePrefabStore(selector) {
22
19
  return useStore(usePrefabStoreApi(), selector);
23
20
  }
@@ -32,7 +29,7 @@ export function usePrefabChildIds(nodeId) {
32
29
  }
33
30
  export function createPrefabStore(prefab) {
34
31
  return createStore()(subscribeWithSelector((set, get) => (Object.assign(Object.assign({}, normalizePrefab(prefab)), { replacePrefab: (nextPrefab) => {
35
- set(normalizePrefab(nextPrefab, get().revision + 1));
32
+ set(normalizePrefab(nextPrefab));
36
33
  }, updateNode: (id, update) => {
37
34
  const state = get();
38
35
  const node = state.nodesById[id];
@@ -45,26 +42,6 @@ export function createPrefabStore(prefab) {
45
42
  set(createPrefabPatch(state, {
46
43
  nodesById: Object.assign(Object.assign({}, state.nodesById), { [id]: nextNode }),
47
44
  }, nextAssetRefCounts));
48
- }, updateNodes: (updates) => {
49
- if (updates.length === 0)
50
- return;
51
- const state = get();
52
- let nextNodesById = null;
53
- let nextAssetRefCounts = state.assetRefCounts;
54
- for (const { id, update } of updates) {
55
- const currentNode = (nextNodesById !== null && nextNodesById !== void 0 ? nextNodesById : state.nodesById)[id];
56
- if (!currentNode)
57
- continue;
58
- const nextNode = update(currentNode);
59
- if (nextNode === currentNode)
60
- continue;
61
- nextNodesById !== null && nextNodesById !== void 0 ? nextNodesById : (nextNodesById = Object.assign({}, state.nodesById));
62
- nextNodesById[id] = nextNode;
63
- nextAssetRefCounts = updateAssetRefsForNodeChange(nextAssetRefCounts, currentNode, nextNode);
64
- }
65
- if (!nextNodesById)
66
- return;
67
- set(createPrefabPatch(state, { nodesById: nextNodesById }, nextAssetRefCounts));
68
45
  }, addChild: (parentId, node) => {
69
46
  var _a;
70
47
  const state = get();
@@ -152,15 +129,6 @@ export function createPrefabStore(prefab) {
152
129
  parentIdById: nextParentIdById,
153
130
  }, nextAssetRefCounts));
154
131
  return duplicatedRootId;
155
- }, toggleNodeFlag: (id, key) => {
156
- const state = get();
157
- const node = state.nodesById[id];
158
- if (!node)
159
- return;
160
- const nextNode = Object.assign(Object.assign({}, node), { [key]: !node[key] });
161
- set(createPrefabPatch(state, {
162
- nodesById: Object.assign(Object.assign({}, state.nodesById), { [id]: nextNode }),
163
- }));
164
132
  }, moveNode: (draggedId, targetId, position) => {
165
133
  var _a, _b, _c;
166
134
  const state = get();
package/package.json CHANGED
@@ -1,51 +1,51 @@
1
1
  {
2
- "name": "react-three-game",
3
- "version": "0.0.93",
4
- "description": "high performance 3D game engine built in React",
5
- "main": "dist/index.js",
6
- "module": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "files": [
9
- "dist",
10
- "README.md",
11
- "LICENSE"
12
- ],
13
- "scripts": {
14
- "clean": "rm -rf dist",
15
- "watch": "npm run clean && tsc --watch",
16
- "dev": "concurrently \"npm run watch\" \"cd docs && npm run dev\"",
17
- "build": "npm run clean && tsc",
18
- "release": "npm run build && npm publish --access public"
19
- },
20
- "keywords": [],
21
- "author": "prnth",
22
- "license": "VPL",
23
- "type": "module",
24
- "workspaces": [
25
- "docs"
26
- ],
27
- "peerDependencies": {
28
- "@react-three/drei": ">=10.0.0",
29
- "@react-three/fiber": ">=9.0.0",
30
- "react": ">=18.0.0",
31
- "react-dom": ">=18.0.0",
32
- "three": ">=0.182.0",
33
- "three-text": ">=0.4.4"
34
- },
35
- "devDependencies": {
36
- "@react-three/drei": "^10.7.7",
37
- "@react-three/fiber": "^9.5.0",
38
- "@types/react": "^19.2.9",
39
- "@types/react-dom": "^19.2.3",
40
- "@types/three": "^0.182.0",
41
- "concurrently": "^9.2.1",
42
- "react": "^19.2.4",
43
- "react-dom": "^19.2.4",
44
- "three": "^0.184.0",
45
- "typescript": "^5.9.3",
46
- "vite": "^7.3.1"
47
- },
48
- "dependencies": {
49
- "zustand": "^5.0.12"
50
- }
2
+ "name": "react-three-game",
3
+ "version": "0.0.95",
4
+ "description": "high performance 3D game engine built in React",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "scripts": {
14
+ "clean": "rm -rf dist",
15
+ "watch": "npm run clean && tsc --watch",
16
+ "dev": "concurrently \"npm run watch\" \"cd docs && npm run dev\"",
17
+ "build": "npm run clean && tsc",
18
+ "release": "npm run build && npm publish --access public"
19
+ },
20
+ "keywords": [],
21
+ "author": "prnth",
22
+ "license": "VPL",
23
+ "type": "module",
24
+ "workspaces": [
25
+ "docs"
26
+ ],
27
+ "peerDependencies": {
28
+ "@react-three/drei": ">=10.0.0",
29
+ "@react-three/fiber": ">=9.0.0",
30
+ "react": ">=18.0.0",
31
+ "react-dom": ">=18.0.0",
32
+ "three": ">=0.182.0",
33
+ "three-text": ">=0.4.4"
34
+ },
35
+ "devDependencies": {
36
+ "@react-three/drei": "^10.7.7",
37
+ "@react-three/fiber": "^9.5.0",
38
+ "@types/react": "^19.2.9",
39
+ "@types/react-dom": "^19.2.3",
40
+ "@types/three": "^0.182.0",
41
+ "concurrently": "^9.2.1",
42
+ "react": "^19.2.4",
43
+ "react-dom": "^19.2.4",
44
+ "three": "^0.184.0",
45
+ "typescript": "^5.9.3",
46
+ "vite": "^7.3.1"
47
+ },
48
+ "dependencies": {
49
+ "zustand": "^5.0.12"
50
+ }
51
51
  }