@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.
Files changed (206) hide show
  1. package/dist/cjs/collaborative/collaborativeScene.js +16 -8
  2. package/dist/cjs/collaborative/collaborativeScene.js.map +1 -1
  3. package/dist/cjs/core/i18n.js +3 -3
  4. package/dist/cjs/dance/DanceBridge.js +65 -30
  5. package/dist/cjs/dance/DanceBridge.js.map +1 -1
  6. package/dist/cjs/dance/DanceScoreEngine.js +37 -23
  7. package/dist/cjs/dance/DanceScoreEngine.js.map +1 -1
  8. package/dist/cjs/dance/PoseDetector.js +92 -49
  9. package/dist/cjs/dance/PoseDetector.js.map +1 -1
  10. package/dist/cjs/material/NiceMaterialEditor.js +134 -91
  11. package/dist/cjs/material/NiceMaterialEditor.js.map +1 -1
  12. package/dist/cjs/material/materialEditorUtils.js +86 -55
  13. package/dist/cjs/material/materialEditorUtils.js.map +1 -1
  14. package/dist/cjs/model/ModelEditor.js +16 -14
  15. package/dist/cjs/model/ModelEditor.js.map +1 -1
  16. package/dist/cjs/model/ModelEditorLeftPanel.js +21 -15
  17. package/dist/cjs/model/ModelEditorLeftPanel.js.map +1 -1
  18. package/dist/cjs/model/ModelEditorMenuBar.js +23 -10
  19. package/dist/cjs/model/ModelEditorMenuBar.js.map +1 -1
  20. package/dist/cjs/model/ModelEditorRightPanel.js +32 -27
  21. package/dist/cjs/model/ModelEditorRightPanel.js.map +1 -1
  22. package/dist/cjs/model/ModelEditorSubComponents.js +20 -20
  23. package/dist/cjs/model/ModelEditorSubComponents.js.map +1 -1
  24. package/dist/cjs/model/ModelEditorTimeline.js +12 -11
  25. package/dist/cjs/model/ModelEditorTimeline.js.map +1 -1
  26. package/dist/cjs/model/ModelEditorToolbar.js +5 -5
  27. package/dist/cjs/model/ModelEditorToolbar.js.map +1 -1
  28. package/dist/cjs/model/ModelEditorViewport.js +12 -8
  29. package/dist/cjs/model/ModelEditorViewport.js.map +1 -1
  30. package/dist/cjs/model/ModelViewer.js +16 -15
  31. package/dist/cjs/model/ModelViewer.js.map +1 -1
  32. package/dist/cjs/model/NiceArmatureEditor.js +53 -30
  33. package/dist/cjs/model/NiceArmatureEditor.js.map +1 -1
  34. package/dist/cjs/model/NiceMorphTargetEditor.js +51 -30
  35. package/dist/cjs/model/NiceMorphTargetEditor.js.map +1 -1
  36. package/dist/cjs/model/NiceOctree.js +62 -37
  37. package/dist/cjs/model/NiceOctree.js.map +1 -1
  38. package/dist/cjs/model/NicePhysicsSimulation.js +74 -36
  39. package/dist/cjs/model/NicePhysicsSimulation.js.map +1 -1
  40. package/dist/cjs/model/NiceProceduralGeometry.js +101 -31
  41. package/dist/cjs/model/NiceProceduralGeometry.js.map +1 -1
  42. package/dist/cjs/model/NiceTerrainEditor.js +88 -38
  43. package/dist/cjs/model/NiceTerrainEditor.js.map +1 -1
  44. package/dist/cjs/model/NiceWeightPainter.js +46 -24
  45. package/dist/cjs/model/NiceWeightPainter.js.map +1 -1
  46. package/dist/cjs/model/NiceXRPreview.js +89 -43
  47. package/dist/cjs/model/NiceXRPreview.js.map +1 -1
  48. package/dist/cjs/model/cadModeUtils.js +2 -2
  49. package/dist/cjs/model/cadModeUtils.js.map +1 -1
  50. package/dist/cjs/model/editorShortcuts.js +69 -35
  51. package/dist/cjs/model/editorShortcuts.js.map +1 -1
  52. package/dist/cjs/model/modelEditorTypes.js +56 -52
  53. package/dist/cjs/model/modelEditorTypes.js.map +1 -1
  54. package/dist/cjs/model/modelEditorUtils.js +356 -131
  55. package/dist/cjs/model/modelEditorUtils.js.map +1 -1
  56. package/dist/cjs/model/simsModeUtils.js +819 -74
  57. package/dist/cjs/model/simsModeUtils.js.map +1 -1
  58. package/dist/cjs/model/useModelEditor.js +501 -394
  59. package/dist/cjs/model/useModelEditor.js.map +1 -1
  60. package/dist/cjs/model/useModelViewer.js +117 -86
  61. package/dist/cjs/model/useModelViewer.js.map +1 -1
  62. package/dist/cjs/particle/NiceParticleEditor.js +126 -69
  63. package/dist/cjs/particle/NiceParticleEditor.js.map +1 -1
  64. package/dist/cjs/particle/particleEditorUtils.js +64 -27
  65. package/dist/cjs/particle/particleEditorUtils.js.map +1 -1
  66. package/dist/cjs/rendering/NiceCascadedShadows.js +35 -23
  67. package/dist/cjs/rendering/NiceCascadedShadows.js.map +1 -1
  68. package/dist/cjs/rendering/NiceRenderExport.js +26 -12
  69. package/dist/cjs/rendering/NiceRenderExport.js.map +1 -1
  70. package/dist/cjs/rendering/NiceSSAO.js +28 -23
  71. package/dist/cjs/rendering/NiceSSAO.js.map +1 -1
  72. package/dist/cjs/rendering/NiceSSR.js +22 -18
  73. package/dist/cjs/rendering/NiceSSR.js.map +1 -1
  74. package/dist/cjs/rendering/NiceWebGPURenderer.js +60 -37
  75. package/dist/cjs/rendering/NiceWebGPURenderer.js.map +1 -1
  76. package/dist/cjs/ui/dist/NiceErrorBoundary-D75yr_WE.js +572 -0
  77. package/dist/cjs/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
  78. package/dist/cjs/ui/dist/NiceForm-CKoJA6NG.js +4979 -0
  79. package/dist/cjs/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
  80. package/dist/cjs/ui/dist/NiceModal-1QX7NhyH.js +98 -0
  81. package/dist/cjs/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
  82. package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5244 -0
  83. package/dist/cjs/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
  84. package/dist/cjs/ui/dist/NicePagination-DbE-uOkl.js +174 -0
  85. package/dist/cjs/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
  86. package/dist/cjs/ui/dist/NicePinCodeInput-B8cI8zu8.js +10459 -0
  87. package/dist/cjs/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
  88. package/dist/cjs/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6313 -0
  89. package/dist/cjs/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
  90. package/dist/cjs/ui/dist/NiceTabs-DzLHzwuA.js +1639 -0
  91. package/dist/cjs/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
  92. package/dist/cjs/ui/dist/NiceWindow-DeC83yfE.js +807 -0
  93. package/dist/cjs/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
  94. package/dist/cjs/ui/dist/charts-BAS21jkC.js +3833 -0
  95. package/dist/cjs/ui/dist/charts-BAS21jkC.js.map +1 -0
  96. package/dist/cjs/ui/dist/core-Da43q-pO.js +11683 -0
  97. package/dist/cjs/ui/dist/core-Da43q-pO.js.map +1 -0
  98. package/dist/cjs/ui/dist/index-pAuGTbuB.js +28876 -0
  99. package/dist/cjs/ui/dist/index-pAuGTbuB.js.map +1 -0
  100. package/dist/cjs/uv/NiceUVEditor.js +115 -86
  101. package/dist/cjs/uv/NiceUVEditor.js.map +1 -1
  102. package/dist/cjs/uv/uvEditorUtils.js +41 -23
  103. package/dist/cjs/uv/uvEditorUtils.js.map +1 -1
  104. package/dist/esm/collaborative/collaborativeScene.js +16 -8
  105. package/dist/esm/collaborative/collaborativeScene.js.map +1 -1
  106. package/dist/esm/dance/DanceBridge.js +55 -20
  107. package/dist/esm/dance/DanceBridge.js.map +1 -1
  108. package/dist/esm/dance/DanceScoreEngine.js +29 -15
  109. package/dist/esm/dance/DanceScoreEngine.js.map +1 -1
  110. package/dist/esm/dance/PoseDetector.js +73 -30
  111. package/dist/esm/dance/PoseDetector.js.map +1 -1
  112. package/dist/esm/material/NiceMaterialEditor.js +115 -72
  113. package/dist/esm/material/NiceMaterialEditor.js.map +1 -1
  114. package/dist/esm/material/materialEditorUtils.js +86 -55
  115. package/dist/esm/material/materialEditorUtils.js.map +1 -1
  116. package/dist/esm/model/ModelEditor.js +16 -14
  117. package/dist/esm/model/ModelEditor.js.map +1 -1
  118. package/dist/esm/model/ModelEditorLeftPanel.js +21 -15
  119. package/dist/esm/model/ModelEditorLeftPanel.js.map +1 -1
  120. package/dist/esm/model/ModelEditorMenuBar.js +23 -10
  121. package/dist/esm/model/ModelEditorMenuBar.js.map +1 -1
  122. package/dist/esm/model/ModelEditorRightPanel.js +32 -27
  123. package/dist/esm/model/ModelEditorRightPanel.js.map +1 -1
  124. package/dist/esm/model/ModelEditorSubComponents.js +17 -17
  125. package/dist/esm/model/ModelEditorSubComponents.js.map +1 -1
  126. package/dist/esm/model/ModelEditorTimeline.js +12 -11
  127. package/dist/esm/model/ModelEditorTimeline.js.map +1 -1
  128. package/dist/esm/model/ModelEditorToolbar.js +5 -5
  129. package/dist/esm/model/ModelEditorToolbar.js.map +1 -1
  130. package/dist/esm/model/ModelEditorViewport.js +12 -8
  131. package/dist/esm/model/ModelEditorViewport.js.map +1 -1
  132. package/dist/esm/model/ModelViewer.js +8 -7
  133. package/dist/esm/model/ModelViewer.js.map +1 -1
  134. package/dist/esm/model/NiceArmatureEditor.js +36 -13
  135. package/dist/esm/model/NiceArmatureEditor.js.map +1 -1
  136. package/dist/esm/model/NiceMorphTargetEditor.js +34 -13
  137. package/dist/esm/model/NiceMorphTargetEditor.js.map +1 -1
  138. package/dist/esm/model/NiceOctree.js +47 -22
  139. package/dist/esm/model/NiceOctree.js.map +1 -1
  140. package/dist/esm/model/NicePhysicsSimulation.js +51 -13
  141. package/dist/esm/model/NicePhysicsSimulation.js.map +1 -1
  142. package/dist/esm/model/NiceProceduralGeometry.js +94 -24
  143. package/dist/esm/model/NiceProceduralGeometry.js.map +1 -1
  144. package/dist/esm/model/NiceTerrainEditor.js +70 -20
  145. package/dist/esm/model/NiceTerrainEditor.js.map +1 -1
  146. package/dist/esm/model/NiceWeightPainter.js +33 -11
  147. package/dist/esm/model/NiceWeightPainter.js.map +1 -1
  148. package/dist/esm/model/NiceXRPreview.js +72 -26
  149. package/dist/esm/model/NiceXRPreview.js.map +1 -1
  150. package/dist/esm/model/cadModeUtils.js +2 -2
  151. package/dist/esm/model/cadModeUtils.js.map +1 -1
  152. package/dist/esm/model/editorShortcuts.js +69 -35
  153. package/dist/esm/model/editorShortcuts.js.map +1 -1
  154. package/dist/esm/model/modelEditorTypes.js +56 -52
  155. package/dist/esm/model/modelEditorTypes.js.map +1 -1
  156. package/dist/esm/model/modelEditorUtils.js +356 -131
  157. package/dist/esm/model/modelEditorUtils.js.map +1 -1
  158. package/dist/esm/model/simsModeUtils.js +819 -74
  159. package/dist/esm/model/simsModeUtils.js.map +1 -1
  160. package/dist/esm/model/useModelEditor.js +384 -277
  161. package/dist/esm/model/useModelEditor.js.map +1 -1
  162. package/dist/esm/model/useModelViewer.js +56 -25
  163. package/dist/esm/model/useModelViewer.js.map +1 -1
  164. package/dist/esm/particle/NiceParticleEditor.js +116 -59
  165. package/dist/esm/particle/NiceParticleEditor.js.map +1 -1
  166. package/dist/esm/particle/particleEditorUtils.js +64 -27
  167. package/dist/esm/particle/particleEditorUtils.js.map +1 -1
  168. package/dist/esm/rendering/NiceCascadedShadows.js +24 -12
  169. package/dist/esm/rendering/NiceCascadedShadows.js.map +1 -1
  170. package/dist/esm/rendering/NiceRenderExport.js +22 -8
  171. package/dist/esm/rendering/NiceRenderExport.js.map +1 -1
  172. package/dist/esm/rendering/NiceSSAO.js +11 -6
  173. package/dist/esm/rendering/NiceSSAO.js.map +1 -1
  174. package/dist/esm/rendering/NiceSSR.js +9 -5
  175. package/dist/esm/rendering/NiceSSR.js.map +1 -1
  176. package/dist/esm/rendering/NiceWebGPURenderer.js +40 -17
  177. package/dist/esm/rendering/NiceWebGPURenderer.js.map +1 -1
  178. package/dist/esm/ui/dist/NiceErrorBoundary-D75yr_WE.js +563 -0
  179. package/dist/esm/ui/dist/NiceErrorBoundary-D75yr_WE.js.map +1 -0
  180. package/dist/esm/ui/dist/NiceForm-CKoJA6NG.js +4960 -0
  181. package/dist/esm/ui/dist/NiceForm-CKoJA6NG.js.map +1 -0
  182. package/dist/esm/ui/dist/NiceModal-1QX7NhyH.js +96 -0
  183. package/dist/esm/ui/dist/NiceModal-1QX7NhyH.js.map +1 -0
  184. package/dist/esm/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js +5201 -0
  185. package/dist/esm/ui/dist/NiceModuleLifecyclePanel-CMrPbSw9.js.map +1 -0
  186. package/dist/esm/ui/dist/NicePagination-DbE-uOkl.js +172 -0
  187. package/dist/esm/ui/dist/NicePagination-DbE-uOkl.js.map +1 -0
  188. package/dist/esm/ui/dist/NicePinCodeInput-B8cI8zu8.js +10408 -0
  189. package/dist/esm/ui/dist/NicePinCodeInput-B8cI8zu8.js.map +1 -0
  190. package/dist/esm/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js +6296 -0
  191. package/dist/esm/ui/dist/NiceSavedQueryPanel-CZ5bYOe_.js.map +1 -0
  192. package/dist/esm/ui/dist/NiceTabs-DzLHzwuA.js +1630 -0
  193. package/dist/esm/ui/dist/NiceTabs-DzLHzwuA.js.map +1 -0
  194. package/dist/esm/ui/dist/NiceWindow-DeC83yfE.js +796 -0
  195. package/dist/esm/ui/dist/NiceWindow-DeC83yfE.js.map +1 -0
  196. package/dist/esm/ui/dist/charts-BAS21jkC.js +3809 -0
  197. package/dist/esm/ui/dist/charts-BAS21jkC.js.map +1 -0
  198. package/dist/esm/ui/dist/core-Da43q-pO.js +11502 -0
  199. package/dist/esm/ui/dist/core-Da43q-pO.js.map +1 -0
  200. package/dist/esm/ui/dist/index-pAuGTbuB.js +28792 -0
  201. package/dist/esm/ui/dist/index-pAuGTbuB.js.map +1 -0
  202. package/dist/esm/uv/NiceUVEditor.js +91 -62
  203. package/dist/esm/uv/NiceUVEditor.js.map +1 -1
  204. package/dist/esm/uv/uvEditorUtils.js +41 -23
  205. package/dist/esm/uv/uvEditorUtils.js.map +1 -1
  206. package/package.json +2 -2
