@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,68 +1,393 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var ui = require('@nice2dev/ui');
5
- var React = require('react');
6
- var i18n = require('../core/i18n.js');
7
- var ModelViewer_module = require('./ModelViewer.module.css.js');
8
- var useModelViewer = require('./useModelViewer.js');
9
-
10
- const NAV_MODES = ['orbit', 'fps', 'fly', 'walkthrough'];
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const ui = require("@nice2dev/ui");
5
+ const React = require("react");
6
+ const i18n = require("../core/i18n.js");
7
+ const ModelViewer_module = require("./ModelViewer.module.css.js");
8
+ const useModelViewer = require("./useModelViewer.js");
9
+ const NAV_MODES = ["orbit", "fps", "fly", "walkthrough"];
11
10
  const NAV_META = {
12
- orbit: { icon: 'globe', label: 'Orbit' },
13
- fps: { icon: 'user', label: 'FPS' },
14
- fly: { icon: 'rocket', label: 'Fly' },
15
- walkthrough: { icon: 'home', label: 'Walk' },
11
+ orbit: { icon: "globe", label: "Orbit" },
12
+ fps: { icon: "user", label: "FPS" },
13
+ fly: { icon: "rocket", label: "Fly" },
14
+ walkthrough: { icon: "home", label: "Walk" }
16
15
  };
