@nice2dev/ui-3d 1.3.15 → 1.3.17

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 (108) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/cjs/collaborative/collaborativeScene.js +160 -206
  3. package/dist/cjs/core/editorAsk.js +51 -41
  4. package/dist/cjs/core/i18n.js +13 -14
  5. package/dist/cjs/core/threeCompat.js +29 -42
  6. package/dist/cjs/dance/DanceBridge.js +148 -177
  7. package/dist/cjs/dance/DanceScoreEngine.js +209 -221
  8. package/dist/cjs/dance/PoseDetector.js +302 -275
  9. package/dist/cjs/index.js +110 -113
  10. package/dist/cjs/material/MaterialEditor.module.css.js +242 -5
  11. package/dist/cjs/material/NiceMaterialEditor.js +1213 -757
  12. package/dist/cjs/material/materialEditorTypes.js +35 -49
  13. package/dist/cjs/material/materialEditorUtils.js +684 -747
  14. package/dist/cjs/material/materialNodeDefinitions.js +1411 -1459
  15. package/dist/cjs/model/ModelEditor.js +90 -40
  16. package/dist/cjs/model/ModelEditor.module.css.js +257 -5
  17. package/dist/cjs/model/ModelEditorLeftPanel.js +126 -47
  18. package/dist/cjs/model/ModelEditorMenuBar.js +359 -32
  19. package/dist/cjs/model/ModelEditorRightPanel.js +647 -131
  20. package/dist/cjs/model/ModelEditorSubComponents.js +277 -112
  21. package/dist/cjs/model/ModelEditorTimeline.js +232 -34
  22. package/dist/cjs/model/ModelEditorToolbar.js +170 -14
  23. package/dist/cjs/model/ModelEditorViewport.js +231 -39
  24. package/dist/cjs/model/ModelViewer.js +388 -63
  25. package/dist/cjs/model/ModelViewer.module.css.js +77 -5
  26. package/dist/cjs/model/NiceArmatureEditor.js +473 -274
  27. package/dist/cjs/model/NiceMorphTargetEditor.js +333 -227
  28. package/dist/cjs/model/NiceOctree.js +372 -320
  29. package/dist/cjs/model/NicePhysicsSimulation.js +528 -298
  30. package/dist/cjs/model/NiceProceduralGeometry.js +673 -300
  31. package/dist/cjs/model/NiceTerrainEditor.js +595 -385
  32. package/dist/cjs/model/NiceWeightPainter.js +384 -261
  33. package/dist/cjs/model/NiceXRPreview.js +385 -308
  34. package/dist/cjs/model/cadModeUtils.js +103 -106
  35. package/dist/cjs/model/editorShortcuts.js +171 -194
  36. package/dist/cjs/model/modelEditorTypes.js +100 -118
  37. package/dist/cjs/model/modelEditorUtils.js +1061 -1146
  38. package/dist/cjs/model/simsModeUtils.js +1023 -1053
  39. package/dist/cjs/model/useModelEditor.js +1977 -1933
  40. package/dist/cjs/model/useModelViewer.js +633 -665
  41. package/dist/cjs/nice2dev-ui-3d.css +1 -1
  42. package/dist/cjs/particle/NiceParticleEditor.js +1186 -571
  43. package/dist/cjs/particle/ParticleEditor.module.css.js +122 -5
  44. package/dist/cjs/particle/particleEditorTypes.js +62 -70
  45. package/dist/cjs/particle/particleEditorUtils.js +998 -1013
  46. package/dist/cjs/rendering/NiceCascadedShadows.js +381 -259
  47. package/dist/cjs/rendering/NiceRenderExport.js +424 -337
  48. package/dist/cjs/rendering/NiceSSAO.js +454 -337
  49. package/dist/cjs/rendering/NiceSSR.js +387 -261
  50. package/dist/cjs/rendering/NiceWebGPURenderer.js +359 -230
  51. package/dist/cjs/uv/NiceUVEditor.js +787 -550
  52. package/dist/cjs/uv/UVEditor.module.css.js +53 -5
  53. package/dist/cjs/uv/uvEditorTypes.js +59 -76
  54. package/dist/cjs/uv/uvEditorUtils.js +501 -575
  55. package/dist/esm/collaborative/collaborativeScene.js +163 -205
  56. package/dist/esm/core/editorAsk.js +53 -40
  57. package/dist/esm/core/i18n.js +15 -13
  58. package/dist/esm/core/threeCompat.js +18 -26
  59. package/dist/esm/dance/DanceBridge.js +151 -176
  60. package/dist/esm/dance/DanceScoreEngine.js +211 -220
  61. package/dist/esm/dance/PoseDetector.js +304 -274
  62. package/dist/esm/index.js +258 -36
  63. package/dist/esm/material/MaterialEditor.module.css.js +242 -3
  64. package/dist/esm/material/NiceMaterialEditor.js +1215 -756
  65. package/dist/esm/material/materialEditorTypes.js +45 -48
  66. package/dist/esm/material/materialEditorUtils.js +713 -746
  67. package/dist/esm/material/materialNodeDefinitions.js +1415 -1458
  68. package/dist/esm/model/ModelEditor.js +91 -39
  69. package/dist/esm/model/ModelEditor.module.css.js +257 -3
  70. package/dist/esm/model/ModelEditorLeftPanel.js +126 -45
  71. package/dist/esm/model/ModelEditorMenuBar.js +359 -30
  72. package/dist/esm/model/ModelEditorRightPanel.js +634 -114
  73. package/dist/esm/model/ModelEditorSubComponents.js +265 -94
  74. package/dist/esm/model/ModelEditorTimeline.js +232 -32
  75. package/dist/esm/model/ModelEditorToolbar.js +170 -12
  76. package/dist/esm/model/ModelEditorViewport.js +231 -37
  77. package/dist/esm/model/ModelViewer.js +389 -62
  78. package/dist/esm/model/ModelViewer.module.css.js +77 -3
  79. package/dist/esm/model/NiceArmatureEditor.js +462 -258
  80. package/dist/esm/model/NiceMorphTargetEditor.js +322 -211
  81. package/dist/esm/model/NiceOctree.js +361 -304
  82. package/dist/esm/model/NicePhysicsSimulation.js +517 -282
  83. package/dist/esm/model/NiceProceduralGeometry.js +667 -284
  84. package/dist/esm/model/NiceTerrainEditor.js +584 -369
  85. package/dist/esm/model/NiceWeightPainter.js +373 -245
  86. package/dist/esm/model/NiceXRPreview.js +374 -292
  87. package/dist/esm/model/cadModeUtils.js +95 -88
  88. package/dist/esm/model/editorShortcuts.js +172 -193
  89. package/dist/esm/model/modelEditorTypes.js +90 -100
  90. package/dist/esm/model/modelEditorUtils.js +1056 -1128
  91. package/dist/esm/model/simsModeUtils.js +1021 -1035
  92. package/dist/esm/model/useModelEditor.js +1946 -1920
  93. package/dist/esm/model/useModelViewer.js +619 -647
  94. package/dist/esm/nice2dev-ui-3d.css +1 -1
  95. package/dist/esm/particle/NiceParticleEditor.js +1188 -570
  96. package/dist/esm/particle/ParticleEditor.module.css.js +122 -3
  97. package/dist/esm/particle/particleEditorTypes.js +69 -69
  98. package/dist/esm/particle/particleEditorUtils.js +1027 -1012
  99. package/dist/esm/rendering/NiceCascadedShadows.js +370 -243
  100. package/dist/esm/rendering/NiceRenderExport.js +413 -321
  101. package/dist/esm/rendering/NiceSSAO.js +450 -328
  102. package/dist/esm/rendering/NiceSSR.js +383 -252
  103. package/dist/esm/rendering/NiceWebGPURenderer.js +326 -214
  104. package/dist/esm/uv/NiceUVEditor.js +788 -549
  105. package/dist/esm/uv/UVEditor.module.css.js +53 -3
  106. package/dist/esm/uv/uvEditorTypes.js +68 -75
  107. package/dist/esm/uv/uvEditorUtils.js +515 -557
  108. package/package.json +7 -12
