@nice2dev/ui-3d 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/cjs/material/NiceMaterialEditor.js +1 -0
- package/dist/cjs/model/ModelEditor.js +7 -1
- package/dist/cjs/model/ModelEditorMenuBar.js +5 -5
- package/dist/cjs/model/ModelEditorRightPanel.js +13 -9
- package/dist/cjs/model/ModelEditorSubComponents.js +9 -3
- package/dist/cjs/model/ModelEditorTimeline.js +3 -1
- package/dist/cjs/model/ModelEditorToolbar.js +1 -1
- package/dist/cjs/model/ModelEditorViewport.js +5 -2
- package/dist/cjs/model/ModelViewer.js +4 -4
- package/dist/cjs/model/NiceArmatureEditor.js +4 -4
- package/dist/cjs/model/NiceMorphTargetEditor.js +3 -1
- package/dist/cjs/model/NiceOctree.js +7 -4
- package/dist/cjs/model/NicePhysicsSimulation.js +4 -4
- package/dist/cjs/model/NiceProceduralGeometry.js +3 -3
- package/dist/cjs/model/NiceTerrainEditor.js +2 -2
- package/dist/cjs/model/NiceWeightPainter.js +2 -2
- package/dist/cjs/model/NiceXRPreview.js +6 -3
- package/dist/cjs/model/useModelEditor.js +92 -73
- package/dist/cjs/model/useModelViewer.js +13 -6
- package/dist/cjs/particle/NiceParticleEditor.js +10 -3
- package/dist/cjs/rendering/NiceCascadedShadows.js +1 -1
- package/dist/cjs/rendering/NiceRenderExport.js +2 -2
- package/dist/cjs/rendering/NiceSSAO.js +2 -1
- package/dist/cjs/rendering/NiceSSR.js +2 -1
- package/dist/cjs/rendering/NiceWebGPURenderer.js +2 -1
- package/dist/cjs/uv/NiceUVEditor.js +3 -3
- package/dist/esm/material/NiceMaterialEditor.js +1 -0
- package/dist/esm/model/ModelEditor.js +7 -1
- package/dist/esm/model/ModelEditorMenuBar.js +5 -5
- package/dist/esm/model/ModelEditorRightPanel.js +13 -9
- package/dist/esm/model/ModelEditorSubComponents.js +9 -3
- package/dist/esm/model/ModelEditorTimeline.js +3 -1
- package/dist/esm/model/ModelEditorToolbar.js +1 -1
- package/dist/esm/model/ModelEditorViewport.js +5 -2
- package/dist/esm/model/ModelViewer.js +4 -4
- package/dist/esm/model/NiceArmatureEditor.js +4 -4
- package/dist/esm/model/NiceMorphTargetEditor.js +3 -1
- package/dist/esm/model/NiceOctree.js +7 -4
- package/dist/esm/model/NicePhysicsSimulation.js +4 -4
- package/dist/esm/model/NiceProceduralGeometry.js +3 -3
- package/dist/esm/model/NiceTerrainEditor.js +2 -2
- package/dist/esm/model/NiceWeightPainter.js +2 -2
- package/dist/esm/model/NiceXRPreview.js +6 -3
- package/dist/esm/model/useModelEditor.js +92 -73
- package/dist/esm/model/useModelViewer.js +13 -6
- package/dist/esm/particle/NiceParticleEditor.js +10 -3
- package/dist/esm/rendering/NiceCascadedShadows.js +1 -1
- package/dist/esm/rendering/NiceRenderExport.js +2 -2
- package/dist/esm/rendering/NiceSSAO.js +2 -1
- package/dist/esm/rendering/NiceSSR.js +2 -1
- package/dist/esm/rendering/NiceWebGPURenderer.js +2 -1
- package/dist/esm/uv/NiceUVEditor.js +3 -3
- package/package.json +2 -2
|
@@ -281,6 +281,7 @@ function useSSAO(renderer, scene, camera, configOverride) {
|
|
|
281
281
|
blurMat.dispose();
|
|
282
282
|
ortho.remove(quad);
|
|
283
283
|
};
|
|
284
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the uniforms' first values; the next effect updates them without rebuilding the render targets
|
|
284
285
|
}, [renderer, camera, config.resolution]);
|
|
285
286
|
// Update uniforms
|
|
286
287
|
useEffect(() => {
|
|
@@ -339,7 +340,7 @@ function useSSAO(renderer, scene, camera, configOverride) {
|
|
|
339
340
|
const NiceSSAO = ({ renderer, scene, camera, config: configProp, className = '', }) => {
|
|
340
341
|
const { t } = useNiceTranslation();
|
|
341
342
|
const { config, setConfig } = useSSAO(renderer, scene, camera, configProp);
|
|
342
|
-
return (jsxs("div", { className: `nice-ssao ${className}`, style: { display: 'grid', gap: 8, fontSize: 13 }, children: [jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxs("strong", { children: [jsx(NiceIcon, { name: "circle", size: 14 }), " ", t('ssao.ambientOcclusion', 'Ambient Occlusion')] }), jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 11 }, children: [jsx("input", { type: "checkbox", checked: config.enabled, onChange: (e) => setConfig({ enabled: e.target.checked }) }), t('ssao.enabled', 'Enabled')] })] }), jsxs("label", { children: [
|
|
343
|
+
return (jsxs("div", { className: `nice-ssao ${className}`, style: { display: 'grid', gap: 8, fontSize: 13 }, children: [jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxs("strong", { children: [jsx(NiceIcon, { name: "circle", size: 14 }), " ", t('ssao.ambientOcclusion', 'Ambient Occlusion')] }), jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 11 }, children: [jsx("input", { type: "checkbox", checked: config.enabled, onChange: (e) => setConfig({ enabled: e.target.checked }) }), t('ssao.enabled', 'Enabled')] })] }), jsxs("label", { children: [t('ssao.mode', 'Mode:'), jsxs("select", { value: config.mode, onChange: (e) => setConfig({ mode: e.target.value }), style: { width: '100%', marginTop: 2 }, children: [jsx("option", { value: "ssao", children: t('ssao.ssao', 'SSAO') }), jsx("option", { value: "hbao", children: t('ssao.hbao', 'HBAO') })] })] }), jsxs("label", { children: [t('ssao.samples', 'Samples: {samples}').replace('{samples}', String(config.samples)), jsx("input", { type: "range", min: 8, max: 128, step: 8, value: config.samples, onChange: (e) => setConfig({ samples: parseInt(e.target.value, 10) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssao.radius', 'Radius: {radius}').replace('{radius}', String(config.radius.toFixed(2))), jsx("input", { type: "range", min: 0.1, max: 5, step: 0.1, value: config.radius, onChange: (e) => setConfig({ radius: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssao.intensity', 'Intensity: {intensity}').replace('{intensity}', String(config.intensity.toFixed(2))), jsx("input", { type: "range", min: 0, max: 3, step: 0.1, value: config.intensity, onChange: (e) => setConfig({ intensity: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssao.bias', 'Bias: {bias}').replace('{bias}', String(config.bias.toFixed(3))), jsx("input", { type: "range", min: 0.001, max: 0.1, step: 0.001, value: config.bias, onChange: (e) => setConfig({ bias: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssao.resolution', 'Resolution: {resolution}').replace('{resolution}', String(config.resolution.toFixed(2))), jsx("input", { type: "range", min: 0.25, max: 1, step: 0.25, value: config.resolution, onChange: (e) => setConfig({ resolution: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: 6 }, children: [jsx("input", { type: "checkbox", checked: config.blurEnabled, onChange: (e) => setConfig({ blurEnabled: e.target.checked }) }), t('ssao.bilateralBlurSize', 'Bilateral Blur (size: {blurSize})').replace('{blurSize}', String(config.blurSize))] })] }));
|
|
343
344
|
};
|
|
344
345
|
|
|
345
346
|
export { NiceSSAO, useSSAO };
|
|
@@ -207,6 +207,7 @@ function useSSR(renderer, scene, camera, configOverride) {
|
|
|
207
207
|
material.dispose();
|
|
208
208
|
ortho.remove(quad);
|
|
209
209
|
};
|
|
210
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- the uniforms' first values; the next effect updates them without rebuilding the render targets
|
|
210
211
|
}, [renderer, camera, config.resolution]);
|
|
211
212
|
// Update uniforms when config changes
|
|
212
213
|
useEffect(() => {
|
|
@@ -256,7 +257,7 @@ function useSSR(renderer, scene, camera, configOverride) {
|
|
|
256
257
|
const NiceSSR = ({ renderer, scene, camera, config: configProp, className = '', }) => {
|
|
257
258
|
const { t } = useNiceTranslation();
|
|
258
259
|
const { config, setConfig } = useSSR(renderer, scene, camera, configProp);
|
|
259
|
-
return (jsxs("div", { className: `nice-ssr ${className}`, style: { display: 'grid', gap: 8, fontSize: 13 }, children: [jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxs("strong", { children: [jsx(NiceIcon, { name: "copy", size: 14 }), ' ', t('ssr.screenSpaceReflections', 'Screen-Space Reflections')] }), jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 11 }, children: [jsx("input", { type: "checkbox", checked: config.enabled, onChange: (e) => setConfig({ enabled: e.target.checked }) }), t('ssr.enabled', 'Enabled')] })] }), jsxs("label", { children: [
|
|
260
|
+
return (jsxs("div", { className: `nice-ssr ${className}`, style: { display: 'grid', gap: 8, fontSize: 13 }, children: [jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [jsxs("strong", { children: [jsx(NiceIcon, { name: "copy", size: 14 }), ' ', t('ssr.screenSpaceReflections', 'Screen-Space Reflections')] }), jsxs("label", { style: { display: 'flex', alignItems: 'center', gap: 4, fontSize: 11 }, children: [jsx("input", { type: "checkbox", checked: config.enabled, onChange: (e) => setConfig({ enabled: e.target.checked }) }), t('ssr.enabled', 'Enabled')] })] }), jsxs("label", { children: [t('ssr.maxSteps', 'Max Steps: {maxSteps}').replace('{maxSteps}', String(config.maxSteps)), jsx("input", { type: "range", min: 16, max: 256, step: 16, value: config.maxSteps, onChange: (e) => setConfig({ maxSteps: parseInt(e.target.value, 10) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.maxDistance', 'Max Distance: {maxDistance}').replace('{maxDistance}', String(config.maxDistance)), jsx("input", { type: "range", min: 5, max: 200, step: 5, value: config.maxDistance, onChange: (e) => setConfig({ maxDistance: parseInt(e.target.value, 10) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.intensity', 'Intensity: {intensity}').replace('{intensity}', String(config.intensity.toFixed(2))), jsx("input", { type: "range", min: 0, max: 1, step: 0.05, value: config.intensity, onChange: (e) => setConfig({ intensity: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.thickness', 'Thickness: {thickness}').replace('{thickness}', String(config.thickness.toFixed(2))), jsx("input", { type: "range", min: 0.05, max: 2, step: 0.05, value: config.thickness, onChange: (e) => setConfig({ thickness: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.jitter', 'Jitter: {jitter}').replace('{jitter}', String(config.jitter.toFixed(2))), jsx("input", { type: "range", min: 0, max: 1, step: 0.05, value: config.jitter, onChange: (e) => setConfig({ jitter: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.resolutionScale', 'Resolution Scale: {resolution}').replace('{resolution}', String(config.resolution.toFixed(2))), jsx("input", { type: "range", min: 0.25, max: 1, step: 0.25, value: config.resolution, onChange: (e) => setConfig({ resolution: parseFloat(e.target.value) }), style: { width: '100%' } })] }), jsxs("label", { children: [t('ssr.fresnel', 'Fresnel: {fresnelExponent}').replace('{fresnelExponent}', String(config.fresnelExponent.toFixed(1))), jsx("input", { type: "range", min: 1, max: 8, step: 0.5, value: config.fresnelExponent, onChange: (e) => setConfig({ fresnelExponent: parseFloat(e.target.value) }), style: { width: '100%' } })] })] }));
|
|
260
261
|
};
|
|
261
262
|
|
|
262
263
|
export { NiceSSR, useSSR };
|
|
@@ -131,6 +131,7 @@ function useWebGPURenderer(canvas, scene, camera, width = 800, height = 600, onR
|
|
|
131
131
|
disposed = true;
|
|
132
132
|
(_a = rendererRef.current) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
133
133
|
};
|
|
134
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- one renderer per canvas, made with the first settings; the effects below apply later changes, and onRendererReady reports that one renderer
|
|
134
135
|
}, [canvas]);
|
|
135
136
|
// Update renderer settings reactively
|
|
136
137
|
useEffect(() => {
|
|
@@ -218,7 +219,7 @@ const NiceWebGPURenderer = ({ canvas, scene, camera, width, height, onRendererRe
|
|
|
218
219
|
borderRadius: 4,
|
|
219
220
|
background: isWebGPU ? 'var(--nice-success, #22c55e)' : 'var(--nice-warning, #f59e0b)',
|
|
220
221
|
color: 'var(--nice-color-white, #fff)',
|
|
221
|
-
}, children: isWebGPU ? 'WebGPU' : 'WebGL' })] }), !isReady && jsx("div", { style: { opacity: 0.6, fontSize: 11 }, children:
|
|
222
|
+
}, children: isWebGPU ? 'WebGPU' : 'WebGL' })] }), !isReady && (jsx("div", { style: { opacity: 0.6, fontSize: 11 }, children: t('webGPURenderer.initializing', 'Initializing…') })), capabilities && (jsxs("div", { style: { fontSize: 10, opacity: 0.7, lineHeight: 1.5 }, children: [t('webGPURenderer.gpu', 'GPU: {adapterName}').replace('{adapterName}', String(capabilities.adapterName)), jsx("br", {}), t('webGPURenderer.vendor', 'Vendor: {vendor}').replace('{vendor}', String(capabilities.vendor)), jsx("br", {}), t('webGPURenderer.maxTexturePx', 'Max Texture: {maxTextureDimension2D}px').replace('{maxTextureDimension2D}', String(capabilities.maxTextureDimension2D)), capabilities.features.length > 0 && (jsxs(Fragment, { children: [jsx("br", {}), t('webGPURenderer.features', 'Features: {features}').replace('{features}', String(capabilities.features.length))] }))] })), jsxs("label", { children: [t('webGPURenderer.toneMapping', 'Tone Mapping:'), jsx("select", { value: toneMapping, onChange: (e) => setToneMapping(parseInt(e.target.value, 10)), style: { width: '100%', marginTop: 2 }, children: TONE_MAPPINGS.map((tm) => (jsx("option", { value: tm.value, children: tm.label }, tm.value))) })] }), jsxs("label", { children: [t('webGPURenderer.exposure', 'Exposure: {toneMappingExposure}').replace('{toneMappingExposure}', String(toneMappingExposure.toFixed(2))), jsx("input", { type: "range", min: 0.1, max: 3, step: 0.05, value: toneMappingExposure, onChange: (e) => setToneMappingExposure(parseFloat(e.target.value)), style: { width: '100%' } })] }), jsxs("label", { children: [t('webGPURenderer.outputColorSpace', 'Output Color Space:'), jsxs("select", { value: outputColorSpace, onChange: (e) => setOutputColorSpace(e.target.value), style: { width: '100%', marginTop: 2 }, children: [jsx("option", { value: THREE.SRGBColorSpace, children: "sRGB" }), jsx("option", { value: THREE.LinearSRGBColorSpace, children: t('webGPURenderer.linearSrgb', 'Linear sRGB') })] })] }), jsxs("label", { children: [t('webGPURenderer.pixelRatio', 'Pixel Ratio: {pixelRatio}').replace('{pixelRatio}', String(pixelRatio.toFixed(1))), jsx("input", { type: "range", min: 0.5, max: 3, step: 0.5, value: pixelRatio, onChange: (e) => setPixelRatio(parseFloat(e.target.value)), style: { width: '100%' } })] })] }));
|
|
222
223
|
};
|
|
223
224
|
|
|
224
225
|
export { NiceWebGPURenderer, useWebGPURenderer };
|
|
@@ -551,14 +551,14 @@ const NiceUVEditor = ({ geometry, texture, channel = 'uv', onUVChange, onSelecti
|
|
|
551
551
|
})) }), t('uvEditor.showDistortion', 'Show Distortion')] }), jsxs("label", { className: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: state.display.showIslandBounds, onChange: (e) => setState((prev) => ({
|
|
552
552
|
...prev,
|
|
553
553
|
display: { ...prev.display, showIslandBounds: e.target.checked },
|
|
554
|
-
})) }), t('uvEditor.showIslandBounds', 'Show Island Bounds')] })] }), jsxs("div", { className: styles.panel, children: [jsx("h4", { className: styles.panelTitle, children: t('uvEditor.statistics', 'Statistics') }), jsxs("div", { className: styles.stat, children: [jsx("span", { children:
|
|
554
|
+
})) }), t('uvEditor.showIslandBounds', 'Show Island Bounds')] })] }), jsxs("div", { className: styles.panel, children: [jsx("h4", { className: styles.panelTitle, children: t('uvEditor.statistics', 'Statistics') }), jsxs("div", { className: styles.stat, children: [jsx("span", { children: t('uvEditor.vertices', 'Vertices:') }), jsx("span", { children: meshData.vertices.size })] }), jsxs("div", { className: styles.stat, children: [jsx("span", { children: t('uvEditor.faces', 'Faces:') }), jsx("span", { children: meshData.faces.size })] }), jsxs("div", { className: styles.stat, children: [jsx("span", { children: t('uvEditor.islands', 'Islands:') }), jsx("span", { children: meshData.islands.size })] }), jsxs("div", { className: styles.stat, children: [jsx("span", { children: t('uvEditor.selected', 'Selected:') }), jsx("span", { children: getSelectedVertices(meshData).length })] })] }), jsxs("div", { className: styles.panel, children: [jsx("h4", { className: styles.panelTitle, children: t('uvEditor.snapping', 'Snapping') }), jsxs("label", { className: styles.checkbox, children: [jsx("input", { type: "checkbox", checked: state.snapping, onChange: (e) => setState((prev) => ({
|
|
555
555
|
...prev,
|
|
556
556
|
snapping: e.target.checked,
|
|
557
|
-
})) }), t('uvEditor.enableSnapping', 'Enable Snapping')] }), jsxs("label", { className: styles.rangeLabel, children: [
|
|
557
|
+
})) }), t('uvEditor.enableSnapping', 'Enable Snapping')] }), jsxs("label", { className: styles.rangeLabel, children: [t('uvEditor.snapSize', 'Snap Size: {snapSize}').replace('{snapSize}', String(state.snapSize.toFixed(4))), jsx("input", { type: "range", min: "0.001", max: "0.25", step: "0.001", value: state.snapSize, onChange: (e) => setState((prev) => ({
|
|
558
558
|
...prev,
|
|
559
559
|
snapSize: parseFloat(e.target.value),
|
|
560
560
|
})) })] })] })] })) : undefined;
|
|
561
|
-
return (jsxs("div", { style: { position: 'relative', width, height }, children: [jsx("span", { style: { position: 'absolute', top: 6, right: 6, zIndex: 30 }, children: jsx(NiceTutorialButton, { steps: resolveTutorial(tutorial, UV_EDITOR_TOUR) }) }), jsx(NiceAppShell, { className: `nice-uv-editor ${styles.uvEditor} ${className !== null && className !== void 0 ? className : ''}`, flush: true, toolbar: toolbarSlot, rightSidebar: sidebarSlot, statusBar: jsxs("div", { className: styles.statusBar, children: [
|
|
561
|
+
return (jsxs("div", { style: { position: 'relative', width, height }, children: [jsx("span", { style: { position: 'absolute', top: 6, right: 6, zIndex: 30 }, children: jsx(NiceTutorialButton, { steps: resolveTutorial(tutorial, UV_EDITOR_TOUR) }) }), jsx(NiceAppShell, { className: `nice-uv-editor ${styles.uvEditor} ${className !== null && className !== void 0 ? className : ''}`, flush: true, toolbar: toolbarSlot, rightSidebar: sidebarSlot, statusBar: jsxs("div", { className: styles.statusBar, children: [jsx("span", { children: t('uvEditor.tool', 'Tool: {activeTool}').replace('{activeTool}', String(state.activeTool)) }), jsx("span", { children: t('uvEditor.mode', 'Mode: {selectionMode}').replace('{selectionMode}', String(state.selectionMode)) }), jsx("span", { children: t('uvEditor.zoom', 'Zoom: {zoom}%').replace('{zoom}', String((state.zoom * 100).toFixed(0))) }), jsx("span", { children: t('uvEditor.channel', 'Channel: {activeChannel}').replace('{activeChannel}', String(state.activeChannel)) })] }), children: jsxs("div", { ref: containerRef, className: styles.viewport, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, onMouseLeave: handleMouseUp, onWheel: handleWheel, children: [jsx("canvas", { ref: canvasRef, className: styles.canvas }), !meshData && (jsx("div", { className: styles.noGeometry, children: t('uvEditor.noGeometrySelected', 'No geometry selected') }))] }) })] }));
|
|
562
562
|
};
|
|
563
563
|
|
|
564
564
|
export { NiceUVEditor };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nice2dev/ui-3d",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Nice2Dev 3D Editor — Blender-style 3D model editor component for React, powered by Three.js",
|
|
5
5
|
"author": "NiceToDev <contact@nicetodev.com>",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"three": ">=0.150.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@nice2dev/ui": "^1.2.
|
|
68
|
+
"@nice2dev/ui": "^1.2.2",
|
|
69
69
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
70
70
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
71
71
|
"@rollup/plugin-typescript": "^12.3.0",
|