@@ -1,9 +1,9 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { useRef, useState, useMemo, useEffect, useCallback, useReducer } from 'react';
3
+ import styles from './MaterialEditor.module.css.js';
3
4
  import { MAX_ZOOM, MIN_ZOOM, NODE_CATEGORY_COLORS, NODE_CATEGORY_NAMES, NODE_WIDTH, NODE_HEADER_HEIGHT, PORT_HEIGHT, PORT_TYPE_COLORS, DEFAULT_GRID_SIZE } from './materialEditorTypes.js';
4
- import { MATERIAL_NODE_MAP, searchNodes, MATERIAL_NODE_DEFINITIONS } from './materialNodeDefinitions.js';
5
5
  import { compileShader, importGraphFromJSON, exportGraphToJSON, screenToGraph, updateNodeInGraph, calculateZoomToFit, cloneNode, generateNodeId, removeNodesFromGraph, removeConnectionFromGraph, getNodeDefinition, canConnect, createConnection, addConnectionToGraph, moveNodesInGraph, createNode, addNodeToGraph, createEmptyGraph } from './materialEditorUtils.js';
6
- import styles from './MaterialEditor.module.css.js';
6
+ import { MATERIAL_NODE_MAP, searchNodes, MATERIAL_NODE_DEFINITIONS } from './materialNodeDefinitions.js';
7
7
 