17
- const NavLabel = ({ mode }) => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ui.NiceIcon, { name: NAV_META[mode].icon, size: 14 }), " ", NAV_META[mode].label] }));
18
- const NiceModelViewer = ({ className, showToolbar = true, showStatusBar = true, showInfoPanel = true, toolbarExtra, onFileDrop, children, ...viewerProps }) => {
19
- const { t } = i18n.useNiceTranslation();
20
- const api = useModelViewer.useModelViewer(viewerProps);
21
- const [panelOpen, setPanelOpen] = React.useState(false);
22
- const [dragOver, setDragOver] = React.useState(false);
23
- const fileInputRef = React.useRef(null);
24
- /* ── drag & drop ── */
25
- const handleDragOver = React.useCallback((e) => {
26
- e.preventDefault();
27
- setDragOver(true);
28
- }, []);
29
- const handleDragLeave = React.useCallback((e) => {
30
- e.preventDefault();
31
- setDragOver(false);
32
- }, []);
33
- const handleDrop = React.useCallback((e) => {
34
- var _a;
35
- e.preventDefault();
36
- setDragOver(false);
37
- const file = (_a = e.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0];
38
- if (file) {
39
- onFileDrop === null || onFileDrop === void 0 ? void 0 : onFileDrop(file);
40
- api.loadFile(file);
16
+ const NavLabel = ({ mode }) => /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17
+ /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: NAV_META[mode].icon, size: 14 }),
18
+ " ",
19
+ NAV_META[mode].label
20
+ ] });
21
+ const NiceModelViewer = ({
22
+ className,
23
+ showToolbar = true,
24
+ showStatusBar = true,
25
+ showInfoPanel = true,
26
+ toolbarExtra,
27
+ onFileDrop,
28
+ children,
29
+ ...viewerProps
30
+ }) => {
31
+ const { t } = i18n.useNiceTranslation();
32
+ const api = useModelViewer.useModelViewer(viewerProps);
33
+ const [panelOpen, setPanelOpen] = React.useState(false);
34
+ const [dragOver, setDragOver] = React.useState(false);
35
+ const fileInputRef = React.useRef(null);
36
+ const handleDragOver = React.useCallback((e) => {
37
+ e.preventDefault();
38
+ setDragOver(true);
39
+ }, []);
40
+ const handleDragLeave = React.useCallback((e) => {
41
+ e.preventDefault();
42
+ setDragOver(false);
43
+ }, []);
44
+ const handleDrop = React.useCallback(
45
+ (e) => {
46
+ e.preventDefault();
47
+ setDragOver(false);
48
+ const file = e.dataTransfer.files?.[0];
49
+ if (file) {
50
+ onFileDrop?.(file);
51
+ api.loadFile(file);
52
+ }
53
+ },
54
+ [api, onFileDrop]
55
+ );
56
+ const cycleNav = React.useCallback(() => {
57
+ const idx = NAV_MODES.indexOf(api.navigationMode);
58
+ api.setNavigationMode(NAV_MODES[(idx + 1) % NAV_MODES.length]);
59
+ }, [api]);
60
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${ModelViewer_module.default.root} ${className ?? ""}`, children: [
61
+ showToolbar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.toolbar, children: [
62
+ /* @__PURE__ */ jsxRuntime.jsxs(
63
+ ui.NiceButton,
64
+ {
65
+ className: ModelViewer_module.default.toolBtn,
66
+ variant: "ghost",
67
+ size: "sm",
68
+ title: t("modelViewer.openFile", "Open file…"),
69
+ onClick: () => fileInputRef.current?.click(),
70
+ children: [
71
+ /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "folder", size: 14 }),
72
+ " ",
73
+ t("modelViewer.open", "Open")
74
+ ]
41
75
  }
42
- }, [api, onFileDrop]);
43
- /* ── nav cycle ── */
44
- const cycleNav = React.useCallback(() => {
45
- const idx = NAV_MODES.indexOf(api.navigationMode);
46
- api.setNavigationMode(NAV_MODES[(idx + 1) % NAV_MODES.length]);
47
- }, [api]);
48
- return (jsxRuntime.jsxs("div", { className: `${ModelViewer_module.root} ${className !== null && className !== void 0 ? className : ''}`, children: [showToolbar && (jsxRuntime.jsxs("div", { className: ModelViewer_module.toolbar, children: [jsxRuntime.jsxs(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", title: t('modelViewer.openFile', 'Open file…'), onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "folder", size: 14 }), " ", t('modelViewer.open', 'Open')] }), jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: ".fbx,.glb,.gltf,.obj,.dae,.stl,.ply", style: { display: 'none' }, onChange: (e) => {
49
- var _a;
50
- const f = (_a = e.target.files) === null || _a === void 0 ? void 0 : _a[0];
51
- if (f) {
52
- api.loadFile(f);
53
- }
54
- e.target.value = '';
55
- } }), jsxRuntime.jsx("div", { className: ModelViewer_module.toolSep }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", title: t('modelViewer.navigationMode', 'Navigation mode'), onClick: cycleNav, children: jsxRuntime.jsx(NavLabel, { mode: api.navigationMode }) }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: api.wireframe ? 'primary' : 'ghost', size: "sm", onClick: () => api.setWireframe(!api.wireframe), title: t('modelViewer.wireframe', 'Wireframe'), "aria-label": t('modelViewer.wireframe', 'Wireframe'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "square", size: 16 }) }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: api.showGrid ? 'primary' : 'ghost', size: "sm", onClick: () => api.setShowGrid(!api.showGrid), title: t('modelViewer.grid', 'Grid'), "aria-label": t('modelViewer.grid', 'Grid'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "grid", size: 16 }) }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: api.clippingEnabled ? 'primary' : 'ghost', size: "sm", onClick: () => api.setClippingEnabled(!api.clippingEnabled), title: t('modelViewer.clippingPlane', 'Clipping plane'), "aria-label": t('modelViewer.clippingPlane', 'Clipping plane'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "scissors", size: 16 }) }), api.clippingEnabled && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ui.NiceSelect, { className: ModelViewer_module.animSelect, value: api.clippingAxis, onChange: (val) => api.setClippingAxis(val), options: [
56
- { value: 'x', label: 'X' },
57
- { value: 'y', label: 'Y' },
58
- { value: 'z', label: 'Z' },
59
- ] }), jsxRuntime.jsx(ui.NiceSlider, { min: -10, max: 10, step: 0.1, value: api.clippingPosition, onChange: (val) => api.setClippingPosition(val), style: { width: 60 } })] })), jsxRuntime.jsx("div", { className: ModelViewer_module.toolSep }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", onClick: api.zoomToFit, title: t('modelViewer.zoomToFit', 'Zoom to fit'), "aria-label": t('modelViewer.zoomToFit', 'Zoom to fit'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "search", size: 16 }) }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", onClick: api.resetCamera, title: t('modelViewer.resetCamera', 'Reset camera'), "aria-label": t('modelViewer.resetCamera', 'Reset camera'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "home", size: 16 }) }), jsxRuntime.jsx("div", { className: ModelViewer_module.toolSep }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", onClick: () => {
60
- const url = api.screenshot();
61
- const a = document.createElement('a');
62
- a.href = url;
63
- a.download = 'screenshot.png';
64
- a.click();
65
- }, title: t('modelViewer.screenshot', 'Screenshot'), "aria-label": t('modelViewer.screenshot', 'Screenshot'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "camera", size: 16 }) }), jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", onClick: api.toggleFullscreen, title: t('modelViewer.fullscreen', 'Fullscreen'), "aria-label": t('modelViewer.fullscreen', 'Fullscreen'), children: jsxRuntime.jsx(ui.NiceIcon, { name: api.isFullscreen ? 'collapse' : 'expand', size: 16 }) }), toolbarExtra, showInfoPanel && (jsxRuntime.jsx("div", { className: ModelViewer_module.toolRight, children: jsxRuntime.jsx(ui.NiceButton, { className: `${ModelViewer_module.toolBtn} ${panelOpen ? ModelViewer_module.active : ''}`, variant: panelOpen ? 'primary' : 'ghost', size: "sm", onClick: () => setPanelOpen(!panelOpen), title: t('modelViewer.infoPanel', 'Info panel'), "aria-label": t('modelViewer.infoPanel', 'Info panel'), children: jsxRuntime.jsx(ui.NiceIcon, { name: "info", size: 16 }) }) }))] })), jsxRuntime.jsxs("div", { className: ModelViewer_module.viewport, ref: api.mountRef, tabIndex: 0, onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, children: [api.loading && (jsxRuntime.jsxs("div", { className: ModelViewer_module.loadingOverlay, children: [jsxRuntime.jsx("span", { className: ModelViewer_module.loadingText, children: t('modelViewer.loadingModel', 'Loading model…') }), jsxRuntime.jsx("div", { className: ModelViewer_module.loadingBar, children: jsxRuntime.jsx("div", { className: ModelViewer_module.loadingBarFill, style: { width: `${(api.loadProgress * 100).toFixed(0)}%` } }) })] })), api.error && (jsxRuntime.jsxs("div", { className: ModelViewer_module.errorOverlay, children: [jsxRuntime.jsx(ui.NiceIcon, { name: "warning", size: 28 }), jsxRuntime.jsx("span", { style: { marginTop: 8 }, children: api.error })] })), dragOver && (jsxRuntime.jsx("div", { className: ModelViewer_module.dropZone, children: t('modelViewer.drop3dModelFileHere', 'Drop 3D model file here') }))] }), jsxRuntime.jsxs("div", { className: `${ModelViewer_module.sidePanel} ${!panelOpen ? ModelViewer_module.hidden : ''}`, children: [jsxRuntime.jsxs("div", { className: ModelViewer_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelViewer_module.panelTitle, children: t('modelViewer.modelInfo', 'Model Info') }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelRow, children: [jsxRuntime.jsx("label", { children: t('modelViewer.triangles', 'Triangles') }), jsxRuntime.jsx("span", { children: api.polyCount.toLocaleString() })] }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelRow, children: [jsxRuntime.jsx("label", { children: t('modelViewer.meshes', 'Meshes') }), jsxRuntime.jsx("span", { children: api.meshCount })] }), api.dimensions && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: ModelViewer_module.panelRow, children: [jsxRuntime.jsx("label", { children: t('modelViewer.width', 'Width') }), jsxRuntime.jsx("span", { children: api.dimensions.width })] }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelRow, children: [jsxRuntime.jsx("label", { children: t('modelViewer.height', 'Height') }), jsxRuntime.jsx("span", { children: api.dimensions.height })] }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelRow, children: [jsxRuntime.jsx("label", { children: t('modelViewer.depth', 'Depth') }), jsxRuntime.jsx("span", { children: api.dimensions.depth })] })] }))] }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelViewer_module.panelTitle, children: t('modelViewer.navigation', 'Navigation') }), NAV_MODES.map((m) => (jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: api.navigationMode === m ? 'primary' : 'ghost', size: "sm", onClick: () => api.setNavigationMode(m), children: jsxRuntime.jsx(NavLabel, { mode: m }) }, m)))] }), jsxRuntime.jsxs("div", { className: ModelViewer_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelViewer_module.panelTitle, children: t('modelViewer.autoRotate', 'Auto Rotate') }), jsxRuntime.jsx(ui.NiceSlider, { min: 0, max: 10, step: 0.5, value: api.autoRotateSpeed, onChange: (val) => api.setAutoRotateSpeed(val), style: { width: '100%' } })] }), api.animations.length > 0 && (jsxRuntime.jsxs("div", { className: ModelViewer_module.panelSection, children: [jsxRuntime.jsx("div", { className: ModelViewer_module.panelTitle, children: t('modelViewer.animations', 'Animations') }), api.animations.map((name, i) => (jsxRuntime.jsxs(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: api.activeAnimIdx === i ? 'primary' : 'ghost', size: "sm", onClick: () => api.playAnimation(i), children: [jsxRuntime.jsx(ui.NiceIcon, { name: "play", size: 14 }), " ", name] }, i)))] }))] }), jsxRuntime.jsxs("div", { className: `${ModelViewer_module.animBar} ${api.animations.length === 0 ? ModelViewer_module.hidden : ''}`, children: [jsxRuntime.jsx(ui.NiceButton, { className: ModelViewer_module.toolBtn, variant: "ghost", size: "sm", onClick: api.togglePlay, "aria-label": t('modelViewer.playPause', 'Play/Pause'), children: jsxRuntime.jsx(ui.NiceIcon, { name: api.isPlaying ? 'pause' : 'play', size: 16 }) }), jsxRuntime.jsx(ui.NiceSelect, { className: ModelViewer_module.animSelect, value: String(api.activeAnimIdx), onChange: (val) => api.playAnimation(parseInt(val)), options: api.animations.map((n, i) => ({ value: String(i), label: n })) }), jsxRuntime.jsx(ui.NiceSlider, { className: ModelViewer_module.animSlider, min: 0, max: api.animDuration || 1, step: 0.01, value: api.animTime, onChange: (val) => api.seekAnim(val) }), jsxRuntime.jsxs("span", { className: ModelViewer_module.toolLabel, children: [api.animTime.toFixed(1), "s / ", api.animDuration.toFixed(1), "s"] })] }), showStatusBar && (jsxRuntime.jsxs("div", { className: ModelViewer_module.statusBar, children: [jsxRuntime.jsx("span", { children: api.statusText }), jsxRuntime.jsxs("div", { className: ModelViewer_module.statusRight, children: [jsxRuntime.jsx("span", { children: jsxRuntime.jsx(NavLabel, { mode: api.navigationMode }) }), api.dimensions && (jsxRuntime.jsxs("span", { children: [api.dimensions.width, "\u00D7", api.dimensions.height, "\u00D7", api.dimensions.depth] }))] })] })), children === null || children === void 0 ? void 0 : children(api)] }));
76
+ ),
77
+ /* @__PURE__ */ jsxRuntime.jsx(
78
+ "input",
79
+ {
80
+ ref: fileInputRef,
81
+ type: "file",
82
+ accept: ".fbx,.glb,.gltf,.obj,.dae,.stl,.ply",
83
+ style: { display: "none" },
84
+ onChange: (e) => {
85
+ const f = e.target.files?.[0];
86
+ if (f) {
87
+ api.loadFile(f);
88
+ }
89
+ e.target.value = "";
90
+ }
91
+ }
92
+ ),
93
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.toolSep }),
94
+ /* @__PURE__ */ jsxRuntime.jsx(
95
+ ui.NiceButton,
96
+ {
97
+ className: ModelViewer_module.default.toolBtn,
98
+ variant: "ghost",
99
+ size: "sm",
100
+ title: t("modelViewer.navigationMode", "Navigation mode"),
101
+ onClick: cycleNav,
102
+ children: /* @__PURE__ */ jsxRuntime.jsx(NavLabel, { mode: api.navigationMode })
103
+ }
104
+ ),
105
+ /* @__PURE__ */ jsxRuntime.jsx(
106
+ ui.NiceButton,
107
+ {
108
+ className: ModelViewer_module.default.toolBtn,
109
+ variant: api.wireframe ? "primary" : "ghost",
110
+ size: "sm",
111
+ onClick: () => api.setWireframe(!api.wireframe),
112
+ title: t("modelViewer.wireframe", "Wireframe"),
113
+ "aria-label": t("modelViewer.wireframe", "Wireframe"),
114
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "square", size: 16 })
115
+ }
116
+ ),
117
+ /* @__PURE__ */ jsxRuntime.jsx(
118
+ ui.NiceButton,
119
+ {
120
+ className: ModelViewer_module.default.toolBtn,
121
+ variant: api.showGrid ? "primary" : "ghost",
122
+ size: "sm",
123
+ onClick: () => api.setShowGrid(!api.showGrid),
124
+ title: t("modelViewer.grid", "Grid"),
125
+ "aria-label": t("modelViewer.grid", "Grid"),
126
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "grid", size: 16 })
127
+ }
128
+ ),
129
+ /* @__PURE__ */ jsxRuntime.jsx(
130
+ ui.NiceButton,
131
+ {
132
+ className: ModelViewer_module.default.toolBtn,
133
+ variant: api.clippingEnabled ? "primary" : "ghost",
134
+ size: "sm",
135
+ onClick: () => api.setClippingEnabled(!api.clippingEnabled),
136
+ title: t("modelViewer.clippingPlane", "Clipping plane"),
137
+ "aria-label": t("modelViewer.clippingPlane", "Clipping plane"),
138
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "scissors", size: 16 })
139
+ }
140
+ ),
141
+ api.clippingEnabled && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
142
+ /* @__PURE__ */ jsxRuntime.jsx(
143
+ ui.NiceSelect,
144
+ {
145
+ className: ModelViewer_module.default.animSelect,
146
+ value: api.clippingAxis,
147
+ onChange: (val) => api.setClippingAxis(val),
148
+ options: [
149
+ { value: "x", label: "X" },
150
+ { value: "y", label: "Y" },
151
+ { value: "z", label: "Z" }
152
+ ]
153
+ }
154
+ ),
155
+ /* @__PURE__ */ jsxRuntime.jsx(
156
+ ui.NiceSlider,
157
+ {
158
+ min: -10,
159
+ max: 10,
160
+ step: 0.1,
161
+ value: api.clippingPosition,
162
+ onChange: (val) => api.setClippingPosition(val),
163
+ style: { width: 60 }
164
+ }
165
+ )
166
+ ] }),
167
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.toolSep }),
168
+ /* @__PURE__ */ jsxRuntime.jsx(
169
+ ui.NiceButton,
170
+ {
171
+ className: ModelViewer_module.default.toolBtn,
172
+ variant: "ghost",
173
+ size: "sm",
174
+ onClick: api.zoomToFit,
175
+ title: t("modelViewer.zoomToFit", "Zoom to fit"),
176
+ "aria-label": t("modelViewer.zoomToFit", "Zoom to fit"),
177
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "search", size: 16 })
178
+ }
179
+ ),
180
+ /* @__PURE__ */ jsxRuntime.jsx(
181
+ ui.NiceButton,
182
+ {
183
+ className: ModelViewer_module.default.toolBtn,
184
+ variant: "ghost",
185
+ size: "sm",
186
+ onClick: api.resetCamera,
187
+ title: t("modelViewer.resetCamera", "Reset camera"),
188
+ "aria-label": t("modelViewer.resetCamera", "Reset camera"),
189
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "home", size: 16 })
190
+ }
191
+ ),
192
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.toolSep }),
193
+ /* @__PURE__ */ jsxRuntime.jsx(
194
+ ui.NiceButton,
195
+ {
196
+ className: ModelViewer_module.default.toolBtn,
197
+ variant: "ghost",
198
+ size: "sm",
199
+ onClick: () => {
200
+ const url = api.screenshot();
201
+ const a = document.createElement("a");
202
+ a.href = url;
203
+ a.download = "screenshot.png";
204
+ a.click();
205
+ },
206
+ title: t("modelViewer.screenshot", "Screenshot"),
207
+ "aria-label": t("modelViewer.screenshot", "Screenshot"),
208
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "camera", size: 16 })
209
+ }
210
+ ),
211
+ /* @__PURE__ */ jsxRuntime.jsx(
212
+ ui.NiceButton,
213
+ {
214
+ className: ModelViewer_module.default.toolBtn,
215
+ variant: "ghost",
216
+ size: "sm",
217
+ onClick: api.toggleFullscreen,
218
+ title: t("modelViewer.fullscreen", "Fullscreen"),
219
+ "aria-label": t("modelViewer.fullscreen", "Fullscreen"),
220
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: api.isFullscreen ? "collapse" : "expand", size: 16 })
221
+ }
222
+ ),
223
+ toolbarExtra,
224
+ showInfoPanel && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.toolRight, children: /* @__PURE__ */ jsxRuntime.jsx(
225
+ ui.NiceButton,
226
+ {
227
+ className: `${ModelViewer_module.default.toolBtn} ${panelOpen ? ModelViewer_module.default.active : ""}`,
228
+ variant: panelOpen ? "primary" : "ghost",
229
+ size: "sm",
230
+ onClick: () => setPanelOpen(!panelOpen),
231
+ title: t("modelViewer.infoPanel", "Info panel"),
232
+ "aria-label": t("modelViewer.infoPanel", "Info panel"),
233
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "info", size: 16 })
234
+ }
235
+ ) })
236
+ ] }),
237
+ /* @__PURE__ */ jsxRuntime.jsxs(
238
+ "div",
239
+ {
240
+ className: ModelViewer_module.default.viewport,
241
+ ref: api.mountRef,
242
+ tabIndex: 0,
243
+ onDragOver: handleDragOver,
244
+ onDragLeave: handleDragLeave,
245
+ onDrop: handleDrop,
246
+ children: [
247
+ api.loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.loadingOverlay, children: [
248
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ModelViewer_module.default.loadingText, children: t("modelViewer.loadingModel", "Loading model…") }),
249
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.loadingBar, children: /* @__PURE__ */ jsxRuntime.jsx(
250
+ "div",
251
+ {
252
+ className: ModelViewer_module.default.loadingBarFill,
253
+ style: { width: `${(api.loadProgress * 100).toFixed(0)}%` }
254
+ }
255
+ ) })
256
+ ] }),
257
+ api.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.errorOverlay, children: [
258
+ /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "warning", size: 28 }),
259
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginTop: 8 }, children: api.error })
260
+ ] }),
261
+ dragOver && /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.dropZone, children: t("modelViewer.drop3dModelFileHere", "Drop 3D model file here") })
262
+ ]
263
+ }
264
+ ),
265
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${ModelViewer_module.default.sidePanel} ${!panelOpen ? ModelViewer_module.default.hidden : ""}`, children: [
266
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelSection, children: [
267
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.panelTitle, children: t("modelViewer.modelInfo", "Model Info") }),
268
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelRow, children: [
269
+ /* @__PURE__ */ jsxRuntime.jsx("label", { children: t("modelViewer.triangles", "Triangles") }),
270
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.polyCount.toLocaleString() })
271
+ ] }),
272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelRow, children: [
273
+ /* @__PURE__ */ jsxRuntime.jsx("label", { children: t("modelViewer.meshes", "Meshes") }),
274
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.meshCount })
275
+ ] }),
276
+ api.dimensions && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
277
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelRow, children: [
278
+ /* @__PURE__ */ jsxRuntime.jsx("label", { children: t("modelViewer.width", "Width") }),
279
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.dimensions.width })
280
+ ] }),
281
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelRow, children: [
282
+ /* @__PURE__ */ jsxRuntime.jsx("label", { children: t("modelViewer.height", "Height") }),
283
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.dimensions.height })
284
+ ] }),
285
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelRow, children: [
286
+ /* @__PURE__ */ jsxRuntime.jsx("label", { children: t("modelViewer.depth", "Depth") }),
287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.dimensions.depth })
288
+ ] })
289
+ ] })
290
+ ] }),
291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelSection, children: [
292
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.panelTitle, children: t("modelViewer.navigation", "Navigation") }),
293
+ NAV_MODES.map((m) => /* @__PURE__ */ jsxRuntime.jsx(
294
+ ui.NiceButton,
295
+ {
296
+ className: ModelViewer_module.default.toolBtn,
297
+ variant: api.navigationMode === m ? "primary" : "ghost",
298
+ size: "sm",
299
+ onClick: () => api.setNavigationMode(m),
300
+ children: /* @__PURE__ */ jsxRuntime.jsx(NavLabel, { mode: m })
301
+ },
302
+ m
303
+ ))
304
+ ] }),
305
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelSection, children: [
306
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.panelTitle, children: t("modelViewer.autoRotate", "Auto Rotate") }),
307
+ /* @__PURE__ */ jsxRuntime.jsx(
308
+ ui.NiceSlider,
309
+ {
310
+ min: 0,
311
+ max: 10,
312
+ step: 0.5,
313
+ value: api.autoRotateSpeed,
314
+ onChange: (val) => api.setAutoRotateSpeed(val),
315
+ style: { width: "100%" }
316
+ }
317
+ )
318
+ ] }),
319
+ api.animations.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.panelSection, children: [
320
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: ModelViewer_module.default.panelTitle, children: t("modelViewer.animations", "Animations") }),
321
+ api.animations.map((name, i) => /* @__PURE__ */ jsxRuntime.jsxs(
322
+ ui.NiceButton,
323
+ {
324
+ className: ModelViewer_module.default.toolBtn,
325
+ variant: api.activeAnimIdx === i ? "primary" : "ghost",
326
+ size: "sm",
327
+ onClick: () => api.playAnimation(i),
328
+ children: [
329
+ /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: "play", size: 14 }),
330
+ " ",
331
+ name
332
+ ]
333
+ },
334
+ i
335
+ ))
336
+ ] })
337
+ ] }),
338
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${ModelViewer_module.default.animBar} ${api.animations.length === 0 ? ModelViewer_module.default.hidden : ""}`, children: [
339
+ /* @__PURE__ */ jsxRuntime.jsx(
340
+ ui.NiceButton,
341
+ {
342
+ className: ModelViewer_module.default.toolBtn,
343
+ variant: "ghost",
344
+ size: "sm",
345
+ onClick: api.togglePlay,
346
+ "aria-label": t("modelViewer.playPause", "Play/Pause"),
347
+ children: /* @__PURE__ */ jsxRuntime.jsx(ui.NiceIcon, { name: api.isPlaying ? "pause" : "play", size: 16 })
348
+ }
349
+ ),
350
+ /* @__PURE__ */ jsxRuntime.jsx(
351
+ ui.NiceSelect,
352
+ {
353
+ className: ModelViewer_module.default.animSelect,
354
+ value: String(api.activeAnimIdx),
355
+ onChange: (val) => api.playAnimation(parseInt(val)),
356
+ options: api.animations.map((n, i) => ({ value: String(i), label: n }))
357
+ }
358
+ ),
359
+ /* @__PURE__ */ jsxRuntime.jsx(
360
+ ui.NiceSlider,
361
+ {
362
+ className: ModelViewer_module.default.animSlider,
363
+ min: 0,
364
+ max: api.animDuration || 1,
365
+ step: 0.01,
366
+ value: api.animTime,
367
+ onChange: (val) => api.seekAnim(val)
368
+ }
369
+ ),
370
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: ModelViewer_module.default.toolLabel, children: [
371
+ api.animTime.toFixed(1),
372
+ "s / ",
373
+ api.animDuration.toFixed(1),
374
+ "s"
375
+ ] })
376
+ ] }),
377
+ showStatusBar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.statusBar, children: [
378
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: api.statusText }),
379
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ModelViewer_module.default.statusRight, children: [
380
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(NavLabel, { mode: api.navigationMode }) }),
381
+ api.dimensions && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
382
+ api.dimensions.width,
383
+ "×",
384
+ api.dimensions.height,
385
+ "×",
386
+ api.dimensions.depth
387
+ ] })
388
+ ] })
389
+ ] }),
390
+ children?.(api)
391
+ ] });
66
392
  };
67
-
68
393
  exports.NiceModelViewer = NiceModelViewer;
@@ -1,5 +1,77 @@
1
- 'use strict';
2
-
3
- var styles = {"root":"ModelViewer-module_root__6Fbj3","toolbar":"ModelViewer-module_toolbar__EQJRN","toolBtn":"ModelViewer-module_toolBtn__f9833","active":"ModelViewer-module_active__MgURC","toolSep":"ModelViewer-module_toolSep__5zuAK","toolLabel":"ModelViewer-module_toolLabel__PcpJC","toolRight":"ModelViewer-module_toolRight__VSuzD","viewport":"ModelViewer-module_viewport__-1llx","loadingOverlay":"ModelViewer-module_loadingOverlay__Ayyci","loadingBar":"ModelViewer-module_loadingBar__RDqVv","loadingBarFill":"ModelViewer-module_loadingBarFill__zvIoP","loadingText":"ModelViewer-module_loadingText__6OGeA","errorOverlay":"ModelViewer-module_errorOverlay__ASUqN","sidePanel":"ModelViewer-module_sidePanel__-QFkd","hidden":"ModelViewer-module_hidden__yoMuq","panelSection":"ModelViewer-module_panelSection__bH-O3","panelTitle":"ModelViewer-module_panelTitle__xsn3e","panelRow":"ModelViewer-module_panelRow__3QxnD","animBar":"ModelViewer-module_animBar__qcYi5","animSlider":"ModelViewer-module_animSlider__9AQzN","animSelect":"ModelViewer-module_animSelect__LhFWD","statusBar":"ModelViewer-module_statusBar__-3uuA","statusRight":"ModelViewer-module_statusRight__vI51s","dropZone":"ModelViewer-module_dropZone__eNrPo"};
4
-
5
- module.exports = styles;
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const root = "_root_bqnwl_5";
4
+ const toolbar = "_toolbar_bqnwl_33";
5
+ const toolBtn = "_toolBtn_bqnwl_55";
6
+ const active = "_active_bqnwl_89";
7
+ const toolSep = "_toolSep_bqnwl_105";
8
+ const toolLabel = "_toolLabel_bqnwl_117";
9
+ const toolRight = "_toolRight_bqnwl_129";
10
+ const viewport = "_viewport_bqnwl_145";
11
+ const loadingOverlay = "_loadingOverlay_bqnwl_189";
12
+ const loadingBar = "_loadingBar_bqnwl_209";
13
+ const loadingBarFill = "_loadingBarFill_bqnwl_225";
14
+ const loadingText = "_loadingText_bqnwl_235";
15
+ const errorOverlay = "_errorOverlay_bqnwl_249";
16
+ const sidePanel = "_sidePanel_bqnwl_275";
17
+ const hidden = "_hidden_bqnwl_307";
18
+ const panelSection = "_panelSection_bqnwl_313";
19
+ const panelTitle = "_panelTitle_bqnwl_323";
20
+ const panelRow = "_panelRow_bqnwl_337";
21
+ const animBar = "_animBar_bqnwl_369";
22
+ const animSlider = "_animSlider_bqnwl_395";
23
+ const animSelect = "_animSelect_bqnwl_427";
24
+ const statusBar = "_statusBar_bqnwl_449";
25
+ const statusRight = "_statusRight_bqnwl_473";
26
+ const dropZone = "_dropZone_bqnwl_533";
27
+ const styles = {
28
+ root,
29
+ toolbar,
30
+ toolBtn,
31
+ active,
32
+ toolSep,
33
+ toolLabel,
34
+ toolRight,
35
+ viewport,
36
+ loadingOverlay,
37
+ loadingBar,
38
+ loadingBarFill,
39
+ loadingText,
40
+ errorOverlay,
41
+ sidePanel,
42
+ hidden,
43
+ panelSection,
44
+ panelTitle,
45
+ panelRow,
46
+ animBar,
47
+ animSlider,
48
+ animSelect,
49
+ statusBar,
50
+ statusRight,
51
+ dropZone
52
+ };
53
+ exports.active = active;
54
+ exports.animBar = animBar;
55
+ exports.animSelect = animSelect;
56
+ exports.animSlider = animSlider;
57
+ exports.default = styles;
58
+ exports.dropZone = dropZone;
59
+ exports.errorOverlay = errorOverlay;
60
+ exports.hidden = hidden;
61
+ exports.loadingBar = loadingBar;
62
+ exports.loadingBarFill = loadingBarFill;
63
+ exports.loadingOverlay = loadingOverlay;
64
+ exports.loadingText = loadingText;
65
+ exports.panelRow = panelRow;
66
+ exports.panelSection = panelSection;
67
+ exports.panelTitle = panelTitle;
68
+ exports.root = root;
69
+ exports.sidePanel = sidePanel;
70
+ exports.statusBar = statusBar;
71
+ exports.statusRight = statusRight;
72
+ exports.toolBtn = toolBtn;
73
+ exports.toolLabel = toolLabel;
74
+ exports.toolRight = toolRight;
75
+ exports.toolSep = toolSep;
76
+ exports.toolbar = toolbar;
77
+ exports.viewport = viewport;