@nice2dev/ui-3d 1.1.0 → 1.1.1
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/collaborative/collaborativeScene.js +16 -8
- package/dist/cjs/collaborative/collaborativeScene.js.map +1 -1
- package/dist/cjs/core/i18n.js +3 -3
- package/dist/cjs/dance/DanceBridge.js +65 -30
- package/dist/cjs/dance/DanceBridge.js.map +1 -1
- package/dist/cjs/dance/DanceScoreEngine.js +37 -23
- package/dist/cjs/dance/DanceScoreEngine.js.map +1 -1
- package/dist/cjs/dance/PoseDetector.js +92 -49
- package/dist/cjs/dance/PoseDetector.js.map +1 -1
- package/dist/cjs/material/NiceMaterialEditor.js +134 -91
- package/dist/cjs/material/NiceMaterialEditor.js.map +1 -1
- package/dist/cjs/material/materialEditorUtils.js +86 -55
- package/dist/cjs/material/materialEditorUtils.js.map +1 -1
- package/dist/cjs/model/ModelEditor.js +16 -14
- package/dist/cjs/model/ModelEditor.js.map +1 -1
- package/dist/cjs/model/ModelEditorLeftPanel.js +21 -15
- package/dist/cjs/model/ModelEditorLeftPanel.js.map +1 -1
- package/dist/cjs/model/ModelEditorMenuBar.js +23 -10
- package/dist/cjs/model/ModelEditorMenuBar.js.map +1 -1
- package/dist/cjs/model/ModelEditorRightPanel.js +32 -27
- package/dist/cjs/model/ModelEditorRightPanel.js.map +1 -1
- package/dist/cjs/model/ModelEditorSubComponents.js +20 -20
- package/dist/cjs/model/ModelEditorSubComponents.js.map +1 -1
- package/dist/cjs/model/ModelEditorTimeline.js +12 -11
- package/dist/cjs/model/ModelEditorTimeline.js.map +1 -1
- package/dist/cjs/model/ModelEditorToolbar.js +5 -5
- package/dist/cjs/model/ModelEditorToolbar.js.map +1 -1
- package/dist/cjs/model/ModelEditorViewport.js +12 -8
- package/dist/cjs/model/ModelEditorViewport.js.map +1 -1
- package/dist/cjs/model/ModelViewer.js +16 -15
- package/dist/cjs/model/ModelViewer.js.map +1 -1
- package/dist/cjs/model/NiceArmatureEditor.js +53 -30
- package/dist/cjs/model/NiceArmatureEditor.js.map +1 -1
- package/dist/cjs/model/NiceMorphTargetEditor.js +51 -30
- package/dist/cjs/model/NiceMorphTargetEditor.js.map +1 -1
- package/dist/cjs/model/NiceOctree.js +62 -37
- package/dist/cjs/model/NiceOctree.js.map +1 -1
- package/dist/cjs/model/NicePhysicsSimulation.js +74 -36
- package/dist/cjs/model/NicePhysicsSimulation.js.map +1 -1
- package/dist/cjs/model/NiceProceduralGeometry.js +101 -31
- package/dist/cjs/model/NiceProceduralGeometry.js.map +1 -1
- package/dist/cjs/model/NiceTerrainEditor.js +88 -38
- package/dist/cjs/model/NiceTerrainEditor.js.map +1 -1
- package/dist/cjs/model/NiceWeightPainter.js +46 -24
- package/dist/cjs/model/NiceWeightPainter.js.map +1 -1
- package/dist/cjs/model/NiceXRPreview.js +89 -43
- package/dist/cjs/model/NiceXRPreview.js.map +1 -1
- package/dist/cjs/model/cadModeUtils.js +2 -2
- package/dist/cjs/model/cadModeUtils.js.map +1 -1
- package/dist/cjs/model/editorShortcuts.js +69 -35
- package/dist/cjs/model/editorShortcuts.js.map +1 -1
- package/dist/cjs/model/modelEditorTypes.js +56 -52
- package/dist/cjs/model/modelEditorTypes.js.map +1 -1
- package/dist/cjs/model/modelEditorUtils.js +356 -131
- package/dist/cjs/model/modelEditorUtils.js.map +1 -1
- package/dist/cjs/model/simsModeUtils.js +819 -74
- package/dist/cjs/model/simsModeUtils.js.map +1 -1
- package/dist/cjs/model/useModelEditor.js +501 -394
- package/dist/cjs/model/useModelEditor.js.map +1 -1
- package/dist/cjs/model/useModelViewer.js +117 -86
- package/dist/cjs/model/useModelViewer.js.map +1 -1
- package/dist/cjs/particle/NiceParticleEditor.js +126 -69
- package/dist/cjs/particle/NiceParticleEditor.js.map +1 -1
- package/dist/cjs/particle/particleEditorUtils.js +64 -27
- package/dist/cjs/particle/particleEditorUtils.js.map +1 -1
- package/dist/cjs/rendering/NiceCascadedShadows.js +35 -23
- package/dist/cjs/rendering/NiceCascadedShadows.js.map +1 -1
- package/dist/cjs/rendering/NiceRenderExport.js +26 -12
- package/dist/cjs/rendering/NiceRenderExport.js.map +1 -1
- package/dist/cjs/rendering/NiceSSAO.js +28 -23
- package/dist/cjs/rendering/NiceSSAO.js.map +1 -1
- package/dist/cjs/rendering/NiceSSR.js +22 -18
- package/dist/cjs/rendering/NiceSSR.js.map +1 -1
- package/dist/cjs/rendering/NiceWebGPURenderer.js +60 -37
- package/dist/cjs/rendering/NiceWebGPURenderer.js.map +1 -1
- package/dist/cjs/ui/dist/NiceErrorBoundary-D75yr_WE.js +572 -0
- package/dist/cjs/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
- package/dist/cjs/ui/dist/NiceForm-CKoJA6NG.js +4979 -0
- package/dist/cjs/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
- package/dist/cjs/ui/dist/NiceModal-1QX7NhyH.js +98 -0
- package/dist/cjs/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
- package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5244 -0
- package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
- package/dist/cjs/ui/dist/NicePagination-DbE-uOkl.js +174 -0
- package/dist/cjs/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
- package/dist/cjs/ui/dist/NicePinCodeInput-B8cI8zu8.js +10459 -0
- package/dist/cjs/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
- package/dist/cjs/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6313 -0
- package/dist/cjs/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
- package/dist/cjs/ui/dist/NiceTabs-DzLHzwuA.js +1639 -0
- package/dist/cjs/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
- package/dist/cjs/ui/dist/NiceWindow-DeC83yfE.js +807 -0
- package/dist/cjs/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
- package/dist/cjs/ui/dist/charts-BAS21jkC.js +3833 -0
- package/dist/cjs/ui/dist/charts-BAS21jkC.js.map +1 -0
- package/dist/cjs/ui/dist/core-Da43q-pO.js +11683 -0
- package/dist/cjs/ui/dist/core-Da43q-pO.js.map +1 -0
- package/dist/cjs/ui/dist/index-pAuGTbuB.js +28876 -0
- package/dist/cjs/ui/dist/index-pAuGTbuB.js.map +1 -0
- package/dist/cjs/uv/NiceUVEditor.js +115 -86
- package/dist/cjs/uv/NiceUVEditor.js.map +1 -1
- package/dist/cjs/uv/uvEditorUtils.js +41 -23
- package/dist/cjs/uv/uvEditorUtils.js.map +1 -1
- package/dist/esm/collaborative/collaborativeScene.js +16 -8
- package/dist/esm/collaborative/collaborativeScene.js.map +1 -1
- package/dist/esm/dance/DanceBridge.js +55 -20
- package/dist/esm/dance/DanceBridge.js.map +1 -1
- package/dist/esm/dance/DanceScoreEngine.js +29 -15
- package/dist/esm/dance/DanceScoreEngine.js.map +1 -1
- package/dist/esm/dance/PoseDetector.js +73 -30
- package/dist/esm/dance/PoseDetector.js.map +1 -1
- package/dist/esm/material/NiceMaterialEditor.js +115 -72
- package/dist/esm/material/NiceMaterialEditor.js.map +1 -1
- package/dist/esm/material/materialEditorUtils.js +86 -55
- package/dist/esm/material/materialEditorUtils.js.map +1 -1
- package/dist/esm/model/ModelEditor.js +16 -14
- package/dist/esm/model/ModelEditor.js.map +1 -1
- package/dist/esm/model/ModelEditorLeftPanel.js +21 -15
- package/dist/esm/model/ModelEditorLeftPanel.js.map +1 -1
- package/dist/esm/model/ModelEditorMenuBar.js +23 -10
- package/dist/esm/model/ModelEditorMenuBar.js.map +1 -1
- package/dist/esm/model/ModelEditorRightPanel.js +32 -27
- package/dist/esm/model/ModelEditorRightPanel.js.map +1 -1
- package/dist/esm/model/ModelEditorSubComponents.js +17 -17
- package/dist/esm/model/ModelEditorSubComponents.js.map +1 -1
- package/dist/esm/model/ModelEditorTimeline.js +12 -11
- package/dist/esm/model/ModelEditorTimeline.js.map +1 -1
- package/dist/esm/model/ModelEditorToolbar.js +5 -5
- package/dist/esm/model/ModelEditorToolbar.js.map +1 -1
- package/dist/esm/model/ModelEditorViewport.js +12 -8
- package/dist/esm/model/ModelEditorViewport.js.map +1 -1
- package/dist/esm/model/ModelViewer.js +8 -7
- package/dist/esm/model/ModelViewer.js.map +1 -1
- package/dist/esm/model/NiceArmatureEditor.js +36 -13
- package/dist/esm/model/NiceArmatureEditor.js.map +1 -1
- package/dist/esm/model/NiceMorphTargetEditor.js +34 -13
- package/dist/esm/model/NiceMorphTargetEditor.js.map +1 -1
- package/dist/esm/model/NiceOctree.js +47 -22
- package/dist/esm/model/NiceOctree.js.map +1 -1
- package/dist/esm/model/NicePhysicsSimulation.js +51 -13
- package/dist/esm/model/NicePhysicsSimulation.js.map +1 -1
- package/dist/esm/model/NiceProceduralGeometry.js +94 -24
- package/dist/esm/model/NiceProceduralGeometry.js.map +1 -1
- package/dist/esm/model/NiceTerrainEditor.js +70 -20
- package/dist/esm/model/NiceTerrainEditor.js.map +1 -1
- package/dist/esm/model/NiceWeightPainter.js +33 -11
- package/dist/esm/model/NiceWeightPainter.js.map +1 -1
- package/dist/esm/model/NiceXRPreview.js +72 -26
- package/dist/esm/model/NiceXRPreview.js.map +1 -1
- package/dist/esm/model/cadModeUtils.js +2 -2
- package/dist/esm/model/cadModeUtils.js.map +1 -1
- package/dist/esm/model/editorShortcuts.js +69 -35
- package/dist/esm/model/editorShortcuts.js.map +1 -1
- package/dist/esm/model/modelEditorTypes.js +56 -52
- package/dist/esm/model/modelEditorTypes.js.map +1 -1
- package/dist/esm/model/modelEditorUtils.js +356 -131
- package/dist/esm/model/modelEditorUtils.js.map +1 -1
- package/dist/esm/model/simsModeUtils.js +819 -74
- package/dist/esm/model/simsModeUtils.js.map +1 -1
- package/dist/esm/model/useModelEditor.js +384 -277
- package/dist/esm/model/useModelEditor.js.map +1 -1
- package/dist/esm/model/useModelViewer.js +56 -25
- package/dist/esm/model/useModelViewer.js.map +1 -1
- package/dist/esm/particle/NiceParticleEditor.js +116 -59
- package/dist/esm/particle/NiceParticleEditor.js.map +1 -1
- package/dist/esm/particle/particleEditorUtils.js +64 -27
- package/dist/esm/particle/particleEditorUtils.js.map +1 -1
- package/dist/esm/rendering/NiceCascadedShadows.js +24 -12
- package/dist/esm/rendering/NiceCascadedShadows.js.map +1 -1
- package/dist/esm/rendering/NiceRenderExport.js +22 -8
- package/dist/esm/rendering/NiceRenderExport.js.map +1 -1
- package/dist/esm/rendering/NiceSSAO.js +11 -6
- package/dist/esm/rendering/NiceSSAO.js.map +1 -1
- package/dist/esm/rendering/NiceSSR.js +9 -5
- package/dist/esm/rendering/NiceSSR.js.map +1 -1
- package/dist/esm/rendering/NiceWebGPURenderer.js +40 -17
- package/dist/esm/rendering/NiceWebGPURenderer.js.map +1 -1
- package/dist/esm/ui/dist/NiceErrorBoundary-D75yr_WE.js +563 -0
- package/dist/esm/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
- package/dist/esm/ui/dist/NiceForm-CKoJA6NG.js +4960 -0
- package/dist/esm/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
- package/dist/esm/ui/dist/NiceModal-1QX7NhyH.js +96 -0
- package/dist/esm/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
- package/dist/esm/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5201 -0
- package/dist/esm/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
- package/dist/esm/ui/dist/NicePagination-DbE-uOkl.js +172 -0
- package/dist/esm/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
- package/dist/esm/ui/dist/NicePinCodeInput-B8cI8zu8.js +10408 -0
- package/dist/esm/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
- package/dist/esm/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6296 -0
- package/dist/esm/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
- package/dist/esm/ui/dist/NiceTabs-DzLHzwuA.js +1630 -0
- package/dist/esm/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
- package/dist/esm/ui/dist/NiceWindow-DeC83yfE.js +796 -0
- package/dist/esm/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
- package/dist/esm/ui/dist/charts-BAS21jkC.js +3809 -0
- package/dist/esm/ui/dist/charts-BAS21jkC.js.map +1 -0
- package/dist/esm/ui/dist/core-Da43q-pO.js +11502 -0
- package/dist/esm/ui/dist/core-Da43q-pO.js.map +1 -0
- package/dist/esm/ui/dist/index-pAuGTbuB.js +28792 -0
- package/dist/esm/ui/dist/index-pAuGTbuB.js.map +1 -0
- package/dist/esm/uv/NiceUVEditor.js +91 -62
- package/dist/esm/uv/NiceUVEditor.js.map +1 -1
- package/dist/esm/uv/uvEditorUtils.js +41 -23
- package/dist/esm/uv/uvEditorUtils.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var
|
|
4
|
+
var _e = require('react');
|
|
5
|
+
var MaterialEditor_module = require('./MaterialEditor.module.css.js');
|
|
5
6
|
var materialEditorTypes = require('./materialEditorTypes.js');
|
|
6
|
-
var materialNodeDefinitions = require('./materialNodeDefinitions.js');
|
|
7
7
|
var materialEditorUtils = require('./materialEditorUtils.js');
|
|
8
|
-
var
|
|
8
|
+
var materialNodeDefinitions = require('./materialNodeDefinitions.js');
|
|
9
9
|
|
|
10
10
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
11
11
|
State Reducer
|
|
@@ -43,8 +43,9 @@ function materialEditorReducer(state, action) {
|
|
|
43
43
|
switch (action.type) {
|
|
44
44
|
case 'ADD_NODE': {
|
|
45
45
|
const node = materialEditorUtils.createNode(action.nodeType, action.position);
|
|
46
|
-
if (!node)
|
|
46
|
+
if (!node) {
|
|
47
47
|
return state;
|
|
48
|
+
}
|
|
48
49
|
const newState = pushToUndoStack(state);
|
|
49
50
|
return {
|
|
50
51
|
...newState,
|
|
@@ -69,9 +70,10 @@ function materialEditorReducer(state, action) {
|
|
|
69
70
|
}
|
|
70
71
|
case 'UPDATE_NODE_PROPERTY': {
|
|
71
72
|
const newState = pushToUndoStack(state);
|
|
72
|
-
const node = newState.graph.nodes.find(n => n.id === action.nodeId);
|
|
73
|
-
if (!node)
|
|
73
|
+
const node = newState.graph.nodes.find((n) => n.id === action.nodeId);
|
|
74
|
+
if (!node) {
|
|
74
75
|
return state;
|
|
76
|
+
}
|
|
75
77
|
return {
|
|
76
78
|
...newState,
|
|
77
79
|
graph: materialEditorUtils.updateNodeInGraph(newState.graph, action.nodeId, {
|
|
@@ -81,9 +83,10 @@ function materialEditorReducer(state, action) {
|
|
|
81
83
|
}
|
|
82
84
|
case 'UPDATE_INPUT_VALUE': {
|
|
83
85
|
const newState = pushToUndoStack(state);
|
|
84
|
-
const node = newState.graph.nodes.find(n => n.id === action.nodeId);
|
|
85
|
-
if (!node)
|
|
86
|
+
const node = newState.graph.nodes.find((n) => n.id === action.nodeId);
|
|
87
|
+
if (!node) {
|
|
86
88
|
return state;
|
|
89
|
+
}
|
|
87
90
|
return {
|
|
88
91
|
...newState,
|
|
89
92
|
graph: materialEditorUtils.updateNodeInGraph(newState.graph, action.nodeId, {
|
|
@@ -92,21 +95,25 @@ function materialEditorReducer(state, action) {
|
|
|
92
95
|
};
|
|
93
96
|
}
|
|
94
97
|
case 'CONNECT': {
|
|
95
|
-
const sourceNode = state.graph.nodes.find(n => n.id === action.connection.sourceNodeId);
|
|
96
|
-
const targetNode = state.graph.nodes.find(n => n.id === action.connection.targetNodeId);
|
|
97
|
-
if (!sourceNode || !targetNode)
|
|
98
|
+
const sourceNode = state.graph.nodes.find((n) => n.id === action.connection.sourceNodeId);
|
|
99
|
+
const targetNode = state.graph.nodes.find((n) => n.id === action.connection.targetNodeId);
|
|
100
|
+
if (!sourceNode || !targetNode) {
|
|
98
101
|
return state;
|
|
102
|
+
}
|
|
99
103
|
const sourceDef = materialEditorUtils.getNodeDefinition(sourceNode);
|
|
100
104
|
const targetDef = materialEditorUtils.getNodeDefinition(targetNode);
|
|
101
|
-
if (!sourceDef || !targetDef)
|
|
105
|
+
if (!sourceDef || !targetDef) {
|
|
102
106
|
return state;
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
107
|
+
}
|
|
108
|
+
const sourcePort = sourceDef.outputs.find((p) => p.id === action.connection.sourcePortId);
|
|
109
|
+
const targetPort = targetDef.inputs.find((p) => p.id === action.connection.targetPortId);
|
|
110
|
+
if (!sourcePort || !targetPort) {
|
|
106
111
|
return state;
|
|
112
|
+
}
|
|
107
113
|
const { valid } = materialEditorUtils.canConnect(sourceNode, sourcePort, targetNode, targetPort, state.graph.connections);
|
|
108
|
-
if (!valid)
|
|
114
|
+
if (!valid) {
|
|
109
115
|
return state;
|
|
116
|
+
}
|
|
110
117
|
const newState = pushToUndoStack(state);
|
|
111
118
|
const connection = materialEditorUtils.createConnection(action.connection.sourceNodeId, action.connection.sourcePortId, action.connection.targetNodeId, action.connection.targetPortId);
|
|
112
119
|
return {
|
|
@@ -119,7 +126,7 @@ function materialEditorReducer(state, action) {
|
|
|
119
126
|
return {
|
|
120
127
|
...newState,
|
|
121
128
|
graph: materialEditorUtils.removeConnectionFromGraph(newState.graph, action.connectionId),
|
|
122
|
-
selectedConnections: state.selectedConnections.filter(id => id !== action.connectionId),
|
|
129
|
+
selectedConnections: state.selectedConnections.filter((id) => id !== action.connectionId),
|
|
123
130
|
};
|
|
124
131
|
}
|
|
125
132
|
case 'SELECT_NODES': {
|
|
@@ -143,8 +150,8 @@ function materialEditorReducer(state, action) {
|
|
|
143
150
|
case 'SELECT_ALL': {
|
|
144
151
|
return {
|
|
145
152
|
...state,
|
|
146
|
-
selectedNodes: state.graph.nodes.map(n => n.id),
|
|
147
|
-
selectedConnections: state.graph.connections.map(c => c.id),
|
|
153
|
+
selectedNodes: state.graph.nodes.map((n) => n.id),
|
|
154
|
+
selectedConnections: state.graph.connections.map((c) => c.id),
|
|
148
155
|
};
|
|
149
156
|
}
|
|
150
157
|
case 'DESELECT_ALL': {
|
|
@@ -155,19 +162,21 @@ function materialEditorReducer(state, action) {
|
|
|
155
162
|
};
|
|
156
163
|
}
|
|
157
164
|
case 'COPY': {
|
|
158
|
-
const nodesToCopy = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id));
|
|
159
|
-
const connectionsToCopy = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
165
|
+
const nodesToCopy = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id));
|
|
166
|
+
const connectionsToCopy = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
167
|
+
state.selectedNodes.includes(c.targetNodeId));
|
|
160
168
|
return {
|
|
161
169
|
...state,
|
|
162
170
|
clipboard: { nodes: nodesToCopy, connections: connectionsToCopy },
|
|
163
171
|
};
|
|
164
172
|
}
|
|
165
173
|
case 'PASTE': {
|
|
166
|
-
if (!state.clipboard)
|
|
174
|
+
if (!state.clipboard) {
|
|
167
175
|
return state;
|
|
176
|
+
}
|
|
168
177
|
const newState = pushToUndoStack(state);
|
|
169
178
|
const idMap = new Map();
|
|
170
|
-
const newNodes = state.clipboard.nodes.map(node => {
|
|
179
|
+
const newNodes = state.clipboard.nodes.map((node) => {
|
|
171
180
|
const newId = materialEditorUtils.generateNodeId();
|
|
172
181
|
idMap.set(node.id, newId);
|
|
173
182
|
return {
|
|
@@ -180,7 +189,7 @@ function materialEditorReducer(state, action) {
|
|
|
180
189
|
selected: false,
|
|
181
190
|
};
|
|
182
191
|
});
|
|
183
|
-
const newConnections = state.clipboard.connections.map(conn => ({
|
|
192
|
+
const newConnections = state.clipboard.connections.map((conn) => ({
|
|
184
193
|
...conn,
|
|
185
194
|
id: materialEditorUtils.generateNodeId(),
|
|
186
195
|
sourceNodeId: idMap.get(conn.sourceNodeId),
|
|
@@ -193,31 +202,33 @@ function materialEditorReducer(state, action) {
|
|
|
193
202
|
nodes: [...newState.graph.nodes, ...newNodes],
|
|
194
203
|
connections: [...newState.graph.connections, ...newConnections],
|
|
195
204
|
},
|
|
196
|
-
selectedNodes: newNodes.map(n => n.id),
|
|
205
|
+
selectedNodes: newNodes.map((n) => n.id),
|
|
197
206
|
};
|
|
198
207
|
}
|
|
199
208
|
case 'CUT': {
|
|
200
|
-
const nodesToCut = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
|
|
201
|
-
const connectionsToCut = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
209
|
+
const nodesToCut = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
|
|
210
|
+
const connectionsToCut = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
211
|
+
state.selectedNodes.includes(c.targetNodeId));
|
|
202
212
|
const newState = pushToUndoStack(state);
|
|
203
213
|
return {
|
|
204
214
|
...newState,
|
|
205
215
|
clipboard: { nodes: nodesToCut, connections: connectionsToCut },
|
|
206
|
-
graph: materialEditorUtils.removeNodesFromGraph(newState.graph, nodesToCut.map(n => n.id)),
|
|
216
|
+
graph: materialEditorUtils.removeNodesFromGraph(newState.graph, nodesToCut.map((n) => n.id)),
|
|
207
217
|
selectedNodes: [],
|
|
208
218
|
};
|
|
209
219
|
}
|
|
210
220
|
case 'DUPLICATE': {
|
|
211
|
-
const nodesToDupe = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
|
|
221
|
+
const nodesToDupe = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
|
|
212
222
|
const newState = pushToUndoStack(state);
|
|
213
223
|
const idMap = new Map();
|
|
214
|
-
const newNodes = nodesToDupe.map(node => {
|
|
224
|
+
const newNodes = nodesToDupe.map((node) => {
|
|
215
225
|
const cloned = materialEditorUtils.cloneNode(node);
|
|
216
226
|
idMap.set(node.id, cloned.id);
|
|
217
227
|
return cloned;
|
|
218
228
|
});
|
|
219
|
-
const connectionsToDupe = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
220
|
-
|
|
229
|
+
const connectionsToDupe = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
|
|
230
|
+
state.selectedNodes.includes(c.targetNodeId));
|
|
231
|
+
const newConnections = connectionsToDupe.map((conn) => ({
|
|
221
232
|
...conn,
|
|
222
233
|
id: materialEditorUtils.generateNodeId(),
|
|
223
234
|
sourceNodeId: idMap.get(conn.sourceNodeId),
|
|
@@ -230,12 +241,13 @@ function materialEditorReducer(state, action) {
|
|
|
230
241
|
nodes: [...newState.graph.nodes, ...newNodes],
|
|
231
242
|
connections: [...newState.graph.connections, ...newConnections],
|
|
232
243
|
},
|
|
233
|
-
selectedNodes: newNodes.map(n => n.id),
|
|
244
|
+
selectedNodes: newNodes.map((n) => n.id),
|
|
234
245
|
};
|
|
235
246
|
}
|
|
236
247
|
case 'UNDO': {
|
|
237
|
-
if (state.undoStack.length === 0)
|
|
248
|
+
if (state.undoStack.length === 0) {
|
|
238
249
|
return state;
|
|
250
|
+
}
|
|
239
251
|
const previous = state.undoStack[state.undoStack.length - 1];
|
|
240
252
|
return {
|
|
241
253
|
...state,
|
|
@@ -247,8 +259,9 @@ function materialEditorReducer(state, action) {
|
|
|
247
259
|
};
|
|
248
260
|
}
|
|
249
261
|
case 'REDO': {
|
|
250
|
-
if (state.redoStack.length === 0)
|
|
262
|
+
if (state.redoStack.length === 0) {
|
|
251
263
|
return state;
|
|
264
|
+
}
|
|
252
265
|
const next = state.redoStack[state.redoStack.length - 1];
|
|
253
266
|
return {
|
|
254
267
|
...state,
|
|
@@ -281,7 +294,7 @@ function materialEditorReducer(state, action) {
|
|
|
281
294
|
return {
|
|
282
295
|
...state,
|
|
283
296
|
expandedCategories: state.expandedCategories.includes(action.category)
|
|
284
|
-
? state.expandedCategories.filter(c => c !== action.category)
|
|
297
|
+
? state.expandedCategories.filter((c) => c !== action.category)
|
|
285
298
|
: [...state.expandedCategories, action.category],
|
|
286
299
|
};
|
|
287
300
|
case 'COLLAPSE_NODE':
|
|
@@ -338,9 +351,9 @@ function materialEditorReducer(state, action) {
|
|
|
338
351
|
Hook: useMaterialEditor
|
|
339
352
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
340
353
|
function useMaterialEditor(initialGraph) {
|
|
341
|
-
const [state, dispatch] =
|
|
354
|
+
const [state, dispatch] = _e.useReducer(materialEditorReducer, initialGraph, createInitialState);
|
|
342
355
|
// Auto-compile when graph changes
|
|
343
|
-
|
|
356
|
+
_e.useEffect(() => {
|
|
344
357
|
if (state.autoCompile && !state.compiling) {
|
|
345
358
|
const timeout = setTimeout(() => {
|
|
346
359
|
dispatch({ type: 'COMPILE' });
|
|
@@ -353,10 +366,8 @@ function useMaterialEditor(initialGraph) {
|
|
|
353
366
|
return { state, dispatch };
|
|
354
367
|
}
|
|
355
368
|
function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCategory, onAddNode, onDragStart, }) {
|
|
356
|
-
const filteredNodes = searchQuery
|
|
357
|
-
|
|
358
|
-
: materialNodeDefinitions.MATERIAL_NODE_DEFINITIONS;
|
|
359
|
-
const categories = ke.useMemo(() => {
|
|
369
|
+
const filteredNodes = searchQuery ? materialNodeDefinitions.searchNodes(searchQuery) : materialNodeDefinitions.MATERIAL_NODE_DEFINITIONS;
|
|
370
|
+
const categories = _e.useMemo(() => {
|
|
360
371
|
const cats = new Map();
|
|
361
372
|
for (const node of filteredNodes) {
|
|
362
373
|
if (!cats.has(node.category)) {
|
|
@@ -366,15 +377,18 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
|
|
|
366
377
|
}
|
|
367
378
|
return cats;
|
|
368
379
|
}, [filteredNodes]);
|
|
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: {
|
|
380
|
+
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: {
|
|
381
|
+
backgroundColor: nodeDef.color || materialEditorTypes.NODE_CATEGORY_COLORS[nodeDef.category],
|
|
382
|
+
} }), jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
|
|
370
383
|
}
|
|
371
384
|
function GraphNode({ node, definition, selected, viewTransform, connections, onSelect, onMove, onStartConnection, }) {
|
|
372
|
-
const nodeRef =
|
|
373
|
-
const [isDragging, setIsDragging] =
|
|
374
|
-
const dragStart =
|
|
385
|
+
const nodeRef = _e.useRef(null);
|
|
386
|
+
const [isDragging, setIsDragging] = _e.useState(false);
|
|
387
|
+
const dragStart = _e.useRef(null);
|
|
375
388
|
const handleMouseDown = (e) => {
|
|
376
|
-
if (e.button !== 0)
|
|
389
|
+
if (e.button !== 0) {
|
|
377
390
|
return;
|
|
391
|
+
}
|
|
378
392
|
e.stopPropagation();
|
|
379
393
|
if (!selected) {
|
|
380
394
|
onSelect(node.id, e.shiftKey || e.ctrlKey);
|
|
@@ -384,9 +398,10 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
|
|
|
384
398
|
dragStart.current = { x: e.clientX, y: e.clientY };
|
|
385
399
|
}
|
|
386
400
|
};
|
|
387
|
-
|
|
388
|
-
if (!isDragging)
|
|
401
|
+
_e.useEffect(() => {
|
|
402
|
+
if (!isDragging) {
|
|
389
403
|
return;
|
|
404
|
+
}
|
|
390
405
|
const handleMouseMove = (e) => {
|
|
391
406
|
if (dragStart.current) {
|
|
392
407
|
const delta = {
|
|
@@ -430,27 +445,29 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
|
|
|
430
445
|
transform: `scale(${viewTransform.zoom})`,
|
|
431
446
|
transformOrigin: 'top left',
|
|
432
447
|
}, onMouseDown: handleMouseDown, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.nodeHeader, style: { backgroundColor: nodeColor }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.nodeTitle, children: definition.name }), node.locked && jsxRuntime.jsx("span", { className: MaterialEditor_module.lockIcon, children: "\uD83D\uDD12" })] }), !node.collapsed && (jsxRuntime.jsxs("div", { className: MaterialEditor_module.nodePorts, children: [jsxRuntime.jsx("div", { className: MaterialEditor_module.inputPorts, children: definition.inputs.map((port, index) => {
|
|
433
|
-
const isConnected = connections.some(c => c.targetNodeId === node.id && c.targetPortId === port.id);
|
|
434
|
-
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.port, style: { top: index * materialEditorTypes.PORT_HEIGHT + materialEditorTypes.NODE_HEADER_HEIGHT }, children: [jsxRuntime.jsx("div", { className: `${MaterialEditor_module.portHandle} ${MaterialEditor_module.inputHandle} ${isConnected ? MaterialEditor_module.connected : ''}`, style: { backgroundColor: materialEditorTypes.PORT_TYPE_COLORS[port.dataType] }, onMouseDown: e => handlePortMouseDown(e, port.id, 'input') }), jsxRuntime.jsx("span", { className: MaterialEditor_module.portLabel, children: port.name })] }, port.id));
|
|
448
|
+
const isConnected = connections.some((c) => c.targetNodeId === node.id && c.targetPortId === port.id);
|
|
449
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.port, style: { top: index * materialEditorTypes.PORT_HEIGHT + materialEditorTypes.NODE_HEADER_HEIGHT }, children: [jsxRuntime.jsx("div", { className: `${MaterialEditor_module.portHandle} ${MaterialEditor_module.inputHandle} ${isConnected ? MaterialEditor_module.connected : ''}`, style: { backgroundColor: materialEditorTypes.PORT_TYPE_COLORS[port.dataType] }, onMouseDown: (e) => handlePortMouseDown(e, port.id, 'input') }), jsxRuntime.jsx("span", { className: MaterialEditor_module.portLabel, children: port.name })] }, port.id));
|
|
435
450
|
}) }), jsxRuntime.jsx("div", { className: MaterialEditor_module.outputPorts, children: definition.outputs.map((port, index) => {
|
|
436
|
-
const isConnected = connections.some(c => c.sourceNodeId === node.id && c.sourcePortId === port.id);
|
|
437
|
-
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.port, style: { top: index * materialEditorTypes.PORT_HEIGHT + materialEditorTypes.NODE_HEADER_HEIGHT }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.portLabel, children: port.name }), jsxRuntime.jsx("div", { className: `${MaterialEditor_module.portHandle} ${MaterialEditor_module.outputHandle} ${isConnected ? MaterialEditor_module.connected : ''}`, style: { backgroundColor: materialEditorTypes.PORT_TYPE_COLORS[port.dataType] }, onMouseDown: e => handlePortMouseDown(e, port.id, 'output') })] }, port.id));
|
|
438
|
-
}) })] })), node.comment &&
|
|
451
|
+
const isConnected = connections.some((c) => c.sourceNodeId === node.id && c.sourcePortId === port.id);
|
|
452
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.port, style: { top: index * materialEditorTypes.PORT_HEIGHT + materialEditorTypes.NODE_HEADER_HEIGHT }, children: [jsxRuntime.jsx("span", { className: MaterialEditor_module.portLabel, children: port.name }), jsxRuntime.jsx("div", { className: `${MaterialEditor_module.portHandle} ${MaterialEditor_module.outputHandle} ${isConnected ? MaterialEditor_module.connected : ''}`, style: { backgroundColor: materialEditorTypes.PORT_TYPE_COLORS[port.dataType] }, onMouseDown: (e) => handlePortMouseDown(e, port.id, 'output') })] }, port.id));
|
|
453
|
+
}) })] })), node.comment && jsxRuntime.jsx("div", { className: MaterialEditor_module.nodeComment, children: node.comment })] }));
|
|
439
454
|
}
|
|
440
455
|
function Toolbar({ canUndo, canRedo, canPaste, hasSelection, autoCompile, compiling, showGrid, snapToGrid, onUndo, onRedo, onCopy, onCut, onPaste, onDuplicate, onDelete, onSelectAll, onZoomToFit, onToggleGrid, onToggleSnap, onToggleAutoCompile, onCompile, onNew, onExport, onImport, }) {
|
|
441
456
|
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
457
|
}
|
|
443
458
|
function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
444
|
-
const canvasRef =
|
|
459
|
+
const canvasRef = _e.useRef(null);
|
|
445
460
|
const previewModes = ['sphere', 'cube', 'plane', 'cylinder', 'torus'];
|
|
446
461
|
// Simple preview rendering (in real implementation would use Three.js)
|
|
447
|
-
|
|
462
|
+
_e.useEffect(() => {
|
|
448
463
|
const canvas = canvasRef.current;
|
|
449
|
-
if (!canvas)
|
|
464
|
+
if (!canvas) {
|
|
450
465
|
return;
|
|
466
|
+
}
|
|
451
467
|
const ctx = canvas.getContext('2d');
|
|
452
|
-
if (!ctx)
|
|
468
|
+
if (!ctx) {
|
|
453
469
|
return;
|
|
470
|
+
}
|
|
454
471
|
// Simple gradient preview
|
|
455
472
|
const gradient = ctx.createRadialGradient(100, 100, 0, 100, 100, 100);
|
|
456
473
|
if ((shader === null || shader === void 0 ? void 0 : shader.errors.length) === 0) {
|
|
@@ -468,35 +485,36 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
|
|
|
468
485
|
ctx.arc(100, 100, 80, 0, Math.PI * 2);
|
|
469
486
|
ctx.fill();
|
|
470
487
|
}, [shader, mode]);
|
|
471
|
-
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewPanel, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewHeader, children: [jsxRuntime.jsx("span", { children: "Preview" }), jsxRuntime.jsx("select", { value: mode, onChange: e => onModeChange(e.target.value), className: MaterialEditor_module.previewModeSelect, children: previewModes.map(m => (jsxRuntime.jsx("option", { value: m, children: m.charAt(0).toUpperCase() + m.slice(1) }, m))) })] }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewCanvas, children: [compiling && jsxRuntime.jsx("div", { className: MaterialEditor_module.previewCompiling, children: "Compiling..." }), jsxRuntime.jsx("canvas", { ref: canvasRef, width: 200, height: 200 })] }), (shader === null || shader === void 0 ? void 0 : shader.errors.length) ? (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewErrors, children: shader.errors.slice(0, 3).map((err, i) => (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewError, children: err.message }, i))) })) : null] }));
|
|
488
|
+
return (jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewPanel, children: [jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewHeader, children: [jsxRuntime.jsx("span", { children: "Preview" }), jsxRuntime.jsx("select", { value: mode, onChange: (e) => onModeChange(e.target.value), className: MaterialEditor_module.previewModeSelect, children: previewModes.map((m) => (jsxRuntime.jsx("option", { value: m, children: m.charAt(0).toUpperCase() + m.slice(1) }, m))) })] }), jsxRuntime.jsxs("div", { className: MaterialEditor_module.previewCanvas, children: [compiling && jsxRuntime.jsx("div", { className: MaterialEditor_module.previewCompiling, children: "Compiling..." }), jsxRuntime.jsx("canvas", { ref: canvasRef, width: 200, height: 200 })] }), (shader === null || shader === void 0 ? void 0 : shader.errors.length) ? (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewErrors, children: shader.errors.slice(0, 3).map((err, i) => (jsxRuntime.jsx("div", { className: MaterialEditor_module.previewError, children: err.message }, i))) })) : null] }));
|
|
472
489
|
}
|
|
473
490
|
/* ═══════════════════════════════════════════════════════════════════════════
|
|
474
491
|
Main Component
|
|
475
492
|
═══════════════════════════════════════════════════════════════════════════ */
|
|
476
493
|
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
494
|
const { state, dispatch } = useMaterialEditor(initialGraph);
|
|
478
|
-
const canvasRef =
|
|
479
|
-
const [pendingConnection, setPendingConnection] =
|
|
495
|
+
const canvasRef = _e.useRef(null);
|
|
496
|
+
const [pendingConnection, setPendingConnection] = _e.useState(null);
|
|
480
497
|
// Merge custom node definitions
|
|
481
|
-
const definitions =
|
|
498
|
+
const definitions = _e.useMemo(() => {
|
|
482
499
|
const map = new Map(materialNodeDefinitions.MATERIAL_NODE_MAP);
|
|
483
|
-
customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach(def => map.set(def.type, def));
|
|
500
|
+
customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach((def) => map.set(def.type, def));
|
|
484
501
|
return map;
|
|
485
502
|
}, [customNodes]);
|
|
486
503
|
// Notify parent of changes
|
|
487
|
-
|
|
504
|
+
_e.useEffect(() => {
|
|
488
505
|
onGraphChange === null || onGraphChange === void 0 ? void 0 : onGraphChange(state.graph);
|
|
489
506
|
}, [state.graph, onGraphChange]);
|
|
490
|
-
|
|
507
|
+
_e.useEffect(() => {
|
|
491
508
|
if (state.compiledShader) {
|
|
492
509
|
onCompile === null || onCompile === void 0 ? void 0 : onCompile(state.compiledShader);
|
|
493
510
|
}
|
|
494
511
|
}, [state.compiledShader, onCompile]);
|
|
495
512
|
// Keyboard shortcuts
|
|
496
|
-
|
|
513
|
+
_e.useEffect(() => {
|
|
497
514
|
const handleKeyDown = (e) => {
|
|
498
|
-
if (readOnly)
|
|
515
|
+
if (readOnly) {
|
|
499
516
|
return;
|
|
517
|
+
}
|
|
500
518
|
const isCtrl = e.ctrlKey || e.metaKey;
|
|
501
519
|
if (isCtrl && e.key === 'z') {
|
|
502
520
|
e.preventDefault();
|
|
@@ -553,14 +571,15 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
553
571
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
554
572
|
}, [readOnly, state.selectedNodes, dispatch]);
|
|
555
573
|
// Handle wheel zoom
|
|
556
|
-
const handleWheel =
|
|
574
|
+
const handleWheel = _e.useCallback((e) => {
|
|
557
575
|
var _a;
|
|
558
576
|
e.preventDefault();
|
|
559
577
|
const delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
560
578
|
const newZoom = Math.min(materialEditorTypes.MAX_ZOOM, Math.max(materialEditorTypes.MIN_ZOOM, state.viewTransform.zoom * delta));
|
|
561
579
|
const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
562
|
-
if (!rect)
|
|
580
|
+
if (!rect) {
|
|
563
581
|
return;
|
|
582
|
+
}
|
|
564
583
|
const mouseX = e.clientX - rect.left;
|
|
565
584
|
const mouseY = e.clientY - rect.top;
|
|
566
585
|
const newX = mouseX - (mouseX - state.viewTransform.x) * (newZoom / state.viewTransform.zoom);
|
|
@@ -571,8 +590,8 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
571
590
|
});
|
|
572
591
|
}, [state.viewTransform, dispatch]);
|
|
573
592
|
// Handle canvas pan
|
|
574
|
-
const [isPanning, setIsPanning] =
|
|
575
|
-
const panStart =
|
|
593
|
+
const [isPanning, setIsPanning] = _e.useState(false);
|
|
594
|
+
const panStart = _e.useRef(null);
|
|
576
595
|
const handleCanvasMouseDown = (e) => {
|
|
577
596
|
if (e.button === 1 || (e.button === 0 && e.altKey)) {
|
|
578
597
|
setIsPanning(true);
|
|
@@ -617,11 +636,13 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
617
636
|
var _a;
|
|
618
637
|
e.preventDefault();
|
|
619
638
|
const nodeType = e.dataTransfer.getData('text/plain');
|
|
620
|
-
if (!nodeType)
|
|
639
|
+
if (!nodeType) {
|
|
621
640
|
return;
|
|
641
|
+
}
|
|
622
642
|
const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
623
|
-
if (!rect)
|
|
643
|
+
if (!rect) {
|
|
624
644
|
return;
|
|
645
|
+
}
|
|
625
646
|
const position = materialEditorUtils.screenToGraph({ x: e.clientX - rect.left, y: e.clientY - rect.top }, state.viewTransform);
|
|
626
647
|
dispatch({ type: 'ADD_NODE', nodeType, position });
|
|
627
648
|
};
|
|
@@ -661,8 +682,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
661
682
|
input.onchange = async (e) => {
|
|
662
683
|
var _a;
|
|
663
684
|
const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
664
|
-
if (!file)
|
|
685
|
+
if (!file) {
|
|
665
686
|
return;
|
|
687
|
+
}
|
|
666
688
|
const text = await file.text();
|
|
667
689
|
const graph = materialEditorUtils.importGraphFromJSON(text);
|
|
668
690
|
if (graph) {
|
|
@@ -673,24 +695,37 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
673
695
|
};
|
|
674
696
|
// Render connections
|
|
675
697
|
const renderConnections = () => {
|
|
676
|
-
return state.graph.connections.map(conn => {
|
|
677
|
-
const sourceNode = state.graph.nodes.find(n => n.id === conn.sourceNodeId);
|
|
678
|
-
const targetNode = state.graph.nodes.find(n => n.id === conn.targetNodeId);
|
|
679
|
-
if (!sourceNode || !targetNode)
|
|
698
|
+
return state.graph.connections.map((conn) => {
|
|
699
|
+
const sourceNode = state.graph.nodes.find((n) => n.id === conn.sourceNodeId);
|
|
700
|
+
const targetNode = state.graph.nodes.find((n) => n.id === conn.targetNodeId);
|
|
701
|
+
if (!sourceNode || !targetNode) {
|
|
680
702
|
return null;
|
|
703
|
+
}
|
|
681
704
|
const sourceDef = definitions.get(sourceNode.type);
|
|
682
705
|
const targetDef = definitions.get(targetNode.type);
|
|
683
|
-
if (!sourceDef || !targetDef)
|
|
706
|
+
if (!sourceDef || !targetDef) {
|
|
684
707
|
return null;
|
|
685
|
-
|
|
686
|
-
const
|
|
687
|
-
|
|
708
|
+
}
|
|
709
|
+
const sourcePortIndex = sourceDef.outputs.findIndex((p) => p.id === conn.sourcePortId);
|
|
710
|
+
const targetPortIndex = targetDef.inputs.findIndex((p) => p.id === conn.targetPortId);
|
|
711
|
+
if (sourcePortIndex === -1 || targetPortIndex === -1) {
|
|
688
712
|
return null;
|
|
713
|
+
}
|
|
689
714
|
const sourcePort = sourceDef.outputs[sourcePortIndex];
|
|
690
715
|
const x1 = (sourceNode.position.x + materialEditorTypes.NODE_WIDTH) * state.viewTransform.zoom + state.viewTransform.x;
|
|
691
|
-
const y1 = (sourceNode.position.y +
|
|
716
|
+
const y1 = (sourceNode.position.y +
|
|
717
|
+
materialEditorTypes.NODE_HEADER_HEIGHT +
|
|
718
|
+
sourcePortIndex * materialEditorTypes.PORT_HEIGHT +
|
|
719
|
+
materialEditorTypes.PORT_HEIGHT / 2) *
|
|
720
|
+
state.viewTransform.zoom +
|
|
721
|
+
state.viewTransform.y;
|
|
692
722
|
const x2 = targetNode.position.x * state.viewTransform.zoom + state.viewTransform.x;
|
|
693
|
-
const y2 = (targetNode.position.y +
|
|
723
|
+
const y2 = (targetNode.position.y +
|
|
724
|
+
materialEditorTypes.NODE_HEADER_HEIGHT +
|
|
725
|
+
targetPortIndex * materialEditorTypes.PORT_HEIGHT +
|
|
726
|
+
materialEditorTypes.PORT_HEIGHT / 2) *
|
|
727
|
+
state.viewTransform.zoom +
|
|
728
|
+
state.viewTransform.y;
|
|
694
729
|
const isSelected = state.selectedConnections.includes(conn.id);
|
|
695
730
|
const controlX = (x1 + x2) / 2;
|
|
696
731
|
return (jsxRuntime.jsx("path", { d: `M ${x1} ${y1} C ${controlX} ${y1}, ${controlX} ${y2}, ${x2} ${y2}`, fill: "none", stroke: isSelected ? '#fff' : materialEditorTypes.PORT_TYPE_COLORS[sourcePort.dataType], strokeWidth: isSelected ? 3 : 2, className: MaterialEditor_module.connection, onClick: () => dispatch({ type: 'SELECT_CONNECTIONS', connectionIds: [conn.id] }) }, conn.id));
|
|
@@ -699,11 +734,13 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
699
734
|
// Render pending connection
|
|
700
735
|
const renderPendingConnection = () => {
|
|
701
736
|
var _a;
|
|
702
|
-
if (!pendingConnection)
|
|
737
|
+
if (!pendingConnection) {
|
|
703
738
|
return null;
|
|
739
|
+
}
|
|
704
740
|
const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
|
|
705
|
-
if (!rect)
|
|
741
|
+
if (!rect) {
|
|
706
742
|
return null;
|
|
743
|
+
}
|
|
707
744
|
const x1 = pendingConnection.startPosition.x - rect.left;
|
|
708
745
|
const y1 = pendingConnection.startPosition.y - rect.top;
|
|
709
746
|
const x2 = pendingConnection.currentPosition.x - rect.left;
|
|
@@ -713,8 +750,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
713
750
|
};
|
|
714
751
|
// Render grid
|
|
715
752
|
const renderGrid = () => {
|
|
716
|
-
if (!state.showGrid)
|
|
753
|
+
if (!state.showGrid) {
|
|
717
754
|
return null;
|
|
755
|
+
}
|
|
718
756
|
const gridSize = state.gridSize * state.viewTransform.zoom;
|
|
719
757
|
const offsetX = state.viewTransform.x % gridSize;
|
|
720
758
|
const offsetY = state.viewTransform.y % gridSize;
|
|
@@ -724,12 +762,17 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
|
|
|
724
762
|
dispatch({ type: 'COMPILE' });
|
|
725
763
|
const shader = materialEditorUtils.compileShader(state.graph, definitions);
|
|
726
764
|
dispatch({ type: 'SET_COMPILED_SHADER', shader });
|
|
727
|
-
}, onNew: () => dispatch({ type: 'NEW_GRAPH' }), onExport: handleExport, onImport: handleImport })), jsxRuntime.jsxs("div", { className: MaterialEditor_module.editorBody, children: [showPalette && (jsxRuntime.jsx(NodePalette, { searchQuery: state.searchQuery, expandedCategories: state.expandedCategories, onSearch: query => dispatch({ type: 'SET_SEARCH_QUERY', query }), onToggleCategory: cat => dispatch({ type: 'TOGGLE_CATEGORY', category: cat }), onAddNode: handlePaletteAddNode, onDragStart: handlePaletteDragStart })), jsxRuntime.jsxs("div", { ref: canvasRef, className: MaterialEditor_module.graphCanvas, onWheel: handleWheel, onMouseDown: handleCanvasMouseDown, onMouseMove: handleCanvasMouseMove, onMouseUp: handleCanvasMouseUp, onMouseLeave: handleCanvasMouseUp, onDragOver: handleDragOver, onDrop: handleDrop, children: [jsxRuntime.jsxs("svg", { className: MaterialEditor_module.connectionsSvg, children: [jsxRuntime.jsx("defs", { children: renderGrid() }), state.showGrid && jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" }), renderConnections(), renderPendingConnection()] }), state.graph.nodes.map(node => {
|
|
765
|
+
}, onNew: () => dispatch({ type: 'NEW_GRAPH' }), onExport: handleExport, onImport: handleImport })), jsxRuntime.jsxs("div", { className: MaterialEditor_module.editorBody, children: [showPalette && (jsxRuntime.jsx(NodePalette, { searchQuery: state.searchQuery, expandedCategories: state.expandedCategories, onSearch: (query) => dispatch({ type: 'SET_SEARCH_QUERY', query }), onToggleCategory: (cat) => dispatch({ type: 'TOGGLE_CATEGORY', category: cat }), onAddNode: handlePaletteAddNode, onDragStart: handlePaletteDragStart })), jsxRuntime.jsxs("div", { ref: canvasRef, className: MaterialEditor_module.graphCanvas, onWheel: handleWheel, onMouseDown: handleCanvasMouseDown, onMouseMove: handleCanvasMouseMove, onMouseUp: handleCanvasMouseUp, onMouseLeave: handleCanvasMouseUp, onDragOver: handleDragOver, onDrop: handleDrop, children: [jsxRuntime.jsxs("svg", { className: MaterialEditor_module.connectionsSvg, children: [jsxRuntime.jsx("defs", { children: renderGrid() }), state.showGrid && jsxRuntime.jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" }), renderConnections(), renderPendingConnection()] }), state.graph.nodes.map((node) => {
|
|
728
766
|
const def = definitions.get(node.type);
|
|
729
|
-
if (!def)
|
|
767
|
+
if (!def) {
|
|
730
768
|
return null;
|
|
731
|
-
|
|
732
|
-
|
|
769
|
+
}
|
|
770
|
+
return (jsxRuntime.jsx(GraphNode, { node: node, definition: def, selected: state.selectedNodes.includes(node.id), viewTransform: state.viewTransform, connections: state.graph.connections, onSelect: (nodeId, additive) => dispatch({ type: 'SELECT_NODES', nodeIds: [nodeId], additive }), onMove: (nodeId, delta) => dispatch({
|
|
771
|
+
type: 'MOVE_NODES',
|
|
772
|
+
nodeIds: state.selectedNodes.includes(nodeId) ? state.selectedNodes : [nodeId],
|
|
773
|
+
delta,
|
|
774
|
+
}), onStartConnection: handleStartConnection }, node.id));
|
|
775
|
+
})] }), showPreview && (jsxRuntime.jsx(PreviewPanel, { shader: state.compiledShader, mode: state.previewMode, compiling: state.compiling, onModeChange: (mode) => dispatch({ type: 'SET_PREVIEW_MODE', mode }) }))] })] }));
|
|
733
776
|
}
|
|
734
777
|
|
|
735
778
|
exports.NiceMaterialEditor = NiceMaterialEditor;
|