@@ -1,14 +1,172 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { NiceButton, NiceIcon } from '@nice2dev/ui';
3
- import React from 'react';
4
- import { useNiceTranslation } from '../core/i18n.js';
5
- import styles from './ModelEditor.module.css.js';
6
-
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { NiceButton, NiceIcon } from "@nice2dev/ui";
3
+ import React from "react";
4
+ import { useNiceTranslation } from "../core/i18n.js";
5
+ import styles from "./ModelEditor.module.css.js";
7
6
  const ModelEditorToolbar = /* @__PURE__ */ Object.assign(
8
- /* @__PURE__ */ React.memo(({ api }) => {
7
+ /* @__PURE__ */ React.memo(({ api }) => {
9
8
  const { t } = useNiceTranslation();
10
- const { transformMode, setTransformMode, snapEnabled, setSnapEnabled, gizmoSpace, setGizmoSpace, rootObjectRef, focusOnObject, setCameraPreset, deleteSelected, duplicateSelected, selectedNode, } = api;
11
- return (jsxs("div", { className: styles.toolbar, children: [jsx(NiceButton, { className: styles.toolBtn, variant: transformMode === 'translate' ? 'primary' : 'ghost', size: "sm", onClick: () => setTransformMode('translate'), title: t('modelEditorToolbar.translateG', 'Translate (G)'), "aria-label": t('modelEditorToolbar.translateG', 'Translate (G)'), children: jsx(NiceIcon, { name: "move", size: 16 }) }), jsx(NiceButton, { className: styles.toolBtn, variant: transformMode === 'rotate' ? 'primary' : 'ghost', size: "sm", onClick: () => setTransformMode('rotate'), title: t('modelEditorToolbar.rotateR', 'Rotate (R)'), "aria-label": t('modelEditorToolbar.rotateR', 'Rotate (R)'), children: jsx(NiceIcon, { name: "refresh", size: 16 }) }), jsx(NiceButton, { className: styles.toolBtn, variant: transformMode === 'scale' ? 'primary' : 'ghost', size: "sm", onClick: () => setTransformMode('scale'), title: t('modelEditorToolbar.scaleS', 'Scale (S)'), "aria-label": t('modelEditorToolbar.scaleS', 'Scale (S)'), children: jsx(NiceIcon, { name: "hexagon", size: 16 }) }), jsx("div", { className: styles.toolSep }), jsx(NiceButton, { className: styles.toolBtn, variant: snapEnabled ? 'primary' : 'ghost', size: "sm", onClick: () => setSnapEnabled((v) => !v), title: t('modelEditorToolbar.snapToGridState', 'Snap to Grid ({state})').replace('{state}', snapEnabled ? t('modelEditorToolbar.on', 'ON') : t('modelEditorToolbar.off', 'OFF')), "aria-label": t('modelEditorToolbar.snapToGrid', 'Snap to Grid'), children: jsx(NiceIcon, { name: "grid", size: 16 }) }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: () => setGizmoSpace((s) => (s === 'local' ? 'world' : 'local')), title: t('modelEditorToolbar.orientation', 'Orientation: {gizmoSpace}').replace('{gizmoSpace}', String(gizmoSpace)), "aria-label": t('modelEditorToolbar.orientation', 'Orientation: {gizmoSpace}').replace('{gizmoSpace}', String(gizmoSpace)), children: jsx(NiceIcon, { name: gizmoSpace === 'local' ? 'target' : 'globe', size: 16 }) }), jsx("div", { className: styles.toolSep }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: () => rootObjectRef.current && focusOnObject(rootObjectRef.current), title: t('modelEditorToolbar.focusF', 'Focus (F)'), "aria-label": t('modelEditorToolbar.focusF', 'Focus (F)'), children: jsx(NiceIcon, { name: "target", size: 16 }) }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset('front'), title: t('modelEditorToolbar.frontViewNumpad1', 'Front view (Numpad 1)'), children: "1" }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset('right'), title: t('modelEditorToolbar.rightViewNumpad3', 'Right view (Numpad 3)'), children: "3" }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: () => setCameraPreset('top'), title: t('modelEditorToolbar.topViewNumpad7', 'Top view (Numpad 7)'), children: "7" }), jsx("div", { className: styles.toolSep }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: deleteSelected, title: t('modelEditorToolbar.deleteSelectedDel', 'Delete selected (Del)'), "aria-label": t('modelEditorToolbar.deleteSelectedDel', 'Delete selected (Del)'), children: jsx(NiceIcon, { name: "trash", size: 16 }) }), jsx(NiceButton, { className: styles.toolBtn, variant: "ghost", size: "sm", onClick: duplicateSelected, title: t('modelEditorToolbar.duplicateShiftD', 'Duplicate (Shift+D)'), disabled: !selectedNode, "aria-label": t('modelEditorToolbar.duplicateShiftD', 'Duplicate (Shift+D)'), children: jsx(NiceIcon, { name: "clipboard", size: 16 }) })] }));
12
- }), { displayName: 'ModelEditorToolbar' });
13
-
14
- export { ModelEditorToolbar as default };
9
+ const {
10
+ transformMode,
11
+ setTransformMode,
12
+ snapEnabled,
13
+ setSnapEnabled,
14
+ gizmoSpace,
15
+ setGizmoSpace,
16
+ rootObjectRef,
17
+ focusOnObject,
18
+ setCameraPreset,
19
+ deleteSelected,
20
+ duplicateSelected,
21
+ selectedNode
22
+ } = api;
23
+ return /* @__PURE__ */ jsxs("div", { className: styles.toolbar, children: [
24
+ /* @__PURE__ */ jsx(
25
+ NiceButton,
26
+ {
27
+ className: styles.toolBtn,
28
+ variant: transformMode === "translate" ? "primary" : "ghost",
29
+ size: "sm",
30
+ onClick: () => setTransformMode("translate"),
31
+ title: t("modelEditorToolbar.translateG", "Translate (G)"),
32
+ "aria-label": t("modelEditorToolbar.translateG", "Translate (G)"),
33
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "move", size: 16 })
34
+ }
35
+ ),
36
+ /* @__PURE__ */ jsx(
37
+ NiceButton,
38
+ {
39
+ className: styles.toolBtn,
40
+ variant: transformMode === "rotate" ? "primary" : "ghost",
41
+ size: "sm",
42
+ onClick: () => setTransformMode("rotate"),
43
+ title: t("modelEditorToolbar.rotateR", "Rotate (R)"),
44
+ "aria-label": t("modelEditorToolbar.rotateR", "Rotate (R)"),
45
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "refresh", size: 16 })
46
+ }
47
+ ),
48
+ /* @__PURE__ */ jsx(
49
+ NiceButton,
50
+ {
51
+ className: styles.toolBtn,
52
+ variant: transformMode === "scale" ? "primary" : "ghost",
53
+ size: "sm",
54
+ onClick: () => setTransformMode("scale"),
55
+ title: t("modelEditorToolbar.scaleS", "Scale (S)"),
56
+ "aria-label": t("modelEditorToolbar.scaleS", "Scale (S)"),
57
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "hexagon", size: 16 })
58
+ }
59
+ ),
60
+ /* @__PURE__ */ jsx("div", { className: styles.toolSep }),
61
+ /* @__PURE__ */ jsx(
62
+ NiceButton,
63
+ {
64
+ className: styles.toolBtn,
65
+ variant: snapEnabled ? "primary" : "ghost",
66
+ size: "sm",
67
+ onClick: () => setSnapEnabled((v) => !v),
68
+ title: t("modelEditorToolbar.snapToGridState", "Snap to Grid ({state})").replace(
69
+ "{state}",
70
+ snapEnabled ? t("modelEditorToolbar.on", "ON") : t("modelEditorToolbar.off", "OFF")
71
+ ),
72
+ "aria-label": t("modelEditorToolbar.snapToGrid", "Snap to Grid"),
73
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "grid", size: 16 })
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsx(
77
+ NiceButton,
78
+ {
79
+ className: styles.toolBtn,
80
+ variant: "ghost",
81
+ size: "sm",
82
+ onClick: () => setGizmoSpace((s) => s === "local" ? "world" : "local"),
83
+ title: t("modelEditorToolbar.orientation", "Orientation: {gizmoSpace}").replace(
84
+ "{gizmoSpace}",
85
+ String(gizmoSpace)
86
+ ),
87
+ "aria-label": t("modelEditorToolbar.orientation", "Orientation: {gizmoSpace}").replace(
88
+ "{gizmoSpace}",
89
+ String(gizmoSpace)
90
+ ),
91
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: gizmoSpace === "local" ? "target" : "globe", size: 16 })
92
+ }
93
+ ),
94
+ /* @__PURE__ */ jsx("div", { className: styles.toolSep }),
95
+ /* @__PURE__ */ jsx(
96
+ NiceButton,
97
+ {
98
+ className: styles.toolBtn,
99
+ variant: "ghost",
100
+ size: "sm",
101
+ onClick: () => rootObjectRef.current && focusOnObject(rootObjectRef.current),
102
+ title: t("modelEditorToolbar.focusF", "Focus (F)"),
103
+ "aria-label": t("modelEditorToolbar.focusF", "Focus (F)"),
104
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "target", size: 16 })
105
+ }
106
+ ),
107
+ /* @__PURE__ */ jsx(
108
+ NiceButton,
109
+ {
110
+ className: styles.toolBtn,
111
+ variant: "ghost",
112
+ size: "sm",
113
+ onClick: () => setCameraPreset("front"),
114
+ title: t("modelEditorToolbar.frontViewNumpad1", "Front view (Numpad 1)"),
115
+ children: "1"
116
+ }
117
+ ),
118
+ /* @__PURE__ */ jsx(
119
+ NiceButton,
120
+ {
121
+ className: styles.toolBtn,
122
+ variant: "ghost",
123
+ size: "sm",
124
+ onClick: () => setCameraPreset("right"),
125
+ title: t("modelEditorToolbar.rightViewNumpad3", "Right view (Numpad 3)"),
126
+ children: "3"
127
+ }
128
+ ),
129
+ /* @__PURE__ */ jsx(
130
+ NiceButton,
131
+ {
132
+ className: styles.toolBtn,
133
+ variant: "ghost",
134
+ size: "sm",
135
+ onClick: () => setCameraPreset("top"),
136
+ title: t("modelEditorToolbar.topViewNumpad7", "Top view (Numpad 7)"),
137
+ children: "7"
138
+ }
139
+ ),
140
+ /* @__PURE__ */ jsx("div", { className: styles.toolSep }),
141
+ /* @__PURE__ */ jsx(
142
+ NiceButton,
143
+ {
144
+ className: styles.toolBtn,
145
+ variant: "ghost",
146
+ size: "sm",
147
+ onClick: deleteSelected,
148
+ title: t("modelEditorToolbar.deleteSelectedDel", "Delete selected (Del)"),
149
+ "aria-label": t("modelEditorToolbar.deleteSelectedDel", "Delete selected (Del)"),
150
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "trash", size: 16 })
151
+ }
152
+ ),
153
+ /* @__PURE__ */ jsx(
154
+ NiceButton,
155
+ {
156
+ className: styles.toolBtn,
157
+ variant: "ghost",
158
+ size: "sm",
159
+ onClick: duplicateSelected,
160
+ title: t("modelEditorToolbar.duplicateShiftD", "Duplicate (Shift+D)"),
161
+ disabled: !selectedNode,
162
+ "aria-label": t("modelEditorToolbar.duplicateShiftD", "Duplicate (Shift+D)"),
163
+ children: /* @__PURE__ */ jsx(NiceIcon, { name: "clipboard", size: 16 })
164
+ }
165
+ )
166
+ ] });
167
+ }),
168
+ { displayName: "ModelEditorToolbar" }
169
+ );
170
+ export {
171
+ ModelEditorToolbar as default
172
+ };
@@ -1,41 +1,235 @@
1
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import { NiceIcon, clickOnActivationKey } from '@nice2dev/ui';
3
- import React from 'react';
4
- import { useNiceTranslation } from '../core/i18n.js';
5
- import styles from './ModelEditor.module.css.js';
6
-
7
- /** The viewport badge per editor mode: [key, English]. */
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import { NiceIcon, clickOnActivationKey } from "@nice2dev/ui";
3
+ import React from "react";
4
+ import { useNiceTranslation } from "../core/i18n.js";
5
+ import styles from "./ModelEditor.module.css.js";
8
6
  const MODE_BADGE = {
9
- object: ['modelEditorViewport.objectMode', 'OBJECT MODE'],
10
- edit: ['modelEditorViewport.editMode', 'EDIT MODE'],
11
- pose: ['modelEditorViewport.poseMode', 'POSE MODE'],
12
- cad: ['modelEditorViewport.cadMode', 'CAD MODE'],
13
- sims: ['modelEditorViewport.simsMode', 'SIMS MODE'],
7
+ object: ["modelEditorViewport.objectMode", "OBJECT MODE"],
8
+ edit: ["modelEditorViewport.editMode", "EDIT MODE"],
9
+ pose: ["modelEditorViewport.poseMode", "POSE MODE"],
10
+ cad: ["modelEditorViewport.cadMode", "CAD MODE"],
11
+ sims: ["modelEditorViewport.simsMode", "SIMS MODE"]
14
12
  };
