react-three-game 0.0.12 → 0.0.14
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.
- package/assets/favicon.ico +0 -0
- package/assets/react-three-game-logo.png +0 -0
- package/dist/tools/prefabeditor/PrefabRoot.js +18 -19
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +2 -2
- package/dist/tools/prefabeditor/components/SpotLightComponent.js +22 -8
- package/package.json +1 -1
- package/src/tools/prefabeditor/PrefabRoot.tsx +8 -15
- package/src/tools/prefabeditor/components/PhysicsComponent.tsx +1 -7
- package/src/tools/prefabeditor/components/SpotLightComponent.tsx +84 -14
|
Binary file
|
|
Binary file
|
|
@@ -75,17 +75,14 @@ export const PrefabRoot = forwardRef(({ editMode, data, onPrefabChange, selected
|
|
|
75
75
|
localMatrix.decompose(lp, lq, ls);
|
|
76
76
|
const le = new Euler().setFromQuaternion(lq);
|
|
77
77
|
// 4. Write back LOCAL transform into the prefab node
|
|
78
|
-
const newRoot = updatePrefabNode(data.root, selectedId, (node) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
},
|
|
87
|
-
}, geometry: (_a = node.components) === null || _a === void 0 ? void 0 : _a.geometry, material: (_b = node.components) === null || _b === void 0 ? void 0 : _b.material, model: (_c = node.components) === null || _c === void 0 ? void 0 : _c.model }) }));
|
|
88
|
-
});
|
|
78
|
+
const newRoot = updatePrefabNode(data.root, selectedId, (node) => (Object.assign(Object.assign({}, node), { components: Object.assign(Object.assign({}, node === null || node === void 0 ? void 0 : node.components), { transform: {
|
|
79
|
+
type: "Transform",
|
|
80
|
+
properties: {
|
|
81
|
+
position: [lp.x, lp.y, lp.z],
|
|
82
|
+
rotation: [le.x, le.y, le.z],
|
|
83
|
+
scale: [ls.x, ls.y, ls.z],
|
|
84
|
+
},
|
|
85
|
+
} }) })));
|
|
89
86
|
onPrefabChange(Object.assign(Object.assign({}, data), { root: newRoot }));
|
|
90
87
|
};
|
|
91
88
|
useEffect(() => {
|
|
@@ -173,11 +170,11 @@ function GameObjectRenderer({ gameObject, selectedId, onSelect, registerRef, loa
|
|
|
173
170
|
// --- 5. Render children (always relative transforms) ---
|
|
174
171
|
const children = ((_d = gameObject.children) !== null && _d !== void 0 ? _d : []).map((child) => (_jsx(GameObjectRenderer, { gameObject: child, selectedId: selectedId, onSelect: onSelect, registerRef: registerRef, loadedModels: loadedModels, loadedTextures: loadedTextures, editMode: editMode, parentMatrix: worldMatrix }, child.id)));
|
|
175
172
|
// --- 4. Wrap with physics if needed ---
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
const physicsWrapped = wrapPhysicsIfNeeded(gameObject,
|
|
173
|
+
// Only wrap the core content (geometry/model), not children
|
|
174
|
+
// Children should be siblings, not inside the physics body
|
|
175
|
+
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
|
|
179
176
|
// --- 6. Final group wrapper ---
|
|
180
|
-
return (
|
|
177
|
+
return (_jsxs("group", { ref: (el) => registerRef(gameObject.id, el), position: transformProps.position, rotation: transformProps.rotation, scale: transformProps.scale, onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, children: [physicsWrapped, children] }));
|
|
181
178
|
}
|
|
182
179
|
// Helper: render an instanced GameInstance (terminal node)
|
|
183
180
|
function renderInstancedNode(gameObject, worldMatrix, ctx) {
|
|
@@ -211,10 +208,12 @@ function renderCoreNode(gameObject, ctx, parentMatrix) {
|
|
|
211
208
|
};
|
|
212
209
|
const allComponentViews = gameObject.components
|
|
213
210
|
? Object.entries(gameObject.components)
|
|
214
|
-
.filter(([key]) => key !== 'geometry' && key !== 'material' && key !== 'model')
|
|
211
|
+
.filter(([key]) => key !== 'geometry' && key !== 'material' && key !== 'model' && key !== 'transform' && key !== 'physics')
|
|
215
212
|
.map(([key, comp]) => {
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
if (!comp || !comp.type)
|
|
214
|
+
return null;
|
|
215
|
+
const def = getComponent(comp.type);
|
|
216
|
+
if (!def || !def.View)
|
|
218
217
|
return null;
|
|
219
218
|
return _jsx(def.View, Object.assign({ properties: comp.properties }, contextProps), key);
|
|
220
219
|
})
|
|
@@ -240,7 +239,7 @@ function wrapPhysicsIfNeeded(gameObject, content, ctx) {
|
|
|
240
239
|
const physicsDef = getComponent('Physics');
|
|
241
240
|
if (!physicsDef || !physicsDef.View)
|
|
242
241
|
return content;
|
|
243
|
-
return (_jsx(physicsDef.View, { properties: Object.assign(Object.assign({}, physics.properties), { id: gameObject.id }),
|
|
242
|
+
return (_jsx(physicsDef.View, { properties: Object.assign(Object.assign({}, physics.properties), { id: gameObject.id }), editMode: ctx.editMode, children: content }));
|
|
244
243
|
}
|
|
245
244
|
export default PrefabRoot;
|
|
246
245
|
function getNodeTransformProps(node) {
|
|
@@ -3,10 +3,10 @@ function PhysicsComponentEditor({ component, onUpdate }) {
|
|
|
3
3
|
return _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Type" }), _jsxs("select", { className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: component.properties.type, onChange: e => onUpdate({ type: e.target.value }), children: [_jsx("option", { value: "dynamic", children: "Dynamic" }), _jsx("option", { value: "fixed", children: "Fixed" })] })] });
|
|
4
4
|
}
|
|
5
5
|
import { RigidBody } from "@react-three/rapier";
|
|
6
|
-
function PhysicsComponentView({ properties, children,
|
|
6
|
+
function PhysicsComponentView({ properties, children, editMode }) {
|
|
7
7
|
if (editMode)
|
|
8
8
|
return children;
|
|
9
|
-
return (_jsx(RigidBody, {
|
|
9
|
+
return (_jsx(RigidBody, { type: properties.type, colliders: "cuboid", children: children }));
|
|
10
10
|
}
|
|
11
11
|
const PhysicsComponent = {
|
|
12
12
|
name: 'Physics',
|
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
function SpotLightComponentEditor({ component, onUpdate }) {
|
|
3
|
-
|
|
3
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4
|
+
// Provide default values to prevent NaN
|
|
5
|
+
const props = {
|
|
6
|
+
color: (_a = component.properties.color) !== null && _a !== void 0 ? _a : '#ffffff',
|
|
7
|
+
intensity: (_b = component.properties.intensity) !== null && _b !== void 0 ? _b : 1.0,
|
|
8
|
+
angle: (_c = component.properties.angle) !== null && _c !== void 0 ? _c : Math.PI / 6,
|
|
9
|
+
penumbra: (_d = component.properties.penumbra) !== null && _d !== void 0 ? _d : 0.5,
|
|
10
|
+
distance: (_e = component.properties.distance) !== null && _e !== void 0 ? _e : 100,
|
|
11
|
+
castShadow: (_f = component.properties.castShadow) !== null && _f !== void 0 ? _f : true
|
|
12
|
+
};
|
|
13
|
+
return _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Color" }), _jsxs("div", { className: "flex gap-0.5", children: [_jsx("input", { type: "color", className: "h-5 w-5 bg-transparent border-none cursor-pointer", value: props.color, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'color': e.target.value })) }), _jsx("input", { type: "text", className: "flex-1 bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.color, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'color': e.target.value })) })] })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Intensity" }), _jsx("input", { type: "number", step: "0.1", className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.intensity, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'intensity': parseFloat(e.target.value) })) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Angle" }), _jsx("input", { type: "number", step: "0.1", min: "0", max: Math.PI, className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.angle, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'angle': parseFloat(e.target.value) })) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Penumbra" }), _jsx("input", { type: "number", step: "0.1", min: "0", max: "1", className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.penumbra, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'penumbra': parseFloat(e.target.value) })) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Distance" }), _jsx("input", { type: "number", step: "1", min: "0", className: "w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50", value: props.distance, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'distance': parseFloat(e.target.value) })) })] }), _jsxs("div", { children: [_jsx("label", { className: "block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5", children: "Cast Shadow" }), _jsx("input", { type: "checkbox", className: "h-4 w-4 bg-black/40 border border-cyan-500/30 cursor-pointer", checked: props.castShadow, onChange: e => onUpdate(Object.assign(Object.assign({}, component.properties), { 'castShadow': e.target.checked })) })] })] });
|
|
4
14
|
}
|
|
5
15
|
// The view component for SpotLight
|
|
6
16
|
function SpotLightView({ properties }) {
|
|
7
|
-
|
|
8
|
-
|
|
17
|
+
var _a, _b, _c, _d, _e, _f;
|
|
18
|
+
// Provide defaults in case properties are missing
|
|
19
|
+
const color = (_a = properties.color) !== null && _a !== void 0 ? _a : '#ffffff';
|
|
20
|
+
const intensity = (_b = properties.intensity) !== null && _b !== void 0 ? _b : 1.0;
|
|
21
|
+
const angle = (_c = properties.angle) !== null && _c !== void 0 ? _c : Math.PI / 6;
|
|
22
|
+
const penumbra = (_d = properties.penumbra) !== null && _d !== void 0 ? _d : 0.5;
|
|
23
|
+
const distance = (_e = properties.distance) !== null && _e !== void 0 ? _e : 100;
|
|
24
|
+
const castShadow = (_f = properties.castShadow) !== null && _f !== void 0 ? _f : true;
|
|
25
|
+
return (_jsx(_Fragment, { children: _jsx("spotLight", { color: color, intensity: intensity, angle: angle, penumbra: penumbra, distance: distance, castShadow: castShadow }) }));
|
|
9
26
|
}
|
|
10
27
|
const SpotLightComponent = {
|
|
11
28
|
name: 'SpotLight',
|
|
12
29
|
Editor: SpotLightComponentEditor,
|
|
13
30
|
View: SpotLightView,
|
|
14
|
-
defaultProperties: {
|
|
15
|
-
color: '#ffffff',
|
|
16
|
-
intensity: 1.0
|
|
17
|
-
}
|
|
31
|
+
defaultProperties: {}
|
|
18
32
|
};
|
|
19
33
|
export default SpotLightComponent;
|
package/package.json
CHANGED
|
@@ -103,9 +103,6 @@ export const PrefabRoot = forwardRef<Group, {
|
|
|
103
103
|
scale: [ls.x, ls.y, ls.z] as [number, number, number],
|
|
104
104
|
},
|
|
105
105
|
},
|
|
106
|
-
geometry: node.components?.geometry,
|
|
107
|
-
material: node.components?.material,
|
|
108
|
-
model: node.components?.model,
|
|
109
106
|
},
|
|
110
107
|
}));
|
|
111
108
|
|
|
@@ -272,14 +269,9 @@ function GameObjectRenderer({
|
|
|
272
269
|
));
|
|
273
270
|
|
|
274
271
|
// --- 4. Wrap with physics if needed ---
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
{core}
|
|
279
|
-
{children}
|
|
280
|
-
</>
|
|
281
|
-
);
|
|
282
|
-
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, content, ctx);
|
|
272
|
+
// Only wrap the core content (geometry/model), not children
|
|
273
|
+
// Children should be siblings, not inside the physics body
|
|
274
|
+
const physicsWrapped = wrapPhysicsIfNeeded(gameObject, core, ctx);
|
|
283
275
|
|
|
284
276
|
// --- 6. Final group wrapper ---
|
|
285
277
|
return (
|
|
@@ -293,6 +285,7 @@ function GameObjectRenderer({
|
|
|
293
285
|
onPointerUp={handlePointerUp}
|
|
294
286
|
>
|
|
295
287
|
{physicsWrapped}
|
|
288
|
+
{children}
|
|
296
289
|
</group>
|
|
297
290
|
);
|
|
298
291
|
}
|
|
@@ -340,10 +333,11 @@ function renderCoreNode(gameObject: GameObjectType, ctx: any, parentMatrix: Matr
|
|
|
340
333
|
};
|
|
341
334
|
const allComponentViews = gameObject.components
|
|
342
335
|
? Object.entries(gameObject.components)
|
|
343
|
-
.filter(([key]) => key !== 'geometry' && key !== 'material' && key !== 'model')
|
|
336
|
+
.filter(([key]) => key !== 'geometry' && key !== 'material' && key !== 'model' && key !== 'transform' && key !== 'physics')
|
|
344
337
|
.map(([key, comp]) => {
|
|
345
|
-
|
|
346
|
-
|
|
338
|
+
if (!comp || !comp.type) return null;
|
|
339
|
+
const def = getComponent(comp.type);
|
|
340
|
+
if (!def || !def.View) return null;
|
|
347
341
|
return <def.View key={key} properties={comp.properties} {...contextProps} />;
|
|
348
342
|
})
|
|
349
343
|
: null;
|
|
@@ -403,7 +397,6 @@ function wrapPhysicsIfNeeded(gameObject: GameObjectType, content: React.ReactNod
|
|
|
403
397
|
return (
|
|
404
398
|
<physicsDef.View
|
|
405
399
|
properties={{ ...physics.properties, id: gameObject.id }}
|
|
406
|
-
registerRef={ctx.registerRef}
|
|
407
400
|
editMode={ctx.editMode}
|
|
408
401
|
>
|
|
409
402
|
{content}
|
|
@@ -16,17 +16,11 @@ function PhysicsComponentEditor({ component, onUpdate }: { component: any; onUpd
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import { RigidBody } from "@react-three/rapier";
|
|
19
|
-
import { Object3D } from "three";
|
|
20
|
-
import { useRef } from "react";
|
|
21
19
|
|
|
22
|
-
function PhysicsComponentView({ properties, children,
|
|
20
|
+
function PhysicsComponentView({ properties, children, editMode }: any) {
|
|
23
21
|
if (editMode) return children;
|
|
24
22
|
return (
|
|
25
23
|
<RigidBody
|
|
26
|
-
ref={el => registerRef && registerRef(properties.id, el as unknown as Object3D)}
|
|
27
|
-
position={transform?.position}
|
|
28
|
-
rotation={transform?.rotation}
|
|
29
|
-
scale={transform?.scale}
|
|
30
24
|
type={properties.type}
|
|
31
25
|
colliders="cuboid"
|
|
32
26
|
>
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
|
|
2
2
|
import { Component } from "./ComponentRegistry";
|
|
3
|
+
import { useRef } from "react";
|
|
3
4
|
|
|
4
5
|
function SpotLightComponentEditor({ component, onUpdate }: { component: any; onUpdate: (newComp: any) => void }) {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
// Provide default values to prevent NaN
|
|
7
|
+
const props = {
|
|
8
|
+
color: component.properties.color ?? '#ffffff',
|
|
9
|
+
intensity: component.properties.intensity ?? 1.0,
|
|
10
|
+
angle: component.properties.angle ?? Math.PI / 6,
|
|
11
|
+
penumbra: component.properties.penumbra ?? 0.5,
|
|
12
|
+
distance: component.properties.distance ?? 100,
|
|
13
|
+
castShadow: component.properties.castShadow ?? true
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
return <div className="flex flex-col gap-2">
|
|
17
|
+
<div>
|
|
7
18
|
<label className="block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5">Color</label>
|
|
8
19
|
<div className="flex gap-0.5">
|
|
9
20
|
<input
|
|
10
21
|
type="color"
|
|
11
22
|
className="h-5 w-5 bg-transparent border-none cursor-pointer"
|
|
12
|
-
value={
|
|
13
|
-
onChange={e => onUpdate({ 'color': e.target.value })}
|
|
23
|
+
value={props.color}
|
|
24
|
+
onChange={e => onUpdate({ ...component.properties, 'color': e.target.value })}
|
|
14
25
|
/>
|
|
15
26
|
<input
|
|
16
27
|
type="text"
|
|
17
28
|
className="flex-1 bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50"
|
|
18
|
-
value={
|
|
19
|
-
onChange={e => onUpdate({ 'color': e.target.value })}
|
|
29
|
+
value={props.color}
|
|
30
|
+
onChange={e => onUpdate({ ...component.properties, 'color': e.target.value })}
|
|
20
31
|
/>
|
|
21
32
|
</div>
|
|
22
33
|
</div>
|
|
@@ -26,8 +37,52 @@ function SpotLightComponentEditor({ component, onUpdate }: { component: any; onU
|
|
|
26
37
|
type="number"
|
|
27
38
|
step="0.1"
|
|
28
39
|
className="w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50"
|
|
29
|
-
value={
|
|
30
|
-
onChange={e => onUpdate({ 'intensity': parseFloat(e.target.value) })}
|
|
40
|
+
value={props.intensity}
|
|
41
|
+
onChange={e => onUpdate({ ...component.properties, 'intensity': parseFloat(e.target.value) })}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div>
|
|
45
|
+
<label className="block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5">Angle</label>
|
|
46
|
+
<input
|
|
47
|
+
type="number"
|
|
48
|
+
step="0.1"
|
|
49
|
+
min="0"
|
|
50
|
+
max={Math.PI}
|
|
51
|
+
className="w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50"
|
|
52
|
+
value={props.angle}
|
|
53
|
+
onChange={e => onUpdate({ ...component.properties, 'angle': parseFloat(e.target.value) })}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
<div>
|
|
57
|
+
<label className="block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5">Penumbra</label>
|
|
58
|
+
<input
|
|
59
|
+
type="number"
|
|
60
|
+
step="0.1"
|
|
61
|
+
min="0"
|
|
62
|
+
max="1"
|
|
63
|
+
className="w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50"
|
|
64
|
+
value={props.penumbra}
|
|
65
|
+
onChange={e => onUpdate({ ...component.properties, 'penumbra': parseFloat(e.target.value) })}
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
<div>
|
|
69
|
+
<label className="block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5">Distance</label>
|
|
70
|
+
<input
|
|
71
|
+
type="number"
|
|
72
|
+
step="1"
|
|
73
|
+
min="0"
|
|
74
|
+
className="w-full bg-black/40 border border-cyan-500/30 px-1 py-0.5 text-[10px] text-cyan-300 font-mono focus:outline-none focus:border-cyan-400/50"
|
|
75
|
+
value={props.distance}
|
|
76
|
+
onChange={e => onUpdate({ ...component.properties, 'distance': parseFloat(e.target.value) })}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
<div>
|
|
80
|
+
<label className="block text-[9px] text-cyan-400/60 uppercase tracking-wider mb-0.5">Cast Shadow</label>
|
|
81
|
+
<input
|
|
82
|
+
type="checkbox"
|
|
83
|
+
className="h-4 w-4 bg-black/40 border border-cyan-500/30 cursor-pointer"
|
|
84
|
+
checked={props.castShadow}
|
|
85
|
+
onChange={e => onUpdate({ ...component.properties, 'castShadow': e.target.checked })}
|
|
31
86
|
/>
|
|
32
87
|
</div>
|
|
33
88
|
</div>;
|
|
@@ -36,18 +91,33 @@ function SpotLightComponentEditor({ component, onUpdate }: { component: any; onU
|
|
|
36
91
|
|
|
37
92
|
// The view component for SpotLight
|
|
38
93
|
function SpotLightView({ properties }: { properties: any }) {
|
|
39
|
-
//
|
|
40
|
-
|
|
94
|
+
// Provide defaults in case properties are missing
|
|
95
|
+
const color = properties.color ?? '#ffffff';
|
|
96
|
+
const intensity = properties.intensity ?? 1.0;
|
|
97
|
+
const angle = properties.angle ?? Math.PI / 6;
|
|
98
|
+
const penumbra = properties.penumbra ?? 0.5;
|
|
99
|
+
const distance = properties.distance ?? 100;
|
|
100
|
+
const castShadow = properties.castShadow ?? true;
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<>
|
|
104
|
+
<spotLight
|
|
105
|
+
color={color}
|
|
106
|
+
intensity={intensity}
|
|
107
|
+
angle={angle}
|
|
108
|
+
penumbra={penumbra}
|
|
109
|
+
distance={distance}
|
|
110
|
+
castShadow={castShadow}
|
|
111
|
+
/>
|
|
112
|
+
</>
|
|
113
|
+
);
|
|
41
114
|
}
|
|
42
115
|
|
|
43
116
|
const SpotLightComponent: Component = {
|
|
44
117
|
name: 'SpotLight',
|
|
45
118
|
Editor: SpotLightComponentEditor,
|
|
46
119
|
View: SpotLightView,
|
|
47
|
-
defaultProperties: {
|
|
48
|
-
color: '#ffffff',
|
|
49
|
-
intensity: 1.0
|
|
50
|
-
}
|
|
120
|
+
defaultProperties: {}
|
|
51
121
|
};
|
|
52
122
|
|
|
53
123
|
export default SpotLightComponent;
|