@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
@@ -46,16 +46,18 @@ class UndoRedoStack {
46
46
  }
47
47
  undo() {
48
48
  const action = this.undoStack.pop();
49
- if (!action)
49
+ if (!action) {
50
50
  return null;
51
+ }
51
52
  action.undo();
52
53
  this.redoStack.push(action);
53
54
  return action.label;
54
55
  }
55
56
  redo() {
56
57
  const action = this.redoStack.pop();
57
- if (!action)
58
+ if (!action) {
58
59
  return null;
60
+ }
59
61
  action.redo();
60
62
  this.undoStack.push(action);
61
63
  return action.label;
@@ -88,11 +90,13 @@ const DEFAULT_LOD_LEVELS = [
88
90
  * Returns a new geometry with reduced vertex count.
89
91
  */
90
92
  function decimateGeometry(geometry, ratio) {
91
- if (ratio >= 1.0)
93
+ if (ratio >= 1.0) {
92
94
  return geometry.clone();
93
- const posAttr = geometry.getAttribute("position");
94
- if (!posAttr)
95
+ }
96
+ const posAttr = geometry.getAttribute('position');
97
+ if (!posAttr) {
95
98
  return geometry.clone();
99
+ }
96
100
  const positions = Array.from(posAttr.array);
97
101
  const vertexCount = posAttr.count;
98
102
  const targetCount = Math.max(3, Math.floor(vertexCount * ratio));
@@ -151,7 +155,7 @@ function decimateGeometry(geometry, ratio) {
151
155
  }
152
156
  }
153
157
  const result = new THREE__namespace.BufferGeometry();
154
- result.setAttribute("position", new THREE__namespace.BufferAttribute(newPositions, 3));
158
+ result.setAttribute('position', new THREE__namespace.BufferAttribute(newPositions, 3));
155
159
  result.setIndex(newIndices);
156
160
  result.computeVertexNormals();
157
161
  return result;
@@ -161,7 +165,7 @@ function decimateGeometry(geometry, ratio) {
161
165
  */
162
166
  function generateLOD(mesh, levels = DEFAULT_LOD_LEVELS) {
163
167
  const lod = new THREE__namespace.LOD();
164
- lod.name = mesh.name + "_LOD";
168
+ lod.name = mesh.name + '_LOD';
165
169
  lod.position.copy(mesh.position);
166
170
  lod.rotation.copy(mesh.rotation);
167
171
  lod.scale.copy(mesh.scale);
@@ -179,44 +183,233 @@ function generateLOD(mesh, levels = DEFAULT_LOD_LEVELS) {
179
183
  }
180
184
  const PBR_PRESETS = [
181
185
  // Metals
182
- { name: "Gold", category: "Metal", params: { color: 0xffd700, metalness: 1.0, roughness: 0.15 } },
183
- { name: "Silver", category: "Metal", params: { color: 0xc0c0c0, metalness: 1.0, roughness: 0.1 } },
184
- { name: "Copper", category: "Metal", params: { color: 0xb87333, metalness: 1.0, roughness: 0.25 } },
185
- { name: "Iron", category: "Metal", params: { color: 0x808080, metalness: 0.95, roughness: 0.6 } },
186
- { name: "Brushed Steel", category: "Metal", params: { color: 0xa0a0a0, metalness: 0.95, roughness: 0.4 } },
187
- { name: "Chrome", category: "Metal", params: { color: 0xdddddd, metalness: 1.0, roughness: 0.02 } },
188
- { name: "Bronze", category: "Metal", params: { color: 0xcd7f32, metalness: 0.9, roughness: 0.35 } },
189
- { name: "Aluminum", category: "Metal", params: { color: 0xd6d6d6, metalness: 0.85, roughness: 0.2 } },
186
+ { name: 'Gold', category: 'Metal', params: { color: 0xffd700, metalness: 1.0, roughness: 0.15 } },
187
+ {
188
+ name: 'Silver',
189
+ category: 'Metal',
190
+ params: { color: 0xc0c0c0, metalness: 1.0, roughness: 0.1 },
191
+ },
192
+ {
193
+ name: 'Copper',
194
+ category: 'Metal',
195
+ params: { color: 0xb87333, metalness: 1.0, roughness: 0.25 },
196
+ },
197
+ { name: 'Iron', category: 'Metal', params: { color: 0x808080, metalness: 0.95, roughness: 0.6 } },
198
+ {
199
+ name: 'Brushed Steel',
200
+ category: 'Metal',
201
+ params: { color: 0xa0a0a0, metalness: 0.95, roughness: 0.4 },
202
+ },
203
+ {
204
+ name: 'Chrome',
205
+ category: 'Metal',
206
+ params: { color: 0xdddddd, metalness: 1.0, roughness: 0.02 },
207
+ },
208
+ {
209
+ name: 'Bronze',
210
+ category: 'Metal',
211
+ params: { color: 0xcd7f32, metalness: 0.9, roughness: 0.35 },
212
+ },
213
+ {
214
+ name: 'Aluminum',
215
+ category: 'Metal',
216
+ params: { color: 0xd6d6d6, metalness: 0.85, roughness: 0.2 },
217
+ },
190
218
  // Non-metals
191
- { name: "Plastic (White)", category: "Plastic", params: { color: 0xf0f0f0, metalness: 0.0, roughness: 0.3 } },
192
- { name: "Plastic (Red)", category: "Plastic", params: { color: 0xcc2222, metalness: 0.0, roughness: 0.35 } },
193
- { name: "Rubber", category: "Plastic", params: { color: 0x333333, metalness: 0.0, roughness: 0.9 } },
219
+ {
220
+ name: 'Plastic (White)',
221
+ category: 'Plastic',
222
+ params: { color: 0xf0f0f0, metalness: 0.0, roughness: 0.3 },
223
+ },
224
+ {
225
+ name: 'Plastic (Red)',
226
+ category: 'Plastic',
227
+ params: { color: 0xcc2222, metalness: 0.0, roughness: 0.35 },
228
+ },
229
+ {
230
+ name: 'Rubber',
231
+ category: 'Plastic',
232
+ params: { color: 0x333333, metalness: 0.0, roughness: 0.9 },
233
+ },
194
234
  // Glass
195
- { name: "Clear Glass", category: "Glass", params: { color: 0xffffff, metalness: 0.0, roughness: 0.0, opacity: 0.15, transparent: true, ior: 1.5, transmission: 0.95 } },
196
- { name: "Frosted Glass", category: "Glass", params: { color: 0xeeeeff, metalness: 0.0, roughness: 0.5, opacity: 0.3, transparent: true, ior: 1.5, transmission: 0.7 } },
197
- { name: "Tinted Glass", category: "Glass", params: { color: 0x224488, metalness: 0.0, roughness: 0.05, opacity: 0.3, transparent: true, ior: 1.5, transmission: 0.8 } },
235
+ {
236
+ name: 'Clear Glass',
237
+ category: 'Glass',
238
+ params: {
239
+ color: 0xffffff,
240
+ metalness: 0.0,
241
+ roughness: 0.0,
242
+ opacity: 0.15,
243
+ transparent: true,
244
+ ior: 1.5,
245
+ transmission: 0.95,
246
+ },
247
+ },
248
+ {
249
+ name: 'Frosted Glass',
250
+ category: 'Glass',
251
+ params: {
252
+ color: 0xeeeeff,
253
+ metalness: 0.0,
254
+ roughness: 0.5,
255
+ opacity: 0.3,
256
+ transparent: true,
257
+ ior: 1.5,
258
+ transmission: 0.7,
259
+ },
260
+ },
261
+ {
262
+ name: 'Tinted Glass',
263
+ category: 'Glass',
264
+ params: {
265
+ color: 0x224488,
266
+ metalness: 0.0,
267
+ roughness: 0.05,
268
+ opacity: 0.3,
269
+ transparent: true,
270
+ ior: 1.5,
271
+ transmission: 0.8,
272
+ },
273
+ },
198
274
  // Natural
199
- { name: "Wood (Light)", category: "Natural", params: { color: 0xc19a6b, metalness: 0.0, roughness: 0.7 } },
200
- { name: "Wood (Dark)", category: "Natural", params: { color: 0x5c3317, metalness: 0.0, roughness: 0.65 } },
201
- { name: "Stone", category: "Natural", params: { color: 0x888888, metalness: 0.0, roughness: 0.85 } },
202
- { name: "Marble", category: "Natural", params: { color: 0xf0ece0, metalness: 0.0, roughness: 0.15 } },
203
- { name: "Clay", category: "Natural", params: { color: 0xb5651d, metalness: 0.0, roughness: 0.8 } },
204
- { name: "Concrete", category: "Natural", params: { color: 0x999999, metalness: 0.0, roughness: 0.95 } },
275
+ {
276
+ name: 'Wood (Light)',
277
+ category: 'Natural',
278
+ params: { color: 0xc19a6b, metalness: 0.0, roughness: 0.7 },
279
+ },
280
+ {
281
+ name: 'Wood (Dark)',
282
+ category: 'Natural',
283
+ params: { color: 0x5c3317, metalness: 0.0, roughness: 0.65 },
284
+ },
285
+ {
286
+ name: 'Stone',
287
+ category: 'Natural',
288
+ params: { color: 0x888888, metalness: 0.0, roughness: 0.85 },
289
+ },
290
+ {
291
+ name: 'Marble',
292
+ category: 'Natural',
293
+ params: { color: 0xf0ece0, metalness: 0.0, roughness: 0.15 },
294
+ },
295
+ {
296
+ name: 'Clay',
297
+ category: 'Natural',
298
+ params: { color: 0xb5651d, metalness: 0.0, roughness: 0.8 },
299
+ },
300
+ {
301
+ name: 'Concrete',
302
+ category: 'Natural',
303
+ params: { color: 0x999999, metalness: 0.0, roughness: 0.95 },
304
+ },
205
305
  // Fabric
206
- { name: "Cotton (White)", category: "Fabric", params: { color: 0xf5f5dc, metalness: 0.0, roughness: 0.9, sheen: 0.5, sheenRoughness: 0.8, sheenColor: 0xffffff } },
207
- { name: "Silk", category: "Fabric", params: { color: 0xe3dac9, metalness: 0.0, roughness: 0.3, sheen: 1.0, sheenRoughness: 0.3, sheenColor: 0xffeedd } },
208
- { name: "Velvet", category: "Fabric", params: { color: 0x800020, metalness: 0.0, roughness: 0.95, sheen: 0.9, sheenRoughness: 0.9, sheenColor: 0xff4060 } },
209
- { name: "Leather", category: "Fabric", params: { color: 0x553322, metalness: 0.0, roughness: 0.6 } },
210
- { name: "Denim", category: "Fabric", params: { color: 0x3b5998, metalness: 0.0, roughness: 0.85 } },
306
+ {
307
+ name: 'Cotton (White)',
308
+ category: 'Fabric',
309
+ params: {
310
+ color: 0xf5f5dc,
311
+ metalness: 0.0,
312
+ roughness: 0.9,
313
+ sheen: 0.5,
314
+ sheenRoughness: 0.8,
315
+ sheenColor: 0xffffff,
316
+ },
317
+ },
318
+ {
319
+ name: 'Silk',
320
+ category: 'Fabric',
321
+ params: {
322
+ color: 0xe3dac9,
323
+ metalness: 0.0,
324
+ roughness: 0.3,
325
+ sheen: 1.0,
326
+ sheenRoughness: 0.3,
327
+ sheenColor: 0xffeedd,
328
+ },
329
+ },
330
+ {
331
+ name: 'Velvet',
332
+ category: 'Fabric',
333
+ params: {
334
+ color: 0x800020,
335
+ metalness: 0.0,
336
+ roughness: 0.95,
337
+ sheen: 0.9,
338
+ sheenRoughness: 0.9,
339
+ sheenColor: 0xff4060,
340
+ },
341
+ },
342
+ {
343
+ name: 'Leather',
344
+ category: 'Fabric',
345
+ params: { color: 0x553322, metalness: 0.0, roughness: 0.6 },
346
+ },
347
+ {
348
+ name: 'Denim',
349
+ category: 'Fabric',
350
+ params: { color: 0x3b5998, metalness: 0.0, roughness: 0.85 },
351
+ },
211
352
  // Skin
212
- { name: "Skin (Light)", category: "Skin", params: { color: 0xffdbac, metalness: 0.0, roughness: 0.55 } },
213
- { name: "Skin (Medium)", category: "Skin", params: { color: 0xc68642, metalness: 0.0, roughness: 0.5 } },
214
- { name: "Skin (Dark)", category: "Skin", params: { color: 0x8d5524, metalness: 0.0, roughness: 0.5 } },
353
+ {
354
+ name: 'Skin (Light)',
355
+ category: 'Skin',
356
+ params: { color: 0xffdbac, metalness: 0.0, roughness: 0.55 },
357
+ },
358
+ {
359
+ name: 'Skin (Medium)',
360
+ category: 'Skin',
361
+ params: { color: 0xc68642, metalness: 0.0, roughness: 0.5 },
362
+ },
363
+ {
364
+ name: 'Skin (Dark)',
365
+ category: 'Skin',
366
+ params: { color: 0x8d5524, metalness: 0.0, roughness: 0.5 },
367
+ },
215
368
  // Special
216
- { name: "Car Paint", category: "Special", params: { color: 0xcc0000, metalness: 0.5, roughness: 0.15, clearcoat: 1.0, clearcoatRoughness: 0.05 } },
217
- { name: "Emissive (Blue)", category: "Special", params: { color: 0x111111, metalness: 0.0, roughness: 0.5, emissive: 0x0088ff, emissiveIntensity: 2.0 } },
218
- { name: "Emissive (Orange)", category: "Special", params: { color: 0x111111, metalness: 0.0, roughness: 0.5, emissive: 0xff6600, emissiveIntensity: 2.0 } },
219
- { name: "Neon", category: "Special", params: { color: 0x000000, metalness: 0.0, roughness: 0.1, emissive: 0x00ff88, emissiveIntensity: 5.0 } },
369
+ {
370
+ name: 'Car Paint',
371
+ category: 'Special',
372
+ params: {
373
+ color: 0xcc0000,
374
+ metalness: 0.5,
375
+ roughness: 0.15,
376
+ clearcoat: 1.0,
377
+ clearcoatRoughness: 0.05,
378
+ },
379
+ },
380
+ {
381
+ name: 'Emissive (Blue)',
382
+ category: 'Special',
383
+ params: {
384
+ color: 0x111111,
385
+ metalness: 0.0,
386
+ roughness: 0.5,
387
+ emissive: 0x0088ff,
388
+ emissiveIntensity: 2.0,
389
+ },
390
+ },
391
+ {
392
+ name: 'Emissive (Orange)',
393
+ category: 'Special',
394
+ params: {
395
+ color: 0x111111,
396
+ metalness: 0.0,
397
+ roughness: 0.5,
398
+ emissive: 0xff6600,
399
+ emissiveIntensity: 2.0,
400
+ },
401
+ },
402
+ {
403
+ name: 'Neon',
404
+ category: 'Special',
405
+ params: {
406
+ color: 0x000000,
407
+ metalness: 0.0,
408
+ roughness: 0.1,
409
+ emissive: 0x00ff88,
410
+ emissiveIntensity: 5.0,
411
+ },
412
+ },
220
413
  ];
221
414
  /**
222
415
  * Apply a PBR preset to a MeshStandardMaterial or MeshPhysicalMaterial.
@@ -230,39 +423,52 @@ function applyPBRPreset(material, preset) {
230
423
  material.color.setHex(p.color);
231
424
  material.metalness = p.metalness;
232
425
  material.roughness = p.roughness;
233
- if (p.emissive != null)
426
+ if (p.emissive != null) {
234
427
  material.emissive.setHex(p.emissive);
235
- if (p.emissiveIntensity != null)
428
+ }
429
+ if (p.emissiveIntensity != null) {
236
430
  material.emissiveIntensity = p.emissiveIntensity;
237
- if (p.opacity != null)
431
+ }
432
+ if (p.opacity != null) {
238
433
  material.opacity = p.opacity;
434
+ }
239
435
  material.transparent = (_a = p.transparent) !== null && _a !== void 0 ? _a : false;
240
- if (p.clearcoat != null)
436
+ if (p.clearcoat != null) {
241
437
  material.clearcoat = p.clearcoat;
242
- if (p.clearcoatRoughness != null)
438
+ }
439
+ if (p.clearcoatRoughness != null) {
243
440
  material.clearcoatRoughness = p.clearcoatRoughness;
244
- if (p.ior != null)
441
+ }
442
+ if (p.ior != null) {
245
443
  material.ior = p.ior;
246
- if (p.transmission != null)
444
+ }
445
+ if (p.transmission != null) {
247
446
  material.transmission = p.transmission;
248
- if (p.sheen != null)
447
+ }
448
+ if (p.sheen != null) {
249
449
  material.sheen = p.sheen;
250
- if (p.sheenRoughness != null)
450
+ }
451
+ if (p.sheenRoughness != null) {
251
452
  material.sheenRoughness = p.sheenRoughness;
252
- if (p.sheenColor != null)
453
+ }
454
+ if (p.sheenColor != null) {
253
455
  material.sheenColor.setHex(p.sheenColor);
456
+ }
254
457
  material.needsUpdate = true;
255
458
  }
256
459
  else if (material instanceof THREE__namespace.MeshStandardMaterial && !needsPhysical) {
257
460
  material.color.setHex(p.color);
258
461
  material.metalness = p.metalness;
259
462
  material.roughness = p.roughness;
260
- if (p.emissive != null)
463
+ if (p.emissive != null) {
261
464
  material.emissive.setHex(p.emissive);
262
- if (p.emissiveIntensity != null)
465
+ }
466
+ if (p.emissiveIntensity != null) {
263
467
  material.emissiveIntensity = p.emissiveIntensity;
264
- if (p.opacity != null)
468
+ }
469
+ if (p.opacity != null) {
265
470
  material.opacity = p.opacity;
471
+ }
266
472
  material.transparent = (_b = p.transparent) !== null && _b !== void 0 ? _b : false;
267
473
  material.needsUpdate = true;
268
474
  }
@@ -299,10 +505,10 @@ function convertToInstanced(parent) {
299
505
  var _a;
300
506
  const groups = new Map();
301
507
  parent.traverse((child) => {
302
- if (child instanceof THREE__namespace.Mesh && !child.name.startsWith("__")) {
508
+ if (child instanceof THREE__namespace.Mesh && !child.name.startsWith('__')) {
303
509
  const geoId = child.geometry.uuid;
304
510
  const matId = Array.isArray(child.material)
305
- ? child.material.map((m) => m.uuid).join(",")
511
+ ? child.material.map((m) => m.uuid).join(',')
306
512
  : child.material.uuid;
307
513
  const key = `${geoId}|${matId}`;
308
514
  let list = groups.get(key);
@@ -316,11 +522,12 @@ function convertToInstanced(parent) {
316
522
  let created = 0;
317
523
  let removed = 0;
318
524
  for (const [, meshes] of groups) {
319
- if (meshes.length < 2)
525
+ if (meshes.length < 2) {
320
526
  continue;
527
+ }
321
528
  const source = meshes[0];
322
529
  const instancedMesh = new THREE__namespace.InstancedMesh(source.geometry, source.material, meshes.length);
323
- instancedMesh.name = source.name + "_Instanced";
530
+ instancedMesh.name = source.name + '_Instanced';
324
531
  instancedMesh.castShadow = source.castShadow;
325
532
  instancedMesh.receiveShadow = source.receiveShadow;
326
533
  const matrix = new THREE__namespace.Matrix4();
@@ -352,9 +559,10 @@ function countTriangles(object) {
352
559
  count += geo.index.count / 3;
353
560
  }
354
561
  else {
355
- const pos = geo.getAttribute("position");
356
- if (pos)
562
+ const pos = geo.getAttribute('position');
563
+ if (pos) {
357
564
  count += pos.count / 3;
565
+ }
358
566
  }
359
567
  }
360
568
  });
@@ -388,8 +596,8 @@ function measureAngle(a, b, c) {
388
596
  const HDRI_PRESETS = [
389
597
  // Studio
390
598
  {
391
- name: "Studio Soft",
392
- category: "Studio",
599
+ name: 'Studio Soft',
600
+ category: 'Studio',
393
601
  bgColor: 0x1a1a2e,
394
602
  envIntensity: 1.0,
395
603
  ambientColor: 0xffffff,
@@ -400,8 +608,8 @@ const HDRI_PRESETS = [
400
608
  exposure: 1.0,
401
609
  },
402
610
  {
403
- name: "Studio High Key",
404
- category: "Studio",
611
+ name: 'Studio High Key',
612
+ category: 'Studio',
405
613
  bgColor: 0xf0f0f0,
406
614
  envIntensity: 1.2,
407
615
  ambientColor: 0xffffff,
@@ -412,8 +620,8 @@ const HDRI_PRESETS = [
412
620
  exposure: 1.2,
413
621
  },
414
622
  {
415
- name: "Studio Low Key",
416
- category: "Studio",
623
+ name: 'Studio Low Key',
624
+ category: 'Studio',
417
625
  bgColor: 0x0a0a0a,
418
626
  envIntensity: 0.5,
419
627
  ambientColor: 0x222244,
@@ -424,8 +632,8 @@ const HDRI_PRESETS = [
424
632
  exposure: 0.8,
425
633
  },
426
634
  {
427
- name: "Studio Rim",
428
- category: "Studio",
635
+ name: 'Studio Rim',
636
+ category: 'Studio',
429
637
  bgColor: 0x111111,
430
638
  envIntensity: 0.3,
431
639
  ambientColor: 0x111122,
@@ -437,8 +645,8 @@ const HDRI_PRESETS = [
437
645
  },
438
646
  // Outdoor
439
647
  {
440
- name: "Sunny Day",
441
- category: "Outdoor",
648
+ name: 'Sunny Day',
649
+ category: 'Outdoor',
442
650
  bgColor: 0x87ceeb,
443
651
  envIntensity: 1.0,
444
652
  ambientColor: 0x8ec8f0,
@@ -449,8 +657,8 @@ const HDRI_PRESETS = [
449
657
  exposure: 1.0,
450
658
  },
451
659
  {
452
- name: "Overcast",
453
- category: "Outdoor",
660
+ name: 'Overcast',
661
+ category: 'Outdoor',
454
662
  bgColor: 0xb0b0b8,
455
663
  envIntensity: 0.8,
456
664
  ambientColor: 0xccccdd,
@@ -462,8 +670,8 @@ const HDRI_PRESETS = [
462
670
  exposure: 1.0,
463
671
  },
464
672
  {
465
- name: "Golden Hour",
466
- category: "Outdoor",
673
+ name: 'Golden Hour',
674
+ category: 'Outdoor',
467
675
  bgColor: 0xff8844,
468
676
  envIntensity: 1.0,
469
677
  ambientColor: 0xffaa55,
@@ -474,8 +682,8 @@ const HDRI_PRESETS = [
474
682
  exposure: 1.1,
475
683
  },
476
684
  {
477
- name: "Blue Hour",
478
- category: "Outdoor",
685
+ name: 'Blue Hour',
686
+ category: 'Outdoor',
479
687
  bgColor: 0x1a2a4a,
480
688
  envIntensity: 0.6,
481
689
  ambientColor: 0x334466,
@@ -486,8 +694,8 @@ const HDRI_PRESETS = [
486
694
  exposure: 0.8,
487
695
  },
488
696
  {
489
- name: "Night",
490
- category: "Outdoor",
697
+ name: 'Night',
698
+ category: 'Outdoor',
491
699
  bgColor: 0x050510,
492
700
  envIntensity: 0.1,
493
701
  ambientColor: 0x111133,
@@ -499,8 +707,8 @@ const HDRI_PRESETS = [
499
707
  },
500
708
  // Interior
501
709
  {
502
- name: "Warm Interior",
503
- category: "Interior",
710
+ name: 'Warm Interior',
711
+ category: 'Interior',
504
712
  bgColor: 0x2a1a10,
505
713
  envIntensity: 0.7,
506
714
  ambientColor: 0xffddaa,
@@ -511,8 +719,8 @@ const HDRI_PRESETS = [
511
719
  exposure: 1.0,
512
720
  },
513
721
  {
514
- name: "Cool Office",
515
- category: "Interior",
722
+ name: 'Cool Office',
723
+ category: 'Interior',
516
724
  bgColor: 0x1a2230,
517
725
  envIntensity: 0.8,
518
726
  ambientColor: 0xddeeff,
@@ -523,8 +731,8 @@ const HDRI_PRESETS = [
523
731
  exposure: 1.0,
524
732
  },
525
733
  {
526
- name: "Gallery",
527
- category: "Interior",
734
+ name: 'Gallery',
735
+ category: 'Interior',
528
736
  bgColor: 0xfafafa,
529
737
  envIntensity: 1.0,
530
738
  ambientColor: 0xffffff,
@@ -536,8 +744,8 @@ const HDRI_PRESETS = [
536
744
  },
537
745
  // Dramatic
538
746
  {
539
- name: "Neon City",
540
- category: "Dramatic",
747
+ name: 'Neon City',
748
+ category: 'Dramatic',
541
749
  bgColor: 0x0a0015,
542
750
  envIntensity: 0.4,
543
751
  ambientColor: 0xff00ff,
@@ -548,8 +756,8 @@ const HDRI_PRESETS = [
548
756
  exposure: 1.0,
549
757
  },
550
758
  {
551
- name: "Cinematic",
552
- category: "Dramatic",
759
+ name: 'Cinematic',
760
+ category: 'Dramatic',
553
761
  bgColor: 0x0f0f1a,
554
762
  envIntensity: 0.5,
555
763
  ambientColor: 0x223344,
@@ -560,8 +768,8 @@ const HDRI_PRESETS = [
560
768
  exposure: 0.9,
561
769
  },
562
770
  {
563
- name: "Sunrise",
564
- category: "Dramatic",
771
+ name: 'Sunrise',
772
+ category: 'Dramatic',
565
773
  bgColor: 0xff6633,
566
774
  envIntensity: 0.8,
567
775
  ambientColor: 0xffaa66,
@@ -572,8 +780,8 @@ const HDRI_PRESETS = [
572
780
  exposure: 1.2,
573
781
  },
574
782
  {
575
- name: "Desert",
576
- category: "Dramatic",
783
+ name: 'Desert',
784
+ category: 'Dramatic',
577
785
  bgColor: 0xe8c888,
578
786
  envIntensity: 1.0,
579
787
  ambientColor: 0xddcc99,
@@ -596,10 +804,12 @@ function applyHDRIPreset(scene, renderer, preset) {
596
804
  let ambient;
597
805
  let directional;
598
806
  scene.traverse((child) => {
599
- if (child instanceof THREE__namespace.AmbientLight && !ambient)
807
+ if (child instanceof THREE__namespace.AmbientLight && !ambient) {
600
808
  ambient = child;
601
- if (child instanceof THREE__namespace.DirectionalLight && !directional)
809
+ }
810
+ if (child instanceof THREE__namespace.DirectionalLight && !directional) {
602
811
  directional = child;
812
+ }
603
813
  });
604
814
  if (ambient != null) {
605
815
  ambient.color.setHex(preset.ambientColor);
@@ -628,11 +838,13 @@ function snapToVertex(point, scene, maxDistance = Infinity) {
628
838
  let minDist = maxDistance;
629
839
  const tmpV = new THREE__namespace.Vector3();
630
840
  scene.traverse((child) => {
631
- if (!(child instanceof THREE__namespace.Mesh))
841
+ if (!(child instanceof THREE__namespace.Mesh)) {
632
842
  return;
633
- const posAttr = child.geometry.getAttribute("position");
634
- if (!posAttr)
843
+ }
844
+ const posAttr = child.geometry.getAttribute('position');
845
+ if (!posAttr) {
635
846
  return;
847
+ }
636
848
  child.updateWorldMatrix(true, false);
637
849
  for (let i = 0; i < posAttr.count; i++) {
638
850
  tmpV.fromBufferAttribute(posAttr, i);
@@ -640,7 +852,7 @@ function snapToVertex(point, scene, maxDistance = Infinity) {
640
852
  const d = point.distanceTo(tmpV);
641
853
  if (d < minDist) {
642
854
  minDist = d;
643
- closest = { point: tmpV.clone(), target: "vertex", object: child };
855
+ closest = { point: tmpV.clone(), target: 'vertex', object: child };
644
856
  }
645
857
  }
646
858
  });
@@ -653,11 +865,13 @@ function snapToEdge(point, scene, maxDistance = Infinity) {
653
865
  const a = new THREE__namespace.Vector3();
654
866
  const b = new THREE__namespace.Vector3();
655
867
  scene.traverse((child) => {
656
- if (!(child instanceof THREE__namespace.Mesh))
868
+ if (!(child instanceof THREE__namespace.Mesh)) {
657
869
  return;
658
- const posAttr = child.geometry.getAttribute("position");
659
- if (!posAttr)
870
+ }
871
+ const posAttr = child.geometry.getAttribute('position');
872
+ if (!posAttr) {
660
873
  return;
874
+ }
661
875
  const index = child.geometry.index;
662
876
  child.updateWorldMatrix(true, false);
663
877
  const processEdge = (i0, i1) => {
@@ -667,7 +881,7 @@ function snapToEdge(point, scene, maxDistance = Infinity) {
667
881
  const d = point.distanceTo(closestOnEdge);
668
882
  if (d < minDist) {
669
883
  minDist = d;
670
- closest = { point: closestOnEdge.clone(), target: "edge", object: child };
884
+ closest = { point: closestOnEdge.clone(), target: 'edge', object: child };
671
885
  }
672
886
  };
673
887
  if (index) {
@@ -699,23 +913,25 @@ function closestPointOnSegment(p, a, b) {
699
913
  * Multi-mode snap: tries vertex/edge/grid in priority order.
700
914
  * Returns the best snap within maxDistance, or grid snap as fallback.
701
915
  */
702
- function snapMulti(point, scene, gridSize, modes = ["vertex", "edge", "grid"], maxDistance = 0.5) {
916
+ function snapMulti(point, scene, gridSize, modes = ['vertex', 'edge', 'grid'], maxDistance = 0.5) {
703
917
  for (const mode of modes) {
704
- if (mode === "vertex") {
918
+ if (mode === 'vertex') {
705
919
  const result = snapToVertex(point, scene, maxDistance);
706
- if (result)
920
+ if (result) {
707
921
  return result;
922
+ }
708
923
  }
709
- else if (mode === "edge") {
924
+ else if (mode === 'edge') {
710
925
  const result = snapToEdge(point, scene, maxDistance);
711
- if (result)
926
+ if (result) {
712
927
  return result;
928
+ }
713
929
  }
714
- else if (mode === "grid") {
715
- return { point: snapToGrid(point, gridSize), target: "grid" };
930
+ else if (mode === 'grid') {
931
+ return { point: snapToGrid(point, gridSize), target: 'grid' };
716
932
  }
717
933
  }
718
- return { point: snapToGrid(point, gridSize), target: "grid" };
934
+ return { point: snapToGrid(point, gridSize), target: 'grid' };
719
935
  }
720
936
  /** Evaluate a cubic bezier segment at parameter t (0-1). */
721
937
  function cubicBezier(p0, p1, p2, p3, t) {
@@ -730,15 +946,19 @@ function cubicBezier(p0, p1, p2, p3, t) {
730
946
  function evaluateTrack(track, time) {
731
947
  var _a, _b;
732
948
  const { keyframes } = track;
733
- if (keyframes.length === 0)
949
+ if (keyframes.length === 0) {
734
950
  return 0;
735
- if (keyframes.length === 1)
951
+ }
952
+ if (keyframes.length === 1) {
736
953
  return keyframes[0].value;
954
+ }
737
955
  // Clamp to range
738
- if (time <= keyframes[0].time)
956
+ if (time <= keyframes[0].time) {
739
957
  return keyframes[0].value;
740
- if (time >= keyframes[keyframes.length - 1].time)
958
+ }
959
+ if (time >= keyframes[keyframes.length - 1].time) {
741
960
  return keyframes[keyframes.length - 1].value;
961
+ }
742
962
  // Find surrounding keyframes
743
963
  let left = 0;
744
964
  for (let i = 1; i < keyframes.length; i++) {
@@ -751,21 +971,22 @@ function evaluateTrack(track, time) {
751
971
  const kfL = keyframes[left];
752
972
  const kfR = keyframes[right];
753
973
  const dt = kfR.time - kfL.time;
754
- if (dt === 0)
974
+ if (dt === 0) {
755
975
  return kfL.value;
976
+ }
756
977
  const t = (time - kfL.time) / dt;
757
978
  switch (kfL.interpolation) {
758
- case "constant":
979
+ case 'constant':
759
980
  return kfL.value;
760
- case "linear":
981
+ case 'linear':
761
982
  return kfL.value + (kfR.value - kfL.value) * t;
762
- case "ease-in":
983
+ case 'ease-in':
763
984
  return kfL.value + (kfR.value - kfL.value) * (t * t);
764
- case "ease-out":
985
+ case 'ease-out':
765
986
  return kfL.value + (kfR.value - kfL.value) * (1 - (1 - t) * (1 - t));
766
- case "ease-in-out":
767
- return kfL.value + (kfR.value - kfL.value) * (t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t));
768
- case "bezier": {
987
+ case 'ease-in-out':
988
+ return (kfL.value + (kfR.value - kfL.value) * (t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t)));
989
+ case 'bezier': {
769
990
  const handleR = (_a = kfL.handleRight) !== null && _a !== void 0 ? _a : { y: 0 };
770
991
  const handleL = (_b = kfR.handleLeft) !== null && _b !== void 0 ? _b : { y: 0 };
771
992
  return cubicBezier(kfL.value, kfL.value + handleR.y, kfR.value + handleL.y, kfR.value, t);
@@ -775,7 +996,7 @@ function evaluateTrack(track, time) {
775
996
  }
776
997
  }
777
998
  /** Insert or update a keyframe at a given time. */
778
- function setKeyframe(track, time, value, interpolation = "bezier") {
999
+ function setKeyframe(track, time, value, interpolation = 'bezier') {
779
1000
  // Find existing keyframe at same time (within epsilon)
780
1001
  const epsilon = 0.001;
781
1002
  const existingIdx = track.keyframes.findIndex((kf) => Math.abs(kf.time - time) < epsilon);
@@ -825,7 +1046,7 @@ function createAnimationClip(name, tracks, sampleRate = 30) {
825
1046
  /** Trigger a file download in the browser. */
826
1047
  function downloadBlob(blob, filename) {
827
1048
  const url = URL.createObjectURL(blob);
828
- const a = document.createElement("a");
1049
+ const a = document.createElement('a');
829
1050
  a.href = url;
830
1051
  a.download = filename;
831
1052
  document.body.appendChild(a);
@@ -850,9 +1071,10 @@ async function exportSceneUSDZ(scene) {
850
1071
  const { USDZExporter } = await import('three/examples/jsm/exporters/USDZExporter.js');
851
1072
  const exporter = new USDZExporter();
852
1073
  const arraybuffer = await new Promise((resolve, reject) => {
1074
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- USDZExporter.parse callback signature varies between three.js minor versions
853
1075
  exporter.parse(scene, resolve, reject);
854
1076
  });
855
- return new Blob([arraybuffer], { type: "model/vnd.usdz+zip" });
1077
+ return new Blob([arraybuffer], { type: 'model/vnd.usdz+zip' });
856
1078
  }
857
1079
  /**
858
1080
  * Setup crossfade between two animation actions.
@@ -883,8 +1105,9 @@ function makeAdditiveAction(mixer, clip, referenceClip) {
883
1105
  */
884
1106
  function blendAnimations(actions) {
885
1107
  const totalWeight = actions.reduce((sum, a) => sum + a.weight, 0);
886
- if (totalWeight === 0)
1108
+ if (totalWeight === 0) {
887
1109
  return;
1110
+ }
888
1111
  for (const { action, weight } of actions) {
889
1112
  const normalizedWeight = weight / totalWeight;
890
1113
  action.setEffectiveWeight(normalizedWeight);
@@ -908,12 +1131,14 @@ function solveIKChain(skeleton, chain) {
908
1131
  const bones = [];
909
1132
  for (const name of boneNames) {
910
1133
  const bone = skeleton.bones.find((b) => b.name === name);
911
- if (!bone)
1134
+ if (!bone) {
912
1135
  return false;
1136
+ }
913
1137
  bones.push(bone);
914
1138
  }
915
- if (bones.length < 2)
1139
+ if (bones.length < 2) {
916
1140
  return false;
1141
+ }
917
1142
  const endEffector = bones[bones.length - 1];
918
1143
  const endPos = new THREE__namespace.Vector3();
919
1144
  const toEnd = new THREE__namespace.Vector3();
@@ -963,10 +1188,10 @@ function solveIKChain(skeleton, chain) {
963
1188
  }
964
1189
  /** Standard quad viewport layout. */
965
1190
  const QUAD_VIEWPORT = [
966
- { preset: "perspective", x: 0.5, y: 0.5, width: 0.5, height: 0.5 },
967
- { preset: "top", x: 0, y: 0.5, width: 0.5, height: 0.5 },
968
- { preset: "front", x: 0, y: 0, width: 0.5, height: 0.5 },
969
- { preset: "right", x: 0.5, y: 0, width: 0.5, height: 0.5 },
1191
+ { preset: 'perspective', x: 0.5, y: 0.5, width: 0.5, height: 0.5 },
1192
+ { preset: 'top', x: 0, y: 0.5, width: 0.5, height: 0.5 },
1193
+ { preset: 'front', x: 0, y: 0, width: 0.5, height: 0.5 },
1194
+ { preset: 'right', x: 0.5, y: 0, width: 0.5, height: 0.5 },
970
1195
  ];
971
1196
  /** Camera position/rotation for orthographic viewport presets. */
972
1197
  const VIEWPORT_CAMERAS = {
@@ -984,7 +1209,7 @@ const VIEWPORT_CAMERAS = {
984
1209
  function createViewportCamera(preset, aspect = 1, frustumSize = 10) {
985
1210
  const config = VIEWPORT_CAMERAS[preset];
986
1211
  if (config.ortho) {
987
- const camera = new THREE__namespace.OrthographicCamera(-frustumSize * aspect / 2, frustumSize * aspect / 2, frustumSize / 2, -frustumSize / 2, 0.01, 10000);
1212
+ const camera = new THREE__namespace.OrthographicCamera((-frustumSize * aspect) / 2, (frustumSize * aspect) / 2, frustumSize / 2, -frustumSize / 2, 0.01, 10000);
988
1213
  camera.position.set(...config.position);
989
1214
  camera.up.set(...config.up);
990
1215
  camera.lookAt(0, 0, 0);