@nice2dev/ui-3d 1.0.3 → 1.0.5
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/cjs/core/i18n.js +3 -3
- package/dist/cjs/dance/DanceBridge.js +13 -13
- package/dist/cjs/dance/DanceScoreEngine.js +8 -8
- package/dist/cjs/dance/PoseDetector.js +20 -20
- package/dist/cjs/material/NiceMaterialEditor.js +19 -19
- package/dist/cjs/model/ModelEditorLeftPanel.js +3 -3
- package/dist/cjs/model/ModelEditorMenuBar.js +2 -2
- package/dist/cjs/model/ModelEditorRightPanel.js +2 -2
- package/dist/cjs/model/ModelEditorSubComponents.js +3 -3
- package/dist/cjs/model/ModelEditorTimeline.js +3 -3
- package/dist/cjs/model/ModelEditorToolbar.js +2 -2
- package/dist/cjs/model/ModelEditorViewport.js +2 -2
- package/dist/cjs/model/ModelViewer.js +8 -8
- package/dist/cjs/model/NiceArmatureEditor.js +18 -18
- package/dist/cjs/model/NiceMorphTargetEditor.js +18 -18
- package/dist/cjs/model/NiceOctree.js +16 -16
- package/dist/cjs/model/NicePhysicsSimulation.js +24 -24
- package/dist/cjs/model/NiceProceduralGeometry.js +8 -8
- package/dist/cjs/model/NiceTerrainEditor.js +19 -19
- package/dist/cjs/model/NiceWeightPainter.js +14 -14
- package/dist/cjs/model/NiceXRPreview.js +18 -18
- package/dist/cjs/model/useModelEditor.js +127 -127
- package/dist/cjs/model/useModelViewer.js +61 -61
- package/dist/cjs/particle/NiceParticleEditor.js +11 -11
- package/dist/cjs/rendering/NiceCascadedShadows.js +12 -12
- package/dist/cjs/rendering/NiceRenderExport.js +5 -5
- package/dist/cjs/rendering/NiceSSAO.js +18 -18
- package/dist/cjs/rendering/NiceSSR.js +14 -14
- package/dist/cjs/rendering/NiceWebGPURenderer.js +21 -21
- package/dist/cjs/ui/dist/index.js +47227 -31319
- package/dist/cjs/ui/dist/index.js.map +1 -1
- package/dist/cjs/uv/NiceUVEditor.js +24 -24
- package/dist/esm/model/ModelEditorLeftPanel.js +5 -5
- package/dist/esm/model/ModelEditorMenuBar.js +5 -5
- package/dist/esm/model/ModelEditorRightPanel.js +17 -17
- package/dist/esm/model/ModelEditorSubComponents.js +6 -6
- package/dist/esm/model/ModelEditorTimeline.js +5 -5
- package/dist/esm/model/ModelEditorToolbar.js +4 -4
- package/dist/esm/model/ModelEditorViewport.js +2 -2
- package/dist/esm/model/ModelViewer.js +5 -5
- package/dist/esm/ui/dist/index.js +36901 -21016
- package/dist/esm/ui/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cjs/core/i18n.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
|
|
6
6
|
const fallback = (_key, defaultValue) => defaultValue;
|
|
7
|
-
const NiceI18nContext =
|
|
7
|
+
const NiceI18nContext = Ue.createContext(fallback);
|
|
8
8
|
const NiceI18nProvider = ({ t, children }) => (jsxRuntime.jsx(NiceI18nContext.Provider, { value: t, children: children }));
|
|
9
9
|
function useNiceTranslation() {
|
|
10
|
-
const t =
|
|
10
|
+
const t = Ue.useContext(NiceI18nContext);
|
|
11
11
|
return { t };
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var Ue = require('react');
|
|
4
4
|
var DanceScoreEngine = require('./DanceScoreEngine.js');
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -113,13 +113,13 @@ class DanceBridge {
|
|
|
113
113
|
}
|
|
114
114
|
// ── React hook: useDanceBridge ──────────────────────────────────
|
|
115
115
|
function useDanceBridge(config, callbacks) {
|
|
116
|
-
const bridgeRef =
|
|
117
|
-
const [state, setState] =
|
|
118
|
-
const [lastScore, setLastScore] =
|
|
119
|
-
const [result, setResult] =
|
|
120
|
-
const [combo, setCombo] =
|
|
121
|
-
const [progress, setProgress] =
|
|
122
|
-
|
|
116
|
+
const bridgeRef = Ue.useRef(null);
|
|
117
|
+
const [state, setState] = Ue.useState('idle');
|
|
118
|
+
const [lastScore, setLastScore] = Ue.useState(null);
|
|
119
|
+
const [result, setResult] = Ue.useState(null);
|
|
120
|
+
const [combo, setCombo] = Ue.useState(0);
|
|
121
|
+
const [progress, setProgress] = Ue.useState(0);
|
|
122
|
+
Ue.useEffect(() => {
|
|
123
123
|
if (!config) {
|
|
124
124
|
bridgeRef.current = null;
|
|
125
125
|
return;
|
|
@@ -134,11 +134,11 @@ function useDanceBridge(config, callbacks) {
|
|
|
134
134
|
return () => { bridgeRef.current = null; };
|
|
135
135
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
136
136
|
}, [config]);
|
|
137
|
-
const start =
|
|
138
|
-
const pause =
|
|
139
|
-
const resume =
|
|
140
|
-
const stop =
|
|
141
|
-
const feedFrame =
|
|
137
|
+
const start = Ue.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.start(); }, []);
|
|
138
|
+
const pause = Ue.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.pause(); }, []);
|
|
139
|
+
const resume = Ue.useCallback(() => { var _a; (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.resume(); }, []);
|
|
140
|
+
const stop = Ue.useCallback(() => { var _a, _b; return (_b = (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.stop()) !== null && _b !== void 0 ? _b : null; }, []);
|
|
141
|
+
const feedFrame = Ue.useCallback((frame) => {
|
|
142
142
|
var _a, _b;
|
|
143
143
|
const score = (_b = (_a = bridgeRef.current) === null || _a === void 0 ? void 0 : _a.feedFrame(frame)) !== null && _b !== void 0 ? _b : null;
|
|
144
144
|
if (bridgeRef.current)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var Ue = require('react');
|
|
4
4
|
|
|
5
5
|
// ── Default config ──────────────────────────────────────────────
|
|
6
6
|
const DEFAULT_CONFIG = {
|
|
@@ -179,25 +179,25 @@ class DanceScoreEngine {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
function useDanceScore(config) {
|
|
182
|
-
const engineRef =
|
|
183
|
-
const [lastScore, setLastScore] =
|
|
184
|
-
const [result, setResult] =
|
|
185
|
-
const loadReference =
|
|
182
|
+
const engineRef = Ue.useRef(new DanceScoreEngine(config));
|
|
183
|
+
const [lastScore, setLastScore] = Ue.useState(null);
|
|
184
|
+
const [result, setResult] = Ue.useState(null);
|
|
185
|
+
const loadReference = Ue.useCallback((seq) => {
|
|
186
186
|
engineRef.current.loadReference(seq);
|
|
187
187
|
setLastScore(null);
|
|
188
188
|
setResult(null);
|
|
189
189
|
}, []);
|
|
190
|
-
const scoreFrame =
|
|
190
|
+
const scoreFrame = Ue.useCallback((frame) => {
|
|
191
191
|
const score = engineRef.current.scoreFrame(frame);
|
|
192
192
|
setLastScore(score);
|
|
193
193
|
return score;
|
|
194
194
|
}, []);
|
|
195
|
-
const finish =
|
|
195
|
+
const finish = Ue.useCallback(() => {
|
|
196
196
|
const r = engineRef.current.getResult();
|
|
197
197
|
setResult(r);
|
|
198
198
|
return r;
|
|
199
199
|
}, []);
|
|
200
|
-
const reset =
|
|
200
|
+
const reset = Ue.useCallback(() => {
|
|
201
201
|
engineRef.current.reset();
|
|
202
202
|
setLastScore(null);
|
|
203
203
|
setResult(null);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
|
|
6
6
|
// ── Standard keypoint definitions (COCO 17-keypoint model) ──────
|
|
7
7
|
const COCO_KEYPOINTS = [
|
|
@@ -31,14 +31,14 @@ function createSimulatedKeypoints() {
|
|
|
31
31
|
// ── Hook: usePoseDetection ──────────────────────────────────────
|
|
32
32
|
function usePoseDetection(config = {}) {
|
|
33
33
|
const { maxPersons = 1, minConfidence = 0.5, targetFps = 30, } = config;
|
|
34
|
-
const [isDetecting, setIsDetecting] =
|
|
35
|
-
const latestFrameRef =
|
|
36
|
-
const frameIndexRef =
|
|
37
|
-
const rafRef =
|
|
38
|
-
const streamRef =
|
|
39
|
-
const videoRef =
|
|
40
|
-
const callbackRef =
|
|
41
|
-
const processFrame =
|
|
34
|
+
const [isDetecting, setIsDetecting] = Ue.useState(false);
|
|
35
|
+
const latestFrameRef = Ue.useRef(null);
|
|
36
|
+
const frameIndexRef = Ue.useRef(0);
|
|
37
|
+
const rafRef = Ue.useRef(0);
|
|
38
|
+
const streamRef = Ue.useRef(null);
|
|
39
|
+
const videoRef = Ue.useRef(null);
|
|
40
|
+
const callbackRef = Ue.useRef(null);
|
|
41
|
+
const processFrame = Ue.useCallback(() => {
|
|
42
42
|
var _a;
|
|
43
43
|
if (!videoRef.current || videoRef.current.readyState < 2) {
|
|
44
44
|
rafRef.current = requestAnimationFrame(processFrame);
|
|
@@ -64,7 +64,7 @@ function usePoseDetection(config = {}) {
|
|
|
64
64
|
(_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, frame);
|
|
65
65
|
rafRef.current = requestAnimationFrame(processFrame);
|
|
66
66
|
}, [maxPersons, minConfidence, targetFps]);
|
|
67
|
-
const start =
|
|
67
|
+
const start = Ue.useCallback(async (video, onFrame) => {
|
|
68
68
|
try {
|
|
69
69
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
70
70
|
video: { facingMode: 'user', width: { ideal: 640 }, height: { ideal: 480 } },
|
|
@@ -82,7 +82,7 @@ function usePoseDetection(config = {}) {
|
|
|
82
82
|
throw new Error(`Camera access failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
83
83
|
}
|
|
84
84
|
}, [processFrame]);
|
|
85
|
-
const stop =
|
|
85
|
+
const stop = Ue.useCallback(() => {
|
|
86
86
|
var _a;
|
|
87
87
|
cancelAnimationFrame(rafRef.current);
|
|
88
88
|
(_a = streamRef.current) === null || _a === void 0 ? void 0 : _a.getTracks().forEach(t => t.stop());
|
|
@@ -91,22 +91,22 @@ function usePoseDetection(config = {}) {
|
|
|
91
91
|
videoRef.current.srcObject = null;
|
|
92
92
|
setIsDetecting(false);
|
|
93
93
|
}, []);
|
|
94
|
-
|
|
94
|
+
Ue.useEffect(() => () => { stop(); }, [stop]);
|
|
95
95
|
return { start, stop, isDetecting, getLatestFrame: () => latestFrameRef.current };
|
|
96
96
|
}
|
|
97
97
|
// ── Component: PoseDetector ─────────────────────────────────────
|
|
98
|
-
const NicePoseDetector =
|
|
98
|
+
const NicePoseDetector = Ue.forwardRef(function NicePoseDetector(props, ref) {
|
|
99
99
|
const { onFrame, onStart, onStop, onError, className, style, width = 640, height = 480, mirror = true, showSkeleton = true, showConfidence = false, ...config } = props;
|
|
100
|
-
const videoRef =
|
|
101
|
-
const canvasRef =
|
|
100
|
+
const videoRef = Ue.useRef(null);
|
|
101
|
+
const canvasRef = Ue.useRef(null);
|
|
102
102
|
const detection = usePoseDetection(config);
|
|
103
|
-
|
|
103
|
+
Ue.useImperativeHandle(ref, () => ({
|
|
104
104
|
start: handleStart,
|
|
105
105
|
stop: handleStop,
|
|
106
106
|
getLatestFrame: detection.getLatestFrame,
|
|
107
107
|
get isDetecting() { return detection.isDetecting; },
|
|
108
108
|
}));
|
|
109
|
-
const drawSkeleton =
|
|
109
|
+
const drawSkeleton = Ue.useCallback((frame) => {
|
|
110
110
|
var _a, _b, _c, _d, _e, _f;
|
|
111
111
|
const ctx = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getContext('2d');
|
|
112
112
|
if (!ctx || !canvasRef.current)
|
|
@@ -144,11 +144,11 @@ const NicePoseDetector = Ae.forwardRef(function NicePoseDetector(props, ref) {
|
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
}, [showSkeleton, showConfidence]);
|
|
147
|
-
const handleFrame =
|
|
147
|
+
const handleFrame = Ue.useCallback((frame) => {
|
|
148
148
|
drawSkeleton(frame);
|
|
149
149
|
onFrame === null || onFrame === void 0 ? void 0 : onFrame(frame);
|
|
150
150
|
}, [drawSkeleton, onFrame]);
|
|
151
|
-
const handleStart =
|
|
151
|
+
const handleStart = Ue.useCallback(async () => {
|
|
152
152
|
try {
|
|
153
153
|
if (videoRef.current) {
|
|
154
154
|
await detection.start(videoRef.current, handleFrame);
|
|
@@ -159,7 +159,7 @@ const NicePoseDetector = Ae.forwardRef(function NicePoseDetector(props, ref) {
|
|
|
159
159
|
onError === null || onError === void 0 ? void 0 : onError(err instanceof Error ? err : new Error(String(err)));
|
|
160
160
|
}
|
|
161
161
|
}, [detection, handleFrame, onStart, onError]);
|
|
162
|
-
const handleStop =
|
|
162
|
+
const handleStop = Ue.useCallback(() => {
|
|
163
163
|
detection.stop();
|
|
164
164
|
onStop === null || onStop === void 0 ? void 0 : onStop();
|
|
165
165
|
}, [detection, onStop]);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var materialEditorTypes = require('./materialEditorTypes.js');
|
|
6
6
|
var materialNodeDefinitions = require('./materialNodeDefinitions.js');
|
|
7
7
|
var materialEditorUtils = require('./materialEditorUtils.js');
|
|
@@ -338,9 +338,9 @@ function materialEditorReducer(state, action) {
|
|
|
338
338
|
Hook: useMaterialEditor
|
|
339
339
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
340
340
|
function useMaterialEditor(initialGraph) {
|
|
341
|
-
const [state, dispatch] =
|
|
341
|
+
const [state, dispatch] = Ue.useReducer(materialEditorReducer, initialGraph, createInitialState);
|
|
342
342
|
// Auto-compile when graph changes
|
|
343
|
-
|
|
343
|
+
Ue.useEffect(() => {
|
|
344
344
|
if (state.autoCompile && !state.compiling) {
|
|
345
345
|
const timeout = setTimeout(() => {
|
|
346
346
|
dispatch({ type: 'COMPILE' });
|
|
@@ -356,7 +356,7 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
356
356
|
const filteredNodes = searchQuery
|
|
357
357
|
? materialNodeDefinitions.searchNodes(searchQuery)
|
|
358
358
|
: materialNodeDefinitions.MATERIAL_NODE_DEFINITIONS;
|
|
359
|
-
const categories =
|
|
359
|
+
const categories = Ue.useMemo(() => {
|
|
360
360
|
const cats = new Map();
|
|
361
361
|
for (const node of filteredNodes) {
|
|
362
362
|
if (!cats.has(node.category)) {
|
|
@@ -369,9 +369,9 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
369
369
|
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.palette, children: [jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteSearch, children: jsxRuntime.jsx("input", { type: "text", placeholder: "Search nodes...", value: searchQuery, onChange: e => onSearch(e.target.value), className: MaterialEditor_module.searchInput }) }), jsxRuntime.jsx("div", { className: MaterialEditor_module.paletteCategories, children: Array.from(categories.entries()).map(([category, nodes]) => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteCategory, children: [jsxRuntime.jsxs("button", { className: MaterialEditor_module.categoryHeader, onClick: () => onToggleCategory(category), style: { borderLeftColor: materialEditorTypes.NODE_CATEGORY_COLORS[category] }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryIcon, children: expandedCategories.includes(category) ? '▼' : '►' }), jsxRuntime.jsx("span", { children: materialEditorTypes.NODE_CATEGORY_NAMES[category] }), jsxRuntime.jsx("span", { className: MaterialEditor_module.categoryCount, children: nodes.length })] }), expandedCategories.includes(category) && (jsxRuntime.jsx("div", { className: MaterialEditor_module.categoryNodes, children: nodes.map(nodeDef => (jsxRuntime.jsxs("div", { className: MaterialEditor_module.paletteNode, draggable: true, onDragStart: e => onDragStart(nodeDef.type, e), onDoubleClick: () => onAddNode(nodeDef.type), title: nodeDef.description, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeColor, style: { backgroundColor: nodeDef.color || materialEditorTypes.NODE_CATEGORY_COLORS[nodeDef.category] } }), jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
|
|
370
370
|
}
|
|
371
371
|
function GraphNode({ node, definition, selected, viewTransform, connections, onSelect, onMove, onStartConnection, }) {
|
|
372
|
-
const nodeRef =
|
|
373
|
-
const [isDragging, setIsDragging] =
|
|
374
|
-
const dragStart =
|
|
372
|
+
const nodeRef = Ue.useRef(null);
|
|
373
|
+
const [isDragging, setIsDragging] = Ue.useState(false);
|
|
374
|
+
const dragStart = Ue.useRef(null);
|
|
375
375
|
const handleMouseDown = (e) => {
|
|
376
376
|
if (e.button !== 0)
|
|
377
377
|
return;
|
|
@@ -384,7 +384,7 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
|
|
|
384
384
|
dragStart.current = { x: e.clientX, y: e.clientY };
|
|
385
385
|
}
|
|
386
386
|
};
|
|
387
|
-
|
|
387
|
+
Ue.useEffect(() => {
|
|
388
388
|
if (!isDragging)
|
|
389
389
|
return;
|
|
390
390
|
const handleMouseMove = (e) => {
|
|
@@ -441,10 +441,10 @@ function Toolbar({ canUndo, canRedo, canPaste, hasSelection, autoCompile, compil
|
|
|
441
441
|
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbar, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onNew, title: "New Material (Ctrl+N)", children: "\uD83D\uDCC4" }), jsxRuntime.jsx("button", { onClick: onImport, title: "Import (Ctrl+O)", children: "\uD83D\uDCC2" }), jsxRuntime.jsx("button", { onClick: onExport, title: "Export (Ctrl+S)", children: "\uD83D\uDCBE" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onUndo, disabled: !canUndo, title: "Undo (Ctrl+Z)", children: "\u21A9\uFE0F" }), jsxRuntime.jsx("button", { onClick: onRedo, disabled: !canRedo, title: "Redo (Ctrl+Y)", children: "\u21AA\uFE0F" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onCut, disabled: !hasSelection, title: "Cut (Ctrl+X)", children: "\u2702\uFE0F" }), jsxRuntime.jsx("button", { onClick: onCopy, disabled: !hasSelection, title: "Copy (Ctrl+C)", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("button", { onClick: onPaste, disabled: !canPaste, title: "Paste (Ctrl+V)", children: "\uD83D\uDCE5" }), jsxRuntime.jsx("button", { onClick: onDuplicate, disabled: !hasSelection, title: "Duplicate (Ctrl+D)", children: "\uD83D\uDD04" }), jsxRuntime.jsx("button", { onClick: onDelete, disabled: !hasSelection, title: "Delete (Del)", children: "\uD83D\uDDD1\uFE0F" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onSelectAll, title: "Select All (Ctrl+A)", children: "\u2B1C" }), jsxRuntime.jsx("button", { onClick: onZoomToFit, title: "Zoom to Fit (F)", children: "\uD83D\uDD0D" }), jsxRuntime.jsx("button", { onClick: onToggleGrid, className: showGrid ? MaterialEditor_module.active : '', title: "Toggle Grid (G)", children: "#" }), jsxRuntime.jsx("button", { onClick: onToggleSnap, className: snapToGrid ? MaterialEditor_module.active : '', title: "Toggle Snap (S)", children: "\uD83E\uDDF2" })] }), jsxRuntime.jsx("div", { className: MaterialEditor_module.toolbarSeparator }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.toolbarGroup, children: [jsxRuntime.jsx("button", { onClick: onToggleAutoCompile, className: autoCompile ? MaterialEditor_module.active : '', title: "Auto Compile", children: "\u26A1" }), jsxRuntime.jsx("button", { onClick: onCompile, disabled: compiling, title: "Compile (F5)", children: compiling ? '⏳' : '▶️' })] })] }));
|
|
442
442
|
}
|
|
443
443
|
function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
444
|
-
const canvasRef =
|
|
444
|
+
const canvasRef = Ue.useRef(null);
|
|
445
445
|
const previewModes = ['sphere', 'cube', 'plane', 'cylinder', 'torus'];
|
|
446
446
|
// Simple preview rendering (in real implementation would use Three.js)
|
|
447
|
-
|
|
447
|
+
Ue.useEffect(() => {
|
|
448
448
|
const canvas = canvasRef.current;
|
|
449
449
|
if (!canvas)
|
|
450
450
|
return;
|
|
@@ -475,25 +475,25 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
|
475
475
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
476
476
|
function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, customNodes, textures, width = '100%', height = '600px', readOnly = false, showToolbar = true, showPalette = true, showProperties = true, showPreview = true, previewMode: initialPreviewMode = 'sphere', theme = 'dark', className, }) {
|
|
477
477
|
const { state, dispatch } = useMaterialEditor(initialGraph);
|
|
478
|
-
const canvasRef =
|
|
479
|
-
const [pendingConnection, setPendingConnection] =
|
|
478
|
+
const canvasRef = Ue.useRef(null);
|
|
479
|
+
const [pendingConnection, setPendingConnection] = Ue.useState(null);
|
|
480
480
|
// Merge custom node definitions
|
|
481
|
-
const definitions =
|
|
481
|
+
const definitions = Ue.useMemo(() => {
|
|
482
482
|
const map = new Map(materialNodeDefinitions.MATERIAL_NODE_MAP);
|
|
483
483
|
customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach(def => map.set(def.type, def));
|
|
484
484
|
return map;
|
|
485
485
|
}, [customNodes]);
|
|
486
486
|
// Notify parent of changes
|
|
487
|
-
|
|
487
|
+
Ue.useEffect(() => {
|
|
488
488
|
onGraphChange === null || onGraphChange === void 0 ? void 0 : onGraphChange(state.graph);
|
|
489
489
|
}, [state.graph, onGraphChange]);
|
|
490
|
-
|
|
490
|
+
Ue.useEffect(() => {
|
|
491
491
|
if (state.compiledShader) {
|
|
492
492
|
onCompile === null || onCompile === void 0 ? void 0 : onCompile(state.compiledShader);
|
|
493
493
|
}
|
|
494
494
|
}, [state.compiledShader, onCompile]);
|
|
495
495
|
// Keyboard shortcuts
|
|
496
|
-
|
|
496
|
+
Ue.useEffect(() => {
|
|
497
497
|
const handleKeyDown = (e) => {
|
|
498
498
|
if (readOnly)
|
|
499
499
|
return;
|
|
@@ -553,7 +553,7 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
553
553
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
554
554
|
}, [readOnly, state.selectedNodes, dispatch]);
|
|
555
555
|
// Handle wheel zoom
|
|
556
|
-
const handleWheel =
|
|
556
|
+
const handleWheel = Ue.useCallback((e) => {
|
|
557
557
|
var _a;
|
|
558
558
|
e.preventDefault();
|
|
559
559
|
const delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
@@ -571,8 +571,8 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
571
571
|
});
|
|
572
572
|
}, [state.viewTransform, dispatch]);
|
|
573
573
|
// Handle canvas pan
|
|
574
|
-
const [isPanning, setIsPanning] =
|
|
575
|
-
const panStart =
|
|
574
|
+
const [isPanning, setIsPanning] = Ue.useState(false);
|
|
575
|
+
const panStart = Ue.useRef(null);
|
|
576
576
|
const handleCanvasMouseDown = (e) => {
|
|
577
577
|
if (e.button === 1 || (e.button === 0 && e.altKey)) {
|
|
578
578
|
setIsPanning(true);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
6
|
var index = require('../ui/dist/index.js');
|
|
7
7
|
|
|
8
|
-
const ModelEditorLeftPanel =
|
|
8
|
+
const ModelEditorLeftPanel = Ue.memo(({ api }) => {
|
|
9
9
|
const { sceneTree, selectedId, outlinerSearch, setOutlinerSearch, selectObject, rebuildTree, toggleNodeExpanded, toggleNodeVisibility, } = api;
|
|
10
10
|
const renderTreeNode = (node, depth) => {
|
|
11
11
|
// Outliner search filter
|
|
@@ -24,7 +24,7 @@ const ModelEditorLeftPanel = Ae.memo(({ api }) => {
|
|
|
24
24
|
node.type === "light" ? "💡" :
|
|
25
25
|
node.type === "camera" ? "📷" :
|
|
26
26
|
node.type === "helper" ? "◇" : "📁";
|
|
27
|
-
return (jsxRuntime.jsxs(
|
|
27
|
+
return (jsxRuntime.jsxs(Ue.Fragment, { children: [jsxRuntime.jsxs("div", { className: `${ModelEditor_module.treeItem} ${selectedId === node.id ? ModelEditor_module.treeItemActive : ""}`, style: { paddingLeft: depth * 16 + 4 }, onClick: () => selectObject(node), children: [hasChildren ? (jsxRuntime.jsx("span", { className: ModelEditor_module.treeToggle, onClick: (e) => {
|
|
28
28
|
e.stopPropagation();
|
|
29
29
|
toggleNodeExpanded(node);
|
|
30
30
|
}, children: node.expanded ? "▼" : "▶" })) : (jsxRuntime.jsx("span", { className: ModelEditor_module.treeToggle })), jsxRuntime.jsx("span", { className: ModelEditor_module.treeIcon, children: icon }), jsxRuntime.jsx("span", { style: { flex: 1, overflow: "hidden", textOverflow: "ellipsis" }, children: node.name }), jsxRuntime.jsx("span", { className: ModelEditor_module.treeVisibility, onClick: (e) => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
6
|
var index = require('../ui/dist/index.js');
|
|
7
7
|
|
|
8
|
-
const ModelEditorMenuBar =
|
|
8
|
+
const ModelEditorMenuBar = Ue.memo(({ api, hasOnSaveToLibrary }) => {
|
|
9
9
|
const { editorMode, setEditorMode, fileInputRef, mergeInputRef, addMenuOpen, setAddMenuOpen, addPrimitive, addSceneLight, addCameraObject, addEmpty, selectedNode, duplicateSelected, deleteSelected, exportGLTF, exportOBJ, exportSTL, exportPLY, exportUSDZ, saveToLibrary, clearScene, showGrid, setShowGrid, showAxes, setShowAxes, wireframe, setWireframe, showSkeleton, setShowSkeleton, showLightHelpers, setShowLightHelpers, bgColor, setBgColor, } = api;
|
|
10
10
|
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.menuBar, children: [jsxRuntime.jsx(index.NiceSelect, { className: ModelEditor_module.modeSelect, value: editorMode, onChange: (val) => setEditorMode(val), options: [
|
|
11
11
|
{ value: "object", label: "Object Mode" },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var THREE = require('three');
|
|
6
6
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
7
7
|
var modelEditorTypes = require('./modelEditorTypes.js');
|
|
@@ -27,7 +27,7 @@ function _interopNamespaceDefault(e) {
|
|
|
27
27
|
|
|
28
28
|
var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
29
29
|
|
|
30
|
-
const ModelEditorRightPanel =
|
|
30
|
+
const ModelEditorRightPanel = Ue.memo(({ api }) => {
|
|
31
31
|
const { propTab, setPropTab, selectedNode, selectedMaterials, selMaterialIdx, setSelMaterialIdx, setMatRefresh, rebuildTree, aiBusy, aiStatus, rootObjectRef, videoInputRef, bgColor, setBgColor, fogEnabled, setFogEnabled, fogColor, setFogColor, fogNear, setFogNear, fogFar, setFogFar, showLightHelpers, setShowLightHelpers, showGrid, setShowGrid, showAxes, setShowAxes, showSkeleton, setShowSkeleton, snapEnabled, setSnapEnabled, snapGrid, setSnapGrid, setStatusText, } = api;
|
|
32
32
|
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.rightPanel, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.propTabs, children: ["object", "material", "world", "modifiers", "physics"].map((t) => (jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.propTabBtn, variant: propTab === t ? "primary" : "ghost", size: "sm", onClick: () => setPropTab(t), title: t.charAt(0).toUpperCase() + t.slice(1), children: t === "object" ? "🔧" : t === "material" ? "🎨" : t === "world" ? "🌍" : t === "modifiers" ? "🔩" : "⚡" }, t))) }), propTab === "object" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelEditor_module.panelTitle, children: "\uD83D\uDD27 Transform" }), jsxRuntime.jsx("div", { className: ModelEditor_module.panelContent, children: selectedNode ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.propRow, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.propLabel, children: "Name" }), jsxRuntime.jsx(index.NiceTextInput, { className: ModelEditor_module.propInput, value: selectedNode.name, onChange: (val) => {
|
|
33
33
|
selectedNode.object.name = val;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var THREE = require('three');
|
|
6
6
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
7
7
|
var modelEditorTypes = require('./modelEditorTypes.js');
|
|
@@ -31,7 +31,7 @@ var THREE__namespace = /*#__PURE__*/_interopNamespaceDefault(THREE);
|
|
|
31
31
|
═══════════════════════════════════════════ */
|
|
32
32
|
/** Vec3 input row for position/scale */
|
|
33
33
|
const Vec3Row = ({ label, value, onChange }) => {
|
|
34
|
-
const [, forceUpdate] =
|
|
34
|
+
const [, forceUpdate] = Ue.useState(0);
|
|
35
35
|
const set = (axis, v) => {
|
|
36
36
|
const n = parseFloat(v);
|
|
37
37
|
if (!isNaN(n)) {
|
|
@@ -44,7 +44,7 @@ const Vec3Row = ({ label, value, onChange }) => {
|
|
|
44
44
|
};
|
|
45
45
|
/** Vec3 input row for rotation (shows degrees) */
|
|
46
46
|
const Vec3RowDeg = ({ label, value, onChange }) => {
|
|
47
|
-
const [, forceUpdate] =
|
|
47
|
+
const [, forceUpdate] = Ue.useState(0);
|
|
48
48
|
const set = (axis, v) => {
|
|
49
49
|
const n = parseFloat(v);
|
|
50
50
|
if (!isNaN(n)) {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
6
|
var modelEditorTypes = require('./modelEditorTypes.js');
|
|
7
7
|
var index = require('../ui/dist/index.js');
|
|
8
8
|
|
|
9
|
-
const ModelEditorTimeline =
|
|
9
|
+
const ModelEditorTimeline = Ue.memo(({ api }) => {
|
|
10
10
|
const { bottomCollapsed, setBottomCollapsed, animations, activeAnimIdx, isPlaying, animTime, animDuration, animSpeed, setAnimSpeed, loopAnim, setLoopAnim, seekAnim, togglePlay, stopAnim, playClip, mergeInputRef, } = api;
|
|
11
11
|
return (jsxRuntime.jsxs("div", { className: `${ModelEditor_module.bottomPanel} ${bottomCollapsed ? ModelEditor_module.bottomPanelCollapsed : ""}`, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.bottomPanelHeader, children: [jsxRuntime.jsx("span", { className: ModelEditor_module.bottomToggle, onClick: () => setBottomCollapsed((c) => !c), children: bottomCollapsed ? "▶" : "▼" }), jsxRuntime.jsxs("span", { className: ModelEditor_module.bottomPanelTitle, onClick: () => setBottomCollapsed((c) => !c), children: ["Animation (", animations.length, " clip", animations.length !== 1 ? "s" : "", ")"] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsxs("div", { className: ModelEditor_module.transportBar, children: [jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.transportBtn, variant: "ghost", size: "sm", onClick: () => seekAnim(0), title: "Go to start", children: "\u23EE" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.transportBtn, variant: isPlaying ? "primary" : "ghost", size: "sm", onClick: togglePlay, title: "Play/Pause (Space)", children: isPlaying ? "⏸" : "▶" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.transportBtn, variant: "ghost", size: "sm", onClick: stopAnim, title: "Stop", children: "\u23F9" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.transportBtn, variant: loopAnim ? "primary" : "ghost", size: "sm", onClick: () => setLoopAnim((v) => !v), title: "Loop", children: "\uD83D\uDD01" })] }), jsxRuntime.jsxs("span", { className: ModelEditor_module.transportTime, children: [modelEditorTypes.fmtTime(animTime), " / ", modelEditorTypes.fmtTime(animDuration)] }), jsxRuntime.jsx("div", { className: ModelEditor_module.menuSep }), jsxRuntime.jsx("label", { className: ModelEditor_module.menuLabel, children: "Speed" }), jsxRuntime.jsx(index.NiceSlider, { min: 0.1, max: 3, step: 0.1, value: animSpeed, onChange: (val) => setAnimSpeed(val), style: { width: 60 } }), jsxRuntime.jsxs("span", { className: ModelEditor_module.menuLabel, children: [animSpeed.toFixed(1), "\u00D7"] })] }), !bottomCollapsed && (jsxRuntime.jsxs("div", { className: ModelEditor_module.animListArea, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.animList, children: [animations.length === 0 && (jsxRuntime.jsx("div", { style: { color: "#666", fontSize: 10, padding: 8 }, children: "No animations loaded" })), animations.map((anim, i) => (jsxRuntime.jsxs("div", { className: `${ModelEditor_module.animItem} ${i === activeAnimIdx ? ModelEditor_module.animItemActive : ""}`, onClick: () => playClip(i), children: [jsxRuntime.jsx("span", { children: anim.name }), jsxRuntime.jsxs("span", { className: ModelEditor_module.animDuration, children: [anim.duration.toFixed(1), "s"] })] }, `${anim.name}-${i}`))), jsxRuntime.jsx("div", { style: { padding: "4px 8px" }, children: jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.btnSecondary, variant: "ghost", size: "sm", style: { width: "100%", fontSize: 10 }, onClick: () => { var _a; return (_a = mergeInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: "+ Add Animation File" }) })] }), jsxRuntime.jsxs("div", { className: ModelEditor_module.timelineArea, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.timelineRuler, children: [animDuration > 0 &&
|
|
12
12
|
Array.from({ length: Math.ceil(animDuration) + 1 }, (_, i) => {
|
|
13
13
|
const pct = (i / animDuration) * 100;
|
|
14
|
-
return (jsxRuntime.jsxs(
|
|
14
|
+
return (jsxRuntime.jsxs(Ue.Fragment, { children: [jsxRuntime.jsx("div", { className: ModelEditor_module.rulerTick, style: { left: `${pct}%` } }), jsxRuntime.jsxs("span", { className: ModelEditor_module.rulerLabel, style: { left: `${pct}%` }, children: [i, "s"] })] }, i));
|
|
15
15
|
}), animDuration > 0 && (jsxRuntime.jsx("div", { className: ModelEditor_module.playhead, style: {
|
|
16
16
|
left: `${(animTime / animDuration) * 100}%`,
|
|
17
17
|
height: "100%",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
6
|
var index = require('../ui/dist/index.js');
|
|
7
7
|
|
|
8
|
-
const ModelEditorToolbar =
|
|
8
|
+
const ModelEditorToolbar = Ue.memo(({ api }) => {
|
|
9
9
|
const { transformMode, setTransformMode, snapEnabled, setSnapEnabled, gizmoSpace, setGizmoSpace, rootObjectRef, focusOnObject, setCameraPreset, deleteSelected, duplicateSelected, selectedNode, } = api;
|
|
10
10
|
return (jsxRuntime.jsxs("div", { className: ModelEditor_module.toolbar, children: [jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: transformMode === "translate" ? "primary" : "ghost", size: "sm", onClick: () => setTransformMode("translate"), title: "Translate (G)", children: "\u2725" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: transformMode === "rotate" ? "primary" : "ghost", size: "sm", onClick: () => setTransformMode("rotate"), title: "Rotate (R)", children: "\u21BB" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: transformMode === "scale" ? "primary" : "ghost", size: "sm", onClick: () => setTransformMode("scale"), title: "Scale (S)", children: "\u2B21" }), jsxRuntime.jsx("div", { className: ModelEditor_module.toolSep }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: snapEnabled ? "primary" : "ghost", size: "sm", onClick: () => setSnapEnabled((v) => !v), title: `Snap to Grid (${snapEnabled ? "ON" : "OFF"})`, children: "\uD83E\uDDF2" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: () => setGizmoSpace((s) => (s === "local" ? "world" : "local")), title: `Orientation: ${gizmoSpace}`, children: gizmoSpace === "local" ? "🔶" : "🌐" }), jsxRuntime.jsx("div", { className: ModelEditor_module.toolSep }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: () => rootObjectRef.current && focusOnObject(rootObjectRef.current), title: "Focus (F)", children: "\u25CE" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset("front"), title: "Front view (Numpad 1)", children: "1" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset("right"), title: "Right view (Numpad 3)", children: "3" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset("top"), title: "Top view (Numpad 7)", children: "7" }), jsxRuntime.jsx("div", { className: ModelEditor_module.toolSep }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: deleteSelected, title: "Delete selected (Del)", children: "\uD83D\uDDD1" }), jsxRuntime.jsx(index.NiceButton, { className: ModelEditor_module.toolBtn, variant: "ghost", size: "sm", onClick: duplicateSelected, title: "Duplicate (Shift+D)", disabled: !selectedNode, children: "\uD83D\uDCCB" })] }));
|
|
11
11
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelEditor_module = require('./ModelEditor.module.css.js');
|
|
6
6
|
|
|
7
|
-
const ModelEditorViewport =
|
|
7
|
+
const ModelEditorViewport = Ue.memo(({ api }) => {
|
|
8
8
|
const { mountRef, dragOver, handleDragOver, handleDragLeave, handleDrop, handleViewportClick, handleContextMenu, editorMode, polyCount, meshCount, boneCount, shadingMode, setShadingMode, gizmoSpace, setGizmoSpace, contextMenu, closeContextMenu, addPrimitive, addSceneLight, duplicateSelected, deleteSelected, selectedNode, rootObjectRef, focusOnObject, snapEnabled, setSnapEnabled, } = api;
|
|
9
9
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { ref: mountRef, className: `${ModelEditor_module.viewportContainer} ${dragOver ? ModelEditor_module.dragOver : ""}`, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: handleViewportClick, onContextMenu: handleContextMenu, children: [jsxRuntime.jsxs("div", { className: ModelEditor_module.viewportOverlay, children: [jsxRuntime.jsxs("span", { className: ModelEditor_module.viewportBadge, children: [editorMode.toUpperCase(), " MODE"] }), jsxRuntime.jsxs("span", { className: ModelEditor_module.viewportBadge, children: [polyCount.toLocaleString(), " tris \u00B7 ", meshCount, " meshes \u00B7 ", boneCount, " bones"] })] }), jsxRuntime.jsx("div", { className: ModelEditor_module.viewportShadingBar, children: ["wireframe", "solid", "material", "rendered"].map((m) => (jsxRuntime.jsx("button", { className: `${ModelEditor_module.shadingBtn} ${shadingMode === m ? ModelEditor_module.shadingBtnActive : ""}`, onClick: (e) => { e.stopPropagation(); setShadingMode(m); }, title: m.charAt(0).toUpperCase() + m.slice(1), children: m === "wireframe" ? "◇" : m === "solid" ? "◆" : m === "material" ? "🎨" : "☀" }, m))) }), jsxRuntime.jsx("div", { className: ModelEditor_module.viewportGizmoInfo, children: jsxRuntime.jsx("button", { className: ModelEditor_module.shadingBtn, onClick: (e) => {
|
|
10
10
|
e.stopPropagation();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var Ue = require('react');
|
|
5
5
|
var ModelViewer_module = require('./ModelViewer.module.css.js');
|
|
6
6
|
var useModelViewer = require('./useModelViewer.js');
|
|
7
7
|
var index = require('../ui/dist/index.js');
|
|
@@ -14,19 +14,19 @@ const NAV_LABELS = {
|
|
|
14
14
|
};
|
|
15
15
|
const NiceModelViewer = ({ className, showToolbar = true, showStatusBar = true, showInfoPanel = true, toolbarExtra, onFileDrop, children, ...viewerProps }) => {
|
|
16
16
|
const api = useModelViewer.useModelViewer(viewerProps);
|
|
17
|
-
const [panelOpen, setPanelOpen] =
|
|
18
|
-
const [dragOver, setDragOver] =
|
|
19
|
-
const fileInputRef =
|
|
17
|
+
const [panelOpen, setPanelOpen] = Ue.useState(false);
|
|
18
|
+
const [dragOver, setDragOver] = Ue.useState(false);
|
|
19
|
+
const fileInputRef = Ue.useRef(null);
|
|
20
20
|
/* ── drag & drop ── */
|
|
21
|
-
const handleDragOver =
|
|
21
|
+
const handleDragOver = Ue.useCallback((e) => {
|
|
22
22
|
e.preventDefault();
|
|
23
23
|
setDragOver(true);
|
|
24
24
|
}, []);
|
|
25
|
-
const handleDragLeave =
|
|
25
|
+
const handleDragLeave = Ue.useCallback((e) => {
|
|
26
26
|
e.preventDefault();
|
|
27
27
|
setDragOver(false);
|
|
28
28
|
}, []);
|
|
29
|
-
const handleDrop =
|
|
29
|
+
const handleDrop = Ue.useCallback((e) => {
|
|
30
30
|
var _a;
|
|
31
31
|
e.preventDefault();
|
|
32
32
|
setDragOver(false);
|
|
@@ -38,7 +38,7 @@ const NiceModelViewer = ({ className, showToolbar = true, showStatusBar = true,
|
|
|
38
38
|
}, [api, onFileDrop]);
|
|
39
39
|
/* ── nav cycle ── */
|
|
40
40
|
const navModes = ['orbit', 'fps', 'fly', 'walkthrough'];
|
|
41
|
-
const cycleNav =
|
|
41
|
+
const cycleNav = Ue.useCallback(() => {
|
|
42
42
|
const idx = navModes.indexOf(api.navigationMode);
|
|
43
43
|
api.setNavigationMode(navModes[(idx + 1) % navModes.length]);
|
|
44
44
|
}, [api]);
|