8
8
  /* ═══════════════════════════════════════════════════════════════════════════
9
9
  State Reducer
@@ -41,8 +41,9 @@ function materialEditorReducer(state, action) {
41
41
  switch (action.type) {
42
42
  case 'ADD_NODE': {
43
43
  const node = createNode(action.nodeType, action.position);
44
- if (!node)
44
+ if (!node) {
45
45
  return state;
46
+ }
46
47
  const newState = pushToUndoStack(state);
47
48
  return {
48
49
  ...newState,
@@ -67,9 +68,10 @@ function materialEditorReducer(state, action) {
67
68
  }
68
69
  case 'UPDATE_NODE_PROPERTY': {
69
70
  const newState = pushToUndoStack(state);
70
- const node = newState.graph.nodes.find(n => n.id === action.nodeId);
71
- if (!node)
71
+ const node = newState.graph.nodes.find((n) => n.id === action.nodeId);
72
+ if (!node) {
72
73
  return state;
74
+ }
73
75
  return {
74
76
  ...newState,
75
77
  graph: updateNodeInGraph(newState.graph, action.nodeId, {
@@ -79,9 +81,10 @@ function materialEditorReducer(state, action) {
79
81
  }
80
82
  case 'UPDATE_INPUT_VALUE': {
81
83
  const newState = pushToUndoStack(state);
82
- const node = newState.graph.nodes.find(n => n.id === action.nodeId);
83
- if (!node)
84
+ const node = newState.graph.nodes.find((n) => n.id === action.nodeId);
85
+ if (!node) {
84
86
  return state;
87
+ }
85
88
  return {
86
89
  ...newState,
87
90
  graph: updateNodeInGraph(newState.graph, action.nodeId, {
@@ -90,21 +93,25 @@ function materialEditorReducer(state, action) {
90
93
  };
91
94
  }
92
95
  case 'CONNECT': {
93
- const sourceNode = state.graph.nodes.find(n => n.id === action.connection.sourceNodeId);
94
- const targetNode = state.graph.nodes.find(n => n.id === action.connection.targetNodeId);
95
- if (!sourceNode || !targetNode)
96
+ const sourceNode = state.graph.nodes.find((n) => n.id === action.connection.sourceNodeId);
97
+ const targetNode = state.graph.nodes.find((n) => n.id === action.connection.targetNodeId);
98
+ if (!sourceNode || !targetNode) {
96
99
  return state;
100
+ }
97
101
  const sourceDef = getNodeDefinition(sourceNode);
98
102
  const targetDef = getNodeDefinition(targetNode);
99
- if (!sourceDef || !targetDef)
103
+ if (!sourceDef || !targetDef) {
100
104
  return state;
101
- const sourcePort = sourceDef.outputs.find(p => p.id === action.connection.sourcePortId);
102
- const targetPort = targetDef.inputs.find(p => p.id === action.connection.targetPortId);
103
- if (!sourcePort || !targetPort)
105
+ }
106
+ const sourcePort = sourceDef.outputs.find((p) => p.id === action.connection.sourcePortId);
107
+ const targetPort = targetDef.inputs.find((p) => p.id === action.connection.targetPortId);
108
+ if (!sourcePort || !targetPort) {
104
109
  return state;
110
+ }
105
111
  const { valid } = canConnect(sourceNode, sourcePort, targetNode, targetPort, state.graph.connections);
106
- if (!valid)
112
+ if (!valid) {
107
113
  return state;
114
+ }
108
115
  const newState = pushToUndoStack(state);
109
116
  const connection = createConnection(action.connection.sourceNodeId, action.connection.sourcePortId, action.connection.targetNodeId, action.connection.targetPortId);
110
117
  return {
@@ -117,7 +124,7 @@ function materialEditorReducer(state, action) {
117
124
  return {
118
125
  ...newState,
119
126
  graph: removeConnectionFromGraph(newState.graph, action.connectionId),
120
- selectedConnections: state.selectedConnections.filter(id => id !== action.connectionId),
127
+ selectedConnections: state.selectedConnections.filter((id) => id !== action.connectionId),
121
128
  };
122
129
  }
123
130
  case 'SELECT_NODES': {
@@ -141,8 +148,8 @@ function materialEditorReducer(state, action) {
141
148
  case 'SELECT_ALL': {
142
149
  return {
143
150
  ...state,
144
- selectedNodes: state.graph.nodes.map(n => n.id),
145
- selectedConnections: state.graph.connections.map(c => c.id),
151
+ selectedNodes: state.graph.nodes.map((n) => n.id),
152
+ selectedConnections: state.graph.connections.map((c) => c.id),
146
153
  };
147
154
  }
148
155
  case 'DESELECT_ALL': {
@@ -153,19 +160,21 @@ function materialEditorReducer(state, action) {
153
160
  };
154
161
  }
155
162
  case 'COPY': {
156
- const nodesToCopy = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id));
157
- const connectionsToCopy = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) && state.selectedNodes.includes(c.targetNodeId));
163
+ const nodesToCopy = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id));
164
+ const connectionsToCopy = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
165
+ state.selectedNodes.includes(c.targetNodeId));
158
166
  return {
159
167
  ...state,
160
168
  clipboard: { nodes: nodesToCopy, connections: connectionsToCopy },
161
169
  };
162
170
  }
163
171
  case 'PASTE': {
164
- if (!state.clipboard)
172
+ if (!state.clipboard) {
165
173
  return state;
174
+ }
166
175
  const newState = pushToUndoStack(state);
167
176
  const idMap = new Map();
168
- const newNodes = state.clipboard.nodes.map(node => {
177
+ const newNodes = state.clipboard.nodes.map((node) => {
169
178
  const newId = generateNodeId();
170
179
  idMap.set(node.id, newId);
171
180
  return {
@@ -178,7 +187,7 @@ function materialEditorReducer(state, action) {
178
187
  selected: false,
179
188
  };
180
189
  });
181
- const newConnections = state.clipboard.connections.map(conn => ({
190
+ const newConnections = state.clipboard.connections.map((conn) => ({
182
191
  ...conn,
183
192
  id: generateNodeId(),
184
193
  sourceNodeId: idMap.get(conn.sourceNodeId),
@@ -191,31 +200,33 @@ function materialEditorReducer(state, action) {
191
200
  nodes: [...newState.graph.nodes, ...newNodes],
192
201
  connections: [...newState.graph.connections, ...newConnections],
193
202
  },
194
- selectedNodes: newNodes.map(n => n.id),
203
+ selectedNodes: newNodes.map((n) => n.id),
195
204
  };
196
205
  }
197
206
  case 'CUT': {
198
- const nodesToCut = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
199
- const connectionsToCut = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) && state.selectedNodes.includes(c.targetNodeId));
207
+ const nodesToCut = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
208
+ const connectionsToCut = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
209
+ state.selectedNodes.includes(c.targetNodeId));
200
210
  const newState = pushToUndoStack(state);
201
211
  return {
202
212
  ...newState,
203
213
  clipboard: { nodes: nodesToCut, connections: connectionsToCut },
204
- graph: removeNodesFromGraph(newState.graph, nodesToCut.map(n => n.id)),
214
+ graph: removeNodesFromGraph(newState.graph, nodesToCut.map((n) => n.id)),
205
215
  selectedNodes: [],
206
216
  };
207
217
  }
208
218
  case 'DUPLICATE': {
209
- const nodesToDupe = state.graph.nodes.filter(n => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
219
+ const nodesToDupe = state.graph.nodes.filter((n) => state.selectedNodes.includes(n.id) && n.id !== state.graph.outputNodeId);
210
220
  const newState = pushToUndoStack(state);
211
221
  const idMap = new Map();
212
- const newNodes = nodesToDupe.map(node => {
222
+ const newNodes = nodesToDupe.map((node) => {
213
223
  const cloned = cloneNode(node);
214
224
  idMap.set(node.id, cloned.id);
215
225
  return cloned;
216
226
  });
217
- const connectionsToDupe = state.graph.connections.filter(c => state.selectedNodes.includes(c.sourceNodeId) && state.selectedNodes.includes(c.targetNodeId));
218
- const newConnections = connectionsToDupe.map(conn => ({
227
+ const connectionsToDupe = state.graph.connections.filter((c) => state.selectedNodes.includes(c.sourceNodeId) &&
228
+ state.selectedNodes.includes(c.targetNodeId));
229
+ const newConnections = connectionsToDupe.map((conn) => ({
219
230
  ...conn,
220
231
  id: generateNodeId(),
221
232
  sourceNodeId: idMap.get(conn.sourceNodeId),
@@ -228,12 +239,13 @@ function materialEditorReducer(state, action) {
228
239
  nodes: [...newState.graph.nodes, ...newNodes],
229
240
  connections: [...newState.graph.connections, ...newConnections],
230
241
  },
231
- selectedNodes: newNodes.map(n => n.id),
242
+ selectedNodes: newNodes.map((n) => n.id),
232
243
  };
233
244
  }
234
245
  case 'UNDO': {
235
- if (state.undoStack.length === 0)
246
+ if (state.undoStack.length === 0) {
236
247
  return state;
248
+ }
237
249
  const previous = state.undoStack[state.undoStack.length - 1];
238
250
  return {
239
251
  ...state,
@@ -245,8 +257,9 @@ function materialEditorReducer(state, action) {
245
257
  };
246
258
  }
247
259
  case 'REDO': {
248
- if (state.redoStack.length === 0)
260
+ if (state.redoStack.length === 0) {
249
261
  return state;
262
+ }
250
263
  const next = state.redoStack[state.redoStack.length - 1];
251
264
  return {
252
265
  ...state,
@@ -279,7 +292,7 @@ function materialEditorReducer(state, action) {
279
292
  return {
280
293
  ...state,
281
294
  expandedCategories: state.expandedCategories.includes(action.category)
282
- ? state.expandedCategories.filter(c => c !== action.category)
295
+ ? state.expandedCategories.filter((c) => c !== action.category)
283
296
  : [...state.expandedCategories, action.category],
284
297
  };
285
298
  case 'COLLAPSE_NODE':
@@ -351,9 +364,7 @@ function useMaterialEditor(initialGraph) {
351
364
  return { state, dispatch };
352
365
  }
353
366
  function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCategory, onAddNode, onDragStart, }) {
354
- const filteredNodes = searchQuery
355
- ? searchNodes(searchQuery)
356
- : MATERIAL_NODE_DEFINITIONS;
367
+ const filteredNodes = searchQuery ? searchNodes(searchQuery) : MATERIAL_NODE_DEFINITIONS;
357
368
  const categories = useMemo(() => {
358
369
  const cats = new Map();
359
370
  for (const node of filteredNodes) {
@@ -364,15 +375,18 @@ function NodePalette({ searchQuery, expandedCategories, onSearch, onToggleCatego
364
375
  }
365
376
  return cats;
366
377
  }, [filteredNodes]);
367
- return (jsxs("div", { className: styles.palette, children: [jsx("div", { className: styles.paletteSearch, children: jsx("input", { type: "text", placeholder: "Search nodes...", value: searchQuery, onChange: e => onSearch(e.target.value), className: styles.searchInput }) }), jsx("div", { className: styles.paletteCategories, children: Array.from(categories.entries()).map(([category, nodes]) => (jsxs("div", { className: styles.paletteCategory, children: [jsxs("button", { className: styles.categoryHeader, onClick: () => onToggleCategory(category), style: { borderLeftColor: NODE_CATEGORY_COLORS[category] }, children: [jsx("span", { className: styles.categoryIcon, children: expandedCategories.includes(category) ? '▼' : '►' }), jsx("span", { children: NODE_CATEGORY_NAMES[category] }), jsx("span", { className: styles.categoryCount, children: nodes.length })] }), expandedCategories.includes(category) && (jsx("div", { className: styles.categoryNodes, children: nodes.map(nodeDef => (jsxs("div", { className: styles.paletteNode, draggable: true, onDragStart: e => onDragStart(nodeDef.type, e), onDoubleClick: () => onAddNode(nodeDef.type), title: nodeDef.description, children: [jsx("span", { className: styles.nodeColor, style: { backgroundColor: nodeDef.color || NODE_CATEGORY_COLORS[nodeDef.category] } }), jsx("span", { className: styles.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
378
+ return (jsxs("div", { className: styles.palette, children: [jsx("div", { className: styles.paletteSearch, children: jsx("input", { type: "text", placeholder: "Search nodes...", value: searchQuery, onChange: (e) => onSearch(e.target.value), className: styles.searchInput }) }), jsx("div", { className: styles.paletteCategories, children: Array.from(categories.entries()).map(([category, nodes]) => (jsxs("div", { className: styles.paletteCategory, children: [jsxs("button", { className: styles.categoryHeader, onClick: () => onToggleCategory(category), style: { borderLeftColor: NODE_CATEGORY_COLORS[category] }, children: [jsx("span", { className: styles.categoryIcon, children: expandedCategories.includes(category) ? '▼' : '►' }), jsx("span", { children: NODE_CATEGORY_NAMES[category] }), jsx("span", { className: styles.categoryCount, children: nodes.length })] }), expandedCategories.includes(category) && (jsx("div", { className: styles.categoryNodes, children: nodes.map((nodeDef) => (jsxs("div", { className: styles.paletteNode, draggable: true, onDragStart: (e) => onDragStart(nodeDef.type, e), onDoubleClick: () => onAddNode(nodeDef.type), title: nodeDef.description, children: [jsx("span", { className: styles.nodeColor, style: {
379
+ backgroundColor: nodeDef.color || NODE_CATEGORY_COLORS[nodeDef.category],
380
+ } }), jsx("span", { className: styles.nodeName, children: nodeDef.name })] }, nodeDef.type))) }))] }, category))) })] }));
368
381
  }
369
382
  function GraphNode({ node, definition, selected, viewTransform, connections, onSelect, onMove, onStartConnection, }) {
370
383
  const nodeRef = useRef(null);
371
384
  const [isDragging, setIsDragging] = useState(false);
372
385
  const dragStart = useRef(null);
373
386
  const handleMouseDown = (e) => {
374
- if (e.button !== 0)
387
+ if (e.button !== 0) {
375
388
  return;
389
+ }
376
390
  e.stopPropagation();
377
391
  if (!selected) {
378
392
  onSelect(node.id, e.shiftKey || e.ctrlKey);
@@ -383,8 +397,9 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
383
397
  }
384
398
  };
385
399
  useEffect(() => {
386
- if (!isDragging)
400
+ if (!isDragging) {
387
401
  return;
402
+ }
388
403
  const handleMouseMove = (e) => {
389
404
  if (dragStart.current) {
390
405
  const delta = {
@@ -428,12 +443,12 @@ function GraphNode({ node, definition, selected, viewTransform, connections, onS
428
443
  transform: `scale(${viewTransform.zoom})`,
429
444
  transformOrigin: 'top left',
430
445
  }, onMouseDown: handleMouseDown, children: [jsxs("div", { className: styles.nodeHeader, style: { backgroundColor: nodeColor }, children: [jsx("span", { className: styles.nodeTitle, children: definition.name }), node.locked && jsx("span", { className: styles.lockIcon, children: "\uD83D\uDD12" })] }), !node.collapsed && (jsxs("div", { className: styles.nodePorts, children: [jsx("div", { className: styles.inputPorts, children: definition.inputs.map((port, index) => {
431
- const isConnected = connections.some(c => c.targetNodeId === node.id && c.targetPortId === port.id);
432
- return (jsxs("div", { className: styles.port, style: { top: index * PORT_HEIGHT + NODE_HEADER_HEIGHT }, children: [jsx("div", { className: `${styles.portHandle} ${styles.inputHandle} ${isConnected ? styles.connected : ''}`, style: { backgroundColor: PORT_TYPE_COLORS[port.dataType] }, onMouseDown: e => handlePortMouseDown(e, port.id, 'input') }), jsx("span", { className: styles.portLabel, children: port.name })] }, port.id));
446
+ const isConnected = connections.some((c) => c.targetNodeId === node.id && c.targetPortId === port.id);
447
+ return (jsxs("div", { className: styles.port, style: { top: index * PORT_HEIGHT + NODE_HEADER_HEIGHT }, children: [jsx("div", { className: `${styles.portHandle} ${styles.inputHandle} ${isConnected ? styles.connected : ''}`, style: { backgroundColor: PORT_TYPE_COLORS[port.dataType] }, onMouseDown: (e) => handlePortMouseDown(e, port.id, 'input') }), jsx("span", { className: styles.portLabel, children: port.name })] }, port.id));
433
448
  }) }), jsx("div", { className: styles.outputPorts, children: definition.outputs.map((port, index) => {
434
- const isConnected = connections.some(c => c.sourceNodeId === node.id && c.sourcePortId === port.id);
435
- return (jsxs("div", { className: styles.port, style: { top: index * PORT_HEIGHT + NODE_HEADER_HEIGHT }, children: [jsx("span", { className: styles.portLabel, children: port.name }), jsx("div", { className: `${styles.portHandle} ${styles.outputHandle} ${isConnected ? styles.connected : ''}`, style: { backgroundColor: PORT_TYPE_COLORS[port.dataType] }, onMouseDown: e => handlePortMouseDown(e, port.id, 'output') })] }, port.id));
436
- }) })] })), node.comment && (jsx("div", { className: styles.nodeComment, children: node.comment }))] }));
449
+ const isConnected = connections.some((c) => c.sourceNodeId === node.id && c.sourcePortId === port.id);
450
+ return (jsxs("div", { className: styles.port, style: { top: index * PORT_HEIGHT + NODE_HEADER_HEIGHT }, children: [jsx("span", { className: styles.portLabel, children: port.name }), jsx("div", { className: `${styles.portHandle} ${styles.outputHandle} ${isConnected ? styles.connected : ''}`, style: { backgroundColor: PORT_TYPE_COLORS[port.dataType] }, onMouseDown: (e) => handlePortMouseDown(e, port.id, 'output') })] }, port.id));
451
+ }) })] })), node.comment && jsx("div", { className: styles.nodeComment, children: node.comment })] }));
437
452
  }
438
453
  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, }) {
439
454
  return (jsxs("div", { className: styles.toolbar, children: [jsxs("div", { className: styles.toolbarGroup, children: [jsx("button", { onClick: onNew, title: "New Material (Ctrl+N)", children: "\uD83D\uDCC4" }), jsx("button", { onClick: onImport, title: "Import (Ctrl+O)", children: "\uD83D\uDCC2" }), jsx("button", { onClick: onExport, title: "Export (Ctrl+S)", children: "\uD83D\uDCBE" })] }), jsx("div", { className: styles.toolbarSeparator }), jsxs("div", { className: styles.toolbarGroup, children: [jsx("button", { onClick: onUndo, disabled: !canUndo, title: "Undo (Ctrl+Z)", children: "\u21A9\uFE0F" }), jsx("button", { onClick: onRedo, disabled: !canRedo, title: "Redo (Ctrl+Y)", children: "\u21AA\uFE0F" })] }), jsx("div", { className: styles.toolbarSeparator }), jsxs("div", { className: styles.toolbarGroup, children: [jsx("button", { onClick: onCut, disabled: !hasSelection, title: "Cut (Ctrl+X)", children: "\u2702\uFE0F" }), jsx("button", { onClick: onCopy, disabled: !hasSelection, title: "Copy (Ctrl+C)", children: "\uD83D\uDCCB" }), jsx("button", { onClick: onPaste, disabled: !canPaste, title: "Paste (Ctrl+V)", children: "\uD83D\uDCE5" }), jsx("button", { onClick: onDuplicate, disabled: !hasSelection, title: "Duplicate (Ctrl+D)", children: "\uD83D\uDD04" }), jsx("button", { onClick: onDelete, disabled: !hasSelection, title: "Delete (Del)", children: "\uD83D\uDDD1\uFE0F" })] }), jsx("div", { className: styles.toolbarSeparator }), jsxs("div", { className: styles.toolbarGroup, children: [jsx("button", { onClick: onSelectAll, title: "Select All (Ctrl+A)", children: "\u2B1C" }), jsx("button", { onClick: onZoomToFit, title: "Zoom to Fit (F)", children: "\uD83D\uDD0D" }), jsx("button", { onClick: onToggleGrid, className: showGrid ? styles.active : '', title: "Toggle Grid (G)", children: "#" }), jsx("button", { onClick: onToggleSnap, className: snapToGrid ? styles.active : '', title: "Toggle Snap (S)", children: "\uD83E\uDDF2" })] }), jsx("div", { className: styles.toolbarSeparator }), jsxs("div", { className: styles.toolbarGroup, children: [jsx("button", { onClick: onToggleAutoCompile, className: autoCompile ? styles.active : '', title: "Auto Compile", children: "\u26A1" }), jsx("button", { onClick: onCompile, disabled: compiling, title: "Compile (F5)", children: compiling ? '⏳' : '▶️' })] })] }));
@@ -444,11 +459,13 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
444
459
  // Simple preview rendering (in real implementation would use Three.js)
445
460
  useEffect(() => {
446
461
  const canvas = canvasRef.current;
447
- if (!canvas)
462
+ if (!canvas) {
448
463
  return;
464
+ }
449
465
  const ctx = canvas.getContext('2d');
450
- if (!ctx)
466
+ if (!ctx) {
451
467
  return;
468
+ }
452
469
  // Simple gradient preview
453
470
  const gradient = ctx.createRadialGradient(100, 100, 0, 100, 100, 100);
454
471
  if ((shader === null || shader === void 0 ? void 0 : shader.errors.length) === 0) {
@@ -466,7 +483,7 @@ function PreviewPanel({ shader, mode, compiling, onModeChange }) {
466
483
  ctx.arc(100, 100, 80, 0, Math.PI * 2);
467
484
  ctx.fill();
468
485
  }, [shader, mode]);
469
- return (jsxs("div", { className: styles.previewPanel, children: [jsxs("div", { className: styles.previewHeader, children: [jsx("span", { children: "Preview" }), jsx("select", { value: mode, onChange: e => onModeChange(e.target.value), className: styles.previewModeSelect, children: previewModes.map(m => (jsx("option", { value: m, children: m.charAt(0).toUpperCase() + m.slice(1) }, m))) })] }), jsxs("div", { className: styles.previewCanvas, children: [compiling && jsx("div", { className: styles.previewCompiling, children: "Compiling..." }), jsx("canvas", { ref: canvasRef, width: 200, height: 200 })] }), (shader === null || shader === void 0 ? void 0 : shader.errors.length) ? (jsx("div", { className: styles.previewErrors, children: shader.errors.slice(0, 3).map((err, i) => (jsx("div", { className: styles.previewError, children: err.message }, i))) })) : null] }));
486
+ return (jsxs("div", { className: styles.previewPanel, children: [jsxs("div", { className: styles.previewHeader, children: [jsx("span", { children: "Preview" }), jsx("select", { value: mode, onChange: (e) => onModeChange(e.target.value), className: styles.previewModeSelect, children: previewModes.map((m) => (jsx("option", { value: m, children: m.charAt(0).toUpperCase() + m.slice(1) }, m))) })] }), jsxs("div", { className: styles.previewCanvas, children: [compiling && jsx("div", { className: styles.previewCompiling, children: "Compiling..." }), jsx("canvas", { ref: canvasRef, width: 200, height: 200 })] }), (shader === null || shader === void 0 ? void 0 : shader.errors.length) ? (jsx("div", { className: styles.previewErrors, children: shader.errors.slice(0, 3).map((err, i) => (jsx("div", { className: styles.previewError, children: err.message }, i))) })) : null] }));
470
487
  }
471
488
  /* ═══════════════════════════════════════════════════════════════════════════
472
489
  Main Component
@@ -478,7 +495,7 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
478
495
  // Merge custom node definitions
479
496
  const definitions = useMemo(() => {
480
497
  const map = new Map(MATERIAL_NODE_MAP);
481
- customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach(def => map.set(def.type, def));
498
+ customNodes === null || customNodes === void 0 ? void 0 : customNodes.forEach((def) => map.set(def.type, def));
482
499
  return map;
483
500
  }, [customNodes]);
484
501
  // Notify parent of changes
@@ -493,8 +510,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
493
510
  // Keyboard shortcuts
494
511
  useEffect(() => {
495
512
  const handleKeyDown = (e) => {
496
- if (readOnly)
513
+ if (readOnly) {
497
514
  return;
515
+ }
498
516
  const isCtrl = e.ctrlKey || e.metaKey;
499
517
  if (isCtrl && e.key === 'z') {
500
518
  e.preventDefault();
@@ -557,8 +575,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
557
575
  const delta = e.deltaY > 0 ? 0.9 : 1.1;
558
576
  const newZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, state.viewTransform.zoom * delta));
559
577
  const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
560
- if (!rect)
578
+ if (!rect) {
561
579
  return;
580
+ }
562
581
  const mouseX = e.clientX - rect.left;
563
582
  const mouseY = e.clientY - rect.top;
564
583
  const newX = mouseX - (mouseX - state.viewTransform.x) * (newZoom / state.viewTransform.zoom);
@@ -615,11 +634,13 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
615
634
  var _a;
616
635
  e.preventDefault();
617
636
  const nodeType = e.dataTransfer.getData('text/plain');
618
- if (!nodeType)
637
+ if (!nodeType) {
619
638
  return;
639
+ }
620
640
  const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
621
- if (!rect)
641
+ if (!rect) {
622
642
  return;
643
+ }
623
644
  const position = screenToGraph({ x: e.clientX - rect.left, y: e.clientY - rect.top }, state.viewTransform);
624
645
  dispatch({ type: 'ADD_NODE', nodeType, position });
625
646
  };
@@ -659,8 +680,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
659
680
  input.onchange = async (e) => {
660
681
  var _a;
661
682
  const file = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
662
- if (!file)
683
+ if (!file) {
663
684
  return;
685
+ }
664
686
  const text = await file.text();
665
687
  const graph = importGraphFromJSON(text);
666
688
  if (graph) {
@@ -671,24 +693,37 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
671
693
  };
672
694
  // Render connections
673
695
  const renderConnections = () => {
674
- return state.graph.connections.map(conn => {
675
- const sourceNode = state.graph.nodes.find(n => n.id === conn.sourceNodeId);
676
- const targetNode = state.graph.nodes.find(n => n.id === conn.targetNodeId);
677
- if (!sourceNode || !targetNode)
696
+ return state.graph.connections.map((conn) => {
697
+ const sourceNode = state.graph.nodes.find((n) => n.id === conn.sourceNodeId);
698
+ const targetNode = state.graph.nodes.find((n) => n.id === conn.targetNodeId);
699
+ if (!sourceNode || !targetNode) {
678
700
  return null;
701
+ }
679
702
  const sourceDef = definitions.get(sourceNode.type);
680
703
  const targetDef = definitions.get(targetNode.type);
681
- if (!sourceDef || !targetDef)
704
+ if (!sourceDef || !targetDef) {
682
705
  return null;
683
- const sourcePortIndex = sourceDef.outputs.findIndex(p => p.id === conn.sourcePortId);
684
- const targetPortIndex = targetDef.inputs.findIndex(p => p.id === conn.targetPortId);
685
- if (sourcePortIndex === -1 || targetPortIndex === -1)
706
+ }
707
+ const sourcePortIndex = sourceDef.outputs.findIndex((p) => p.id === conn.sourcePortId);
708
+ const targetPortIndex = targetDef.inputs.findIndex((p) => p.id === conn.targetPortId);
709
+ if (sourcePortIndex === -1 || targetPortIndex === -1) {
686
710
  return null;
711
+ }
687
712
  const sourcePort = sourceDef.outputs[sourcePortIndex];
688
713
  const x1 = (sourceNode.position.x + NODE_WIDTH) * state.viewTransform.zoom + state.viewTransform.x;
689
- const y1 = (sourceNode.position.y + NODE_HEADER_HEIGHT + sourcePortIndex * PORT_HEIGHT + PORT_HEIGHT / 2) * state.viewTransform.zoom + state.viewTransform.y;
714
+ const y1 = (sourceNode.position.y +
715
+ NODE_HEADER_HEIGHT +
716
+ sourcePortIndex * PORT_HEIGHT +
717
+ PORT_HEIGHT / 2) *
718
+ state.viewTransform.zoom +
719
+ state.viewTransform.y;
690
720
  const x2 = targetNode.position.x * state.viewTransform.zoom + state.viewTransform.x;
691
- const y2 = (targetNode.position.y + NODE_HEADER_HEIGHT + targetPortIndex * PORT_HEIGHT + PORT_HEIGHT / 2) * state.viewTransform.zoom + state.viewTransform.y;
721
+ const y2 = (targetNode.position.y +
722
+ NODE_HEADER_HEIGHT +
723
+ targetPortIndex * PORT_HEIGHT +
724
+ PORT_HEIGHT / 2) *
725
+ state.viewTransform.zoom +
726
+ state.viewTransform.y;
692
727
  const isSelected = state.selectedConnections.includes(conn.id);
693
728
  const controlX = (x1 + x2) / 2;
694
729
  return (jsx("path", { d: `M ${x1} ${y1} C ${controlX} ${y1}, ${controlX} ${y2}, ${x2} ${y2}`, fill: "none", stroke: isSelected ? '#fff' : PORT_TYPE_COLORS[sourcePort.dataType], strokeWidth: isSelected ? 3 : 2, className: styles.connection, onClick: () => dispatch({ type: 'SELECT_CONNECTIONS', connectionIds: [conn.id] }) }, conn.id));
@@ -697,11 +732,13 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
697
732
  // Render pending connection
698
733
  const renderPendingConnection = () => {
699
734
  var _a;
700
- if (!pendingConnection)
735
+ if (!pendingConnection) {
701
736
  return null;
737
+ }
702
738
  const rect = (_a = canvasRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
703
- if (!rect)
739
+ if (!rect) {
704
740
  return null;
741
+ }
705
742
  const x1 = pendingConnection.startPosition.x - rect.left;
706
743
  const y1 = pendingConnection.startPosition.y - rect.top;
707
744
  const x2 = pendingConnection.currentPosition.x - rect.left;
@@ -711,8 +748,9 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
711
748
  };
712
749
  // Render grid
713
750
  const renderGrid = () => {
714
- if (!state.showGrid)
751
+ if (!state.showGrid) {
715
752
  return null;
753
+ }
716
754
  const gridSize = state.gridSize * state.viewTransform.zoom;
717
755
  const offsetX = state.viewTransform.x % gridSize;
718
756
  const offsetY = state.viewTransform.y % gridSize;
@@ -722,12 +760,17 @@ function NiceMaterialEditor({ graph: initialGraph, onGraphChange, onCompile, cus
722
760
  dispatch({ type: 'COMPILE' });
723
761
  const shader = compileShader(state.graph, definitions);
724
762
  dispatch({ type: 'SET_COMPILED_SHADER', shader });
725
- }, onNew: () => dispatch({ type: 'NEW_GRAPH' }), onExport: handleExport, onImport: handleImport })), jsxs("div", { className: styles.editorBody, children: [showPalette && (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 })), jsxs("div", { ref: canvasRef, className: styles.graphCanvas, onWheel: handleWheel, onMouseDown: handleCanvasMouseDown, onMouseMove: handleCanvasMouseMove, onMouseUp: handleCanvasMouseUp, onMouseLeave: handleCanvasMouseUp, onDragOver: handleDragOver, onDrop: handleDrop, children: [jsxs("svg", { className: styles.connectionsSvg, children: [jsx("defs", { children: renderGrid() }), state.showGrid && jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" }), renderConnections(), renderPendingConnection()] }), state.graph.nodes.map(node => {
763
+ }, onNew: () => dispatch({ type: 'NEW_GRAPH' }), onExport: handleExport, onImport: handleImport })), jsxs("div", { className: styles.editorBody, children: [showPalette && (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 })), jsxs("div", { ref: canvasRef, className: styles.graphCanvas, onWheel: handleWheel, onMouseDown: handleCanvasMouseDown, onMouseMove: handleCanvasMouseMove, onMouseUp: handleCanvasMouseUp, onMouseLeave: handleCanvasMouseUp, onDragOver: handleDragOver, onDrop: handleDrop, children: [jsxs("svg", { className: styles.connectionsSvg, children: [jsx("defs", { children: renderGrid() }), state.showGrid && jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" }), renderConnections(), renderPendingConnection()] }), state.graph.nodes.map((node) => {
726
764
  const def = definitions.get(node.type);
727
- if (!def)
765
+ if (!def) {
728
766
  return null;
729
- return (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({ type: 'MOVE_NODES', nodeIds: state.selectedNodes.includes(nodeId) ? state.selectedNodes : [nodeId], delta }), onStartConnection: handleStartConnection }, node.id));
730
- })] }), showPreview && (jsx(PreviewPanel, { shader: state.compiledShader, mode: state.previewMode, compiling: state.compiling, onModeChange: mode => dispatch({ type: 'SET_PREVIEW_MODE', mode }) }))] })] }));
767
+ }
768
+ return (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({
769
+ type: 'MOVE_NODES',
770
+ nodeIds: state.selectedNodes.includes(nodeId) ? state.selectedNodes : [nodeId],
771
+ delta,
772
+ }), onStartConnection: handleStartConnection }, node.id));
773
+ })] }), showPreview && (jsx(PreviewPanel, { shader: state.compiledShader, mode: state.previewMode, compiling: state.compiling, onModeChange: (mode) => dispatch({ type: 'SET_PREVIEW_MODE', mode }) }))] })] }));
731
774
  }
732
775
 
733
776
  export { NiceMaterialEditor, useMaterialEditor };