15
13
  const ModelEditorViewport = /* @__PURE__ */ Object.assign(
16
- /* @__PURE__ */ React.memo(({ api }) => {
14
+ /* @__PURE__ */ React.memo(({ api }) => {
17
15
  const { t } = useNiceTranslation();
18
- const { mountRef, dragOver, handleDragOver, handleDragLeave, handleDrop, handleViewportClick, handleContextMenu, editorMode, polyCount, meshCount, boneCount, shadingMode, setShadingMode, gizmoSpace, setGizmoSpace, contextMenu, closeContextMenu, addPrimitive, addSceneLight, duplicateSelected, deleteSelected, selectedNode, rootObjectRef, focusOnObject, snapEnabled, setSnapEnabled, } = api;
19
- return (jsxs(Fragment, { children: [jsxs("div", { role: "presentation", ref: mountRef, className: `${styles.viewportContainer} ${dragOver ? styles.dragOver : ''}`, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: handleViewportClick, onContextMenu: handleContextMenu, children: [jsxs("div", { className: styles.viewportOverlay, children: [jsx("span", { className: styles.viewportBadge, children: t(...MODE_BADGE[editorMode]) }), jsx("span", { className: styles.viewportBadge, children: t('modelEditorViewport.trisMeshesBones', '{polyCount} tris · {meshCount} meshes · {boneCount} bones')
20
- .replace('{polyCount}', String(polyCount.toLocaleString()))
21
- .replace('{meshCount}', String(meshCount))
22
- .replace('{boneCount}', String(boneCount)) })] }), jsx("div", { className: styles.viewportShadingBar, children: ['wireframe', 'solid', 'material', 'rendered'].map((m) => (jsx("button", { className: `${styles.shadingBtn} ${shadingMode === m ? styles.shadingBtnActive : ''}`, onClick: (e) => {
23
- e.stopPropagation();
24
- setShadingMode(m);
25
- }, title: m.charAt(0).toUpperCase() + m.slice(1), "aria-label": m.charAt(0).toUpperCase() + m.slice(1), children: jsx(NiceIcon, { name: m === 'wireframe'
26
- ? 'hexagon'
27
- : m === 'solid'
28
- ? 'box'
29
- : m === 'material'
30
- ? 'palette'
31
- : 'lightbulb', size: 16 }) }, m))) }), jsx("div", { className: styles.viewportGizmoInfo, children: jsx("button", { className: styles.shadingBtn, onClick: (e) => {
32
- e.stopPropagation();
33
- setGizmoSpace((s) => (s === 'local' ? 'world' : 'local'));
34
- }, title: t('modelEditorViewport.orientation', 'Orientation: {gizmoSpace}').replace('{gizmoSpace}', String(gizmoSpace)), "aria-label": t('modelEditorViewport.orientation', 'Orientation: {gizmoSpace}').replace('{gizmoSpace}', String(gizmoSpace)), children: gizmoSpace === 'local' ? (jsxs(Fragment, { children: [jsx(NiceIcon, { name: "target", size: 14 }), " ", t('modelEditorViewport.local', 'Local')] })) : (jsxs(Fragment, { children: [jsx(NiceIcon, { name: "globe", size: 14 }), " ", t('modelEditorViewport.world', 'World')] })) }) }), dragOver && (jsx("div", { className: styles.viewportDropZone, children: jsx("span", { children: t('modelEditorViewport.drop3dFilesHere', 'Drop 3D files here') }) }))] }), contextMenu && (jsxs("div", { role: "presentation", className: styles.contextMenu, style: { top: contextMenu.y, left: contextMenu.x }, onClick: closeContextMenu, children: [jsxs("div", { role: "button", tabIndex: 0, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: () => addPrimitive('cube'), children: [jsx("span", { children: t('modelEditorViewport.addCube', 'Add Cube') }), jsx("span", { className: styles.contextKey, children: "Shift+A" })] }), jsx("div", { role: "button", tabIndex: 0, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: () => addPrimitive('sphere'), children: jsx("span", { children: t('modelEditorViewport.addSphere', 'Add Sphere') }) }), jsx("div", { role: "button", tabIndex: 0, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: () => addSceneLight('point'), children: jsx("span", { children: t('modelEditorViewport.addPointLight', 'Add Point Light') }) }), jsx("div", { className: styles.contextSep }), jsxs("div", { role: "button", tabIndex: 0, "aria-disabled": !selectedNode, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: duplicateSelected, style: !selectedNode ? { opacity: 0.4, pointerEvents: 'none' } : {}, children: [jsx("span", { children: t('modelEditorViewport.duplicate', 'Duplicate') }), jsx("span", { className: styles.contextKey, children: "Shift+D" })] }), jsxs("div", { role: "button", tabIndex: 0, "aria-disabled": !selectedNode, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: deleteSelected, style: !selectedNode ? { opacity: 0.4, pointerEvents: 'none' } : {}, children: [jsx("span", { children: t('modelEditorViewport.delete', 'Delete') }), jsx("span", { className: styles.contextKey, children: "Del" })] }), jsx("div", { className: styles.contextSep }), jsxs("div", { role: "button", tabIndex: 0, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: () => {
35
- if (rootObjectRef.current) {
36
- focusOnObject(rootObjectRef.current);
37
- }
38
- }, children: [jsx("span", { children: t('modelEditorViewport.focusCamera', 'Focus Camera') }), jsx("span", { className: styles.contextKey, children: "F" })] }), jsx("div", { role: "button", tabIndex: 0, onKeyDown: clickOnActivationKey, className: styles.contextItem, onClick: () => setSnapEnabled((v) => !v), children: jsxs("span", { children: [snapEnabled && jsx(NiceIcon, { name: "check", size: 14 }), ' ', t('modelEditorViewport.snapToGrid', 'Snap to Grid')] }) })] }))] }));
39
- }), { displayName: 'ModelEditorViewport' });
40
-
41
- export { ModelEditorViewport as default };
16
+ const {
17
+ mountRef,
18
+ dragOver,
19
+ handleDragOver,
20
+ handleDragLeave,
21
+ handleDrop,
22
+ handleViewportClick,
23
+ handleContextMenu,
24
+ editorMode,
25
+ polyCount,
26
+ meshCount,
27
+ boneCount,
28
+ shadingMode,
29
+ setShadingMode,
30
+ gizmoSpace,
31
+ setGizmoSpace,
32
+ contextMenu,
33
+ closeContextMenu,
34
+ addPrimitive,
35
+ addSceneLight,
36
+ duplicateSelected,
37
+ deleteSelected,
38
+ selectedNode,
39
+ rootObjectRef,
40
+ focusOnObject,
41
+ snapEnabled,
42
+ setSnapEnabled
43
+ } = api;
44
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
45
+ /* @__PURE__ */ jsxs(
46
+ "div",
47
+ {
48
+ role: "presentation",
49
+ ref: mountRef,
50
+ className: `${styles.viewportContainer} ${dragOver ? styles.dragOver : ""}`,
51
+ onDragOver: handleDragOver,
52
+ onDragLeave: handleDragLeave,
53
+ onDrop: handleDrop,
54
+ onClick: handleViewportClick,
55
+ onContextMenu: handleContextMenu,
56
+ children: [
57
+ /* @__PURE__ */ jsxs("div", { className: styles.viewportOverlay, children: [
58
+ /* @__PURE__ */ jsx("span", { className: styles.viewportBadge, children: t(...MODE_BADGE[editorMode]) }),
59
+ /* @__PURE__ */ jsx("span", { className: styles.viewportBadge, children: t(
60
+ "modelEditorViewport.trisMeshesBones",
61
+ "{polyCount} tris · {meshCount} meshes · {boneCount} bones"
62
+ ).replace("{polyCount}", String(polyCount.toLocaleString())).replace("{meshCount}", String(meshCount)).replace("{boneCount}", String(boneCount)) })
63
+ ] }),
64
+ /* @__PURE__ */ jsx("div", { className: styles.viewportShadingBar, children: ["wireframe", "solid", "material", "rendered"].map((m) => /* @__PURE__ */ jsx(
65
+ "button",
66
+ {
67
+ className: `${styles.shadingBtn} ${shadingMode === m ? styles.shadingBtnActive : ""}`,
68
+ onClick: (e) => {
69
+ e.stopPropagation();
70
+ setShadingMode(m);
71
+ },
72
+ title: m.charAt(0).toUpperCase() + m.slice(1),
73
+ "aria-label": m.charAt(0).toUpperCase() + m.slice(1),
74
+ children: /* @__PURE__ */ jsx(
75
+ NiceIcon,
76
+ {
77
+ name: m === "wireframe" ? "hexagon" : m === "solid" ? "box" : m === "material" ? "palette" : "lightbulb",
78
+ size: 16
79
+ }
80
+ )
81
+ },
82
+ m
83
+ )) }),
84
+ /* @__PURE__ */ jsx("div", { className: styles.viewportGizmoInfo, children: /* @__PURE__ */ jsx(
85
+ "button",
86
+ {
87
+ className: styles.shadingBtn,
88
+ onClick: (e) => {
89
+ e.stopPropagation();
90
+ setGizmoSpace((s) => s === "local" ? "world" : "local");
91
+ },
92
+ title: t("modelEditorViewport.orientation", "Orientation: {gizmoSpace}").replace(
93
+ "{gizmoSpace}",
94
+ String(gizmoSpace)
95
+ ),
96
+ "aria-label": t("modelEditorViewport.orientation", "Orientation: {gizmoSpace}").replace(
97
+ "{gizmoSpace}",
98
+ String(gizmoSpace)
99
+ ),
100
+ children: gizmoSpace === "local" ? /* @__PURE__ */ jsxs(Fragment, { children: [
101
+ /* @__PURE__ */ jsx(NiceIcon, { name: "target", size: 14 }),
102
+ " ",
103
+ t("modelEditorViewport.local", "Local")
104
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
105
+ /* @__PURE__ */ jsx(NiceIcon, { name: "globe", size: 14 }),
106
+ " ",
107
+ t("modelEditorViewport.world", "World")
108
+ ] })
109
+ }
110
+ ) }),
111
+ dragOver && /* @__PURE__ */ jsx("div", { className: styles.viewportDropZone, children: /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.drop3dFilesHere", "Drop 3D files here") }) })
112
+ ]
113
+ }
114
+ ),
115
+ contextMenu && /* @__PURE__ */ jsxs(
116
+ "div",
117
+ {
118
+ role: "presentation",
119
+ className: styles.contextMenu,
120
+ style: { top: contextMenu.y, left: contextMenu.x },
121
+ onClick: closeContextMenu,
122
+ children: [
123
+ /* @__PURE__ */ jsxs(
124
+ "div",
125
+ {
126
+ role: "button",
127
+ tabIndex: 0,
128
+ onKeyDown: clickOnActivationKey,
129
+ className: styles.contextItem,
130
+ onClick: () => addPrimitive("cube"),
131
+ children: [
132
+ /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.addCube", "Add Cube") }),
133
+ /* @__PURE__ */ jsx("span", { className: styles.contextKey, children: "Shift+A" })
134
+ ]
135
+ }
136
+ ),
137
+ /* @__PURE__ */ jsx(
138
+ "div",
139
+ {
140
+ role: "button",
141
+ tabIndex: 0,
142
+ onKeyDown: clickOnActivationKey,
143
+ className: styles.contextItem,
144
+ onClick: () => addPrimitive("sphere"),
145
+ children: /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.addSphere", "Add Sphere") })
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx(
149
+ "div",
150
+ {
151
+ role: "button",
152
+ tabIndex: 0,
153
+ onKeyDown: clickOnActivationKey,
154
+ className: styles.contextItem,
155
+ onClick: () => addSceneLight("point"),
156
+ children: /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.addPointLight", "Add Point Light") })
157
+ }
158
+ ),
159
+ /* @__PURE__ */ jsx("div", { className: styles.contextSep }),
160
+ /* @__PURE__ */ jsxs(
161
+ "div",
162
+ {
163
+ role: "button",
164
+ tabIndex: 0,
165
+ "aria-disabled": !selectedNode,
166
+ onKeyDown: clickOnActivationKey,
167
+ className: styles.contextItem,
168
+ onClick: duplicateSelected,
169
+ style: !selectedNode ? { opacity: 0.4, pointerEvents: "none" } : {},
170
+ children: [
171
+ /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.duplicate", "Duplicate") }),
172
+ /* @__PURE__ */ jsx("span", { className: styles.contextKey, children: "Shift+D" })
173
+ ]
174
+ }
175
+ ),
176
+ /* @__PURE__ */ jsxs(
177
+ "div",
178
+ {
179
+ role: "button",
180
+ tabIndex: 0,
181
+ "aria-disabled": !selectedNode,
182
+ onKeyDown: clickOnActivationKey,
183
+ className: styles.contextItem,
184
+ onClick: deleteSelected,
185
+ style: !selectedNode ? { opacity: 0.4, pointerEvents: "none" } : {},
186
+ children: [
187
+ /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.delete", "Delete") }),
188
+ /* @__PURE__ */ jsx("span", { className: styles.contextKey, children: "Del" })
189
+ ]
190
+ }
191
+ ),
192
+ /* @__PURE__ */ jsx("div", { className: styles.contextSep }),
193
+ /* @__PURE__ */ jsxs(
194
+ "div",
195
+ {
196
+ role: "button",
197
+ tabIndex: 0,
198
+ onKeyDown: clickOnActivationKey,
199
+ className: styles.contextItem,
200
+ onClick: () => {
201
+ if (rootObjectRef.current) {
202
+ focusOnObject(rootObjectRef.current);
203
+ }
204
+ },
205
+ children: [
206
+ /* @__PURE__ */ jsx("span", { children: t("modelEditorViewport.focusCamera", "Focus Camera") }),
207
+ /* @__PURE__ */ jsx("span", { className: styles.contextKey, children: "F" })
208
+ ]
209
+ }
210
+ ),
211
+ /* @__PURE__ */ jsx(
212
+ "div",
213
+ {
214
+ role: "button",
215
+ tabIndex: 0,
216
+ onKeyDown: clickOnActivationKey,
217
+ className: styles.contextItem,
218
+ onClick: () => setSnapEnabled((v) => !v),
219
+ children: /* @__PURE__ */ jsxs("span", { children: [
220
+ snapEnabled && /* @__PURE__ */ jsx(NiceIcon, { name: "check", size: 14 }),
221
+ " ",
222
+ t("modelEditorViewport.snapToGrid", "Snap to Grid")
223
+ ] })
224
+ }
225
+ )
226
+ ]
227
+ }
228
+ )
229
+ ] });
230
+ }),
231
+ { displayName: "ModelEditorViewport" }
232
+ );
233
+ export {
234
+ ModelEditorViewport as default
235
+ };