react-three-game 0.0.90 → 0.0.92
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/dist/tools/assetviewer/page.js +38 -10
- package/dist/tools/prefabeditor/EditorUI.js +3 -3
- package/dist/tools/prefabeditor/PrefabEditor.js +34 -13
- package/dist/tools/prefabeditor/PrefabRoot.d.ts +0 -1
- package/dist/tools/prefabeditor/PrefabRoot.js +7 -16
- package/dist/tools/prefabeditor/components/BufferGeometryComponent.js +3 -14
- package/dist/tools/prefabeditor/components/DataComponent.js +2 -13
- package/dist/tools/prefabeditor/components/DirectionalLightComponent.js +1 -1
- package/dist/tools/prefabeditor/components/Input.js +17 -29
- package/dist/tools/prefabeditor/components/ModelComponent.js +2 -20
- package/dist/tools/prefabeditor/components/PhysicsComponent.js +29 -8
- package/dist/tools/prefabeditor/components/SoundComponent.js +2 -20
- package/dist/tools/prefabeditor/components/TransformComponent.js +4 -3
- package/dist/tools/prefabeditor/components/lightUtils.js +3 -20
- package/dist/tools/prefabeditor/styles.d.ts +6 -0
- package/dist/tools/prefabeditor/styles.js +70 -57
- package/package.json +1 -1
|
@@ -12,6 +12,34 @@ const styles = {
|
|
|
12
12
|
textLight: { color: '#f9fafb' },
|
|
13
13
|
iconLarge: { fontSize: 20 }
|
|
14
14
|
};
|
|
15
|
+
const assetViewerColors = {
|
|
16
|
+
panelBg: '#111827',
|
|
17
|
+
controlBg: '#1f2937',
|
|
18
|
+
text: '#f9fafb',
|
|
19
|
+
border: 'rgba(255,255,255,0.12)',
|
|
20
|
+
accentBorder: 'rgba(34, 211, 238, 0.3)',
|
|
21
|
+
};
|
|
22
|
+
const assetPickerPopupBaseStyle = {
|
|
23
|
+
background: assetViewerColors.panelBg,
|
|
24
|
+
border: `1px solid ${assetViewerColors.border}`,
|
|
25
|
+
borderRadius: 0,
|
|
26
|
+
boxShadow: '0 4px 16px rgba(0,0,0,0.6)',
|
|
27
|
+
};
|
|
28
|
+
const assetPickerButtonBaseStyle = {
|
|
29
|
+
backgroundColor: assetViewerColors.controlBg,
|
|
30
|
+
color: 'inherit',
|
|
31
|
+
fontSize: 10,
|
|
32
|
+
cursor: 'pointer',
|
|
33
|
+
border: `1px solid ${assetViewerColors.border}`,
|
|
34
|
+
borderRadius: 0,
|
|
35
|
+
};
|
|
36
|
+
const assetPickerWideButtonStyle = Object.assign(Object.assign({}, assetPickerButtonBaseStyle), { width: '100%', padding: '6px 8px' });
|
|
37
|
+
const assetPickerSmallButtonStyle = Object.assign(Object.assign({}, assetPickerButtonBaseStyle), { padding: '4px 8px' });
|
|
38
|
+
const assetPickerEmptyPreviewStyle = {
|
|
39
|
+
backgroundColor: assetViewerColors.controlBg,
|
|
40
|
+
border: `1px dashed ${assetViewerColors.border}`,
|
|
41
|
+
borderRadius: 0,
|
|
42
|
+
};
|
|
15
43
|
function getItemsInPath(files, currentPath) {
|
|
16
44
|
// Remove the leading category folder (e.g., /textures/, /models/, /sounds/)
|
|
17
45
|
const filesWithoutCategory = files.map(file => {
|
|
@@ -39,8 +67,8 @@ function FolderTile({ name, onClick }) {
|
|
|
39
67
|
return (_jsxs("div", { onClick: onClick, style: {
|
|
40
68
|
maxWidth: 60,
|
|
41
69
|
aspectRatio: '1 / 1',
|
|
42
|
-
backgroundColor:
|
|
43
|
-
color:
|
|
70
|
+
backgroundColor: assetViewerColors.controlBg,
|
|
71
|
+
color: assetViewerColors.text,
|
|
44
72
|
cursor: 'pointer',
|
|
45
73
|
display: 'flex',
|
|
46
74
|
flexDirection: 'column',
|
|
@@ -73,7 +101,7 @@ function AssetListViewer({ files, selected, onSelect, renderCard }) {
|
|
|
73
101
|
const pathParts = currentPath.split('/').filter(Boolean);
|
|
74
102
|
pathParts.pop();
|
|
75
103
|
setCurrentPath(pathParts.join('/'));
|
|
76
|
-
}, style: {
|
|
104
|
+
}, style: Object.assign(Object.assign({}, assetPickerSmallButtonStyle), { marginBottom: 4, fontSize: 12, border: 'none' }), children: "\u2190 Back" })), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 4 }, children: [folders.map((folder) => (_jsx(FolderTile, { name: folder, onClick: () => setCurrentPath(currentPath ? `${currentPath}/${folder}` : folder) }, folder))), filesInCurrentPath.map((file) => (_jsx("div", { children: renderCard(file, onSelect) }, file)))] })] }));
|
|
77
105
|
}
|
|
78
106
|
export function TextureListViewer({ files, selected, onSelect, basePath = "" }) {
|
|
79
107
|
return (_jsxs("div", { style: { position: 'relative', width: '100%', height: '100%' }, children: [_jsx("div", { style: { width: '100%', height: '100%', overflowY: 'auto', overflowX: 'hidden', paddingRight: 4 }, children: _jsx(AssetListViewer, { files: files, selected: selected, onSelect: onSelect, renderCard: (file, onSelectHandler) => (_jsx(TextureCard, { file: file, basePath: basePath, onSelect: onSelectHandler })) }) }), _jsx(SharedCanvas, {})] }));
|
|
@@ -172,8 +200,8 @@ function AssetPicker({ value, onChange, basePath, manifestFolder, preview, rende
|
|
|
172
200
|
const fitsLeft = preferredLeft >= 8;
|
|
173
201
|
const left = fitsLeft ? preferredLeft : Math.min(fallbackLeft, window.innerWidth - PICKER_POPUP_WIDTH - 8);
|
|
174
202
|
const top = Math.min(Math.max(8, rect.top), window.innerHeight - PICKER_POPUP_HEIGHT - 8);
|
|
175
|
-
setResolvedPopupStyle(Object.assign({ position: 'fixed', left,
|
|
176
|
-
top, padding: 12, width: PICKER_POPUP_WIDTH, height: PICKER_POPUP_HEIGHT, overflow: 'hidden', zIndex: 1000
|
|
203
|
+
setResolvedPopupStyle(Object.assign(Object.assign({ position: 'fixed', left,
|
|
204
|
+
top, padding: 12, width: PICKER_POPUP_WIDTH, height: PICKER_POPUP_HEIGHT, overflow: 'hidden', zIndex: 1000 }, assetPickerPopupBaseStyle), popupStyle));
|
|
177
205
|
};
|
|
178
206
|
updatePosition();
|
|
179
207
|
window.addEventListener('resize', updatePosition);
|
|
@@ -194,23 +222,23 @@ function AssetPicker({ value, onChange, basePath, manifestFolder, preview, rende
|
|
|
194
222
|
}) }), document.body)] }));
|
|
195
223
|
}
|
|
196
224
|
export function TexturePicker({ value, onChange, basePath = "" }) {
|
|
197
|
-
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "textures", rootStyle: { maxHeight: 128, overflow: 'visible', position: 'relative', display: 'flex', alignItems: 'center' }, changeButtonStyle: {
|
|
225
|
+
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "textures", rootStyle: { maxHeight: 128, overflow: 'visible', position: 'relative', display: 'flex', alignItems: 'center' }, changeButtonStyle: Object.assign(Object.assign({}, assetPickerSmallButtonStyle), { marginTop: 4 }), clearButtonStyle: Object.assign(Object.assign({}, assetPickerSmallButtonStyle), { marginTop: 4, marginLeft: 4 }), preview: _jsx(SingleTextureViewer, { file: value, basePath: basePath }), renderList: ({ files, value: selectedValue, onSelect, basePath: currentBasePath }) => (_jsx(TextureListViewer, { files: files, selected: selectedValue || undefined, onSelect: onSelect, basePath: currentBasePath })) }));
|
|
198
226
|
}
|
|
199
227
|
export function ModelPicker({ value, onChange, basePath = "", pickerKey }) {
|
|
200
|
-
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "models", rootStyle: { maxHeight: 160, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle: {
|
|
228
|
+
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "models", rootStyle: { maxHeight: 160, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle: Object.assign(Object.assign({}, assetPickerWideButtonStyle), { border: `1px solid ${assetViewerColors.accentBorder}` }), clearButtonStyle: Object.assign(Object.assign({}, assetPickerWideButtonStyle), { border: `1px solid ${assetViewerColors.accentBorder}` }), popupStyle: { background: 'rgba(0,0,0,0.9)', border: `1px solid ${assetViewerColors.accentBorder}` }, preview: _jsx("div", { style: { flex: '0 0 auto' }, children: _jsx(SingleModelViewer, { file: value ? `/${value}` : undefined, basePath: basePath }) }), renderList: ({ files, value: selectedValue, onSelect, basePath: currentBasePath }) => (_jsx(ModelListViewer, { files: files, selected: selectedValue ? `/${selectedValue}` : undefined, onSelect: (file) => onSelect(file.startsWith('/') ? file.slice(1) : file), basePath: currentBasePath }, pickerKey)) }));
|
|
201
229
|
}
|
|
202
230
|
export function SoundPicker({ value, onChange, basePath = "" }) {
|
|
203
|
-
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "sound", rootStyle: { maxHeight: 76, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle:
|
|
231
|
+
return (_jsx(AssetPicker, { value: value, onChange: onChange, basePath: basePath, manifestFolder: "sound", rootStyle: { maxHeight: 76, overflow: 'visible', position: 'relative', display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'center' }, controlsStyle: { display: 'flex', flexDirection: 'column', gap: 6, flex: '0 0 84px', minWidth: 84, justifyContent: 'flex-end' }, changeButtonStyle: assetPickerWideButtonStyle, clearButtonStyle: assetPickerWideButtonStyle, preview: _jsx("div", { style: { flex: '0 0 auto', minWidth: 84 }, children: value ? _jsx(SingleSoundViewer, { file: value, basePath: basePath }) : _jsx("div", { style: Object.assign({ width: 84, height: 60 }, assetPickerEmptyPreviewStyle) }) }), renderList: ({ files, value: selectedValue, onSelect, basePath: currentBasePath }) => (_jsx(SoundListViewer, { files: files, selected: selectedValue || undefined, onSelect: onSelect, basePath: currentBasePath })) }));
|
|
204
232
|
}
|
|
205
233
|
// Single Asset Viewer Components - display only one selected asset
|
|
206
234
|
export function SingleTextureViewer({ file, basePath = "" }) {
|
|
207
235
|
if (!file)
|
|
208
|
-
return _jsx("div", { style: { width: 60, aspectRatio: '1 / 1'
|
|
236
|
+
return _jsx("div", { style: Object.assign({ width: 60, aspectRatio: '1 / 1' }, assetPickerEmptyPreviewStyle) });
|
|
209
237
|
return (_jsxs(_Fragment, { children: [_jsx(TextureCard, { file: file, basePath: basePath, onSelect: () => { } }), _jsx(SharedCanvas, {})] }));
|
|
210
238
|
}
|
|
211
239
|
export function SingleModelViewer({ file, basePath = "" }) {
|
|
212
240
|
if (!file)
|
|
213
|
-
return _jsx("div", { style: { width: 112, aspectRatio: '1 / 1'
|
|
241
|
+
return _jsx("div", { style: Object.assign({ width: 112, aspectRatio: '1 / 1' }, assetPickerEmptyPreviewStyle) });
|
|
214
242
|
return (_jsxs(_Fragment, { children: [_jsx(ModelCard, { file: file, basePath: basePath, onSelect: () => { }, size: 112 }), _jsx(SharedCanvas, {})] }));
|
|
215
243
|
}
|
|
216
244
|
export function SingleSoundViewer({ file, basePath = "" }) {
|
|
@@ -43,18 +43,18 @@ function NodeInspector({ node, updateNode, deleteNode, basePath }) {
|
|
|
43
43
|
const available = allKeys.filter(k => !hasComponent(node, k));
|
|
44
44
|
const [preferredAddType, setAddType] = useState(available[0] || "");
|
|
45
45
|
const addType = available.includes(preferredAddType) ? preferredAddType : (available[0] || "");
|
|
46
|
-
return _jsxs("div", { style: inspector.content, children: [_jsxs("div", { style: base.section, children: [_jsxs("div", { style: { display: "flex", marginBottom:
|
|
46
|
+
return _jsxs("div", { style: inspector.content, children: [_jsxs("div", { style: base.section, children: [_jsxs("div", { style: { display: "flex", marginBottom: 4, alignItems: 'center', gap: 4 }, children: [_jsx("div", { style: { fontSize: 10, color: colors.textDim, wordBreak: 'break-all', background: colors.bgLight, padding: '2px 4px', flex: 1, fontFamily: 'monospace', minHeight: 18, boxSizing: 'border-box' }, children: node.id }), _jsx("button", { style: Object.assign(Object.assign(Object.assign({}, base.btn), base.btnDanger), { minWidth: 22, padding: '2px 4px' }), title: "Delete Node", onClick: deleteNode, children: "\u2715" })] }), _jsx("input", { style: base.input, value: (_a = node.name) !== null && _a !== void 0 ? _a : "", placeholder: 'Node name', onChange: e => updateNode(n => (Object.assign(Object.assign({}, n), { name: e.target.value }))) })] }), _jsxs("div", { style: base.section, children: [_jsx("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }, children: _jsx("div", { style: base.label, children: "Components" }) }), node.components && Object.entries(node.components).map(([key, comp]) => {
|
|
47
47
|
if (!comp)
|
|
48
48
|
return null;
|
|
49
49
|
const def = ALL_COMPONENTS[comp.type];
|
|
50
50
|
if (!def)
|
|
51
51
|
return _jsxs("div", { style: { color: colors.danger, fontSize: 11 }, children: ["Unknown: ", comp.type] }, key);
|
|
52
|
-
return (_jsxs("div", { style: componentCard.container, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom:
|
|
52
|
+
return (_jsxs("div", { style: componentCard.container, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 3 }, children: [_jsx("div", { style: { fontSize: 11, fontWeight: 500 }, children: key }), _jsx("button", { style: Object.assign(Object.assign({}, base.btn), { padding: '2px 4px', minWidth: 20 }), title: "Remove Component", onClick: () => updateNode(n => {
|
|
53
53
|
var _a;
|
|
54
54
|
const _b = (_a = n.components) !== null && _a !== void 0 ? _a : {}, _c = key, _ = _b[_c], rest = __rest(_b, [typeof _c === "symbol" ? _c : _c + ""]);
|
|
55
55
|
return Object.assign(Object.assign({}, n), { components: rest });
|
|
56
56
|
}), children: "\u2715" })] }), def.Editor && (_jsx(def.Editor, { component: comp, node: node, onUpdate: (newProps) => updateNode(n => (Object.assign(Object.assign({}, n), { components: Object.assign(Object.assign({}, n.components), { [key]: Object.assign(Object.assign({}, comp), { properties: Object.assign(Object.assign({}, comp.properties), newProps) }) }) }))), basePath: basePath }))] }, key));
|
|
57
|
-
})] }), available.length > 0 && (_jsx("div", { children: _jsxs("div", { style: base.row, children: [_jsx("select", { style: Object.assign(Object.assign({}, base.input), { flex: 1 }), value: addType, onChange: e => setAddType(e.target.value), children: available.map(k => _jsx("option", { value: k, children: k }, k)) }), _jsx("button", { style: base.btn, disabled: !addType, onClick: () => {
|
|
57
|
+
})] }), available.length > 0 && (_jsx("div", { children: _jsxs("div", { style: base.row, children: [_jsx("select", { style: Object.assign(Object.assign({}, base.input), { flex: 1, background: colors.bgInput, border: `1px solid ${colors.border}`, minHeight: 22 }), value: addType, onChange: e => setAddType(e.target.value), children: available.map(k => _jsx("option", { value: k, children: k }, k)) }), _jsx("button", { style: base.btn, disabled: !addType, onClick: () => {
|
|
58
58
|
if (!addType)
|
|
59
59
|
return;
|
|
60
60
|
const def = ALL_COMPONENTS[addType];
|
|
@@ -8,9 +8,10 @@ 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 { MapControls, TransformControls } from "@react-three/drei";
|
|
11
|
+
import { MapControls, TransformControls, useHelper } from "@react-three/drei";
|
|
12
12
|
import GameCanvas from "../../shared/GameCanvas";
|
|
13
|
-
import { useCallback, useEffect,
|
|
13
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState, forwardRef, useImperativeHandle, createContext, useContext } from "react";
|
|
14
|
+
import { BoxHelper } from "three";
|
|
14
15
|
import { findComponentEntry } from "./types";
|
|
15
16
|
import PrefabRoot from "./PrefabRoot";
|
|
16
17
|
import { Physics } from "@react-three/rapier";
|
|
@@ -31,6 +32,12 @@ function isObjectAttachedToRoot(root, object) {
|
|
|
31
32
|
}
|
|
32
33
|
return false;
|
|
33
34
|
}
|
|
35
|
+
function SelectionHelper({ object }) {
|
|
36
|
+
const objectRef = useRef(null);
|
|
37
|
+
objectRef.current = object;
|
|
38
|
+
useHelper(object ? objectRef : null, BoxHelper, "cyan");
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
34
41
|
export var PrefabEditorMode;
|
|
35
42
|
(function (PrefabEditorMode) {
|
|
36
43
|
PrefabEditorMode["Edit"] = "edit";
|
|
@@ -52,6 +59,7 @@ const DEFAULT_PREFAB = {
|
|
|
52
59
|
root: createNode('Root', {}, { id: 'root' })
|
|
53
60
|
};
|
|
54
61
|
const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode: initialMode = PrefabEditorMode.Edit, onChange, showUI = true, enableWindowDrop = true, canvasProps, uiPlugins, children }, ref) => {
|
|
62
|
+
var _a, _b;
|
|
55
63
|
const [mode, setMode] = useState(initialMode);
|
|
56
64
|
const [selectedId, setSelectedId] = useState(null);
|
|
57
65
|
const [transformMode, setTransformMode] = useState("translate");
|
|
@@ -64,21 +72,17 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
64
72
|
const [historyIndex, setHistoryIndex] = useState(0);
|
|
65
73
|
const changeOriginRef = useRef(null);
|
|
66
74
|
const historyIndexRef = useRef(0);
|
|
67
|
-
const [, bumpSelectedObjectVersion] = useReducer((value) => value + 1, 0);
|
|
68
75
|
const prefabRootRef = useRef(null);
|
|
69
76
|
const canvasRef = useRef(null);
|
|
70
77
|
const controlsRef = useRef(null);
|
|
78
|
+
const transformControlsRef = useRef(null);
|
|
79
|
+
const transformProxyRef = useRef(null);
|
|
71
80
|
const onChangeRef = useRef(onChange);
|
|
72
81
|
const isEditMode = mode === PrefabEditorMode.Edit;
|
|
73
82
|
const getPrefab = useCallback(() => denormalizePrefab(prefabStore.getState()), [prefabStore]);
|
|
74
83
|
const getRootObject = useCallback(() => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.root) !== null && _b !== void 0 ? _b : null; }, []);
|
|
75
84
|
const getObject = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getObject(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
76
85
|
const getRigidBody = useCallback((nodeId) => { var _a, _b; return (_b = (_a = prefabRootRef.current) === null || _a === void 0 ? void 0 : _a.getRigidBody(nodeId)) !== null && _b !== void 0 ? _b : null; }, []);
|
|
77
|
-
const handleObjectRefChange = useCallback((nodeId) => {
|
|
78
|
-
if (nodeId !== selectedId)
|
|
79
|
-
return;
|
|
80
|
-
bumpSelectedObjectVersion();
|
|
81
|
-
}, [selectedId]);
|
|
82
86
|
onChangeRef.current = onChange;
|
|
83
87
|
const setSelection = useCallback((nodeId) => {
|
|
84
88
|
const nextNode = nodeId ? prefabStore.getState().nodesById[nodeId] : null;
|
|
@@ -104,7 +108,9 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
104
108
|
updateMode(initialMode);
|
|
105
109
|
}, [initialMode, updateMode]);
|
|
106
110
|
const loadPrefab = useCallback((prefab, options) => {
|
|
111
|
+
var _a;
|
|
107
112
|
changeOriginRef.current = (options === null || options === void 0 ? void 0 : options.notifyChange) === false ? "replace-silent" : "replace";
|
|
113
|
+
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
108
114
|
prefabStore.getState().replacePrefab(prefab);
|
|
109
115
|
if (options === null || options === void 0 ? void 0 : options.resetHistory) {
|
|
110
116
|
setSelectedId(null);
|
|
@@ -171,10 +177,23 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
171
177
|
});
|
|
172
178
|
return () => unsubscribe();
|
|
173
179
|
}, [prefabStore, selectedId]);
|
|
180
|
+
const selectedNode = selectedId ? (_a = prefabStore.getState().nodesById[selectedId]) !== null && _a !== void 0 ? _a : null : null;
|
|
174
181
|
const selectedObject = selectedId ? getObject(selectedId) : null;
|
|
175
|
-
const
|
|
176
|
-
|
|
182
|
+
const selectedHasPhysics = Object.values((_b = selectedNode === null || selectedNode === void 0 ? void 0 : selectedNode.components) !== null && _b !== void 0 ? _b : {}).some(component => (component === null || component === void 0 ? void 0 : component.type) === "Physics");
|
|
183
|
+
const transformObject = isEditMode && (selectedHasPhysics ? transformProxyRef.current : selectedObject)
|
|
184
|
+
&& isObjectAttachedToRoot(getRootObject(), selectedObject)
|
|
185
|
+
? (selectedHasPhysics ? transformProxyRef.current : selectedObject)
|
|
177
186
|
: null;
|
|
187
|
+
useLayoutEffect(() => {
|
|
188
|
+
if (!isEditMode || !selectedHasPhysics || !selectedObject || !transformProxyRef.current) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
selectedObject.updateMatrixWorld(true);
|
|
192
|
+
transformProxyRef.current.matrixAutoUpdate = true;
|
|
193
|
+
selectedObject.matrixWorld.decompose(transformProxyRef.current.position, transformProxyRef.current.quaternion, transformProxyRef.current.scale);
|
|
194
|
+
transformProxyRef.current.updateMatrix();
|
|
195
|
+
transformProxyRef.current.updateMatrixWorld(true);
|
|
196
|
+
}, [isEditMode, selectedHasPhysics, selectedId, selectedObject]);
|
|
178
197
|
const addNode = useCallback((node, options) => {
|
|
179
198
|
var _a;
|
|
180
199
|
const { addChild, rootId } = prefabStore.getState();
|
|
@@ -202,7 +221,9 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
202
221
|
return node;
|
|
203
222
|
}, [addNode]);
|
|
204
223
|
const applyHistory = (index) => {
|
|
224
|
+
var _a;
|
|
205
225
|
changeOriginRef.current = "history";
|
|
226
|
+
(_a = transformControlsRef.current) === null || _a === void 0 ? void 0 : _a.detach();
|
|
206
227
|
prefabStore.getState().replacePrefab(history[index]);
|
|
207
228
|
historyIndexRef.current = index;
|
|
208
229
|
setHistoryIndex(index);
|
|
@@ -274,7 +295,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
274
295
|
const handleTransformChange = () => {
|
|
275
296
|
if (!selectedId)
|
|
276
297
|
return;
|
|
277
|
-
const object = getObject(selectedId);
|
|
298
|
+
const object = selectedHasPhysics ? transformProxyRef.current : getObject(selectedId);
|
|
278
299
|
if (!object)
|
|
279
300
|
return;
|
|
280
301
|
const parentWorld = computeParentWorldMatrix(prefabStore.getState(), selectedId);
|
|
@@ -341,7 +362,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
341
362
|
addModel,
|
|
342
363
|
addTexture
|
|
343
364
|
}), [addModel, addNode, addTexture, clearSelection, getObject, getPrefab, getRigidBody, getRootObject, handleExportGLB, handleExportGLBData, handleScreenshot, loadPrefab, prefabStore]);
|
|
344
|
-
const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection,
|
|
365
|
+
const content = (_jsxs(_Fragment, { children: [isEditMode ? _jsx("gridHelper", { args: [10, 10], position: [0, -1, 0] }) : null, _jsx(PrefabRoot, { ref: prefabRootRef, store: prefabStore, editMode: isEditMode, selectedId: selectedId, onSelect: setSelection, basePath: basePath }), children] }));
|
|
345
366
|
const handleCanvasCreated = useCallback((state) => {
|
|
346
367
|
var _a;
|
|
347
368
|
canvasRef.current = state.gl.domElement;
|
|
@@ -370,7 +391,7 @@ const PrefabEditor = forwardRef(({ basePath, initialPrefab, physics = true, mode
|
|
|
370
391
|
}
|
|
371
392
|
(_d = canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed) === null || _d === void 0 ? void 0 : _d.call(canvasProps, event);
|
|
372
393
|
}
|
|
373
|
-
: canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { colliders: false, debug: isEditMode, paused: isEditMode, children: content })) : content, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_jsx(EditorUI, { selectedId: selectedId, setSelectedId: setSelection, getPrefab: getPrefab, onReplacePrefab: (prefab) => loadPrefab(prefab, { resetHistory: true }), onImportPrefab: importPrefab, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] }) });
|
|
394
|
+
: canvasProps === null || canvasProps === void 0 ? void 0 : canvasProps.onPointerMissed, children: [physics ? (_jsx(Physics, { colliders: false, debug: isEditMode, paused: isEditMode, children: content })) : content, _jsx("group", { ref: transformProxyRef, visible: false }), isEditMode ? _jsx(SelectionHelper, { object: transformObject }) : null, isEditMode && (_jsxs(_Fragment, { children: [_jsx(MapControls, { ref: controlsRef, enableDamping: false, makeDefault: true }), transformObject && (_jsx(TransformControls, { ref: transformControlsRef, object: transformObject, mode: transformMode, space: "local", onObjectChange: handleTransformChange, translationSnap: positionSnap > 0 ? positionSnap : undefined, rotationSnap: rotationSnap > 0 ? rotationSnap : undefined, scaleSnap: scaleSnap > 0 ? scaleSnap : undefined }, `transform-${selectedId}-${transformMode}-${positionSnap}-${rotationSnap}-${scaleSnap}`))] }))] })), showUI && (_jsxs(_Fragment, { children: [_jsxs("div", { style: toolbar.panel, children: [_jsx("button", { style: base.btn, onClick: toggleMode, children: isEditMode ? "▶" : "⏸" }), uiPlugins] }), isEditMode && (_jsx(EditorUI, { selectedId: selectedId, setSelectedId: setSelection, getPrefab: getPrefab, onReplacePrefab: (prefab) => loadPrefab(prefab, { resetHistory: true }), onImportPrefab: importPrefab, basePath: basePath, onUndo: undo, onRedo: redo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1 }))] }))] }) });
|
|
374
395
|
});
|
|
375
396
|
PrefabEditor.displayName = "PrefabEditor";
|
|
376
397
|
export default PrefabEditor;
|
|
@@ -18,7 +18,6 @@ export interface PrefabRootProps {
|
|
|
18
18
|
selectedId?: string | null;
|
|
19
19
|
onSelect?: (id: string | null) => void;
|
|
20
20
|
onClick?: (event: ThreeEvent<PointerEvent>, entity: GameObjectType) => void;
|
|
21
|
-
onObjectRefChange?: (id: string, object: Object3D | null) => void;
|
|
22
21
|
basePath?: string;
|
|
23
22
|
}
|
|
24
23
|
export declare const PrefabRoot: import("react").ForwardRefExoticComponent<PrefabRootProps & import("react").RefAttributes<PrefabRootRef>>;
|
|
@@ -10,9 +10,8 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
-
import { useHelper } from "@react-three/drei";
|
|
14
13
|
import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
15
|
-
import {
|
|
14
|
+
import { Euler, Matrix4, } from "three";
|
|
16
15
|
import { useStore } from "zustand";
|
|
17
16
|
import { useClickValid } from "./useClickValid";
|
|
18
17
|
import { findComponent, getNodeUserData } from "./types";
|
|
@@ -69,7 +68,7 @@ function getNodeMetadataProps(node) {
|
|
|
69
68
|
userData: Object.assign(Object.assign({ prefabNodeId: node.id }, (nodeName ? { prefabNodeName: nodeName } : {})), getNodeUserData(node)),
|
|
70
69
|
};
|
|
71
70
|
}
|
|
72
|
-
export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick,
|
|
71
|
+
export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSelect, onClick, basePath = "" }, ref) => {
|
|
73
72
|
var _a;
|
|
74
73
|
const [models, setModels] = useState({});
|
|
75
74
|
const [textures, setTextures] = useState({});
|
|
@@ -120,8 +119,7 @@ export const PrefabRoot = forwardRef(({ editMode, data, store, selectedId, onSel
|
|
|
120
119
|
}), [getObject]);
|
|
121
120
|
const registerRef = useCallback((id, obj) => {
|
|
122
121
|
objectRefs.current[id] = obj;
|
|
123
|
-
|
|
124
|
-
}, [onObjectRefChange]);
|
|
122
|
+
}, []);
|
|
125
123
|
const registerRigidBodyRef = useCallback((id, rb) => {
|
|
126
124
|
rigidBodyRefs.current.set(id, rb);
|
|
127
125
|
}, []);
|
|
@@ -293,18 +291,10 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
293
291
|
const clickEventName = getNodeClickEventName(gameObject);
|
|
294
292
|
const metadataProps = getNodeMetadataProps(gameObject);
|
|
295
293
|
const groupRef = useRef(null);
|
|
296
|
-
const helperRef = useRef(null);
|
|
297
294
|
const handleGroupRef = useCallback((object) => {
|
|
298
295
|
groupRef.current = object;
|
|
299
296
|
registerRef(nodeId, object);
|
|
300
297
|
}, [nodeId, registerRef]);
|
|
301
|
-
const handleHelperRef = useCallback((object) => {
|
|
302
|
-
helperRef.current = object;
|
|
303
|
-
}, []);
|
|
304
|
-
const handleEditGroupRef = useCallback((object) => {
|
|
305
|
-
handleGroupRef(object);
|
|
306
|
-
handleHelperRef(object);
|
|
307
|
-
}, [handleGroupRef, handleHelperRef]);
|
|
308
298
|
const editClickHandlers = useClickValid(!!editMode && !isLocked, (event) => {
|
|
309
299
|
onSelect === null || onSelect === void 0 ? void 0 : onSelect(nodeId);
|
|
310
300
|
onClick === null || onClick === void 0 ? void 0 : onClick(event, gameObject);
|
|
@@ -318,7 +308,6 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
318
308
|
},
|
|
319
309
|
}
|
|
320
310
|
: undefined;
|
|
321
|
-
useHelper(editMode && isSelected ? helperRef : null, BoxHelper, "cyan");
|
|
322
311
|
const world = parentMatrix.clone().multiply(compose(gameObject));
|
|
323
312
|
const physics = findComponent(gameObject, "Physics");
|
|
324
313
|
const ready = isNodeReady(gameObject, loadedModels);
|
|
@@ -336,8 +325,10 @@ function StandardNode({ nodeId, selectedId, onSelect, onClick, registerRef, load
|
|
|
336
325
|
const renderCtx = { loadedModels, editMode, registerRef };
|
|
337
326
|
const childNodes = _jsx(ChildNodes, { childIds: childIds, parentMatrix: world, selectedId: selectedId, onSelect: onSelect, onClick: onClick, registerRef: registerRef, loadedModels: loadedModels, editMode: editMode });
|
|
338
327
|
const inner = renderCompositionNode(gameObject, renderCtx, primaryClickHandlers, childNodes);
|
|
339
|
-
const
|
|
340
|
-
|
|
328
|
+
const editAnchor = editMode ? (_jsx("mesh", { visible: false, children: _jsx("boxGeometry", { args: [0.01, 0.01, 0.01] }) })) : null;
|
|
329
|
+
const standardNode = (_jsxs("group", Object.assign({ ref: handleGroupRef }, groupProps, (editMode ? editClickHandlers : undefined), { children: [editAnchor, inner] })));
|
|
330
|
+
const physicsNode = hasPhysics && (physicsDef === null || physicsDef === void 0 ? void 0 : physicsDef.View) ? (_jsx(physicsDef.View, Object.assign({ properties: physics.properties }, transformProps, { children: _jsxs("group", Object.assign({ ref: handleGroupRef }, metadataProps, (editMode ? editClickHandlers : undefined), { children: [editAnchor, inner] })) }), physicsKey)) : null;
|
|
331
|
+
return (_jsx(EntityRuntimeScope, { nodeId: nodeId, editMode: editMode, isSelected: isSelected, children: physicsNode !== null && physicsNode !== void 0 ? physicsNode : standardNode }));
|
|
341
332
|
}
|
|
342
333
|
function isRendererHandledComponent(componentType) {
|
|
343
334
|
return componentType === "Transform"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { BooleanField, FieldGroup, StringField } from "./Input";
|
|
3
|
+
import { base, ui } from "../styles";
|
|
3
4
|
const DEFAULT_TRIANGLE_POSITIONS = [
|
|
4
5
|
0, 0, 0,
|
|
5
6
|
1, 0, 0,
|
|
@@ -37,7 +38,7 @@ function getIndexArray(indices) {
|
|
|
37
38
|
return maxIndex > 65535 ? new Uint32Array(indices) : new Uint16Array(indices);
|
|
38
39
|
}
|
|
39
40
|
function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
|
|
40
|
-
return (_jsxs("label", { style: { display: 'grid', gap: 4 }, children: [_jsx("span", { style: {
|
|
41
|
+
return (_jsxs("label", { style: { display: 'grid', gap: 4 }, children: [_jsx("span", { style: Object.assign(Object.assign({}, base.label), { textTransform: 'uppercase', letterSpacing: '0.05em' }), children: label }), _jsx("textarea", { rows: rows, spellCheck: false, defaultValue: toAttributeText(value, fallback), onBlur: (event) => {
|
|
41
42
|
try {
|
|
42
43
|
onChange(parseArrayInput(event.target.value));
|
|
43
44
|
event.target.setCustomValidity('');
|
|
@@ -46,19 +47,7 @@ function BufferArrayField({ label, value, fallback, onChange, rows = 4, }) {
|
|
|
46
47
|
event.target.setCustomValidity('Expected a JSON array of numbers');
|
|
47
48
|
event.target.reportValidity();
|
|
48
49
|
}
|
|
49
|
-
}, style: {
|
|
50
|
-
width: '100%',
|
|
51
|
-
backgroundColor: '#171717',
|
|
52
|
-
border: '1px solid #333',
|
|
53
|
-
padding: '6px 8px',
|
|
54
|
-
fontSize: '11px',
|
|
55
|
-
color: '#eee',
|
|
56
|
-
fontFamily: 'monospace',
|
|
57
|
-
outline: 'none',
|
|
58
|
-
borderRadius: 3,
|
|
59
|
-
resize: 'vertical',
|
|
60
|
-
boxSizing: 'border-box',
|
|
61
|
-
} })] }));
|
|
50
|
+
}, style: Object.assign(Object.assign({}, ui.monoTextInput), { width: '100%', minHeight: rows * 18, padding: '4px 6px', outline: 'none', resize: 'vertical', boxSizing: 'border-box' }) })] }));
|
|
62
51
|
}
|
|
63
52
|
function BufferGeometryComponentEditor({ component, onUpdate, }) {
|
|
64
53
|
var _a;
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { colors } from "../styles";
|
|
3
|
+
import { colors, ui } from "../styles";
|
|
4
4
|
const RESERVED_USER_DATA_KEYS = new Set([
|
|
5
5
|
'prefabNodeId',
|
|
6
6
|
'prefabNodeName',
|
|
7
7
|
]);
|
|
8
|
-
const inputStyle = {
|
|
9
|
-
width: '100%',
|
|
10
|
-
backgroundColor: colors.bgInput,
|
|
11
|
-
border: `1px solid ${colors.border}`,
|
|
12
|
-
padding: '6px 8px',
|
|
13
|
-
fontSize: '11px',
|
|
14
|
-
color: colors.text,
|
|
15
|
-
fontFamily: 'monospace',
|
|
16
|
-
outline: 'none',
|
|
17
|
-
borderRadius: 3,
|
|
18
|
-
boxSizing: 'border-box',
|
|
19
|
-
};
|
|
8
|
+
const inputStyle = Object.assign(Object.assign({}, ui.monoTextInput), { width: '100%', padding: '4px 6px', fontSize: '11px', outline: 'none', boxSizing: 'border-box' });
|
|
20
9
|
function isRecord(value) {
|
|
21
10
|
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
22
11
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { colors } from '../styles';
|
|
3
|
+
import { colors, ui } from '../styles';
|
|
4
4
|
import { useOptionalPrefabStoreApi } from '../prefabStore';
|
|
5
5
|
// ============================================================================
|
|
6
6
|
// Shared Styles (derived from shared color tokens)
|
|
@@ -10,13 +10,13 @@ const styles = {
|
|
|
10
10
|
width: '80px',
|
|
11
11
|
backgroundColor: colors.bgInput,
|
|
12
12
|
border: `1px solid ${colors.border}`,
|
|
13
|
-
padding: '
|
|
13
|
+
padding: '2px 4px',
|
|
14
14
|
fontSize: '11px',
|
|
15
15
|
color: colors.text,
|
|
16
16
|
fontFamily: 'monospace',
|
|
17
17
|
outline: 'none',
|
|
18
18
|
textAlign: 'right',
|
|
19
|
-
borderRadius:
|
|
19
|
+
borderRadius: 0,
|
|
20
20
|
},
|
|
21
21
|
label: {
|
|
22
22
|
display: 'block',
|
|
@@ -229,9 +229,9 @@ export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
|
229
229
|
gap: 4,
|
|
230
230
|
backgroundColor: colors.bgInput,
|
|
231
231
|
border: `1px solid ${colors.border}`,
|
|
232
|
-
borderRadius:
|
|
233
|
-
padding: '4px
|
|
234
|
-
minHeight:
|
|
232
|
+
borderRadius: 0,
|
|
233
|
+
padding: '2px 4px',
|
|
234
|
+
minHeight: 22,
|
|
235
235
|
cursor: 'ew-resize',
|
|
236
236
|
}, onPointerDown: e => startScrub(e, index), onPointerMove: onScrubMove, onPointerUp: endScrub, children: [_jsx("span", { style: {
|
|
237
237
|
fontSize: 11,
|
|
@@ -265,13 +265,13 @@ export function Vector3Input({ label, value, onChange, snap, labelExtra }) {
|
|
|
265
265
|
// ============================================================================
|
|
266
266
|
export function ColorInput({ label, value, onChange }) {
|
|
267
267
|
return (_jsxs("div", { children: [label && _jsx(Label, { children: label }), _jsxs("div", { style: { display: 'flex', gap: 4, justifyContent: 'space-between' }, children: [_jsx("input", { type: "color", style: {
|
|
268
|
-
height:
|
|
268
|
+
height: 22,
|
|
269
269
|
width: 48,
|
|
270
270
|
backgroundColor: colors.bgInput,
|
|
271
271
|
border: `1px solid ${colors.border}`,
|
|
272
|
-
borderRadius:
|
|
272
|
+
borderRadius: 0,
|
|
273
273
|
cursor: 'pointer',
|
|
274
|
-
padding:
|
|
274
|
+
padding: 1,
|
|
275
275
|
flexShrink: 0,
|
|
276
276
|
}, value: value, onChange: e => onChange(e.target.value) }), _jsx("input", { type: "text", style: Object.assign({}, styles.input), value: value, onChange: e => onChange(e.target.value) })] })] }));
|
|
277
277
|
}
|
|
@@ -304,20 +304,20 @@ function SearchSuggestionList({ query, options, onSelect, emptyMessage, }) {
|
|
|
304
304
|
gap: 4,
|
|
305
305
|
maxHeight: 160,
|
|
306
306
|
overflowY: 'auto',
|
|
307
|
-
border:
|
|
308
|
-
borderRadius:
|
|
307
|
+
border: 'none',
|
|
308
|
+
borderRadius: 0,
|
|
309
309
|
background: colors.bgSurface,
|
|
310
|
-
padding:
|
|
310
|
+
padding: 2,
|
|
311
311
|
}, children: filtered.length === 0 ? (_jsx("div", { style: { fontSize: 11, color: colors.textMuted, padding: '4px 6px' }, children: emptyMessage })) : filtered.map(option => (_jsxs("button", { type: "button", onClick: () => onSelect(option.value), style: {
|
|
312
312
|
display: 'flex',
|
|
313
313
|
flexDirection: 'column',
|
|
314
314
|
alignItems: 'flex-start',
|
|
315
315
|
gap: 2,
|
|
316
|
-
border:
|
|
317
|
-
borderRadius:
|
|
318
|
-
background: colors.
|
|
316
|
+
border: 'none',
|
|
317
|
+
borderRadius: 0,
|
|
318
|
+
background: colors.bgSurface,
|
|
319
319
|
color: colors.text,
|
|
320
|
-
padding: '6px
|
|
320
|
+
padding: '4px 6px',
|
|
321
321
|
cursor: 'pointer',
|
|
322
322
|
textAlign: 'left',
|
|
323
323
|
}, children: [_jsx("span", { style: { fontSize: 11, fontWeight: 500 }, children: option.label }), option.description ? (_jsx("span", { style: { fontSize: 10, color: colors.textMuted, fontFamily: 'monospace' }, children: option.description })) : null] }, option.value))) })] }));
|
|
@@ -383,19 +383,7 @@ export function ListEditor({ label, items, renderItem, onAdd, addOptions = [], e
|
|
|
383
383
|
setSelectedAddValue((_b = (_a = addOptions[0]) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : '');
|
|
384
384
|
}
|
|
385
385
|
}, [addOptions, hasAddSelector, selectedAddValue]);
|
|
386
|
-
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(Label, { children: label }), _jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'center' }, children: [hasAddSelector ? (_jsx("div", { style: { minWidth: 140 }, children: _jsx(SelectInput, { value: resolvedAddValue, onChange: setSelectedAddValue, options: canAdd ? addOptions : [{ value: '', label: 'All items added' }] }) })) : null, _jsx("button", { type: "button", onClick: () => onAdd(resolvedAddValue), disabled: !canAddItem, style: {
|
|
387
|
-
width: 22,
|
|
388
|
-
height: 22,
|
|
389
|
-
borderRadius: 3,
|
|
390
|
-
border: `1px solid ${canAddItem ? colors.accentBorder : colors.border}`,
|
|
391
|
-
background: canAddItem ? colors.accentBg : colors.bgSurface,
|
|
392
|
-
color: canAddItem ? colors.accent : colors.textMuted,
|
|
393
|
-
cursor: canAddItem ? 'pointer' : 'not-allowed',
|
|
394
|
-
fontSize: 14,
|
|
395
|
-
lineHeight: 1,
|
|
396
|
-
padding: 0,
|
|
397
|
-
flexShrink: 0,
|
|
398
|
-
}, title: canAddItem ? addButtonTitle : addDisabledTitle, children: "+" })] })] }), items.length === 0 ? (_jsx("div", { style: { fontSize: 11, color: colors.textMuted }, children: emptyMessage })) : null, items.map(renderItem)] }));
|
|
386
|
+
return (_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [_jsx(Label, { children: label }), _jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'center' }, children: [hasAddSelector ? (_jsx("div", { style: { minWidth: 140 }, children: _jsx(SelectInput, { value: resolvedAddValue, onChange: setSelectedAddValue, options: canAdd ? addOptions : [{ value: '', label: 'All items added' }] }) })) : null, _jsx("button", { type: "button", onClick: () => onAdd(resolvedAddValue), disabled: !canAddItem, style: Object.assign(Object.assign({}, ui.compactActionButton), { width: 22, minWidth: 22, height: 22, border: `1px solid ${canAddItem ? colors.accentBorder : colors.border}`, background: canAddItem ? colors.accentBg : colors.bgSurface, color: canAddItem ? colors.accent : colors.textMuted, cursor: canAddItem ? 'pointer' : 'not-allowed', fontSize: 14, lineHeight: 1 }), title: canAddItem ? addButtonTitle : addDisabledTitle, children: "+" })] })] }), items.length === 0 ? (_jsx("div", { style: { fontSize: 11, color: colors.textMuted }, children: emptyMessage })) : null, items.map(renderItem)] }));
|
|
399
387
|
}
|
|
400
388
|
export function NumberField({ name, label, values, onChange, fallback = 0, step, min, max, style, }) {
|
|
401
389
|
var _a;
|
|
@@ -5,7 +5,7 @@ import { BooleanField, FieldGroup, Label, ListEditor, NumberInput, SelectInput,
|
|
|
5
5
|
import { useAssetRuntime } from '../assetRuntime';
|
|
6
6
|
import { EditorContext } from '../PrefabEditor';
|
|
7
7
|
import { getRepeatAxesFromModelProperties, normalizeRepeatAxes } from '../InstanceProvider';
|
|
8
|
-
import { colors } from '../styles';
|
|
8
|
+
import { colors, ui } from '../styles';
|
|
9
9
|
const AXIS_OPTIONS = [
|
|
10
10
|
{ value: 'x', label: 'X' },
|
|
11
11
|
{ value: 'y', label: 'Y' },
|
|
@@ -35,25 +35,7 @@ function RepeatAxisEditor({ axes, onChange, positionSnap, }) {
|
|
|
35
35
|
return (_jsx(ListEditor, { label: "Repeat Axes", items: axes, onAdd: addAxis, addOptions: availableAxisOptions, canAdd: availableAxisOptions.length > 0, emptyMessage: "No repeat axes added.", addButtonTitle: "Add repeat axis", addDisabledTitle: "All axes already in use", renderItem: (axisConfig, index) => {
|
|
36
36
|
const usedByOthers = new Set(axes.filter((_, axisIndex) => axisIndex !== index).map(axis => axis.axis));
|
|
37
37
|
const axisOptions = AXIS_OPTIONS.filter(option => option.value === axisConfig.axis || !usedByOthers.has(option.value));
|
|
38
|
-
return (_jsxs("div", { style: {
|
|
39
|
-
display: 'flex',
|
|
40
|
-
flexDirection: 'column',
|
|
41
|
-
gap: 6,
|
|
42
|
-
padding: 8,
|
|
43
|
-
border: `1px solid ${colors.border}`,
|
|
44
|
-
borderRadius: 4,
|
|
45
|
-
background: colors.bgSurface,
|
|
46
|
-
}, children: [_jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'end' }, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsx(SelectInput, { label: "Axis", value: axisConfig.axis, onChange: (axis) => updateAxis(index, { axis: axis }), options: axisOptions }) }), _jsx("button", { type: "button", onClick: () => removeAxis(index), style: {
|
|
47
|
-
height: 24,
|
|
48
|
-
width: 28,
|
|
49
|
-
borderRadius: 3,
|
|
50
|
-
border: `1px solid ${colors.border}`,
|
|
51
|
-
background: colors.bgInput,
|
|
52
|
-
color: colors.text,
|
|
53
|
-
cursor: 'pointer',
|
|
54
|
-
padding: 0,
|
|
55
|
-
flexShrink: 0,
|
|
56
|
-
}, title: "Remove repeat axis", children: "\u00D7" })] }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsxs("div", { children: [_jsx(Label, { children: "Count" }), _jsx(NumberInput, { value: axisConfig.count, onChange: (count) => updateAxis(index, { count: Math.max(1, Math.floor(count)) }), step: 1, min: 1, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { children: [_jsx(Label, { children: "Offset" }), _jsx(NumberInput, { value: axisConfig.offset, onChange: (offset) => updateAxis(index, { offset: quantize(offset, positionSnap) }), step: positionSnap > 0 ? positionSnap : 0.1, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] })] }, `${axisConfig.axis}-${index}`));
|
|
38
|
+
return (_jsxs("div", { style: Object.assign(Object.assign({}, ui.secondaryPanel), { display: 'flex', flexDirection: 'column', gap: 6 }), children: [_jsxs("div", { style: { display: 'flex', gap: 6, alignItems: 'end' }, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsx(SelectInput, { label: "Axis", value: axisConfig.axis, onChange: (axis) => updateAxis(index, { axis: axis }), options: axisOptions }) }), _jsx("button", { type: "button", onClick: () => removeAxis(index), style: Object.assign(Object.assign({}, ui.compactActionButton), { height: 24, background: colors.bgInput }), title: "Remove repeat axis", children: "\u00D7" })] }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 6 }, children: [_jsxs("div", { children: [_jsx(Label, { children: "Count" }), _jsx(NumberInput, { value: axisConfig.count, onChange: (count) => updateAxis(index, { count: Math.max(1, Math.floor(count)) }), step: 1, min: 1, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] }), _jsxs("div", { children: [_jsx(Label, { children: "Offset" }), _jsx(NumberInput, { value: axisConfig.offset, onChange: (offset) => updateAxis(index, { offset: quantize(offset, positionSnap) }), step: positionSnap > 0 ? positionSnap : 0.1, style: { width: '100%', minWidth: 0, boxSizing: 'border-box' } })] })] })] }, `${axisConfig.axis}-${index}`));
|
|
57
39
|
} }));
|
|
58
40
|
}
|
|
59
41
|
function ModelComponentEditor({ component, node, onUpdate, basePath = "" }) {
|
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
};
|
|
12
12
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
13
|
import { BallCollider, CapsuleCollider, CuboidCollider, RigidBody, useRapier } from "@react-three/rapier";
|
|
14
|
-
import { useCallback, useEffect, useRef } from 'react';
|
|
14
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
15
15
|
import { useAssetRuntime, useEntityRuntime } from "../assetRuntime";
|
|
16
16
|
import { gameEvents, getEntityIdFromRigidBody } from "../GameEvents";
|
|
17
17
|
import { usePrefabNode, usePrefabStore } from "../prefabStore";
|
|
@@ -27,6 +27,7 @@ const colliderSizeFallback = [1, 1, 1];
|
|
|
27
27
|
const colliderRadiusFallback = 0.5;
|
|
28
28
|
const capsuleRadiusFallback = 0.35;
|
|
29
29
|
const capsuleHalfHeightFallback = 0.45;
|
|
30
|
+
const EDIT_MODE_DEBUG_REFRESH_THROTTLE_MS = 120;
|
|
30
31
|
function isManualColliderShape(value) {
|
|
31
32
|
return value === 'cuboid' || value === 'ball' || value === 'capsule';
|
|
32
33
|
}
|
|
@@ -90,10 +91,11 @@ function LockedAxisField({ label, name, values, onChange, }) {
|
|
|
90
91
|
const isLocked = !enabledAxes[index];
|
|
91
92
|
return (_jsx("button", { type: "button", onClick: () => toggleAxisLock(index), style: {
|
|
92
93
|
flex: 1,
|
|
94
|
+
minHeight: 22,
|
|
93
95
|
backgroundColor: isLocked ? colors.dangerBg : colors.bgInput,
|
|
94
96
|
border: `1px solid ${isLocked ? colors.dangerBorder : colors.border}`,
|
|
95
|
-
borderRadius:
|
|
96
|
-
padding: '6px
|
|
97
|
+
borderRadius: 0,
|
|
98
|
+
padding: '2px 6px',
|
|
97
99
|
color: isLocked ? colors.danger : colors.textMuted,
|
|
98
100
|
fontSize: '11px',
|
|
99
101
|
fontFamily: 'monospace',
|
|
@@ -145,11 +147,12 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
145
147
|
? 'capsule'
|
|
146
148
|
: resolvedManualColliderShape;
|
|
147
149
|
const rigidBodyRef = useRef(null);
|
|
150
|
+
const [editRefreshVersion, setEditRefreshVersion] = useState(0);
|
|
151
|
+
const lastEditRefreshAtRef = useRef(0);
|
|
148
152
|
const linearVelocityKey = linearVelocity.join(',');
|
|
149
153
|
const angularVelocityKey = angularVelocity.join(',');
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
: `${type || 'dynamic'}_${colliderType}_${resolvedManualColliderShape}_${colliderSize.join(',')}_${colliderRadius}_${capsuleRadius}_${capsuleHalfHeight}`;
|
|
154
|
+
const transformSignature = `${position === null || position === void 0 ? void 0 : position.join(',')}_${rotation === null || rotation === void 0 ? void 0 : rotation.join(',')}_${scale === null || scale === void 0 ? void 0 : scale.join(',')}`;
|
|
155
|
+
const rbKey = `${type || 'dynamic'}_${colliderType}_${resolvedManualColliderShape}_${colliderSize.join(',')}_${colliderRadius}_${capsuleRadius}_${capsuleHalfHeight}_${editMode ? editRefreshVersion : 0}`;
|
|
153
156
|
const handleRigidBodyRef = useCallback((rigidBody) => {
|
|
154
157
|
rigidBodyRef.current = rigidBody;
|
|
155
158
|
if (!nodeId)
|
|
@@ -178,6 +181,23 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
178
181
|
}
|
|
179
182
|
}
|
|
180
183
|
}, [activeCollisionTypes, rapier, type, colliders]);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (!editMode) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const now = Date.now();
|
|
189
|
+
const delay = Math.max(0, EDIT_MODE_DEBUG_REFRESH_THROTTLE_MS - (now - lastEditRefreshAtRef.current));
|
|
190
|
+
if (delay === 0) {
|
|
191
|
+
lastEditRefreshAtRef.current = now;
|
|
192
|
+
setEditRefreshVersion(version => version + 1);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const timeoutId = setTimeout(() => {
|
|
196
|
+
lastEditRefreshAtRef.current = Date.now();
|
|
197
|
+
setEditRefreshVersion(version => version + 1);
|
|
198
|
+
}, delay);
|
|
199
|
+
return () => clearTimeout(timeoutId);
|
|
200
|
+
}, [editMode, transformSignature]);
|
|
181
201
|
// Seed authored velocities when the body instance changes or the authored values change.
|
|
182
202
|
useEffect(() => {
|
|
183
203
|
if (!rigidBodyRef.current)
|
|
@@ -243,14 +263,15 @@ function PhysicsComponentView({ properties, children, position, rotation, scale
|
|
|
243
263
|
sensor,
|
|
244
264
|
enabledTranslations,
|
|
245
265
|
enabledRotations, name: nodeName, userData: Object.assign({ entityId: nodeId }, userData), onIntersectionEnter: emitSensorEnterEvent ? handleIntersectionEnter : undefined, onIntersectionExit: emitSensorExitEvent ? handleIntersectionExit : undefined, onCollisionEnter: emitCollisionEnterEvent ? handleCollisionEnter : undefined, onCollisionExit: emitCollisionExitEvent ? handleCollisionExit : undefined }, otherProps);
|
|
246
|
-
|
|
266
|
+
const rigidBodyContent = (_jsxs(_Fragment, { children: [!usesAutomaticColliderSource ? renderManualCollider({
|
|
247
267
|
shape: manualColliderShapeToRender,
|
|
248
268
|
sensor,
|
|
249
269
|
colliderSize,
|
|
250
270
|
colliderRadius,
|
|
251
271
|
capsuleRadius,
|
|
252
272
|
capsuleHalfHeight,
|
|
253
|
-
}) : null, children] })
|
|
273
|
+
}) : null, children] }));
|
|
274
|
+
return (_jsx(RigidBody, Object.assign({}, rigidBodyProps, { children: rigidBodyContent }), rbKey));
|
|
254
275
|
}
|
|
255
276
|
const PhysicsComponent = {
|
|
256
277
|
name: 'Physics',
|
|
@@ -5,7 +5,7 @@ import { SoundPicker } from '../../assetviewer/page';
|
|
|
5
5
|
import { useAssetRuntime, useEntityRuntime } from '../assetRuntime';
|
|
6
6
|
import { gameEvents } from '../GameEvents';
|
|
7
7
|
import { BooleanField, FieldGroup, FieldRenderer, ListEditor, NumberField, SelectField, StringField } from './Input';
|
|
8
|
-
import { colors } from '../styles';
|
|
8
|
+
import { colors, ui } from '../styles';
|
|
9
9
|
import { AudioListener } from 'three';
|
|
10
10
|
const CLIP_MODE_OPTIONS = [
|
|
11
11
|
{ value: 'single', label: 'Single Clip' },
|
|
@@ -116,25 +116,7 @@ function SoundComponentEditor({ component, onUpdate, basePath = '' }) {
|
|
|
116
116
|
type: 'select',
|
|
117
117
|
options: CLIP_MODE_OPTIONS.map(option => ({ value: option.value, label: option.label })),
|
|
118
118
|
},
|
|
119
|
-
], values: component.properties, onChange: onUpdate }), _jsx(ListEditor, { label: "Clips", items: clips, onAdd: addClip, emptyMessage: "No clips added.", addButtonTitle: "Add clip", addDisabledTitle: "Add clip", renderItem: (clip, index) => (_jsxs("div", { style: {
|
|
120
|
-
display: 'flex',
|
|
121
|
-
gap: 6,
|
|
122
|
-
alignItems: 'end',
|
|
123
|
-
padding: 8,
|
|
124
|
-
border: `1px solid ${colors.border}`,
|
|
125
|
-
borderRadius: 4,
|
|
126
|
-
background: colors.bgSurface,
|
|
127
|
-
}, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsx(SoundPicker, { value: clip || undefined, onChange: (nextPath) => updateClip(index, nextPath !== null && nextPath !== void 0 ? nextPath : ''), basePath: basePath }) }), _jsx("button", { type: "button", onClick: () => removeClip(index), style: {
|
|
128
|
-
height: 24,
|
|
129
|
-
width: 28,
|
|
130
|
-
borderRadius: 3,
|
|
131
|
-
border: `1px solid ${colors.border}`,
|
|
132
|
-
background: colors.bgInput,
|
|
133
|
-
color: colors.text,
|
|
134
|
-
cursor: 'pointer',
|
|
135
|
-
padding: 0,
|
|
136
|
-
flexShrink: 0,
|
|
137
|
-
}, title: "Remove clip", children: "\u00D7" })] }, `${clip}-${index}`)) }), _jsx(BooleanField, { name: "positional", label: "Positional", values: component.properties, onChange: onUpdate, fallback: false }), positional ? (_jsxs(_Fragment, { children: [_jsx(NumberField, { name: "refDistance", label: "Ref Distance", values: component.properties, onChange: onUpdate, fallback: 1, min: 0.01, step: 0.1 }), _jsx(NumberField, { name: "maxDistance", label: "Max Distance", values: component.properties, onChange: onUpdate, fallback: 24, min: 0.01, step: 0.1 }), _jsx(NumberField, { name: "rolloffFactor", label: "Rolloff", values: component.properties, onChange: onUpdate, fallback: 1, min: 0, step: 0.1 }), _jsx(SelectField, { name: "distanceModel", label: "Distance Model", values: component.properties, onChange: onUpdate, fallback: "inverse", options: [
|
|
119
|
+
], values: component.properties, onChange: onUpdate }), _jsx(ListEditor, { label: "Clips", items: clips, onAdd: addClip, emptyMessage: "No clips added.", addButtonTitle: "Add clip", addDisabledTitle: "Add clip", renderItem: (clip, index) => (_jsxs("div", { style: Object.assign(Object.assign({}, ui.secondaryPanel), { display: 'flex', gap: 6, alignItems: 'end' }), children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: _jsx(SoundPicker, { value: clip || undefined, onChange: (nextPath) => updateClip(index, nextPath !== null && nextPath !== void 0 ? nextPath : ''), basePath: basePath }) }), _jsx("button", { type: "button", onClick: () => removeClip(index), style: Object.assign(Object.assign({}, ui.compactActionButton), { height: 24, background: colors.bgInput }), title: "Remove clip", children: "\u00D7" })] }, `${clip}-${index}`)) }), _jsx(BooleanField, { name: "positional", label: "Positional", values: component.properties, onChange: onUpdate, fallback: false }), positional ? (_jsxs(_Fragment, { children: [_jsx(NumberField, { name: "refDistance", label: "Ref Distance", values: component.properties, onChange: onUpdate, fallback: 1, min: 0.01, step: 0.1 }), _jsx(NumberField, { name: "maxDistance", label: "Max Distance", values: component.properties, onChange: onUpdate, fallback: 24, min: 0.01, step: 0.1 }), _jsx(NumberField, { name: "rolloffFactor", label: "Rolloff", values: component.properties, onChange: onUpdate, fallback: 1, min: 0, step: 0.1 }), _jsx(SelectField, { name: "distanceModel", label: "Distance Model", values: component.properties, onChange: onUpdate, fallback: "inverse", options: [
|
|
138
120
|
{ value: 'inverse', label: 'Inverse' },
|
|
139
121
|
{ value: 'linear', label: 'Linear' },
|
|
140
122
|
{ value: 'exponential', label: 'Exponential' },
|
|
@@ -3,15 +3,16 @@ import { Label, Vector3Input } from "./Input";
|
|
|
3
3
|
import { useEditorContext } from "../PrefabEditor";
|
|
4
4
|
import { colors } from "../styles";
|
|
5
5
|
const buttonStyle = {
|
|
6
|
-
padding: '
|
|
6
|
+
padding: '2px 6px',
|
|
7
7
|
background: colors.bgSurface,
|
|
8
8
|
color: colors.text,
|
|
9
9
|
border: `1px solid ${colors.border}`,
|
|
10
|
-
borderRadius:
|
|
10
|
+
borderRadius: 0,
|
|
11
11
|
cursor: 'pointer',
|
|
12
12
|
font: 'inherit',
|
|
13
13
|
fontSize: 11,
|
|
14
14
|
flex: 1,
|
|
15
|
+
minHeight: 22,
|
|
15
16
|
};
|
|
16
17
|
function TransformModeSelector({ transformMode, setTransformMode }) {
|
|
17
18
|
return (_jsxs("div", { style: { marginBottom: 8 }, children: [_jsx(Label, { children: "Transform Mode" }), _jsx("div", { style: { display: 'flex', gap: 6 }, children: ["translate", "rotate", "scale"].map(mode => {
|
|
@@ -29,7 +30,7 @@ const snapLockBtnStyle = {
|
|
|
29
30
|
background: 'none',
|
|
30
31
|
border: 'none',
|
|
31
32
|
cursor: 'pointer',
|
|
32
|
-
padding:
|
|
33
|
+
padding: 0,
|
|
33
34
|
fontSize: 12,
|
|
34
35
|
lineHeight: 1,
|
|
35
36
|
color: colors.textMuted,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
-
import { colors } from '../styles';
|
|
3
|
+
import { base, colors, ui } from '../styles';
|
|
4
4
|
import { FieldGroup, FieldRow, NumberInput } from './Input';
|
|
5
5
|
export function mergeWithDefaults(defaults, properties) {
|
|
6
6
|
const merged = Object.assign({}, defaults);
|
|
@@ -15,15 +15,7 @@ export function mergeWithDefaults(defaults, properties) {
|
|
|
15
15
|
return merged;
|
|
16
16
|
}
|
|
17
17
|
export function LightSection({ title, children }) {
|
|
18
|
-
return (_jsxs("div", { style: {
|
|
19
|
-
display: 'flex',
|
|
20
|
-
flexDirection: 'column',
|
|
21
|
-
gap: 8,
|
|
22
|
-
padding: '8px 10px',
|
|
23
|
-
border: `1px solid ${colors.border}`,
|
|
24
|
-
borderRadius: 6,
|
|
25
|
-
background: colors.bgSurface,
|
|
26
|
-
}, children: [_jsx("div", { style: {
|
|
18
|
+
return (_jsxs("div", { style: Object.assign(Object.assign({}, ui.secondaryPanel), { display: 'flex', flexDirection: 'column', gap: 8, padding: 6 }), children: [_jsx("div", { style: {
|
|
27
19
|
fontSize: 10,
|
|
28
20
|
textTransform: 'uppercase',
|
|
29
21
|
letterSpacing: '0.08em',
|
|
@@ -51,14 +43,5 @@ export function ShadowBiasField({ name, label, values, onChange, fallback = 0, }
|
|
|
51
43
|
var _a;
|
|
52
44
|
const value = (_a = values[name]) !== null && _a !== void 0 ? _a : fallback;
|
|
53
45
|
const [step, setStep] = useState(() => getBiasStep(value));
|
|
54
|
-
return (_jsx(FieldRow, { label: label, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6 }, children: [_jsx(NumberInput, { value: value, onChange: nextValue => onChange({ [name]: nextValue }), step: step, min: -0.1, max: 0.1, style: { width: 92 } }), _jsx("select", { value: step.toString(), onChange: event => setStep(Number(event.target.value)), style: {
|
|
55
|
-
width: 78,
|
|
56
|
-
backgroundColor: colors.bgInput,
|
|
57
|
-
border: `1px solid ${colors.border}`,
|
|
58
|
-
color: colors.text,
|
|
59
|
-
borderRadius: 3,
|
|
60
|
-
fontSize: 11,
|
|
61
|
-
padding: '3px 6px',
|
|
62
|
-
fontFamily: 'monospace',
|
|
63
|
-
}, title: "Bias scrub step", children: shadowBiasSteps.map(option => (_jsx("option", { value: option, children: formatBiasStep(option) }, option))) })] }) }));
|
|
46
|
+
return (_jsx(FieldRow, { label: label, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6 }, children: [_jsx(NumberInput, { value: value, onChange: nextValue => onChange({ [name]: nextValue }), step: step, min: -0.1, max: 0.1, style: { width: 92 } }), _jsx("select", { value: step.toString(), onChange: event => setStep(Number(event.target.value)), style: Object.assign(Object.assign({}, base.input), { width: 78, fontSize: 11, fontFamily: 'monospace' }), title: "Bias scrub step", children: shadowBiasSteps.map(option => (_jsx("option", { value: option, children: formatBiasStep(option) }, option))) })] }) }));
|
|
64
47
|
}
|
|
@@ -34,6 +34,11 @@ interface ToolbarStyles {
|
|
|
34
34
|
interface ComponentCardStyles {
|
|
35
35
|
container: Style;
|
|
36
36
|
}
|
|
37
|
+
interface UtilityStyles {
|
|
38
|
+
secondaryPanel: Style;
|
|
39
|
+
compactActionButton: Style;
|
|
40
|
+
monoTextInput: Style;
|
|
41
|
+
}
|
|
37
42
|
export declare const colors: {
|
|
38
43
|
bg: string;
|
|
39
44
|
bgSurface: string;
|
|
@@ -64,4 +69,5 @@ export declare const tree: TreeStyles;
|
|
|
64
69
|
export declare const menu: MenuStyles;
|
|
65
70
|
export declare const toolbar: ToolbarStyles;
|
|
66
71
|
export declare const componentCard: ComponentCardStyles;
|
|
72
|
+
export declare const ui: UtilityStyles;
|
|
67
73
|
export {};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
export const colors = {
|
|
2
|
-
bg: '#
|
|
3
|
-
bgSurface: '#
|
|
4
|
-
bgLight: '#
|
|
5
|
-
bgHover: '#
|
|
6
|
-
bgInput: '#
|
|
7
|
-
border: '#
|
|
8
|
-
borderLight: '#
|
|
9
|
-
borderFaint: '#
|
|
10
|
-
text: '#
|
|
11
|
-
textMuted: '#
|
|
12
|
-
textDim: '#
|
|
13
|
-
accent: '#
|
|
14
|
-
accentBg: '
|
|
15
|
-
accentBorder: '
|
|
16
|
-
danger: '#
|
|
17
|
-
dangerBg: '
|
|
18
|
-
dangerBorder: '
|
|
2
|
+
bg: '#f3f3f3',
|
|
3
|
+
bgSurface: '#d7d7d7',
|
|
4
|
+
bgLight: '#fafafa',
|
|
5
|
+
bgHover: '#e6e6e6',
|
|
6
|
+
bgInput: '#f5f5f5',
|
|
7
|
+
border: '#6f6f6f',
|
|
8
|
+
borderLight: '#9a9a9a',
|
|
9
|
+
borderFaint: '#b8b8b8',
|
|
10
|
+
text: '#2f2f2f',
|
|
11
|
+
textMuted: '#5f5f5f',
|
|
12
|
+
textDim: '#7f7f7f',
|
|
13
|
+
accent: '#1e6f89',
|
|
14
|
+
accentBg: '#a9dded',
|
|
15
|
+
accentBorder: '#5e5e5e',
|
|
16
|
+
danger: '#9c3232',
|
|
17
|
+
dangerBg: '#efcaca',
|
|
18
|
+
dangerBorder: '#6f6f6f',
|
|
19
19
|
};
|
|
20
20
|
export const fonts = {
|
|
21
|
-
family: '
|
|
21
|
+
family: 'Tahoma, Verdana, sans-serif',
|
|
22
22
|
size: 11,
|
|
23
23
|
sizeSm: 10,
|
|
24
24
|
};
|
|
@@ -28,44 +28,48 @@ export const base = {
|
|
|
28
28
|
background: colors.bg,
|
|
29
29
|
color: colors.text,
|
|
30
30
|
border: `1px solid ${colors.border}`,
|
|
31
|
-
borderRadius: 4,
|
|
32
31
|
fontFamily: fonts.family,
|
|
33
32
|
fontSize: fonts.size,
|
|
34
|
-
|
|
33
|
+
borderRadius: 0,
|
|
34
|
+
boxShadow: 'none',
|
|
35
35
|
},
|
|
36
36
|
header: {
|
|
37
|
-
padding: '
|
|
37
|
+
padding: '3px 6px',
|
|
38
38
|
display: 'flex',
|
|
39
39
|
alignItems: 'center',
|
|
40
40
|
justifyContent: 'space-between',
|
|
41
41
|
cursor: 'pointer',
|
|
42
42
|
background: colors.bgLight,
|
|
43
|
-
borderBottom: `1px solid ${colors.
|
|
43
|
+
borderBottom: `1px solid ${colors.border}`,
|
|
44
44
|
fontSize: fonts.size,
|
|
45
|
-
fontWeight:
|
|
46
|
-
textTransform: 'uppercase',
|
|
47
|
-
letterSpacing: 0.8,
|
|
45
|
+
fontWeight: 400,
|
|
48
46
|
color: colors.text,
|
|
47
|
+
minHeight: 22,
|
|
48
|
+
boxSizing: 'border-box',
|
|
49
49
|
},
|
|
50
50
|
input: {
|
|
51
51
|
width: '100%',
|
|
52
52
|
background: colors.bgInput,
|
|
53
53
|
border: `1px solid ${colors.border}`,
|
|
54
|
-
borderRadius:
|
|
55
|
-
padding: '
|
|
54
|
+
borderRadius: 0,
|
|
55
|
+
padding: '2px 4px',
|
|
56
56
|
color: colors.text,
|
|
57
57
|
fontSize: fonts.size,
|
|
58
58
|
outline: 'none',
|
|
59
|
+
minHeight: 22,
|
|
60
|
+
boxSizing: 'border-box',
|
|
59
61
|
},
|
|
60
62
|
btn: {
|
|
61
|
-
background: colors.
|
|
63
|
+
background: colors.bgSurface,
|
|
62
64
|
border: `1px solid ${colors.border}`,
|
|
63
|
-
borderRadius:
|
|
64
|
-
padding: '
|
|
65
|
+
borderRadius: 0,
|
|
66
|
+
padding: '2px 6px',
|
|
65
67
|
color: colors.text,
|
|
66
68
|
fontSize: fonts.size,
|
|
67
69
|
cursor: 'pointer',
|
|
68
70
|
outline: 'none',
|
|
71
|
+
minHeight: 22,
|
|
72
|
+
boxSizing: 'border-box',
|
|
69
73
|
},
|
|
70
74
|
btnDanger: {
|
|
71
75
|
background: colors.dangerBg,
|
|
@@ -75,25 +79,22 @@ export const base = {
|
|
|
75
79
|
label: {
|
|
76
80
|
fontSize: fonts.sizeSm,
|
|
77
81
|
color: colors.textMuted,
|
|
78
|
-
marginBottom:
|
|
79
|
-
|
|
80
|
-
letterSpacing: 0.5,
|
|
81
|
-
fontWeight: 500,
|
|
82
|
+
marginBottom: 2,
|
|
83
|
+
fontWeight: 400,
|
|
82
84
|
},
|
|
83
85
|
row: {
|
|
84
86
|
display: 'flex',
|
|
85
|
-
gap:
|
|
87
|
+
gap: 4,
|
|
86
88
|
},
|
|
87
89
|
section: {
|
|
88
|
-
paddingBottom:
|
|
89
|
-
borderBottom: `1px solid ${colors.borderLight}`,
|
|
90
|
+
paddingBottom: 4,
|
|
90
91
|
},
|
|
91
92
|
};
|
|
92
93
|
// Specific panel styles
|
|
93
94
|
export const inspector = {
|
|
94
|
-
panel: Object.assign(Object.assign({}, base.panel), { position: 'absolute', top: 8, right: 8, zIndex: 20, width:
|
|
95
|
+
panel: Object.assign(Object.assign({}, base.panel), { position: 'absolute', top: 8, right: 8, zIndex: 20, width: 300 }),
|
|
95
96
|
content: {
|
|
96
|
-
padding:
|
|
97
|
+
padding: 6,
|
|
97
98
|
maxHeight: '80vh',
|
|
98
99
|
overflowY: 'auto',
|
|
99
100
|
overflowX: 'hidden',
|
|
@@ -102,37 +103,37 @@ export const inspector = {
|
|
|
102
103
|
boxSizing: 'border-box',
|
|
103
104
|
display: 'flex',
|
|
104
105
|
flexDirection: 'column',
|
|
105
|
-
gap:
|
|
106
|
+
gap: 4,
|
|
106
107
|
},
|
|
107
108
|
};
|
|
108
109
|
export const tree = {
|
|
109
110
|
panel: Object.assign(Object.assign({}, base.panel), { maxHeight: '85vh', display: 'flex', flexDirection: 'column', userSelect: 'none' }),
|
|
110
111
|
scroll: {
|
|
111
112
|
overflowY: 'auto',
|
|
112
|
-
padding:
|
|
113
|
+
padding: 2,
|
|
113
114
|
scrollbarWidth: 'thin',
|
|
114
115
|
scrollbarColor: `${colors.bgLight} transparent`,
|
|
115
116
|
},
|
|
116
117
|
row: {
|
|
117
118
|
display: 'flex',
|
|
118
119
|
alignItems: 'center',
|
|
119
|
-
padding: '
|
|
120
|
+
padding: '2px 4px',
|
|
120
121
|
borderBottomWidth: 1,
|
|
121
122
|
borderBottomStyle: 'solid',
|
|
122
123
|
borderBottomColor: colors.borderFaint,
|
|
123
124
|
cursor: 'pointer',
|
|
124
125
|
whiteSpace: 'nowrap',
|
|
125
|
-
borderRadius: 2,
|
|
126
126
|
},
|
|
127
127
|
selected: {
|
|
128
128
|
background: colors.accentBg,
|
|
129
129
|
borderBottomColor: colors.accentBorder,
|
|
130
|
+
boxShadow: 'none',
|
|
130
131
|
},
|
|
131
132
|
iconButton: {
|
|
132
133
|
background: 'none',
|
|
133
134
|
border: 'none',
|
|
134
135
|
cursor: 'pointer',
|
|
135
|
-
padding: '0
|
|
136
|
+
padding: '0 2px',
|
|
136
137
|
fontSize: 14,
|
|
137
138
|
opacity: 0.7,
|
|
138
139
|
color: 'inherit',
|
|
@@ -146,15 +147,15 @@ export const menu = {
|
|
|
146
147
|
width: 'max-content',
|
|
147
148
|
maxWidth: 'min(240px, calc(100vw - 16px))',
|
|
148
149
|
background: colors.bgSurface,
|
|
149
|
-
border:
|
|
150
|
-
borderRadius: 4,
|
|
150
|
+
border: 'none',
|
|
151
151
|
overflow: 'hidden',
|
|
152
|
-
|
|
152
|
+
borderRadius: 0,
|
|
153
|
+
boxShadow: 'none',
|
|
153
154
|
},
|
|
154
155
|
item: {
|
|
155
156
|
width: '100%',
|
|
156
157
|
textAlign: 'left',
|
|
157
|
-
padding: '
|
|
158
|
+
padding: '4px 8px',
|
|
158
159
|
background: 'transparent',
|
|
159
160
|
border: 'none',
|
|
160
161
|
color: colors.text,
|
|
@@ -171,17 +172,17 @@ export const toolbar = {
|
|
|
171
172
|
panel: {
|
|
172
173
|
position: 'absolute',
|
|
173
174
|
top: 8,
|
|
174
|
-
left: '
|
|
175
|
+
left: '232px',
|
|
175
176
|
display: 'flex',
|
|
176
|
-
gap:
|
|
177
|
-
padding: '4px
|
|
177
|
+
gap: 4,
|
|
178
|
+
padding: '2px 4px',
|
|
178
179
|
background: colors.bg,
|
|
179
180
|
border: `1px solid ${colors.border}`,
|
|
180
|
-
borderRadius: 4,
|
|
181
181
|
color: colors.text,
|
|
182
182
|
fontFamily: fonts.family,
|
|
183
183
|
fontSize: fonts.size,
|
|
184
|
-
|
|
184
|
+
borderRadius: 0,
|
|
185
|
+
boxShadow: 'none',
|
|
185
186
|
},
|
|
186
187
|
divider: {
|
|
187
188
|
width: 1,
|
|
@@ -195,10 +196,22 @@ export const toolbar = {
|
|
|
195
196
|
// Reusable component card style for inspector sections
|
|
196
197
|
export const componentCard = {
|
|
197
198
|
container: {
|
|
198
|
-
marginBottom:
|
|
199
|
-
backgroundColor: colors.
|
|
200
|
-
padding:
|
|
201
|
-
|
|
199
|
+
marginBottom: 4,
|
|
200
|
+
backgroundColor: colors.bg,
|
|
201
|
+
padding: 4,
|
|
202
|
+
border: `1px solid ${colors.border}`,
|
|
203
|
+
borderRadius: 0,
|
|
204
|
+
boxShadow: 'none',
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
export const ui = {
|
|
208
|
+
secondaryPanel: {
|
|
209
|
+
background: colors.bgSurface,
|
|
202
210
|
border: `1px solid ${colors.border}`,
|
|
211
|
+
borderRadius: 0,
|
|
212
|
+
padding: 4,
|
|
213
|
+
boxSizing: 'border-box',
|
|
203
214
|
},
|
|
215
|
+
compactActionButton: Object.assign(Object.assign({}, base.btn), { width: 28, minWidth: 28, padding: 0, flexShrink: 0 }),
|
|
216
|
+
monoTextInput: Object.assign(Object.assign({}, base.input), { fontFamily: 'monospace' }),
|
|
204
217
|
};
|